/src/clamav/libclamav/bytecode_detect.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Detect environment for bytecode. |
3 | | * |
4 | | * Copyright (C) 2013-2024 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 | 0 | if (!strcmp(TARGET_ARCH_TYPE, #a)) env->arch = arch_##a |
43 | | |
44 | | extern bool have_clamjit(void); |
45 | | |
46 | | static void cli_print_environment(struct cli_environment *env) |
47 | 0 | { |
48 | 0 | uint32_t id_a = env->platform_id_a; |
49 | 0 | uint32_t id_b = env->platform_id_b; |
50 | 0 | 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 | 0 | cli_dbgmsg("environment detected:\n"); |
54 | 0 | cli_dbgmsg("check_platform(0x%08x, 0x%08x, 0x%08x)\n", |
55 | 0 | id_a, id_b, id_c); |
56 | 0 | cli_dbgmsg("check_platform(0x%02x %01x %01x %02x %02x," |
57 | 0 | "0x%01x %01x %02x %02x %02x," |
58 | 0 | "0x%02x %02x %02x %02x)\n", |
59 | 0 | env->os_category, env->arch, env->compiler, |
60 | 0 | env->functionality_level, |
61 | 0 | env->dconf_level, |
62 | 0 | env->big_endian, |
63 | 0 | env->sizeof_ptr, |
64 | 0 | (env->cpp_version >> 16) & 0xff, |
65 | 0 | (env->cpp_version >> 8) & 0xff, |
66 | 0 | env->cpp_version & 0xff, |
67 | 0 | env->os_features, |
68 | 0 | (env->c_version >> 16) & 0xff, |
69 | 0 | (env->c_version >> 8) & 0xff, |
70 | 0 | env->c_version & 0xff); |
71 | 0 | cli_dbgmsg("check_platform( OS CPU COM FL DCONF,BE PTR CXX VV.VV.VV, FLG CC VV.VV.VV)\n"); |
72 | 0 | cli_dbgmsg("Engine version: %s\n", env->engine_version); |
73 | 0 | cli_dbgmsg("Host triple: %s\n", env->triple); |
74 | 0 | cli_dbgmsg("Host CPU: %s\n", env->cpu); |
75 | 0 | cli_dbgmsg("OS: %s\n", env->sysname); |
76 | 0 | cli_dbgmsg("OS release: %s\n", env->release); |
77 | 0 | cli_dbgmsg("OS version: %s\n", env->version); |
78 | 0 | cli_dbgmsg("OS hardware: %s\n", env->machine); |
79 | 0 | cli_dbgmsg("OS LLVM category: %d\n", env->os); |
80 | 0 | cli_dbgmsg("Has JIT compiled: %d\n", env->has_jit_compiled); |
81 | 0 | cli_dbgmsg("------------------------------------------------------\n"); |
82 | 0 | } |
83 | | |
84 | | #ifdef __linux__ |
85 | | |
86 | | static int detect_PaX(void) |
87 | 0 | { |
88 | 0 | char line[128]; |
89 | 0 | int pax = 0; |
90 | 0 | FILE *f = fopen("/proc/self/status", "r"); |
91 | 0 | if (!f) |
92 | 0 | return 0; |
93 | 0 | while (fgets(line, sizeof(line), f)) { |
94 | 0 | if (!memcmp(line, "PaX:", 4)) { |
95 | 0 | pax = 1; |
96 | 0 | if (!strchr(line, 'm')) |
97 | 0 | pax = 2; |
98 | 0 | break; |
99 | 0 | } |
100 | 0 | } |
101 | 0 | fclose(f); |
102 | 0 | return pax; |
103 | 0 | } |
104 | | |
105 | | static int detect_SELinux(void) |
106 | 0 | { |
107 | 0 | char line[128]; |
108 | 0 | int selinux = 0; |
109 | 0 | int enforce = 0; |
110 | 0 | FILE *f = fopen("/proc/filesystems", "r"); |
111 | 0 | if (!f) { |
112 | 0 | f = fopen("/selinux/enforce", "r"); |
113 | 0 | if (!f && errno == EACCES) |
114 | 0 | return 2; |
115 | 0 | if (f) { |
116 | 0 | if (fscanf(f, "%d", &enforce) == 1) |
117 | 0 | selinux = 2; |
118 | 0 | fclose(f); |
119 | 0 | } |
120 | 0 | return selinux; |
121 | 0 | } |
122 | 0 | while (fgets(line, sizeof(line), f)) { |
123 | 0 | if (strstr(line, "selinuxfs\n")) { |
124 | 0 | selinux = 1; |
125 | 0 | break; |
126 | 0 | } |
127 | 0 | } |
128 | 0 | fclose(f); |
129 | 0 | if (!selinux) |
130 | 0 | return 0; |
131 | | |
132 | 0 | f = fopen("/selinux/enforce", "r"); |
133 | 0 | if (f) { |
134 | 0 | if (fscanf(f, "%d", &enforce) == 1) { |
135 | 0 | if (enforce == 1) |
136 | 0 | selinux = 2; |
137 | 0 | if (enforce == -1) |
138 | 0 | selinux = 0; |
139 | 0 | } |
140 | 0 | fclose(f); |
141 | 0 | } |
142 | 0 | return selinux; |
143 | 0 | } |
144 | | |
145 | | static void detect_os_features(uint8_t *os_features) |
146 | 0 | { |
147 | 0 | int features = 0; |
148 | 0 | switch (detect_PaX()) { |
149 | 0 | case 2: |
150 | 0 | features |= 1 << feature_pax_mprotect; |
151 | | /* fall through */ |
152 | 0 | case 1: |
153 | 0 | features |= 1 << feature_pax; |
154 | 0 | break; |
155 | 0 | default: |
156 | 0 | break; |
157 | 0 | } |
158 | 0 | switch (detect_SELinux()) { |
159 | 0 | case 2: |
160 | 0 | features |= 1 << feature_selinux_enforcing; |
161 | | /* fall through */ |
162 | 0 | case 1: |
163 | 0 | features |= 1 << feature_selinux; |
164 | 0 | break; |
165 | 0 | default: |
166 | 0 | break; |
167 | 0 | } |
168 | | |
169 | 0 | *os_features = features; |
170 | 0 | } |
171 | | #else |
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 | | |
182 | | void cli_detect_environment(struct cli_environment *env) |
183 | 0 | { |
184 | 0 | memset(env, 0, sizeof(*env)); |
185 | 0 | #if WORDS_BIGENDIAN == 0 |
186 | 0 | env->big_endian = 0; |
187 | | #else |
188 | | env->big_endian = 1; |
189 | | #endif |
190 | 0 | env->sizeof_ptr = sizeof(void *); |
191 | | |
192 | | /* -- Detect arch -- */ |
193 | 0 | CHECK_ARCH(i386); |
194 | 0 | else CHECK_ARCH(x86_64); |
195 | 0 | else if (!strcmp(TARGET_ARCH_TYPE, "amd64")) env->arch = arch_x86_64; |
196 | 0 | else if (!strcmp(TARGET_ARCH_TYPE, "AMD64")) env->arch = arch_x86_64; |
197 | 0 | else if (!strcmp(TARGET_ARCH_TYPE, "ppc")) env->arch = arch_ppc32; /* llvm will fix ppc64 */ |
198 | 0 | else CHECK_ARCH(arm); |
199 | 0 | else CHECK_ARCH(sparc); |
200 | 0 | else CHECK_ARCH(sparc64); |
201 | 0 | else CHECK_ARCH(mips); |
202 | 0 | else CHECK_ARCH(mips64); |
203 | 0 | else CHECK_ARCH(alpha); |
204 | 0 | else CHECK_ARCH(hppa1); |
205 | 0 | else CHECK_ARCH(hppa2); |
206 | 0 | else CHECK_ARCH(m68k); |
207 | 0 | else env->arch = arch_unknown; |
208 | | |
209 | | /* -- Detect OS -- */ |
210 | | #ifdef C_AIX |
211 | | env->os_category = os_aix; |
212 | | #elif defined(C_BEOS) |
213 | | env->os_category = os_beos; |
214 | | /* DARWIN must come before BSD since it defines both */ |
215 | | #elif defined(C_DARWIN) |
216 | | env->os_category = os_darwin; |
217 | | #elif defined(C_BSD) |
218 | | env->os_category = os_bsd; |
219 | | #elif defined(C_GNU_HURD) |
220 | | env->os_category = os_gnu_hurd; |
221 | | #elif defined(C_HPUX) |
222 | | env->os_category = os_hpux; |
223 | | #elif defined(C_INTERIX) |
224 | | env->os_category = os_interix; |
225 | | #elif defined(C_IRIX) |
226 | | env->os_category = os_irix; |
227 | | #elif defined(C_KFREEBSD_GNU) |
228 | | env->os_category = os_kfreebsd_gnu; |
229 | | #elif defined(C_LINUX) |
230 | | env->os_category = os_linux; |
231 | | #elif defined(C_OS2) |
232 | | env->os_category = os_os2; |
233 | | #elif defined(C_OSF) |
234 | | env->os_category = os_osf; |
235 | | #elif defined(C_QNX6) |
236 | | env->os_category = os_qnx6; |
237 | | #elif defined(C_SOLARIS) |
238 | | env->os_category = os_solaris; |
239 | | #elif defined(_WIN64) |
240 | | env->os_category = os_win64; |
241 | | #elif defined(_WIN32) |
242 | | env->os_category = os_win32; |
243 | | #else |
244 | | env->os_category = os_generic; |
245 | | #endif |
246 | |
|
247 | 0 | env->os = llvm_os_UnknownOS; |
248 | | /* -- Detect compiler -- */ |
249 | | |
250 | | /* check GNUC last, because some other compilers might define it */ |
251 | | #ifdef __INTEL_COMPILER |
252 | | env->compiler = compiler_intel; |
253 | | env->c_version = __INTEL_COMPILER; |
254 | | #elif defined(_MSC_VER) |
255 | | env->compiler = compiler_msc; |
256 | | env->c_version = _MSC_VER; |
257 | | #elif defined(__SUNPRO_C) |
258 | | env->compiler = compiler_sun; |
259 | | env->c_version = __SUNPRO_C; |
260 | | #elif defined(__GNUC__) |
261 | |
|
262 | 0 | #ifdef __clang__ |
263 | 0 | env->compiler = compiler_clang; |
264 | | #elif defined(__llvm__) |
265 | | env->compiler = compiler_llvm; |
266 | | #else |
267 | | env->compiler = compiler_gnuc; |
268 | | #endif |
269 | 0 | env->c_version = |
270 | 0 | MAKE_VERSION(0, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); |
271 | |
|
272 | | #else |
273 | | env->compiler = compiler_other; |
274 | | env->c_version = 0; |
275 | | #endif |
276 | 0 | env->cpp_version = 0; |
277 | |
|
278 | 0 | env->has_jit_compiled = have_clamjit(); |
279 | | |
280 | | /* engine */ |
281 | 0 | env->functionality_level = cl_retflevel(); |
282 | 0 | env->dconf_level = CL_FLEVEL_DCONF; |
283 | |
|
284 | 0 | INIT_STRFIELD(env->engine_version, cl_retver()); |
285 | 0 | #ifdef HAVE_UNAME_SYSCALL |
286 | 0 | { |
287 | 0 | struct utsname name; |
288 | 0 | if (uname(&name) == 0) { |
289 | 0 | INIT_STRFIELD(env->sysname, name.sysname); |
290 | 0 | INIT_STRFIELD(env->release, name.release); |
291 | 0 | INIT_STRFIELD(env->version, name.version); |
292 | 0 | INIT_STRFIELD(env->machine, name.machine); |
293 | 0 | } |
294 | 0 | } |
295 | 0 | #endif |
296 | | #ifdef _WIN32 |
297 | | { |
298 | | OSVERSIONINFOEX info; |
299 | | info.dwOSVersionInfoSize = sizeof(info); |
300 | | if (GetVersionEx((OSVERSIONINFO *)&info) != 0 && info.dwPlatformId == VER_PLATFORM_WIN32_NT) { |
301 | | if (info.wProductType == VER_NT_WORKSTATION) |
302 | | INIT_STRFIELD(env->sysname, "Microsoft Windows"); |
303 | | else |
304 | | INIT_STRFIELD(env->sysname, "Microsoft Windows Server"); |
305 | | snprintf((char *)env->release, sizeof(env->release), "%d.%d SP%d.%d", |
306 | | info.dwMajorVersion, info.dwMinorVersion, |
307 | | info.wServicePackMajor, info.wServicePackMinor); |
308 | | snprintf((char *)env->version, sizeof(env->version), "Build %d", |
309 | | info.dwBuildNumber); |
310 | | } |
311 | | } |
312 | | |
313 | | #endif |
314 | 0 | if (!env->sysname[0]) { |
315 | 0 | INIT_STRFIELD(env->sysname, TARGET_OS_TYPE); |
316 | 0 | } |
317 | |
|
318 | 0 | detect_os_features(&env->os_features); |
319 | |
|
320 | 0 | cli_detect_env_jit(env); |
321 | |
|
322 | 0 | env->platform_id_a = (env->os_category << 24) | (env->arch << 20) | |
323 | 0 | (env->compiler << 16) | (env->functionality_level << 8) | |
324 | 0 | (env->dconf_level); |
325 | 0 | env->platform_id_b = (env->big_endian << 28) | (env->sizeof_ptr << 24) | |
326 | 0 | env->cpp_version; |
327 | 0 | env->platform_id_c = (env->os_features << 24) | env->c_version; |
328 | 0 | cli_print_environment(env); |
329 | 0 | } |