1 /*
2 * Detect environment for bytecode.
3 *
4 * Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5 * Copyright (C) 2009-2013 Sourcefire, Inc.
6 *
7 * Authors: Török Edvin
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 * MA 02110-1301, USA.
22 */
23
24 #if HAVE_CONFIG_H
25 #include "clamav-config.h"
26 #endif
27
28 #include "clamav.h"
29 #include "target.h"
30
31 #include "bytecode_detect.h"
32 #include "others.h"
33 #include <string.h>
34 #include <stdio.h>
35 #include <errno.h>
36
37 #ifdef HAVE_UNAME_SYSCALL
38 #include <sys/utsname.h>
39 #endif
40
41 #define CHECK_ARCH(a) \
42 if (!strcmp(TARGET_ARCH_TYPE, #a)) env->arch = arch_##a
43
44 extern int have_clamjit;
45
cli_print_environment(struct cli_environment * env)46 static void cli_print_environment(struct cli_environment *env)
47 {
48 uint32_t id_a = env->platform_id_a;
49 uint32_t id_b = env->platform_id_b;
50 uint32_t id_c = env->platform_id_c;
51 /* the bytecode instruction that exactly identifies this platform */
52 /* the space separated groups can be a concrete value, or 0xff for ANY */
53 cli_dbgmsg("environment detected:\n");
54 cli_dbgmsg("check_platform(0x%08x, 0x%08x, 0x%08x)\n",
55 id_a, id_b, id_c);
56 cli_dbgmsg("check_platform(0x%02x %01x %01x %02x %02x,"
57 "0x%01x %01x %02x %02x %02x,"
58 "0x%02x %02x %02x %02x)\n",
59 env->os_category, env->arch, env->compiler,
60 env->functionality_level,
61 env->dconf_level,
62 env->big_endian,
63 env->sizeof_ptr,
64 (env->cpp_version >> 16) & 0xff,
65 (env->cpp_version >> 8) & 0xff,
66 env->cpp_version & 0xff,
67 env->os_features,
68 (env->c_version >> 16) & 0xff,
69 (env->c_version >> 8) & 0xff,
70 env->c_version & 0xff);
71 cli_dbgmsg("check_platform( OS CPU COM FL DCONF,BE PTR CXX VV.VV.VV, FLG CC VV.VV.VV)\n");
72 cli_dbgmsg("Engine version: %s\n", env->engine_version);
73 cli_dbgmsg("Host triple: %s\n", env->triple);
74 cli_dbgmsg("Host CPU: %s\n", env->cpu);
75 cli_dbgmsg("OS: %s\n", env->sysname);
76 cli_dbgmsg("OS release: %s\n", env->release);
77 cli_dbgmsg("OS version: %s\n", env->version);
78 cli_dbgmsg("OS hardware: %s\n", env->machine);
79 cli_dbgmsg("OS LLVM category: %d\n", env->os);
80 cli_dbgmsg("Has JIT compiled: %d\n", env->has_jit_compiled);
81 cli_dbgmsg("------------------------------------------------------\n");
82 }
83
84 #ifdef __linux__
85
detect_PaX(void)86 static int detect_PaX(void)
87 {
88 char line[128];
89 int pax = 0;
90 FILE *f = fopen("/proc/self/status", "r");
91 if (!f)
92 return 0;
93 while (fgets(line, sizeof(line), f)) {
94 if (!memcmp(line, "PaX:", 4)) {
95 pax = 1;
96 if (!strchr(line, 'm'))
97 pax = 2;
98 break;
99 }
100 }
101 fclose(f);
102 return pax;
103 }
104
detect_SELinux(void)105 static int detect_SELinux(void)
106 {
107 char line[128];
108 int selinux = 0;
109 int enforce = 0;
110 FILE *f = fopen("/proc/filesystems", "r");
111 if (!f) {
112 f = fopen("/selinux/enforce", "r");
113 if (!f && errno == EACCES)
114 return 2;
115 if (f) {
116 if (fscanf(f, "%d", &enforce) == 1)
117 selinux = 2;
118 fclose(f);
119 }
120 return selinux;
121 }
122 while (fgets(line, sizeof(line), f)) {
123 if (strstr(line, "selinuxfs\n")) {
124 selinux = 1;
125 break;
126 }
127 }
128 fclose(f);
129 if (!selinux)
130 return 0;
131
132 f = fopen("/selinux/enforce", "r");
133 if (f) {
134 if (fscanf(f, "%d", &enforce) == 1) {
135 if (enforce == 1)
136 selinux = 2;
137 if (enforce == -1)
138 selinux = 0;
139 }
140 fclose(f);
141 }
142 return selinux;
143 }
144
detect_os_features(uint8_t * os_features)145 static void detect_os_features(uint8_t *os_features)
146 {
147 int features = 0;
148 switch (detect_PaX()) {
149 case 2:
150 features |= 1 << feature_pax_mprotect;
151 /* fall through */
152 case 1:
153 features |= 1 << feature_pax;
154 break;
155 default:
156 break;
157 }
158 switch (detect_SELinux()) {
159 case 2:
160 features |= 1 << feature_selinux_enforcing;
161 /* fall through */
162 case 1:
163 features |= 1 << feature_selinux;
164 break;
165 default:
166 break;
167 }
168
169 *os_features = features;
170 }
171 #else
detect_os_features(uint8_t * os_features)172 static void detect_os_features(uint8_t *os_features)
173 {
174 *os_features = 0;
175 }
176 #endif
177
178 /* OS features :
179 * Linux: PaX << 2| SELinux << 1| mmap-RWX
180 * Other: mmap-RWX */
181
cli_detect_environment(struct cli_environment * env)182 void cli_detect_environment(struct cli_environment *env)
183 {
184 memset(env, 0, sizeof(*env));
185 #if WORDS_BIGENDIAN == 0
186 env->big_endian = 0;
187 #else
188 env->big_endian = 1;
189 #endif
190 env->sizeof_ptr = sizeof(void *);
191
192 /* -- Detect arch -- */
193 CHECK_ARCH(i386);
194 else CHECK_ARCH(x86_64);
195 else if (!strcmp(TARGET_ARCH_TYPE, "amd64")) env->arch = arch_x86_64;
196 else if (!strcmp(TARGET_ARCH_TYPE, "ppc")) env->arch = arch_ppc32; /* llvm will fix ppc64 */
197 else CHECK_ARCH(arm);
198 else CHECK_ARCH(sparc);
199 else CHECK_ARCH(sparc64);
200 else CHECK_ARCH(mips);
201 else CHECK_ARCH(mips64);
202 else CHECK_ARCH(alpha);
203 else CHECK_ARCH(hppa1);
204 else CHECK_ARCH(hppa2);
205 else CHECK_ARCH(m68k);
206 else env->arch = arch_unknown;
207
208 /* -- Detect OS -- */
209 #ifdef C_AIX
210 env->os_category = os_aix;
211 #elif defined(C_BEOS)
212 env->os_category = os_beos;
213 /* DARWIN must come before BSD since it defines both */
214 #elif defined(C_DARWIN)
215 env->os_category = os_darwin;
216 #elif defined(C_BSD)
217 env->os_category = os_bsd;
218 #elif defined(C_GNU_HURD)
219 env->os_category = os_gnu_hurd;
220 #elif defined(C_HPUX)
221 env->os_category = os_hpux;
222 #elif defined(C_INTERIX)
223 env->os_category = os_interix;
224 #elif defined(C_IRIX)
225 env->os_category = os_irix;
226 #elif defined(C_KFREEBSD_GNU)
227 env->os_category = os_kfreebsd_gnu;
228 #elif defined(C_LINUX)
229 env->os_category = os_linux;
230 #elif defined(C_OS2)
231 env->os_category = os_os2;
232 #elif defined(C_OSF)
233 env->os_category = os_osf;
234 #elif defined(C_QNX6)
235 env->os_category = os_qnx6;
236 #elif defined(C_SOLARIS)
237 env->os_category = os_solaris;
238 #elif defined(_WIN64)
239 env->os_category = os_win64;
240 #elif defined(_WIN32)
241 env->os_category = os_win32;
242 #else
243 env->os_category = os_generic;
244 #endif
245
246 env->os = llvm_os_UnknownOS;
247 /* -- Detect compiler -- */
248
249 /* check GNUC last, because some other compilers might define it */
250 #ifdef __INTEL_COMPILER
251 env->compiler = compiler_intel;
252 env->c_version = __INTEL_COMPILER;
253 #elif defined(_MSC_VER)
254 env->compiler = compiler_msc;
255 env->c_version = _MSC_VER;
256 #elif defined(__SUNPRO_C)
257 env->compiler = compiler_sun;
258 env->c_version = __SUNPRO_C;
259 #elif defined(__GNUC__)
260
261 #ifdef __clang__
262 env->compiler = compiler_clang;
263 #elif defined(__llvm__)
264 env->compiler = compiler_llvm;
265 #else
266 env->compiler = compiler_gnuc;
267 #endif
268 env->c_version =
269 MAKE_VERSION(0, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
270
271 #else
272 env->compiler = compiler_other;
273 env->c_version = 0;
274 #endif
275 env->cpp_version = 0;
276
277 env->has_jit_compiled = have_clamjit;
278
279 /* engine */
280 env->functionality_level = cl_retflevel();
281 env->dconf_level = CL_FLEVEL_DCONF;
282
283 INIT_STRFIELD(env->engine_version, cl_retver());
284 #ifdef HAVE_UNAME_SYSCALL
285 {
286 struct utsname name;
287 if (uname(&name) == 0) {
288 INIT_STRFIELD(env->sysname, name.sysname);
289 INIT_STRFIELD(env->release, name.release);
290 INIT_STRFIELD(env->version, name.version);
291 INIT_STRFIELD(env->machine, name.machine);
292 }
293 }
294 #endif
295 #ifdef _WIN32
296 {
297 OSVERSIONINFOEX info;
298 info.dwOSVersionInfoSize = sizeof(info);
299 if (GetVersionEx((OSVERSIONINFO *)&info) != 0 && info.dwPlatformId == VER_PLATFORM_WIN32_NT) {
300 if (info.wProductType == VER_NT_WORKSTATION)
301 INIT_STRFIELD(env->sysname, "Microsoft Windows");
302 else
303 INIT_STRFIELD(env->sysname, "Microsoft Windows Server");
304 snprintf((char *)env->release, sizeof(env->release), "%d.%d SP%d.%d",
305 info.dwMajorVersion, info.dwMinorVersion,
306 info.wServicePackMajor, info.wServicePackMinor);
307 snprintf((char *)env->version, sizeof(env->version), "Build %d",
308 info.dwBuildNumber);
309 }
310 }
311
312 #endif
313 if (!env->sysname[0]) {
314 INIT_STRFIELD(env->sysname, TARGET_OS_TYPE);
315 }
316
317 detect_os_features(&env->os_features);
318
319 cli_detect_env_jit(env);
320
321 env->platform_id_a = (env->os_category << 24) | (env->arch << 20) |
322 (env->compiler << 16) | (env->functionality_level << 8) |
323 (env->dconf_level);
324 env->platform_id_b = (env->big_endian << 28) | (env->sizeof_ptr << 24) |
325 env->cpp_version;
326 env->platform_id_c = (env->os_features << 24) | env->c_version;
327 cli_print_environment(env);
328 }
329