mirror of
				https://github.com/Cisco-Talos/clamav.git
				synced 2025-10-31 16:10:54 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			328 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			328 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *  Detect environment for bytecode.
 | |
|  *
 | |
|  *  Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
 | |
|  *  Copyright (C) 2009-2010 Sourcefire, Inc.
 | |
|  *
 | |
|  *  Authors: Török Edvin
 | |
|  *
 | |
|  *  This program is free software; you can redistribute it and/or modify
 | |
|  *  it under the terms of the GNU General Public License version 2 as
 | |
|  *  published by the Free Software Foundation.
 | |
|  *
 | |
|  *  This program is distributed in the hope that it will be useful,
 | |
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  *  GNU General Public License for more details.
 | |
|  *
 | |
|  *  You should have received a copy of the GNU General Public License
 | |
|  *  along with this program; if not, write to the Free Software
 | |
|  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 | |
|  *  MA 02110-1301, USA.
 | |
|  */
 | |
| 
 | |
| #if HAVE_CONFIG_H
 | |
| #include "clamav-config.h"
 | |
| #endif
 | |
| 
 | |
| #include "clamav.h"
 | |
| #include "target.h"
 | |
| #include "cltypes.h"
 | |
| 
 | |
| #include "bytecode_detect.h"
 | |
| #include "others.h"
 | |
| #include <string.h>
 | |
| #include <stdio.h>
 | |
| #include <errno.h>
 | |
| 
 | |
| #ifdef HAVE_UNAME_SYSCALL
 | |
| #include <sys/utsname.h>
 | |
| #endif
 | |
| 
 | |
| #define CHECK_ARCH(a) if (!strcmp(TARGET_ARCH_TYPE, #a)) env->arch = arch_##a
 | |
| 
 | |
| extern int have_clamjit;
 | |
| 
 | |
| static void cli_print_environment(struct cli_environment *env)
 | |
| {
 | |
|     uint32_t id_a = env->platform_id_a;
 | |
|     uint32_t id_b = env->platform_id_b;
 | |
|     uint32_t id_c = env->platform_id_c;
 | |
|     /* the bytecode instruction that exactly identifies this platform */
 | |
|     /* the space separated groups can be a concrete value, or 0xff for ANY */
 | |
|     cli_dbgmsg("environment detected:\n");
 | |
|     cli_dbgmsg("check_platform(0x%08x, 0x%08x, 0x%08x)\n",
 | |
| 	       id_a, id_b, id_c);
 | |
|     cli_dbgmsg("check_platform(0x%02x  %01x  %01x  %02x  %02x,"
 | |
| 	       "0x%01x  %01x       %02x %02x %02x,"
 | |
| 	       "0x%02x    %02x %02x %02x)\n",
 | |
| 	       env->os_category, env->arch, env->compiler,
 | |
| 	       env->functionality_level,
 | |
| 	       env->dconf_level,
 | |
|                env->big_endian,
 | |
|                env->sizeof_ptr,
 | |
| 	       (env->cpp_version >> 16)&0xff,
 | |
| 	       (env->cpp_version >> 8)&0xff,
 | |
| 	       env->cpp_version&0xff,
 | |
| 	       env->os_features,
 | |
| 	       (env->c_version >> 16)&0xff,
 | |
| 	       (env->c_version >> 8)&0xff,
 | |
| 	       env->c_version&0xff);
 | |
|     cli_dbgmsg("check_platform( OS CPU COM FL DCONF,BE PTR CXX VV.VV.VV, FLG CC VV.VV.VV)\n");
 | |
|     cli_dbgmsg("Engine version: %s\n", env->engine_version);
 | |
|     cli_dbgmsg("Host triple: %s\n", env->triple);
 | |
|     cli_dbgmsg("Host CPU: %s\n", env->cpu);
 | |
|     cli_dbgmsg("OS: %s\n", env->sysname);
 | |
|     cli_dbgmsg("OS release: %s\n", env->release);
 | |
|     cli_dbgmsg("OS version: %s\n", env->version);
 | |
|     cli_dbgmsg("OS hardware: %s\n", env->machine);
 | |
|     cli_dbgmsg("OS LLVM category: %d\n", env->os);
 | |
|     cli_dbgmsg("Has JIT compiled: %d\n", env->has_jit_compiled);
 | |
|     cli_dbgmsg("------------------------------------------------------\n");
 | |
| }
 | |
| 
 | |
| #ifdef __linux__
 | |
| 
 | |
| static int detect_PaX(void)
 | |
| {
 | |
|     char line[128];
 | |
|     int pax = 0;
 | |
|     FILE *f = fopen("/proc/self/status", "r");
 | |
|     if (!f)
 | |
| 	return 0;
 | |
|     while (fgets(line, sizeof(line), f)) {
 | |
| 	if (!memcmp(line, "PaX:", 4)) {
 | |
| 	    pax = 1;
 | |
| 	    if (!strchr(line,'m'))
 | |
| 		pax = 2;
 | |
| 	    break;
 | |
| 	}
 | |
|     }
 | |
|     fclose(f);
 | |
|     return pax;
 | |
| }
 | |
| 
 | |
| static int detect_SELinux(void)
 | |
| {
 | |
|     char line[128];
 | |
|     int selinux = 0;
 | |
|     int enforce = 0;
 | |
|     FILE *f = fopen("/proc/filesystems", "r");
 | |
|     if (!f) {
 | |
| 	f = fopen("/selinux/enforce", "r");
 | |
|         if (!f && errno == EACCES)
 | |
| 		return 2;
 | |
| 	if (f) {
 | |
| 	    if (fscanf(f, "%d", &enforce) == 1)
 | |
| 		selinux = 2;
 | |
| 	    fclose(f);
 | |
| 	}
 | |
| 	return selinux;
 | |
|     }
 | |
|     while (fgets(line, sizeof(line), f)) {
 | |
| 	if (strstr(line, "selinuxfs\n")) {
 | |
| 	    selinux = 1;
 | |
| 	    break;
 | |
| 	}
 | |
|     }
 | |
|     fclose(f);
 | |
|     if (!selinux)
 | |
| 	return 0;
 | |
| 
 | |
|     f = fopen("/selinux/enforce", "r");
 | |
|     if (f) {
 | |
| 	if (fscanf(f, "%d", &enforce) == 1) {
 | |
| 	    if (enforce == 1)
 | |
| 		selinux = 2;
 | |
| 	    if (enforce == -1)
 | |
| 		selinux = 0;
 | |
| 	}
 | |
| 	fclose(f);
 | |
|     }
 | |
|     return selinux;
 | |
| }
 | |
| 
 | |
| static void detect_os_features(uint8_t *os_features)
 | |
| {
 | |
|     int features = 0;
 | |
|     switch (detect_PaX()) {
 | |
| 	case 2:
 | |
| 	    features |= 1 << feature_pax_mprotect;
 | |
| 	    /* fall through */
 | |
| 	case 1:
 | |
| 	    features |= 1 << feature_pax;
 | |
| 	    break;
 | |
| 	default:
 | |
| 	    break;
 | |
|     }
 | |
|     switch (detect_SELinux()) {
 | |
| 	case 2:
 | |
| 	    features |= 1 << feature_selinux_enforcing;
 | |
| 	    /* fall through */
 | |
| 	case 1:
 | |
| 	    features |= 1 << feature_selinux;
 | |
| 	    break;
 | |
| 	default:
 | |
| 	    break;
 | |
|     }
 | |
| 
 | |
|     *os_features = features;
 | |
| }
 | |
| #else
 | |
| static void detect_os_features(uint8_t *os_features)
 | |
| {
 | |
|     *os_features = 0;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /* OS features : 
 | |
|  * Linux: PaX << 2| SELinux << 1| mmap-RWX
 | |
|  * Other:                         mmap-RWX */
 | |
| 
 | |
| void cli_detect_environment(struct cli_environment *env)
 | |
| {
 | |
|     memset(env, 0, sizeof(*env));
 | |
| #if WORDS_BIGENDIAN == 0
 | |
|     env->big_endian = 0;
 | |
| #else
 | |
|     env->big_endian = 1;
 | |
| #endif
 | |
|     env->sizeof_ptr = sizeof(void*);
 | |
| 
 | |
|     /* -- Detect arch -- */
 | |
|     CHECK_ARCH(i386);
 | |
|     else CHECK_ARCH(x86_64);
 | |
|     else if (!strcmp(TARGET_ARCH_TYPE,"amd64")) env->arch = arch_x86_64;
 | |
|     else if (!strcmp(TARGET_ARCH_TYPE,"ppc")) env->arch = arch_ppc32;/* llvm will fix ppc64 */
 | |
|     else CHECK_ARCH(arm);
 | |
|     else CHECK_ARCH(sparc);
 | |
|     else CHECK_ARCH(sparc64);
 | |
|     else CHECK_ARCH(mips);
 | |
|     else CHECK_ARCH(mips64);
 | |
|     else CHECK_ARCH(alpha);
 | |
|     else CHECK_ARCH(hppa1);
 | |
|     else CHECK_ARCH(hppa2);
 | |
|     else CHECK_ARCH(m68k);
 | |
|     else env->arch = arch_unknown;
 | |
| 
 | |
|     /* -- Detect OS -- */
 | |
| #ifdef C_AIX
 | |
|     env->os_category = os_aix;
 | |
| #elif defined(C_BEOS)
 | |
|     env->os_category = os_beos;
 | |
|     /* DARWIN must come before BSD since it defines both */
 | |
| #elif defined(C_DARWIN)
 | |
|     env->os_category = os_darwin;
 | |
| #elif defined(C_BSD)
 | |
|     env->os_category = os_bsd;
 | |
| #elif defined(C_GNU_HURD)
 | |
|     env->os_category = os_gnu_hurd;
 | |
| #elif defined(C_HPUX)
 | |
|     env->os_category = os_hpux;
 | |
| #elif defined(C_INTERIX)
 | |
|     env->os_category = os_interix;
 | |
| #elif defined(C_IRIX)
 | |
|     env->os_category = os_irix;
 | |
| #elif defined(C_KFREEBSD_GNU)
 | |
|     env->os_category = os_kfreebsd_gnu;
 | |
| #elif defined(C_LINUX)
 | |
|     env->os_category = os_linux;
 | |
| #elif defined(C_OS2)
 | |
|     env->os_category = os_os2;
 | |
| #elif defined(C_OSF)
 | |
|     env->os_category = os_osf;
 | |
| #elif defined(C_QNX6)
 | |
|     env->os_category = os_qnx6;
 | |
| #elif defined(C_SOLARIS)
 | |
|     env->os_category = os_solaris;
 | |
| #elif defined(_WIN64)
 | |
|     env->os_category = os_win64;
 | |
| #elif defined(_WIN32)
 | |
|     env->os_category = os_win32;
 | |
| #else
 | |
|     env->os_category = os_generic;
 | |
| #endif
 | |
| 
 | |
|     env->os = llvm_os_UnknownOS;
 | |
|     /* -- Detect compiler -- */
 | |
| 
 | |
|     /* check GNUC last, because some other compilers might define it */
 | |
| #ifdef __INTEL_COMPILER
 | |
|     env->compiler = compiler_intel;
 | |
|     env->c_version = __INTEL_COMPILER;
 | |
| #elif defined(_MSC_VER)
 | |
|     env->compiler = compiler_msc;
 | |
|     env->c_version = _MSC_VER;
 | |
| #elif defined(__SUNPRO_C)
 | |
|     env->compiler = compiler_sun;
 | |
|     env->c_version = __SUNPRO_C;
 | |
| #elif defined(__GNUC__)
 | |
| 
 | |
| #ifdef __clang__
 | |
|     env->compiler = compiler_clang;
 | |
| #elif defined(__llvm__)
 | |
|     env->compiler = compiler_llvm;
 | |
| #else
 | |
|     env->compiler = compiler_gnuc;
 | |
| #endif
 | |
|     env->c_version =
 | |
| 	MAKE_VERSION(0, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
 | |
| 
 | |
| #else
 | |
|     env->compiler = compiler_other;
 | |
|     env->c_version = 0;
 | |
| #endif
 | |
|     env->cpp_version = 0;
 | |
| 
 | |
|     env->has_jit_compiled = have_clamjit;
 | |
| 
 | |
|     /* engine */
 | |
|     env->functionality_level = cl_retflevel();
 | |
|     env->dconf_level = CL_FLEVEL_DCONF;
 | |
| 
 | |
|     INIT_STRFIELD(env->engine_version, cl_retver());
 | |
| #ifdef HAVE_UNAME_SYSCALL
 | |
|     {
 | |
| 	struct utsname name;
 | |
| 	if (uname(&name) == 0) {
 | |
| 	    INIT_STRFIELD(env->sysname, name.sysname);
 | |
| 	    INIT_STRFIELD(env->release, name.release);
 | |
| 	    INIT_STRFIELD(env->version, name.version);
 | |
| 	    INIT_STRFIELD(env->machine, name.machine);
 | |
| 	}
 | |
|     }
 | |
| #endif
 | |
| #ifdef _WIN32
 | |
|     {
 | |
| 	OSVERSIONINFOEX info;
 | |
| 	info.dwOSVersionInfoSize = sizeof(info);
 | |
| 	if (GetVersionEx((OSVERSIONINFO *)&info) != 0 && info.dwPlatformId == VER_PLATFORM_WIN32_NT) {
 | |
| 	    if (info.wProductType == VER_NT_WORKSTATION)
 | |
| 		INIT_STRFIELD(env->sysname, "Microsoft Windows");
 | |
| 	    else
 | |
| 		INIT_STRFIELD(env->sysname, "Microsoft Windows Server");
 | |
| 	    snprintf((char*)env->release, sizeof(env->release), "%d.%d SP%d.%d",
 | |
| 		     info.dwMajorVersion, info.dwMinorVersion,
 | |
| 		     info.wServicePackMajor, info.wServicePackMinor);
 | |
| 	    snprintf((char*)env->version, sizeof(env->version),"Build %d",
 | |
| 		     info.dwBuildNumber);
 | |
| 	}
 | |
|     }
 | |
|     
 | |
| #endif
 | |
|     if (!env->sysname[0]) {
 | |
| 	INIT_STRFIELD(env->sysname, TARGET_OS_TYPE);
 | |
|     }
 | |
| 
 | |
|     detect_os_features(&env->os_features);
 | |
| 
 | |
|     cli_detect_env_jit(env);
 | |
| 
 | |
|     env->platform_id_a = (env->os_category << 24) | (env->arch << 20) |
 | |
| 	(env->compiler << 16) | (env->functionality_level << 8) |
 | |
| 	(env->dconf_level);
 | |
|     env->platform_id_b = (env->big_endian << 28) | (env->sizeof_ptr << 24) |
 | |
|       env->cpp_version;
 | |
|     env->platform_id_c = (env->os_features << 24) | env->c_version;
 | |
|     cli_print_environment(env);
 | |
| }
 | 
