Coverage Report

Created: 2024-05-20 06:31

/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
}