GCC Code Coverage Report


Directory: ../replacer/
File: queue.c
Date: 2025-10-28 11:47:20
Coverage Exec Excl Total
Lines: 65.3% 1131 0 1731
Functions: 92.5% 123 0 133
Branches: 44.2% 600 0 1357

Line Branch Exec Source
1 /*
2 * queue.h
3 *
4 * Created on: Sep 3, 2018
5 * Author: alexey
6 */
7 #define _POSIX_C_SOURCE 200809L
8
9 #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__clang__)
10 #define GCC_DIAGNOSTIC_AWARE 1
11 #else
12 #define GCC_DIAGNOSTIC_AWARE 0
13 #endif
14
15 #ifdef __GNUC__
16 #define SUPPRESS_NOT_USED_WARN __attribute__((unused))
17 #else
18 #define SUPPRESS_NOT_USED_WARN
19 #endif
20
21 #include <alloca.h>
22 #include <ctype.h>
23 #include <fcntl.h>
24 #include <libgen.h>
25 #include <linux/limits.h>
26 #include <pthread.h>
27 #include <stdarg.h>
28 #include <stdbool.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #include <sys/time.h>
35 #include <time.h>
36 #include <unistd.h>
37 #include <dlfcn.h>
38 #include <sys/mman.h>
39
40 #include "pcre/pcre.h"
41 #if defined(PA_RULES_VERSION)
42 #include "php_version.h" // PHP_MAJOR_VERSION definition is now available
43 #endif
44
45 #ifdef UNIT_TESTING
46 #define QUEUE_NOINLINE
47 #endif
48
49 #include "../shared-storage/bayrepodump.h"
50 #include "../shared-storage/bayrepomalloc.h"
51 #include "global_data.h"
52 #include "map/map.h"
53 #include "queue.h"
54 #include "queue_buffer.h"
55 #include "reversed_ordered_set/reversed_ordered_set.h"
56 #include "stringfunc.h"
57 #include "counters-saver.h"
58
59 #include "unit_test_common.h"
60
61 #define G_MIN_HANDLE_STRING_SIZE 4
62 #define G_MIN_HANDLE_STRING_SIZE_RCE 1
63 #define G_MAX_PARAM_LENGTH 1024
64
65 #define G_MAX_RESULT_LEN 256
66
67 #define G_NON_LOG_RULE_ID 120000
68
69 #define SIZE_OF_ELEM 1
70 #define OK 0
71 #define PHP_IMUNITY_MIN_ID 80000
72 #define PHP_IMUNITY_MAX_ID 119999
73
74 static map_str_t config_data = map_static_init(0);
75 static params_global_data *parms_data_g_ptr = NULL;
76
77 static char *v2_database_paths[2] = {BIN_F_V2_AGENT, BIN_V2_F};
78 static map_int_t *urls_list = NULL;
79 static reversed_ordered_set_t *files_list = NULL;
80 static map_str_t *funcs = NULL;
81 static map_int_t *func_id = NULL;
82 static map_str_t *func_old_conv = NULL;
83 static map_int_t *writeloggers = NULL;
84 static exclude_rules_list *fp_list_g = NULL;
85 static char *malware_directory_config = NULL;
86 static int malware_directory_config_fd = -1;
87 static reversed_ordered_set_t *exclude_files_list = NULL;
88
89 static params_global_data parms_data_g_ptr_v2 = {NULL,
90 map_static_init(NULL),
91 map_static_init(0),
92 {NULL, 0, 0, NULL},
93 NULL,
94 NULL,
95 map_static_init(NULL),
96 map_static_init(NULL),
97 map_static_init(0),
98 map_static_init(NULL),
99 map_static_init(0),
100 {{NULL, 0, 0, NULL}, NULL, 0},
101 {NULL},
102 0,
103 {NULL, 0, 0, NULL}};
104
105 static params_list server_array = {NULL, NULL, 0, 0};
106 extern char **environ;
107
108 static void *storage = NULL;
109 static void (*storage_free_cb)(void *storage_ptr) = &free;
110 typedef void (*storage_free_cb_ptr)(void *storage_ptr);
111
112 static map_str_t *script_rules_list_map = NULL;
113 static void *script_rules_list_storage = NULL;
114 static void (*script_rules_list_storage_free_cb)(void *storage_ptr) = &free;
115
116 typedef struct __script_rules {
117 rules_list *rules;
118 void *storage;
119 void (*storage_free_cb)(void *storage_ptr);
120 } script_rules_t;
121
122 static map_void_t scripts_rules_map = map_static_init(0);
123
124 #define FAKE_SCRIPT_RULES ((script_rules_t *)(intptr_t)-1)
125
126 static intptr_t current_script_rules_uid = 0;
127 static script_rules_t *current_script_rules = NULL;
128 static intptr_t common_script_rules_uid = 0;
129 static script_rules_t *common_script_rules = NULL;
130 #define I360_PATH_BUFF 4096
131
132 static char current_db_path[I360_PATH_BUFF];
133
134 1 char *i360_get_current_db_path() {
135 1 return current_db_path;
136 }
137
138 #ifndef UNIT_TESTING
139 static
140 #endif
141 58 void i360_load_script_rules() {
142 58 script_rules_list_storage = brp_restore_mmap_dump(LIST_DUMP_F, &script_rules_list_storage_free_cb);
143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (script_rules_list_storage)
144 script_rules_list_map = (map_str_t *)brp_get_pointer_with_number(script_rules_list_storage, 0);
145
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (script_rules_list_map)
147 return;
148
149
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
58 if (script_rules_list_storage && script_rules_list_storage_free_cb)
150 script_rules_list_storage_free_cb(script_rules_list_storage);
151
152 58 script_rules_list_storage = brp_restore_dump(LIST_BIN_F, SECURITY_BYTE);
153 58 script_rules_list_storage_free_cb = &free;
154
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (script_rules_list_storage)
156 script_rules_list_map = (map_str_t *)brp_get_pointer_with_number(script_rules_list_storage, 0);
157
158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (script_rules_list_map)
159 return;
160
161
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
58 if (script_rules_list_storage && script_rules_list_storage_free_cb)
162 script_rules_list_storage_free_cb(script_rules_list_storage);
163 }
164
165 #ifndef UNIT_TESTING
166 static
167 #endif
168 104 void i360_reset_script_rules() {
169 104 map_iter_t iter = map_iter(&scripts_rules_map);
170 const char *key;
171
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 104 times.
104 while ((key = map_next(&scripts_rules_map, &iter))) {
172 script_rules_t *sr = *map_value(&scripts_rules_map, &iter);
173 if (sr == FAKE_SCRIPT_RULES)
174 continue;
175
176 if (sr->storage && sr->storage_free_cb)
177 sr->storage_free_cb(sr->storage);
178
179 free(sr);
180 }
181 104 map_deinit(&scripts_rules_map);
182 104 current_script_rules_uid = 0;
183 104 current_script_rules = NULL;
184 104 common_script_rules_uid = 0;
185 104 common_script_rules = NULL;
186 104 }
187
188 #ifndef UNIT_TESTING
189 static
190 #endif
191 59 void i360_free_script_rules() {
192 59 i360_reset_script_rules();
193
194
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
59 if (script_rules_list_storage && script_rules_list_storage_free_cb)
195 script_rules_list_storage_free_cb(script_rules_list_storage);
196
197 59 script_rules_list_storage = NULL;
198 59 script_rules_list_storage_free_cb = NULL;
199 59 script_rules_list_map = NULL;
200 59 }
201
202 #ifndef UNIT_TESTING
203 static
204 #endif
205 40 void *i360_get_script_rules(const char *file_name, intptr_t uid) {
206 40 int common = 0;
207
208
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
40 if (!script_rules_list_map || !uid)
209 40 return NULL;
210
211 if (file_name && *file_name == '*' && file_name[1] == 0) {
212 common = 1;
213 if (common_script_rules_uid == uid)
214 return (common_script_rules == FAKE_SCRIPT_RULES) ? NULL : common_script_rules;
215 }
216 else {
217 // Fast path
218 if (current_script_rules_uid && current_script_rules_uid == uid)
219 return (current_script_rules == FAKE_SCRIPT_RULES) ? NULL : current_script_rules;
220 }
221
222 intptr_t *script_rules_uid = common ? &common_script_rules_uid : &current_script_rules_uid;
223 script_rules_t **script_current_rules = common ? &common_script_rules : &current_script_rules;
224
225 *script_rules_uid = uid;
226 script_rules_t **script_rules_ptr = (script_rules_t **)map_get(&scripts_rules_map, file_name);
227 *script_current_rules = script_rules_ptr ? *script_rules_ptr : NULL;
228
229 if (*script_current_rules)
230 return (*script_current_rules == FAKE_SCRIPT_RULES) ? NULL : *script_current_rules;
231
232 char **script_rule_file = (char **)map_get(script_rules_list_map, file_name);
233
234 if (!script_rule_file || !*script_rule_file) {
235 map_set(&scripts_rules_map, file_name, (*script_current_rules = FAKE_SCRIPT_RULES));
236 return NULL;
237 }
238
239 char script_rule_file_buffer[PATH_MAX];
240 script_rules_t script_rules = {NULL, NULL, NULL};
241
242 memset(script_rule_file_buffer, 0, PATH_MAX);
243 size_t buf_left = PATH_MAX;
244 i360_strnadd(script_rule_file_buffer, LIST_CONF_PATH, strlen(LIST_CONF_PATH), PATH_MAX, &buf_left);
245 i360_strnadd(script_rule_file_buffer, *script_rule_file, strlen(*script_rule_file), PATH_MAX, &buf_left);
246 i360_strnadd(script_rule_file_buffer, ".sruledump", strlen(".sruledump"), PATH_MAX, &buf_left);
247 script_rules.storage = brp_restore_mmap_dump(script_rule_file_buffer, &script_rules.storage_free_cb);
248
249 if (script_rules.storage)
250 script_rules.rules = (rules_list *)brp_get_pointer_with_number(script_rules.storage, 0);
251
252 if (script_rules.rules) {
253 script_rules_t *sr = malloc(sizeof(script_rules_t));
254 if (sr) {
255 *sr = script_rules;
256 map_set(&scripts_rules_map, file_name, sr);
257 return (*script_current_rules = sr);
258 }
259 }
260
261 if (script_rules.storage && script_rules.storage_free_cb)
262 script_rules.storage_free_cb(script_rules.storage);
263
264 memset(script_rule_file_buffer, 0, PATH_MAX);
265 buf_left = PATH_MAX;
266 i360_strnadd(script_rule_file_buffer, LIST_CONF_PATH, strlen(LIST_CONF_PATH), PATH_MAX, &buf_left);
267 i360_strnadd(script_rule_file_buffer, *script_rule_file, strlen(*script_rule_file), PATH_MAX, &buf_left);
268 i360_strnadd(script_rule_file_buffer, ".srule", strlen(".srule"), PATH_MAX, &buf_left);
269 script_rules.storage = brp_restore_dump(script_rule_file_buffer, SECURITY_BYTE);
270 script_rules.storage_free_cb = &free;
271
272 if (script_rules.storage)
273 script_rules.rules = (rules_list *)brp_get_pointer_with_number(script_rules.storage, 0);
274
275 if (script_rules.rules) {
276 script_rules_t *sr = malloc(sizeof(script_rules_t));
277 if (sr) {
278 *sr = script_rules;
279 map_set(&scripts_rules_map, file_name, sr);
280 return (*script_current_rules = sr);
281 }
282 }
283
284 if (script_rules.storage)
285 script_rules.storage_free_cb(script_rules.storage);
286
287 map_set(&scripts_rules_map, file_name, (*script_current_rules = FAKE_SCRIPT_RULES));
288 40 return NULL;
289 }
290
291 #define G_MAX_TEST_RECOGNIZER_SUB_ID 10
292 #ifndef DEEP_PHP_TESTS
293 #define G_TEST_FLAG "/usr/share/i360-php-opts/test_enabled"
294 #else
295 #define G_TEST_FLAG "test_enabled"
296 #endif
297 static int test_env_enabled = 0;
298
299 #define RGX_MAX_DOCROOT_LEN 4096
300
301 struct timespec stat_rgx_time = {0, 0};
302 static pcre *re_stat_rgx = NULL;
303 static char current_doc_root_rgx[RGX_MAX_DOCROOT_LEN + 1] = {0};
304 static int doc_root_len = 0;
305 static int exclude_list_opt = 1;
306
307 1 void i360_set_exclude_list_opt(int value) {
308 1 exclude_list_opt = value;
309 1 }
310
311 static int i360_compare_timespec_queue(struct timespec *t1, struct timespec *t2) {
312 long int v1, v2;
313 v1 = t1->tv_nsec + t1->tv_sec * 1000000000;
314 v2 = t2->tv_nsec + t2->tv_sec * 1000000000;
315 if (v1 > v2)
316 return 1;
317 else if (v1 < v2)
318 return -1;
319 else
320 return 0;
321 }
322
323 1 void i360_load_exclude_list(char *document_root) {
324 struct stat st;
325
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (document_root) {
326 1 strncpy(current_doc_root_rgx, document_root, RGX_MAX_DOCROOT_LEN);
327 }
328 else {
329 strncpy(current_doc_root_rgx, "/", RGX_MAX_DOCROOT_LEN);
330 }
331 1 doc_root_len = strlen(current_doc_root_rgx);
332
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if (stat(ABS_PATH_RGX, &st) == 0) {
333 if (st.st_size > 0) {
334 if (i360_compare_timespec_queue(&st.st_mtim, &stat_rgx_time) > 0) {
335 stat_rgx_time = st.st_mtim;
336 if (re_stat_rgx) {
337 free(re_stat_rgx);
338 re_stat_rgx = NULL;
339 }
340 re_stat_rgx = calloc(st.st_size, 1);
341 if (re_stat_rgx) {
342 FILE *fp = fopen(ABS_PATH_RGX, "rb");
343 if (fp) {
344 if (!fread(re_stat_rgx, st.st_size, 1, fp)) {
345 free(re_stat_rgx);
346 re_stat_rgx = NULL;
347 }
348 }
349 else {
350 free(re_stat_rgx);
351 re_stat_rgx = NULL;
352 }
353 }
354 }
355 }
356 }
357 1 }
358
359 1 void i360_free_exclude_list() {
360
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (re_stat_rgx) {
361 free(re_stat_rgx);
362 re_stat_rgx = NULL;
363 }
364 1 }
365
366 3 void i360_set_malware_directory_config(char *path) {
367 3 malware_directory_config = path;
368
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (malware_directory_config_fd >= 0) {
369 close(malware_directory_config_fd);
370 }
371
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
3 if (!path) {
372 1 malware_directory_config_fd = -1;
373 1 return;
374 }
375
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (path[0]) {
376 2 malware_directory_config_fd = open(path, O_DIRECTORY);
377 //#ifndef NDEBUG
378 // if (malware_directory_config_fd < 0) {
379 // perror("malware_dir_path error");
380 // }
381 //#endif
382 }
383 }
384
385 1 void i360_check_test_enabled() {
386 #ifndef UNIT_TESTING
387 test_env_enabled = 0;
388 #else
389 1 test_env_enabled = 1;
390 #endif
391 1 }
392
393 1 int i360_is_test_env_enabled() {
394 1 return test_env_enabled;
395 }
396
397 #define TMPBUFF 15000
398
399 /* When reading whitelist rules information from file, it's going to be
400 ** one-fread operation. File content will be read directly to either
401 ** static_wl_buffer (fsize < WL_STATIC_BUFFER_SIZE) or dynamically
402 ** allocated buffer (fsize >= WL_STATIC_BUFFER_SIZE).
403 **
404 ** NOTE: it makes sense to have WL_STATIC_BUFFER_SIZE equal to
405 *4+sizeof(wl_item)*N
406 */
407 #define WL_STATIC_BUFFER_SIZE (size_t)100000
408
409 const char *const STR_WL_INCOMPATIBLE = "error: incompatible rules whitelist file %lu\n";
410 const char *const STR_WL_CORRUPTED = "warning: rules whitelist file might be corrupted\n";
411
412 static unsigned char static_wl_buffer[WL_STATIC_BUFFER_SIZE];
413 static unsigned char *wl_buffer = static_wl_buffer;
414 static unsigned int wl_buffer_size = WL_STATIC_BUFFER_SIZE;
415
416 /* When php file being processed is changed (cur_php_fname), we also
417 ** update whitelist rules files which are associated (see set_cur_php_fname)
418 */
419 static char cur_php_fname[PATH_MAX] = "";
420 static size_t cur_php_fname_len = 0;
421 static intptr_t cur_php_uid = 0;
422 static char *cur_wl_rules = NULL;
423
424 /* How whitelist rules data is being stored in memory may depend
425 ** on whitelist format version
426 */
427 static unsigned int wl_version = WHITELIST_FILE_VER3;
428
429 /* If in whitelist, there is an item with no file name is
430 ** specified (empty string), all the appropriate rules are in
431 ** power for all the files.
432 */
433 static char *super_wl_rules = NULL;
434
435 4 static inline int i360_isset_cur_php_fname() {
436 4 return cur_php_fname[0];
437 }
438 6 static inline void i360_reset_cur_php_fname() {
439 6 cur_php_fname[0] = (char)0;
440 6 cur_php_fname_len = 0;
441 6 cur_php_uid = 0;
442 6 }
443
444 35 void i360_extract_correct_php_script_name(char *cur_php_fname) {
445 35 char *dot = strchr(cur_php_fname, ':');
446
447
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 25 times.
35 if (dot) {
448 10 *dot = 0;
449 10 int string_len = strlen(cur_php_fname) + 1;
450 10 int i = string_len - 2, j = i;
451 10 char *ptr = cur_php_fname;
452 10 dot = ptr + i;
453
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 2 times.
64 while (i >= 0) {
454
10/10
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 22 times.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 14 times.
62 if (!(ptr[i] == '(' || ptr[i] == ')' || (ptr[i] >= '0' && ptr[i] <= '9') || ptr[i] == ' ')) {
455
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if ((i + 1) <= j) {
456
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (ptr[i + 1] == '(') {
457 8 ptr[i + 1] = 0;
458 }
459 }
460 8 break;
461 }
462 54 i--;
463 }
464 }
465 35 }
466
467 26 void i360_set_cur_php_fname(char *fname, map_void_t *whitelist_map, int compile) {
468
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 23 times.
26 if (fname && fname[0] == '[') {
469
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
1 if (compile && i360_isset_cur_php_fname()) {
470 1 i360_reset_cur_php_fname();
471 1 cur_wl_rules = NULL;
472 }
473 1 return;
474 }
475
476
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 23 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
25 if (!compile && i360_isset_cur_php_fname()) {
477
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
1 if (fname && !strcmp(cur_php_fname, fname)) {
478 return;
479 }
480 }
481
482
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 2 times.
25 if (fname) {
483 23 cur_php_uid = (intptr_t)fname;
484 /* using strncpy safely to avoid -Wstringop-truncation (GCC 8) */
485 23 memcpy(cur_php_fname, fname, strlen(fname) + 1);
486
487 23 i360_extract_correct_php_script_name(cur_php_fname);
488
489 23 cur_php_fname_len = strnlen(cur_php_fname, PATH_MAX);
490
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 20 times.
23 void **ptr = map_get((whitelist_map ? whitelist_map : &parms_data_g_ptr->whitelist_map), cur_php_fname);
491
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 13 times.
23 if (ptr) {
492 10 cur_wl_rules = *ptr;
493 }
494 else {
495 23 cur_wl_rules = NULL;
496 }
497 }
498 else {
499 2 i360_reset_cur_php_fname();
500 2 cur_wl_rules = NULL;
501 }
502 }
503
504 3 void i360_free_cur_php_fname() {
505 3 i360_reset_cur_php_fname();
506 3 }
507
508 1 char *i360_get_cur_php_fname() {
509 1 return cur_php_fname;
510 }
511
512 192889 static int i360_wl_item_comp(const void *elem1, const void *elem2) {
513 192889 const unsigned int f = *((unsigned int *)elem1);
514 192889 const unsigned int s = *((unsigned int *)elem2);
515
2/2
✓ Branch 0 taken 179224 times.
✓ Branch 1 taken 13665 times.
192889 if (f < s)
516 179224 return 1;
517
2/2
✓ Branch 0 taken 5889 times.
✓ Branch 1 taken 7776 times.
13665 if (f > s)
518 5889 return -1;
519 7776 return 0;
520 }
521
522 45 void i360_free_queue() {
523 45 i360_reset_script_rules();
524 45 }
525
526 59 void i360_read_internal_config(char *path_to_config) {
527 59 map_init(&config_data);
528 59 FILE *cfg = fopen(path_to_config, "r");
529
1/2
✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
59 if (cfg) {
530 59 char buffer[TMPBUFF * 2] = {0};
531
2/2
✓ Branch 1 taken 265 times.
✓ Branch 2 taken 59 times.
324 while (fgets(buffer, sizeof(buffer), cfg) != NULL) {
532 265 char *key = buffer;
533 265 char *value = buffer;
534 265 int max_length = TMPBUFF * 2;
535
6/8
✓ Branch 0 taken 3073 times.
✓ Branch 1 taken 261 times.
✓ Branch 2 taken 3073 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3073 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3069 times.
✓ Branch 7 taken 4 times.
3334 while (*value != '=' && (max_length > 1) && *value != 0 && *value != '\n') {
536 3069 value++;
537 3069 max_length--;
538 }
539
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 4 times.
265 if (*value == '=') {
540 261 *value = '\0';
541 261 value++;
542
1/2
✓ Branch 0 taken 261 times.
✗ Branch 1 not taken.
261 if (max_length > 0) {
543 261 char *trim_key = i360_my_strtrim(key);
544 261 char *trim_value = i360_my_strtrim(value);
545
2/4
✓ Branch 0 taken 261 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 261 times.
✗ Branch 3 not taken.
261 if (trim_key && trim_value) {
546 261 char *check_exists = (char *)map_get(&config_data, trim_key);
547
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 255 times.
261 if (check_exists) {
548 6 map_remove(&config_data, trim_key);
549 }
550 261 map_set_(&(config_data).base, trim_key, trim_value, strlen(trim_value) + 1);
551 }
552
1/2
✓ Branch 0 taken 261 times.
✗ Branch 1 not taken.
261 if (trim_key)
553 261 free(trim_key);
554
1/2
✓ Branch 0 taken 261 times.
✗ Branch 1 not taken.
261 if (trim_value)
555 261 free(trim_value);
556 }
557 }
558 265 memset(buffer, 0, TMPBUFF * 2);
559 }
560 59 fclose(cfg);
561 }
562 59 }
563
564 60 void i360_free_internal_config() {
565 60 map_str_t map_null = map_static_init(0);
566
2/2
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 1 time.
60 if (memcmp(&config_data, &map_null, sizeof(config_data))) {
567 59 map_deinit(&config_data);
568 59 memset(&config_data, 0, sizeof(config_data));
569 }
570 60 }
571
572 27 char *i360_get_config_key(char *key_name) {
573 27 return (char *)map_get(&config_data, key_name);
574 }
575
576 char *i360_getenv(const char *name, const char *default_value) {
577 if (!name || !*name)
578 return NULL;
579 char *ret = getenv(name);
580 // we expect ret to be alphanumeric or _- and end up with a null byte
581 if (ret && *ret) {
582 int is_valid = 1;
583 const char *p;
584 for (p = ret; *p; p++) {
585 if (!isalnum((unsigned char)*p) && *p != '_' && *p != '-') {
586 is_valid = 0;
587 break;
588 }
589 }
590 if (is_valid) {
591 return i360_inner_strdup(ret);
592 }
593 }
594 if (!default_value || !*default_value) {
595 return NULL;
596 }
597 return i360_inner_strdup((char *)default_value);
598 }
599
600 // params
601
602 10 int i360_add_func_param_value_add(params_list *parms, char *param, char *value, int length,
603 __attribute__((unused)) int add_param) {
604 10 int need_length = (length > G_MAX_PARAM_LENGTH ? G_MAX_PARAM_LENGTH : length);
605 10 params_item *new = calloc(1, sizeof(params_item));
606
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!new) {
607 parms->err = 1;
608 return -1;
609 }
610
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 new->param = i360_inner_strndup(param ? param : "", need_length);
611 10 new->param_len = need_length;
612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!new->param) {
613 free(new);
614 parms->err = 1;
615 return -1;
616 }
617
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (value) {
618 new->value = i360_inner_strdup(value);
619 if (!new->value) {
620 free(new);
621 parms->err = 1;
622 return -1;
623 }
624 }
625
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 7 times.
10 if (parms->head) {
626 3 parms->tail->next = new;
627 3 new->number = parms->tail->number + 1;
628 3 parms->length++;
629 3 parms->tail = new;
630 }
631 else {
632 7 parms->head = new;
633 7 parms->tail = new;
634 7 parms->length = 1;
635 7 new->number = 1;
636 }
637 10 return 0;
638 }
639
640 10 int i360_add_func_param_value(params_list *parms, char *param, __attribute__((unused)) char *value, int length) {
641 10 return i360_add_func_param_value_add(parms, param, NULL, length, 0);
642 }
643
644 9 int i360_add_func_param(params_list *parms, char *param, int length) {
645 9 return i360_add_func_param_value(parms, param, NULL, length);
646 }
647
648 25 void i360_free_func_params(params_list *parms) {
649
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 18 times.
25 if (parms->head) {
650 7 params_item *item = parms->head;
651
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 7 times.
17 while (item) {
652 10 params_item *item_del = item;
653 10 item = item->next;
654
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (item_del->param)
655 10 free(item_del->param);
656
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (item_del->value) {
657 free(item_del->value);
658 }
659 10 free(item_del);
660 }
661 7 parms->head = NULL;
662 7 parms->tail = NULL;
663 7 parms->length = 0;
664 }
665 25 }
666
667 // New params
668
669 static int i360_params_numb = 0;
670
671 #define PROACTIVE_MAX_PARAMS_TO_SAVE 10
672 #define PROACTIVE_MAX_PARAMS_FUNC_NAME PROACTIVE_MAX_PARAMS_TO_SAVE + 1
673 #define PROACTIVE_MAX_PARAMS_PARAM_PRE 8
674 #define PROACTIVE_MAX_PARAMS_FUNC_PRE 10
675
676 static char i360_params_static[PROACTIVE_MAX_PARAMS_FUNC_NAME][G_MAX_PARAM_LENGTH + PROACTIVE_MAX_PARAMS_FUNC_PRE + 1] =
677 {"PHPFP_A=", "PHPFP_B=", "PHPFP_C=", "PHPFP_D=", "PHPFP_E=", "PHPFP_F=",
678 "PHPFP_G=", "PHPFP_H=", "PHPFP_I=", "PHPFP_J=", "PHPFP_NAM="};
679
680 static int i360_params_static_length[PROACTIVE_MAX_PARAMS_FUNC_NAME] = {0};
681
682 47 int i360_add_func_param_value_add_new(const char *param, size_t length) {
683
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 45 times.
47 if (i360_params_numb == PROACTIVE_MAX_PARAMS_TO_SAVE)
684 2 return -1;
685
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 1 time.
45 size_t need_length = (length > G_MAX_PARAM_LENGTH ? (G_MAX_PARAM_LENGTH - 1) : length);
686 45 char *str_ptr = i360_params_static[i360_params_numb];
687 45 str_ptr += PROACTIVE_MAX_PARAMS_PARAM_PRE;
688 45 strncpy(str_ptr, param, need_length + 1);
689 45 i360_params_static_length[i360_params_numb] = need_length;
690 45 i360_params_numb++;
691 45 return 0;
692 }
693
694 33 int i360_add_func_param_value_new(const char *param, size_t length) {
695 33 return i360_add_func_param_value_add_new(param, length);
696 }
697
698 33 int i360_add_func_param_new(const char *param, size_t length) {
699 33 return i360_add_func_param_value_new(param, length);
700 }
701
702 29 void i360_free_func_params_new() {
703 // When we add a parameter, we don't append it, but rather strncpy it fresh
704 // so we don't need to clean up anything except the current number of parameters
705 // This is one of the hottest functions, so it must make sense to optimize it
706 29 i360_params_numb = 0;
707 29 }
708
709 27 char *i360_get_params_new(int *index, int *len) {
710 27 char *ptr = i360_get_params_index_new(index, len);
711
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 7 times.
27 if (*index != -1) {
712 20 *index = *index + 1;
713 }
714 27 return ptr;
715 }
716
717 42 char *i360_get_params_index_new(int *index, int *len) {
718
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 34 times.
42 if (*index >= i360_params_numb) {
719 8 *index = -1;
720 8 *len = 0;
721 8 return NULL;
722 }
723
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (*index >= PROACTIVE_MAX_PARAMS_TO_SAVE) {
724 *index = -1;
725 *len = 0;
726 return NULL;
727 }
728 34 *len = i360_params_static_length[*index];
729 34 char *ptr = i360_params_static[*index];
730 34 ptr += PROACTIVE_MAX_PARAMS_PARAM_PRE;
731 34 return ptr;
732 }
733
734 36 int i360_get_params_new_numb() {
735 36 return i360_params_numb;
736 }
737
738 2 char *i360_get_params_new_raw(int index) {
739
3/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
2 if (index >= PROACTIVE_MAX_PARAMS_TO_SAVE || index >= i360_params_numb) {
740 1 return NULL;
741 }
742 1 return i360_params_static[index];
743 }
744
745 18 char *i360_is_function_hooked(const char *name, char *buffer) {
746 18 char *res = (char *)map_get(funcs, name);
747
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1 time.
18 if (res) {
748 17 buffer[0] = res[0];
749 17 buffer[1] = res[1];
750 17 buffer[2] = res[2];
751 17 return buffer;
752 }
753 1 return NULL;
754 }
755
756 14 int i360_get_params_flags(char *func_info) {
757 14 return (int)(func_info[2] - '0');
758 }
759
760 2 static int i360_fast_bad_syscall_detection_files(__attribute__((unused)) params_list *params, file_value *values) {
761
3/4
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
2 if (!i360_get_params_new_numb() || !values)
762 1 return 0;
763 1 int index = 0;
764 1 int len = 0;
765 1 char *prm = i360_get_params_new(&index, &len);
766
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 while (index != -1) {
767
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (len > G_MIN_HANDLE_STRING_SIZE_RCE) {
768 2 file_value *values_dup = values;
769
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 time.
9 while (values_dup) {
770
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (values_dup->status > 0) {
771 int pcreExecRet;
772 int subStrVec[30];
773
774 8 pcreExecRet = pcre_exec(values_dup->re, values_dup->reE, prm, len, 0, PCRE_ANCHORED | PCRE_NO_START_OPTIMIZE,
775 subStrVec, 30);
776
777
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 7 times.
8 if (pcreExecRet > 0) {
778
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (values_dup->type == 1) {
779 i360_set_logger_rce();
780 }
781 8 return 1;
782 }
783 }
784 7 values_dup = values_dup->next;
785 }
786 }
787 1 prm = i360_get_params_new(&index, &len);
788 }
789 2 return 0;
790 }
791
792 #define MAX_DOMAIN_NAME 256
793
794 9 static void i360_extract_domain_name(char *param, char *buffer, int buffer_len) {
795 9 buffer_len = buffer_len - 1;
796 9 int p_len = strlen(param);
797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!p_len) {
798 strncpy(buffer, "", buffer_len);
799 return;
800 }
801 9 char *ptr = param;
802
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (p_len < 4) {
803 strncpy(buffer, param, buffer_len);
804 }
805 else {
806 9 ptr = strstr(param, "://");
807
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 if (!ptr) { //(ptr && param[0] == 'h' && param[1] == 't' && param[2] == 't' && param[3] == 'p')) {
808 6 ptr = param;
809 }
810 else {
811 3 ptr += 3;
812 }
813 9 int www_len = p_len - (ptr - param);
814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (www_len < 4) {
815 strncpy(buffer, ptr, buffer_len);
816 }
817 else {
818
5/8
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
9 if (ptr[0] == 'w' && ptr[1] == 'w' && ptr[2] == 'w' && ptr[3] == '.') {
819 2 ptr += 4;
820 }
821 9 int copy_len = strcspn(ptr, ":/");
822 9 copy_len = copy_len > buffer_len ? buffer_len : copy_len;
823 9 memcpy(buffer, ptr, copy_len);
824 9 buffer[copy_len] = 0;
825 }
826 }
827 9 return;
828 }
829
830 11 static int i360_fast_bad_syscall_detection_by_map_domain(__attribute__((unused)) params_list *params, map_int_t *m) {
831 11 char domain[MAX_DOMAIN_NAME] = {0};
832
3/4
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
11 if (!i360_get_params_new_numb() || !m)
833 2 return 0;
834 9 int index = 0;
835 9 int len = 0;
836 9 char *prm = i360_get_params_new(&index, &len);
837
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 6 times.
19 while (index != -1) {
838
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 4 times.
13 if (len > G_MIN_HANDLE_STRING_SIZE) {
839 9 i360_extract_domain_name(prm, domain, MAX_DOMAIN_NAME);
840 9 int *val = map_get(m, domain);
841
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if (val) {
842 3 return 1;
843 }
844 }
845 10 prm = i360_get_params_new(&index, &len);
846 }
847 11 return 0;
848 }
849
850 static int i360_fast_bad_syscall_detection_by_map_reverse(struct reversed_ordered_set_t *m) {
851 if (!i360_get_params_new_numb() || !m)
852 return 0;
853 int index = 0;
854 int len = 0;
855 char *prm = i360_get_params_new(&index, &len);
856 while (index != -1) {
857 if (len > G_MIN_HANDLE_STRING_SIZE) {
858 int val = i360_rev_ordered_find_partial(m, prm, len);
859 if (val >= 0) {
860 return 1;
861 }
862 }
863 prm = i360_get_params_new(&index, &len);
864 }
865 return 0;
866 }
867
868 13 void i360_param_check(char *func_info, params_list *params, int flags) {
869
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if (flags) {
870
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
13 if (flags & rce_patterns_list_mask) {
871
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if (i360_fast_bad_syscall_detection_files(params, parms_data_g_ptr->rce_patterns_list)) {
872 1 func_info[0] = (char)toupper((unsigned char)func_info[0]);
873 1 return;
874 }
875 }
876
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 time.
12 if (flags & black_urls_list_mask) {
877
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 8 times.
11 if (i360_fast_bad_syscall_detection_by_map_domain(params, urls_list)) {
878 3 func_info[0] = (char)toupper((unsigned char)func_info[0]);
879 3 return;
880 }
881 }
882 }
883 }
884
885 59 void i360_free_global_copy() {
886
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 1 time.
59 if (parms_data_g_ptr) {
887 58 i360_free_rules_whitelist(&parms_data_g_ptr->whitelist_map);
888 58 map_void_t null_map = map_static_init(0);
889
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (memcmp(&parms_data_g_ptr->whitelist_map, &null_map, sizeof(map_void_t))) {
890 map_deinit(&parms_data_g_ptr->whitelist_map);
891 }
892
893 58 memset(parms_data_g_ptr, 0, sizeof(*parms_data_g_ptr));
894 58 parms_data_g_ptr = NULL;
895 }
896
897
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 6 times.
59 if (storage) {
898 53 storage_free_cb(storage);
899 53 storage = NULL;
900 }
901
902 59 i360_free_script_rules();
903 59 i360_pd_database_deinit();
904 59 }
905
906 6227 static void i360_dump_rules(int dump_fd, int is_empty_rulelist, const char *fname, unsigned int rules[], int len,
907 int dump_zero_ruleid) {
908 #ifndef UNIT_TESTING
909 if (dump_fd < 0)
910 return;
911
912 if (is_empty_rulelist) {
913 dprintf(dump_fd, "\"%s\": []\n", fname);
914 }
915 else {
916 dprintf(dump_fd, "\"%s\":\n", fname);
917
918 size_t rules_ptr = (size_t)rules;
919 if (rules_ptr % sizeof(rules[0]))
920 dprintf(dump_fd, "# rules bad padding warning [%p]\n", rules);
921 else
922 dprintf(dump_fd, "# rules padding ok [%p]\n", rules);
923
924 int i;
925 for (i = 0; i < len; i++)
926 if (rules[i] || dump_zero_ruleid)
927 dprintf(dump_fd, "- %u\n", rules[i]);
928 }
929 #else
930 (void)dump_fd;
931 (void)is_empty_rulelist;
932 (void)fname;
933 (void)rules;
934 (void)len;
935 (void)dump_zero_ruleid;
936 #endif
937 6227 }
938
939 #define WL_FILE_PREFIX_LEN 4
940 #define WHITELIST_SUPER_RULE ""
941
942 7 static void i360_parse_whitelist_data_ver3(unsigned char *buffer, unsigned int buffer_size, map_void_t *map,
943 int dump_fd) {
944 7 unsigned int num_wl_item = (buffer_size - sizeof(unsigned int)) / sizeof(whitelist_file_item);
945
946
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if ((buffer_size - sizeof(unsigned int)) % sizeof(whitelist_file_item)) {
947 return;
948 }
949
950 7 whitelist_file_item *wl_item = (whitelist_file_item *)(((unsigned char *)buffer) + sizeof(unsigned int));
951
952
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 7 times.
219 while (num_wl_item--) {
953 // If no rules are listed, we whitelist all of them
954 212 unsigned char is_whitelist_rule = 0, is_empty_rulelist = !0;
955 212 int i = 0;
956
2/2
✓ Branch 0 taken 6784 times.
✓ Branch 1 taken 212 times.
6996 for (; i < MAX_WHITELIST_RULES; ++i) {
957
2/2
✓ Branch 0 taken 2874 times.
✓ Branch 1 taken 3910 times.
6784 if (wl_item->rules[i]) {
958 2874 is_whitelist_rule = 1;
959 2874 is_empty_rulelist = 0;
960 }
961 }
962
963 212 i360_dump_rules(dump_fd, is_empty_rulelist, wl_item->fname, wl_item->rules, MAX_WHITELIST_RULES,
964 /*dump_zero_ruleid*/ 0);
965
966
4/6
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 207 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
212 if (!strcmp(wl_item->fname, WHITELIST_SUPER_RULE) && !super_wl_rules && is_whitelist_rule) {
967 5 super_wl_rules = (char *)wl_item->rules;
968 5 qsort(super_wl_rules, MAX_WHITELIST_RULES, sizeof(unsigned int), i360_wl_item_comp);
969 }
970 else {
971
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 if (is_whitelist_rule) {
972 207 qsort(wl_item->rules, MAX_WHITELIST_RULES, sizeof(wl_item->rules[0]), i360_wl_item_comp);
973 }
974
975 207 map_set(map, wl_item->fname, wl_item->rules);
976 }
977
978 212 wl_item = (whitelist_file_item *)(((unsigned char *)wl_item) + sizeof(whitelist_file_item));
979 }
980 }
981
982 9 static void i360_parse_whitelist_data_ver4(unsigned char *buffer, unsigned int buffer_size, map_void_t *map,
983 int dump_fd) {
984 9 unsigned char *buffer_end = buffer + buffer_size, *buf = buffer + sizeof(int), *ptr, *wl_fname;
985 unsigned int fname_len, rules_num;
986 unsigned int *rules;
987 unsigned char is_whitelist_rule;
988
989 while (1) {
990 6015 ptr = buf;
991
992 6015 buf += sizeof(unsigned short int);
993
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6015 times.
6015 if (buf >= buffer_end)
994 goto fmt_broken;
995
996 6015 fname_len = *(unsigned short int *)ptr;
997 6015 ptr = buf;
998
999 6015 buf += fname_len;
1000
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6015 times.
6015 if (buf >= buffer_end)
1001 goto fmt_broken;
1002
1003 6015 wl_fname = ptr;
1004 6015 ptr = buf;
1005
1006 6015 buf += sizeof(unsigned char);
1007
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6015 times.
6015 if (buf >= buffer_end)
1008 goto fmt_broken;
1009
1010 6015 rules_num = *(unsigned char *)ptr;
1011 6015 rules = (unsigned int *)buf;
1012 6015 buf += sizeof(int) * rules_num;
1013
1014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6015 times.
6015 if (buf > buffer_end)
1015 goto fmt_broken;
1016
1017 6015 is_whitelist_rule = 0;
1018 6015 unsigned int i = 0;
1019
2/2
✓ Branch 0 taken 84039 times.
✓ Branch 1 taken 6015 times.
90054 for (; i < rules_num; ++i) {
1020
1/2
✓ Branch 0 taken 84039 times.
✗ Branch 1 not taken.
84039 if (rules[i])
1021 84039 is_whitelist_rule = 1;
1022 }
1023
1024 6015 i360_dump_rules(dump_fd, /*is_empty_rulelist*/ (rules_num == 0), (const char *)wl_fname, rules, rules_num,
1025 /*dump_zero_ruleid*/ !0);
1026
1027
5/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6009 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
6015 if (!strcmp((const char *)wl_fname, WHITELIST_SUPER_RULE) && !super_wl_rules && is_whitelist_rule) {
1028 5 super_wl_rules = (char *)ptr;
1029 5 qsort(rules, rules_num, sizeof(unsigned int), i360_wl_item_comp);
1030 }
1031 else {
1032
1/2
✓ Branch 0 taken 6010 times.
✗ Branch 1 not taken.
6010 if (is_whitelist_rule) {
1033 6010 qsort(rules, rules_num, sizeof(unsigned int), i360_wl_item_comp);
1034 }
1035
1036 6010 map_set(map, (const char *)wl_fname, ptr);
1037 }
1038
1039
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6006 times.
6015 if (buf == buffer_end)
1040 9 break;
1041 6006 }
1042 9 return;
1043
1044 fmt_broken:
1045 return;
1046 }
1047
1048 76 void i360_read_whitelist_from_file(map_void_t *map, char *filename) {
1049 76 i360_read_whitelist_from_file2(map, filename, /*dump_fd*/ -1);
1050 76 }
1051
1052 76 void i360_read_whitelist_from_file2(map_void_t *map, char *filename, int dump_fd) {
1053 76 FILE *file = fopen(filename, "rb");
1054
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 60 times.
76 if (file) {
1055
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (!(dump_fd < 0))
1056 dprintf(dump_fd, "---\n");
1057 struct stat statbuf;
1058
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if (stat(filename, &statbuf) == -1) {
1059 fclose(file);
1060 return;
1061 }
1062
1063 // wl_buffer is assumed to be NULL
1064
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (statbuf.st_size >= wl_buffer_size) {
1065
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 7 times.
8 if (wl_buffer != static_wl_buffer)
1066 1 free(wl_buffer);
1067
1068 8 wl_buffer = malloc(statbuf.st_size);
1069 8 wl_buffer_size = statbuf.st_size;
1070 }
1071
1072 // WL_STATIC_BUFFER_SIZE
1073
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 if (fread(wl_buffer, 1, statbuf.st_size, file)) {
1074 16 wl_version = *(unsigned int *)wl_buffer;
1075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (!(dump_fd < 0))
1076 dprintf(dump_fd, "# API_VER: %u\n", wl_version);
1077
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 9 times.
16 if (wl_version == WHITELIST_FILE_VER3) {
1078 7 i360_parse_whitelist_data_ver3(wl_buffer, statbuf.st_size, map, dump_fd);
1079 }
1080
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 else if (wl_version == WHITELIST_FILE_VER4) {
1081 9 i360_parse_whitelist_data_ver4(wl_buffer, statbuf.st_size, map, dump_fd);
1082 }
1083 }
1084
1085
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (!(dump_fd < 0))
1086 dprintf(dump_fd, "...\n");
1087 16 fclose(file);
1088 }
1089 }
1090
1091 78 void i360_free_rules_whitelist(map_void_t *map) {
1092 78 map_void_t null_map = map_static_init(0);
1093
5/6
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 77 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 62 times.
✓ Branch 5 taken 15 times.
78 if (!map || (map && !memcmp(map, &null_map, sizeof(map_void_t)))) {
1094 63 return;
1095 }
1096 15 char *key = NULL;
1097 15 map_iter_t iter = map_iter(map);
1098
1099
2/2
✓ Branch 1 taken 4216 times.
✓ Branch 2 taken 15 times.
4231 while ((key = (char *)map_next(map, &iter))) {
1100 4216 map_remove(map, key);
1101 4216 iter = map_iter(map);
1102 }
1103
1104 15 map_deinit(map);
1105
1106 15 super_wl_rules = NULL;
1107 15 memset(map, 0, sizeof(*map));
1108 }
1109
1110 18 void i360_free_wl_buffer() {
1111
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
18 if (static_wl_buffer != wl_buffer && wl_buffer) {
1112 7 free(wl_buffer);
1113 7 wl_buffer = static_wl_buffer;
1114 7 wl_buffer_size = WL_STATIC_BUFFER_SIZE;
1115 }
1116 18 }
1117
1118 #define GET_DATA_FROM_STORAGE(x) \
1119 x = &parms_data_g_ptr->x; \
1120 if (!x) { \
1121 i360_free_global_copy(); \
1122 return 1; \
1123 }
1124
1125 #define GET_DATA_FROM_STORAGE_TYPE(x, y) \
1126 x = (y)&parms_data_g_ptr->x; \
1127 if (!x) { \
1128 i360_free_global_copy(); \
1129 return 1; \
1130 }
1131
1132 53 static int i360_restore_dump(const char *fname, __attribute__((unused)) char sipher) {
1133 #ifndef UNIT_TESTING
1134 struct flock lock;
1135 memset(&lock, 0, sizeof(struct flock));
1136
1137 int fd = open(LOCK_F, O_RDONLY);
1138 if (fd == -1) {
1139 return 1;
1140 }
1141
1142 lock.l_type = F_RDLCK;
1143
1144 if (fcntl(fd, F_SETLKW, &lock) == -1) {
1145 close(fd);
1146 return 4;
1147 }
1148 #endif
1149
1150 53 storage = brp_restore_dump(fname, SECURITY_BYTE);
1151 53 storage_free_cb = &free;
1152
1153 #ifndef UNIT_TESTING
1154 fcntl(fd, F_UNLCK, &lock);
1155 close(fd);
1156 #endif
1157
1158 /* success */
1159 53 return 0;
1160 }
1161
1162 // Transformate in two items array only
1163 static const char *i360_restore_from_options(__attribute__((unused)) void (**free_cb)(void *ptr)) {
1164 char *result = NULL;
1165 struct {
1166 const char *bin_f, *dump_f;
1167 } options[] = {{BIN_F_AGENT, DUMP_F_AGENT}, {BIN_F, DUMP_F}},
1168 *next = &options[1]; // by default set /usr/share/i360-php-opt/.rules
1169 // Check for .rules time modification
1170 struct stat rules_vers_st, rules_pack_st;
1171 int rules_ver_rc = stat(options[0].bin_f, &rules_vers_st);
1172 int rules_pack_rc = stat(options[1].bin_f, &rules_pack_st);
1173 if ((rules_pack_rc == -1) && (rules_ver_rc == -1)) { // no files at all
1174 return result;
1175 }
1176 else if ((!rules_ver_rc) && (rules_pack_rc == -1)) { // no global rule only agent
1177 next = &options[0];
1178 }
1179 else if ((!rules_ver_rc) && (rules_vers_st.st_mtime >= rules_pack_st.st_mtime)) { // global present by agents more new
1180 // or equal
1181 next = &options[0];
1182 } // by default use global. erlier set
1183
1184 /* using strncpy safely to avoid -Wstringop-truncation (GCC 8) */
1185 size_t bin_f_len = strlen(next->bin_f);
1186 memcpy(current_db_path, next->bin_f, bin_f_len + 1);
1187
1188 struct stat dump_st, bin_st;
1189 int dump_rc = stat(next->dump_f, &dump_st);
1190 int bin_rc = stat(next->bin_f, &bin_st);
1191 if (dump_rc == OK && bin_rc == OK && dump_st.st_mtime >= bin_st.st_mtime) {
1192 result = brp_restore_mmap_dump(next->dump_f, &storage_free_cb);
1193 if (result)
1194 return result;
1195 }
1196 if (bin_rc == OK) {
1197 int rc = i360_restore_dump(next->bin_f, SECURITY_BYTE);
1198 if (rc == OK) {
1199 result = storage;
1200 storage_free_cb = &free;
1201 }
1202 }
1203
1204 return result;
1205 }
1206
1207 58 int i360_make_global_copy(i360_make_global_copy_params *params) {
1208 58 int index = 0;
1209 58 i360_set_database_version(SET_OLD_DBTYPE);
1210
1211
3/4
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
111 if (params && params->rules_file) {
1212 53 int rc = i360_restore_dump(params->rules_file, SECURITY_BYTE);
1213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (rc)
1214 return rc;
1215 //#ifdef UNIT_TESTING
1216 //#pragma GCC diagnostic push
1217 //#pragma GCC diagnostic ignored "-Wextra"
1218 /* https://debarshiray.wordpress.com/2019/04/01/about-wextra-and-wcast-function-type */
1219 // storage_free_cb = (storage_free_cb_ptr)&_test_free_internal;
1220 //#pragma GCC diagnostic pop
1221 //#else
1222 // storage_free_cb = &free;
1223 //#endif
1224 53 storage_free_cb = &free;
1225 }
1226
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 else if (i360_pd_database_init()) {
1227 5 i360_set_database_version(SET_HYPERSCAN_DBTYPE);
1228 5 parms_data_g_ptr = &parms_data_g_ptr_v2;
1229 5 funcs = NULL;
1230 5 func_id = NULL;
1231 5 func_old_conv = NULL;
1232 5 writeloggers = NULL;
1233 5 exclude_files_list = NULL;
1234
1235 5 map_init(&parms_data_g_ptr->whitelist_map);
1236
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
5 if (params && params->application_id && strncmp(params->application_id, "-1", 2) != 0) {
1237 char whitelist_path[PATH_MAX];
1238 snprintf(whitelist_path, PATH_MAX, "%s%s_rules_whitelist", WHITELIST_APP_PATH, params->application_id);
1239 i360_read_whitelist_from_file(&parms_data_g_ptr->whitelist_map, whitelist_path);
1240 } else {
1241 5 i360_read_whitelist_from_file(&parms_data_g_ptr->whitelist_map, WHITELIST_FILE);
1242 }
1243
1244 5 i360_load_script_rules();
1245 5 return 0;
1246 }
1247 else {
1248 storage = (void *)i360_restore_from_options(&storage_free_cb);
1249 }
1250
1251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (!storage) {
1252 i360_free_global_copy();
1253 return 2;
1254 }
1255
1256 53 parms_data_g_ptr = brp_get_pointer_with_number(storage, 0);
1257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (!parms_data_g_ptr) {
1258 i360_free_global_copy();
1259 return 3;
1260 }
1261
1262
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 GET_DATA_FROM_STORAGE(urls_list);
1263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 GET_DATA_FROM_STORAGE(files_list);
1264
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 GET_DATA_FROM_STORAGE(funcs);
1265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 GET_DATA_FROM_STORAGE(func_id);
1266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 GET_DATA_FROM_STORAGE(func_old_conv);
1267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 GET_DATA_FROM_STORAGE(writeloggers);
1268
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 GET_DATA_FROM_STORAGE(exclude_files_list);
1269
1270 53 map_init(&parms_data_g_ptr->whitelist_map);
1271
5/6
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 51 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 1 time.
54 if (params && params->application_id && strncmp(params->application_id, "-1", 2) != 0) {
1272 char whitelist_path[PATH_MAX];
1273 1 snprintf(whitelist_path, PATH_MAX, "%s%s_rules_whitelist", WHITELIST_APP_PATH, params->application_id);
1274 1 i360_read_whitelist_from_file(&parms_data_g_ptr->whitelist_map, whitelist_path);
1275 } else {
1276 52 i360_read_whitelist_from_file(&parms_data_g_ptr->whitelist_map, WHITELIST_FILE);
1277 }
1278
1279 53 fp_list_g = &parms_data_g_ptr->fp_list;
1280
1281 53 file_value *ptr = parms_data_g_ptr->rce_patterns_list;
1282
2/2
✓ Branch 0 taken 356 times.
✓ Branch 1 taken 53 times.
409 while (ptr) {
1283
1/2
✓ Branch 0 taken 356 times.
✗ Branch 1 not taken.
356 if (ptr->status > 0)
1284 356 pcre_pattern_to_host_byte_order(ptr->re, ptr->reE, NULL);
1285 356 ptr = ptr->next;
1286 }
1287
1288 53 rules_list *rules = parms_data_g_ptr->detector;
1289
2/2
✓ Branch 0 taken 268 times.
✓ Branch 1 taken 53 times.
321 while (rules) {
1290
1/2
✓ Branch 0 taken 268 times.
✗ Branch 1 not taken.
268 if (rules->status > 0)
1291 268 pcre_pattern_to_host_byte_order(rules->re, rules->reE, NULL);
1292
1293
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 253 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
268 if ((rules->precheck.param == 2) && (rules->precheck.status > 0)) {
1294 15 pcre_pattern_to_host_byte_order(rules->precheck.re, rules->precheck.reE, NULL);
1295 }
1296
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 268 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
268 if ((rules->fop_pfirst_chk.param == 2) && (rules->fop_pfirst_chk.status > 0)) {
1297 pcre_pattern_to_host_byte_order(rules->fop_pfirst_chk.re, rules->fop_pfirst_chk.reE, NULL);
1298 }
1299
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 268 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
268 if ((rules->fop_psecond_chk.param == 2) && (rules->fop_psecond_chk.status > 0)) {
1300 pcre_pattern_to_host_byte_order(rules->fop_psecond_chk.re, rules->fop_psecond_chk.reE, NULL);
1301 }
1302
1303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 268 times.
268 if (rules->private_fp_list.count) {
1304 int rule_index = 0;
1305 for (rule_index = 0; rule_index < rules->private_fp_list.count; rule_index++) {
1306 rules_list *item = rules->private_fp_list.rules[rule_index];
1307 while (item) {
1308 if (item->status > 0) {
1309 pcre_pattern_to_host_byte_order(item->re, item->reE, NULL);
1310 }
1311 item = item->next;
1312 }
1313 }
1314 }
1315 268 rules = rules->next;
1316 }
1317
1318 53 index = 0;
1319
2/2
✓ Branch 0 taken 535 times.
✓ Branch 1 taken 53 times.
588 for (index = 0; index < fp_list_g->count; index++) {
1320
2/2
✓ Branch 0 taken 470 times.
✓ Branch 1 taken 65 times.
535 if (fp_list_g->rules[index]) {
1321 470 rules_list *rl = fp_list_g->rules[index];
1322
2/2
✓ Branch 0 taken 535 times.
✓ Branch 1 taken 470 times.
1005 while (rl) {
1323
1/2
✓ Branch 0 taken 535 times.
✗ Branch 1 not taken.
535 if (rl->status > 0)
1324 535 pcre_pattern_to_host_byte_order(rl->re, rl->reE, NULL);
1325 535 rl = rl->next;
1326 }
1327 }
1328 }
1329
1330 53 i360_load_script_rules();
1331 53 return 0;
1332 }
1333
1334 9 static int i360_check_fp_inner(const char *queue, size_t queue_len, int check_empty, exclude_rules_list *find_list) {
1335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (find_list == NULL)
1336 return 0;
1337
1338 9 int val = i360_rev_ordered_find_partial(&find_list->files_list, cur_php_fname, strlen(cur_php_fname));
1339
4/6
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
9 if (val >= 0 && find_list->rules && find_list->rules[val]) {
1340 1 rules_list *rl = find_list->rules[val];
1341
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 while (rl) {
1342 // Only for rinit rules checker
1343 // no execution flow, that fp_rules should be marked as A in execution flow
1344 // A (big leter A) never faces in normal execution flow
1345
3/6
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
1 if (rl->status > 0 && rl->raw_regexp && rl->raw_regexp[0] != 'A') {
1346 int pcreExecRet;
1347 int subStrVec[30];
1348
1349 pcreExecRet =
1350 pcre_exec(rl->re, rl->reE, queue, (int)queue_len, 0, PCRE_ANCHORED | PCRE_NO_START_OPTIMIZE, subStrVec, 30);
1351
1352 if (pcreExecRet > 0) {
1353 return 1;
1354 }
1355 }
1356 else {
1357
4/8
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 7 not taken.
1 if (rl->raw_regexp && rl->raw_regexp[0] == 'A' && queue && !queue[0]) {
1358 // rule for i360_check_chain_rinit is in fp_list we shoukd to skip it
1359 1 return 1;
1360 }
1361 }
1362 rl = rl->next;
1363 }
1364 }
1365 else {
1366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (check_empty) {
1367 val = i360_rev_ordered_find_partial(&find_list->files_list, "***", 3);
1368 if (val >= 0) {
1369 rules_list *rl = find_list->rules[val];
1370 while (rl) {
1371 if (rl->status > 0 && rl->raw_regexp && rl->raw_regexp[0] != 'A') {
1372 int pcreExecRet;
1373 int subStrVec[30];
1374
1375 pcreExecRet = pcre_exec(rl->re, rl->reE, queue, (int)queue_len, 0, PCRE_ANCHORED | PCRE_NO_START_OPTIMIZE,
1376 subStrVec, 30);
1377
1378 if (pcreExecRet > 0) {
1379 return 1;
1380 }
1381 }
1382 rl = rl->next;
1383 }
1384 }
1385 }
1386 }
1387 8 return 0;
1388 }
1389
1390 9 int i360_check_fp(const char *queue, size_t queue_len, int check_empty) {
1391 9 return i360_check_fp_inner(queue, queue_len, check_empty, fp_list_g);
1392 }
1393
1394 8 static int i360_precheck_params_ext(rules_list *rule) {
1395
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (!rule->check_ext)
1396 8 return 1;
1397 if ((rule->check_ext_len <= 0))
1398 return 1;
1399
1400 if (i360_get_params_new_numb()) {
1401 int index = 0;
1402 int len = 0;
1403 char *prm = i360_get_params_new(&index, &len);
1404 while (index != -1) {
1405 if (((size_t)len >= rule->check_ext_len) &&
1406 (!strncmp(prm + len - rule->check_ext_len, rule->check_ext, rule->check_ext_len))) {
1407 return 1;
1408 }
1409 prm = i360_get_params_new(&index, &len);
1410 }
1411 }
1412 return 0;
1413 }
1414
1415 10 static int i360_precheck_script_ext(rules_list *rule) {
1416
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 if (!rule->script_ext_param)
1417 8 return 1;
1418
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if ((rule->script_ext_param > 2 || rule->script_ext_param < 0))
1419 return 1;
1420 2 char *ptr = cur_php_fname;
1421
1422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (rule->script_ext_param == 1) {
1423 if (!i360_isset_cur_php_fname() || rule->script_ext_len < 1 || !rule->script_ext) {
1424 return 0;
1425 }
1426
1427 char *ptr = cur_php_fname;
1428
1429 if ((cur_php_fname_len >= rule->script_ext_len) &&
1430 (!strncmp(ptr + cur_php_fname_len - rule->script_ext_len, rule->script_ext, rule->script_ext_len))) {
1431 return 1;
1432 }
1433
1434 return 0;
1435 }
1436 else {
1437
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (rule->script_ext_status > 0) {
1438 int pcreExecRet;
1439 int subStrVec[30];
1440
1441 2 pcreExecRet = pcre_exec(rule->script_ext_re,
1442 NULL, // rule->script_ext_reE,
1443 2 ptr, strlen(ptr), 0, PCRE_NO_START_OPTIMIZE, subStrVec, 30);
1444
1445
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (pcreExecRet > 0) {
1446 2 return 1;
1447 }
1448 }
1449 }
1450 return 0;
1451 }
1452
1453 8 static int i360_check_mail_heuristic(const char *func_name) {
1454 8 char max_param_len[G_MAX_ALT_NAME_LEN] = {0};
1455 8 int index = 0;
1456 8 int len = 0;
1457 8 char *prm = NULL;
1458
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 7 times.
8 if (!strncmp(func_name, "mail", G_MAX_ALT_NAME_LEN)) {
1459 1 return 1;
1460 }
1461
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
7 else if (!strncmp(func_name, "fsockopen", G_MAX_ALT_NAME_LEN) ||
1462 5 !strncmp(func_name, "pfsockopen", G_MAX_ALT_NAME_LEN)) {
1463
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if (i360_get_params_new_numb() > 1) {
1464 1 index = 1;
1465 1 len = 0;
1466 1 prm = i360_get_params_index_new(&index, &len);
1467
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
1 if (len > 0 && prm) {
1468 1 int port = atoi(prm);
1469
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (port == 25 || port == 587 || port == 465) {
1470 1 return 1;
1471 }
1472 }
1473 }
1474 }
1475
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 else if (!strncmp(func_name, "stream_socket_client", G_MAX_ALT_NAME_LEN)) {
1476
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if (i360_get_params_new_numb()) {
1477 1 index = 0;
1478 1 len = 0;
1479 1 prm = i360_get_params_index_new(&index, &len);
1480
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
1 if (prm && len > 0) {
1481 1 memcpy(max_param_len, prm, strnlen(prm, G_MAX_ALT_NAME_LEN - 1));
1482 1 char *str = strchr(max_param_len, ':');
1483
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (str) {
1484 1 str++;
1485 1 int port = atoi(str);
1486
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (port == 25 || port == 587 || port == 465) {
1487 2 return 1;
1488 }
1489 }
1490 }
1491 }
1492 }
1493
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 else if (!strncmp(func_name, "socket_connect", G_MAX_ALT_NAME_LEN)) {
1494
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if (i360_get_params_new_numb() > 2) {
1495 1 index = 2;
1496 1 len = 0;
1497 1 prm = i360_get_params_index_new(&index, &len);
1498
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
1 if (prm && len > 0) {
1499 1 int port = atoi(prm);
1500
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (port == 25 || port == 587 || port == 465) {
1501 1 return 1;
1502 }
1503 }
1504 }
1505 }
1506 8 return 0;
1507 }
1508
1509 14 static int i360_precheck_param_fop(rules_re_t *rule, int index) {
1510
2/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 if ((rule->param > 2 || rule->param <= 0))
1511 14 return 1;
1512 if (i360_get_params_new_numb() < index)
1513 return 0;
1514
1515 int len = 0;
1516 char *prm = i360_get_params_new(&index, &len);
1517 if (index == -1)
1518 return 0;
1519
1520 switch (rule->param) {
1521 case 1:
1522 if (len >= rule->string_len) {
1523 if (!strncmp(prm, rule->string_raw, rule->string_len)) {
1524 return 1;
1525 }
1526 }
1527 break;
1528 case 2:
1529 if (rule->status > 0) {
1530 int pcreExecRet;
1531 int subStrVec[30];
1532 pcreExecRet = pcre_exec(rule->re,
1533 NULL, // rule->reE,
1534 prm, len, 0, PCRE_NO_START_OPTIMIZE, subStrVec, 30);
1535 if (pcreExecRet > 0) {
1536 return 1;
1537 }
1538 }
1539 break;
1540 default:
1541 abort();
1542 }
1543 14 return 0;
1544 }
1545
1546 8 static int i360_precheck_params(int target, rules_re_t *rule) {
1547
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 if (!rule->param)
1548 5 return 1;
1549
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if ((rule->param > 2 || rule->param < 0))
1550 return 1;
1551
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if (i360_get_params_new_numb()) {
1552 3 int index = 0;
1553 3 int len = 0;
1554 3 char *prm = i360_get_params_new(&index, &len);
1555
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
4 while (index != -1) {
1556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (rule->param == 1) {
1557 if (len >= rule->string_len) {
1558 if (!strncmp(prm, rule->string_raw, rule->string_len)) {
1559 2 return 1;
1560 }
1561 }
1562 }
1563
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 else if (rule->param == 2) {
1564
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rule->status > 0) {
1565 int pcreExecRet;
1566 int subStrVec[30];
1567
1568 3 pcreExecRet = pcre_exec(rule->re,
1569 NULL, // rule->reE,
1570 prm, len, 0, PCRE_NO_START_OPTIMIZE, subStrVec, 30);
1571
1572
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 if (pcreExecRet > 0) {
1573 3 return 1;
1574 }
1575 }
1576 }
1577
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (target > 0)
1578 1 break; // for wp core should check only 1 parameter;
1579 prm = i360_get_params_new(&index, &len);
1580 }
1581 }
1582 1 return 0;
1583 }
1584
1585 35 static int i360_is_group_enabled(groups_rules_list *g_rules, unsigned int app_id, size_t enabled_group) {
1586
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
35 if ((g_rules->group_id == enabled_group) && (enabled_group))
1587 return 1;
1588
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 5 times.
35 if (g_rules->enabled) {
1589
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (app_id) {
1590 if (g_rules->app_id == app_id) {
1591 return 1;
1592 }
1593 }
1594 else {
1595 30 return 1;
1596 }
1597 }
1598 5 return 0;
1599 }
1600
1601 11 static int i360_precheck_function_name(rules_list *rule, const char *function_name) {
1602
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5 times.
11 if (rule->has_func_list) {
1603
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (!function_name || !rule->func_list)
1604 return 0;
1605 6 int *res = map_get(rule->func_list, function_name);
1606
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (res)
1607 6 return 1;
1608 return 0;
1609 }
1610 else
1611 5 return 1;
1612 }
1613
1614 2 static int i360_check_exclude_list() {
1615 2 char php_fname[RGX_MAX_DOCROOT_LEN + 1] = "";
1616 2 char cur_php_fname_dir[PATH_MAX] = "";
1617
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!exclude_list_opt)
1618 2 return 0;
1619 if (re_stat_rgx) {
1620 if (i360_get_params_new_numb()) {
1621 strncpy(cur_php_fname_dir, cur_php_fname, PATH_MAX);
1622 char *last_slash = strrchr(cur_php_fname_dir, '/');
1623 if (last_slash)
1624 *last_slash = 0;
1625 else
1626 strncpy(cur_php_fname_dir, "/", PATH_MAX);
1627 int index = 0;
1628 int len = 0;
1629 char *prm = i360_get_params_new(&index, &len);
1630 while (index != -1) {
1631 if (len > 0) {
1632 if (i360_translate_to_real_path(prm, cur_php_fname_dir, php_fname, RGX_MAX_DOCROOT_LEN)) {
1633 memcpy(php_fname, prm, strlen(prm));
1634 }
1635 int pcreExecRet;
1636 int subStrVec[30];
1637 pcreExecRet =
1638 pcre_exec(re_stat_rgx, NULL, php_fname, strlen(php_fname), 0, PCRE_NO_START_OPTIMIZE, subStrVec, 30);
1639 if (pcreExecRet > 0) {
1640 return 1;
1641 }
1642 }
1643 prm = i360_get_params_new(&index, &len);
1644 }
1645 }
1646 }
1647 2 return 0;
1648 }
1649
1650 4 static int i360_precheck_params_for_inclusion() {
1651
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (!malware_directory_config)
1652 4 return 0;
1653
1654 if (!i360_isset_cur_php_fname()) {
1655 return 0;
1656 }
1657
1658 if (i360_get_params_new_numb()) {
1659 int index = 0;
1660 int len = 0;
1661 char *prm = i360_get_params_new(&index, &len);
1662 while (index != -1) {
1663 if ((len > 0) && i360_check_if_file_marked_as_danger(prm, cur_php_fname, malware_directory_config_fd)) {
1664 return 1;
1665 }
1666 prm = i360_get_params_new(&index, &len);
1667 }
1668 }
1669
1670 return 0;
1671 }
1672
1673 1 int i360_precheck_params_for_inclusion_rinit(char *current_script_name) {
1674
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (!malware_directory_config || !current_script_name)
1675 1 return 0;
1676 if (strstr(current_script_name, "index.php"))
1677 return 0;
1678
1679 if (i360_check_if_file_marked_as_danger(current_script_name, current_script_name, malware_directory_config_fd)) {
1680 return 1;
1681 }
1682
1683 return 0;
1684 }
1685
1686 7 static int i360_precheck_susp_file_list(rules_list *rule) {
1687
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (!rule->is_list)
1688 7 return 1;
1689 return i360_fast_bad_syscall_detection_by_map_reverse(&rule->files_list);
1690 }
1691
1692 1 int i360_is_file_white_listed(int rule_id) {
1693 // Those files which names are whitelisted, we exclude
1694 // exclude them from regex search. Bitmask is used
1695
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (cur_wl_rules && (WHITELIST_FILE_VER3 == wl_version) &&
1696 (!((unsigned int *)cur_wl_rules)[0] ||
1697 bsearch(&rule_id, cur_wl_rules, MAX_WHITELIST_RULES, sizeof(int), i360_wl_item_comp)))
1698 return 1;
1699
1700
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 if (cur_wl_rules && (WHITELIST_FILE_VER4 == wl_version) && *(unsigned char *)cur_wl_rules &&
1701 (!((unsigned int *)(cur_wl_rules + 1))[0] ||
1702 bsearch(&rule_id, cur_wl_rules + 1, *(unsigned char *)cur_wl_rules, sizeof(int), i360_wl_item_comp)))
1703 return 1;
1704
1705 // Apply super-rules to every whitelist item
1706
3/6
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
2 if (super_wl_rules && (WHITELIST_FILE_VER3 == wl_version) &&
1707 1 bsearch(&rule_id, super_wl_rules, MAX_WHITELIST_RULES, sizeof(int), i360_wl_item_comp))
1708 return 1;
1709
1710
2/8
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 if (super_wl_rules && (WHITELIST_FILE_VER4 == wl_version) && super_wl_rules[0] &&
1711 bsearch(&rule_id, super_wl_rules + 1, *(unsigned char *)super_wl_rules, sizeof(int), i360_wl_item_comp))
1712 return 1;
1713
1714 1 return 0;
1715 }
1716
1717 5 static int i360_target_detection_by_map_reverse(char *file_name, struct reversed_ordered_set_t *m) {
1718 5 char php_fname[RGX_MAX_DOCROOT_LEN] = {0};
1719 5 char cur_php_fname_dir[PATH_MAX] = {0};
1720
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (!file_name || !m)
1721 return 0;
1722 /* using strncpy safely to avoid -Wstringop-truncation (GCC 8) */
1723 5 size_t cur_php_fname_len = strlen(cur_php_fname);
1724 5 memcpy(cur_php_fname_dir, cur_php_fname, cur_php_fname_len + 1);
1725 5 char *last_slash = strrchr(cur_php_fname_dir, '/');
1726
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (last_slash)
1727 5 *last_slash = 0;
1728 else
1729 strncpy(cur_php_fname_dir, "/", PATH_MAX);
1730
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 if (i360_translate_to_real_path(file_name, cur_php_fname_dir, php_fname, RGX_MAX_DOCROOT_LEN)) {
1731 5 memcpy(php_fname, file_name, strlen(file_name) + 1);
1732 }
1733 5 char file_name_copy[PATH_MAX] = {0};
1734 5 int val = i360_rev_ordered_find_partial(m, php_fname, strlen(php_fname));
1735
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 4 times.
5 if (val >= 0) {
1736 1 return 1;
1737 }
1738 else {
1739 /* using strncpy safely to avoid -Wstringop-truncation (GCC 8) */
1740 4 size_t php_fname_len = strlen(php_fname);
1741 4 memcpy(file_name_copy, php_fname, php_fname_len + 1);
1742 4 char *ptr = strrchr(file_name_copy, '/');
1743
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (ptr) {
1744 4 *ptr = 0;
1745 4 val = i360_rev_ordered_find_partial(m, file_name_copy, strlen(file_name_copy));
1746
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (val >= 0) {
1747 return 1;
1748 }
1749 }
1750 }
1751 5 return 0;
1752 }
1753
1754 2 static int i360_target_fpa_positive(rules_list *rule, char *file_name) {
1755
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (!i360_precheck_script_ext(rule))
1756 return 0;
1757
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (i360_target_detection_by_map_reverse(file_name, exclude_files_list))
1758 return 0;
1759 2 return 1;
1760 }
1761
1762 2 static int i360_target_fpa_postivie_detection_by_map_reverse() {
1763
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!exclude_files_list)
1764 return 0;
1765
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (i360_get_params_new_numb()) {
1766 2 int index = 0;
1767 2 int len = 0;
1768 2 char *prm = i360_get_params_new(&index, &len);
1769
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 while (index != -1) {
1770
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (len > G_MIN_HANDLE_STRING_SIZE) {
1771
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if (i360_target_detection_by_map_reverse(prm, exclude_files_list)) {
1772 1 return 1;
1773 }
1774 }
1775 1 prm = i360_get_params_new(&index, &len);
1776 }
1777 }
1778 1 return 0;
1779 }
1780
1781 1 static int i360_target_wp_core_check_fopen(const char *function_name) {
1782
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (!strncmp(function_name, "fopen", 5)) {
1783 if (i360_get_params_new_numb() > 1) {
1784 int index = 1;
1785 int len = 0;
1786 char *prm = i360_get_params_new(&index, &len);
1787 if (((len == 1) && !strncmp(prm, "r", 1)) || ((len == 2) && !strncmp(prm, "rb", 2))) {
1788 return 1;
1789 }
1790 }
1791 }
1792 1 return 0;
1793 }
1794
1795 7 static int i360_target_wp_core_protect(rules_list *rule, const char *function_name) {
1796
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 if (rule->target <= 0)
1797 5 return 1;
1798
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if (rule->target & TARGET_fpa_negative) {
1799
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if (i360_target_fpa_postivie_detection_by_map_reverse())
1800 return 0;
1801 1 return 1;
1802 }
1803
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 else if (rule->target & TARGET_fpa_notblock_postitive_script_negative) {
1804
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if (i360_target_wp_core_check_fopen(function_name))
1805 return 0;
1806
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if (!i360_target_fpa_postivie_detection_by_map_reverse())
1807 return 1;
1808
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if (!i360_isset_cur_php_fname())
1809 return 0;
1810 1 char *script = cur_php_fname;
1811
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if (i360_target_detection_by_map_reverse(script, exclude_files_list))
1812 return 0;
1813 1 return 1;
1814 }
1815 else if (rule->target & TARGET_fpa_negative_only) {
1816 if (i360_target_wp_core_check_fopen(function_name))
1817 return 0;
1818 if (i360_target_fpa_postivie_detection_by_map_reverse())
1819 return 0;
1820 return 1;
1821 }
1822 return 0;
1823 }
1824
1825 117 static int i360_default_recognizer_rule_match(rules_list *rule, const char *queue, size_t queue_len,
1826 const char *function_name) {
1827
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
117 if (rule->status <= 0 && !rule->detection_type)
1828 return 0;
1829
1830 // Those files which names are whitelisted, we exclude
1831 // exclude them from regex search. Bitmask is used
1832
5/6
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 25 times.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
117 if (cur_wl_rules && (WHITELIST_FILE_VER3 == wl_version) &&
1833
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 (!((unsigned int *)cur_wl_rules)[0] ||
1834 10 bsearch(&(rule->id), cur_wl_rules, MAX_WHITELIST_RULES, sizeof(int), i360_wl_item_comp)))
1835 6 return 0;
1836
1837
6/8
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 25 times.
✗ Branch 7 not taken.
111 if (cur_wl_rules && (WHITELIST_FILE_VER4 == wl_version) && *(unsigned char *)cur_wl_rules &&
1838
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 11 times.
25 (!((unsigned int *)(cur_wl_rules + 1))[0] ||
1839 25 bsearch(&(rule->id), cur_wl_rules + 1, *(unsigned char *)cur_wl_rules, sizeof(int), i360_wl_item_comp)))
1840 14 return 0;
1841
1842 // Apply super-rules to every whitelist item
1843
6/6
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 53 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 23 times.
123 if (super_wl_rules && (WHITELIST_FILE_VER3 == wl_version) &&
1844 26 bsearch(&(rule->id), super_wl_rules, MAX_WHITELIST_RULES, sizeof(int), i360_wl_item_comp))
1845 3 return 0;
1846
1847
7/8
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 53 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 23 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 15 times.
112 if (super_wl_rules && (WHITELIST_FILE_VER4 == wl_version) && super_wl_rules[0] &&
1848 18 bsearch(&(rule->id), super_wl_rules + 1, *(unsigned char *)super_wl_rules, sizeof(int), i360_wl_item_comp))
1849 3 return 0;
1850
1851 int pcreExecRet;
1852 int subStrVec[30];
1853
1854
1/2
✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
91 if (rule->detection_type == 0) {
1855 91 pcreExecRet =
1856 91 pcre_exec(rule->re, rule->reE, queue, (int)queue_len, 0, PCRE_ANCHORED | PCRE_NO_START_OPTIMIZE, subStrVec, 30);
1857 }
1858 else if (rule->detection_type == 1) {
1859 if (!rule->rule_string || !rule->rule_string_len)
1860 return 0;
1861 if (rule->rule_string_len > queue_len)
1862 return 0;
1863 pcreExecRet = strncmp(rule->rule_string, queue, rule->rule_string_len) ? -1 : 1;
1864 }
1865 else {
1866 pcreExecRet = queue[0] == rule->rule_char ? 1 : -1;
1867 }
1868
1869
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 20 times.
91 if (pcreExecRet < 1)
1870 71 return 0;
1871
1872
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
20 if (rule->check_blocked == 2) {
1873
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
6 return (i360_precheck_function_name(rule, function_name) &&
1874
2/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
4 (i360_precheck_params_for_inclusion() || i360_check_exclude_list()) && i360_precheck_susp_file_list(rule));
1875 }
1876
1877
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
18 if (rule->check_blocked == 1)
1878
2/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2 return (i360_precheck_function_name(rule, function_name) && i360_precheck_params_for_inclusion() &&
1879 i360_precheck_susp_file_list(rule));
1880
1881
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (rule->check_mail == 1)
1882 8 return i360_check_mail_heuristic(function_name);
1883
1884
4/6
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 1 time.
16 if (i360_precheck_script_ext(rule) && i360_precheck_params_ext(rule) &&
1885
2/4
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
22 i360_precheck_params(rule->target, &rule->precheck) && i360_precheck_param_fop(&rule->fop_pfirst_chk, 0) &&
1886
2/4
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
21 i360_precheck_param_fop(&rule->fop_psecond_chk, 1) && i360_precheck_function_name(rule, function_name) &&
1887
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
14 i360_precheck_susp_file_list(rule) && i360_target_wp_core_protect(rule, function_name)) {
1888
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 if (rule->is_list || rule->check_fp) {
1889 ((unsigned char*)queue)[0] = (char)toupper((unsigned char)queue[0]);
1890 }
1891 7 return (rule->check_fp != 1)
1892 7 ? ((rule->private_fp_list.count > 0)
1893 ? (!i360_check_fp_inner(queue, queue_len, 0, (exclude_rules_list *)&rule->private_fp_list))
1894
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 : (!i360_check_fp(queue, queue_len, 0)))
1895
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
14 : 1; // fp exclude list
1896 }
1897
1898 117 return 0;
1899 }
1900
1901 #define FNAME_LEN 16
1902
1903 3 int i360_check_null_file_size(const char *fname) {
1904 3 char php_fname[RGX_MAX_DOCROOT_LEN + 1] = "";
1905 3 char cur_php_fname_dir[PATH_MAX] = "";
1906 struct stat st;
1907
1908
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (!fname || *fname == 0)
1909 return 1;
1910
1911 3 strncpy(cur_php_fname_dir, cur_php_fname, PATH_MAX);
1912 3 char *last_slash = strrchr(cur_php_fname_dir, '/');
1913
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 if (last_slash)
1914 2 *last_slash = 0;
1915 else
1916 1 cur_php_fname_dir[0] = '\0';
1917 //strncpy(cur_php_fname_dir, "/", PATH_MAX);
1918
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
3 if (i360_translate_to_real_path(fname, cur_php_fname_dir, php_fname, RGX_MAX_DOCROOT_LEN))
1919 1 memcpy(php_fname, fname, strlen(fname));
1920
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
3 if (!stat(php_fname, &st) && st.st_size)
1921 2 return 0;
1922
1923 3 return 1;
1924 }
1925
1926 20 static rules_list *i360_script_default_recognizer(const char *function_name, const char *queue, size_t queue_len) {
1927 20 const char *names[] = {cur_php_fname, "*"};
1928 size_t i;
1929
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 20 times.
60 for (i = 0; i < sizeof(names)/sizeof(names[0]); ++ i) {
1930 40 script_rules_t *script_rules = i360_get_script_rules(names[i], cur_php_uid);
1931
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (script_rules) {
1932 rules_list *rule = script_rules->rules;
1933 while (rule) {
1934 i360_ull rule_timer = 0;
1935 i360_counter_saver_savetimer(&rule_timer);
1936 if (i360_default_recognizer_rule_match(rule, queue, queue_len, function_name)) {
1937 i360_counter_saver_add_rule(rule->id, rule_timer);
1938 return rule;
1939 }
1940 i360_counter_saver_add_rule(rule->id, rule_timer);
1941
1942 rule = rule->next;
1943 }
1944 }
1945 }
1946
1947 20 return NULL;
1948 }
1949
1950 28 static rules_list *i360_default_recognizer(const char *function_name, const char *queue, size_t queue_len, int level,
1951 unsigned int app_id, int enabled_group) {
1952 28 groups_rules_list *g_rules = parms_data_g_ptr->grp_detector;
1953
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 17 times.
48 while (g_rules) {
1954
2/2
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 3 times.
31 if (i360_is_group_enabled(g_rules, app_id, enabled_group)) {
1955 28 rules_list_ptr *rules_ptr = g_rules->head;
1956
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 17 times.
137 while (rules_ptr) {
1957 120 rules_list *rule = rules_ptr->rule_ptr;
1958
1959
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (rule->level < level) {
1960 rules_ptr = rules_ptr->next;
1961 3 continue;
1962 }
1963
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 117 times.
120 if (rule->target & TARGET_before_execution_negative) {
1964 3 rules_ptr = rules_ptr->next;
1965 3 continue;
1966 }
1967
1968 117 i360_ull rule_timer = 0;
1969 117 i360_counter_saver_savetimer(&rule_timer);
1970
1971
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 106 times.
117 if (i360_default_recognizer_rule_match(rule, queue, queue_len, function_name)) {
1972 11 i360_counter_saver_add_rule(rule->id, rule_timer);
1973 11 return rule;
1974 }
1975
1976 106 i360_counter_saver_add_rule(rule->id, rule_timer);
1977
1978 106 rules_ptr = rules_ptr->next;
1979 }
1980 }
1981 20 g_rules = g_rules->next;
1982 }
1983
1984 17 return i360_script_default_recognizer(function_name, queue, queue_len);
1985 }
1986
1987 33 static int i360_get_app_id() {
1988 33 return 0;
1989 }
1990
1991 28 void i360_check_chain(__attribute__((unused)) params_list *params, chain_result *result, int logger,
1992 const char *function_name, const char *queue, size_t queue_len, int level, int enabled_group) {
1993 28 memset(result, 0, sizeof(chain_result));
1994 28 result->danger_type = NODANGER;
1995 28 result->recognizer_id = I360_RECOGNIZER_ID_NONE;
1996
1997 28 rules_list *rules = i360_default_recognizer(function_name, queue, queue_len, level, i360_get_app_id(), enabled_group);
1998
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 17 times.
28 if (rules) {
1999
3/6
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
11 if ((rules->action == BLOCK_FUNC) || (rules->id >= PHP_IMUNITY_MIN_ID && rules->id <= PHP_IMUNITY_MAX_ID)) {
2000 2 result->block = 1;
2001 }
2002
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
11 if (rules->action != NO_ACTION && rules->check_blocked == 2) {
2003 result->block = 2;
2004 }
2005 11 result->recognizer_id = I360_RECOGNIZER_ID_COMMON;
2006 11 result->chain_id = rules->id;
2007 11 result->danger_type = DANGER;
2008 11 result->recognizer_desr = I360_RECOGNIZER_ID_COMMON_DESC;
2009 11 result->ruldescr = rules->description;
2010 }
2011
2012
3/6
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
28 if ((result->chain_id >= G_NON_LOG_RULE_ID) || (i360_is_rce_logger_log_mode() && (result->danger_type == DANGER))) {
2013 2 result->recognizer_id = I360_RECOGNIZER_ID_INTERNAL;
2014 2 result->recognizer_desr = I360_RECOGNIZER_ID_INTERNAL_DESC;
2015 }
2016
2017
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 26 times.
28 if (logger) {
2018
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if (result->danger_type) {
2019 1 result->action = LOG_ONLY;
2020 }
2021 else {
2022 1 result->recognizer_desr = I360_RECOGNIZER_ID_LOG_DESC;
2023 1 result->action = LOG_ONLY;
2024 1 result->recognizer_id = I360_RECOGNIZER_ID_LOG;
2025 1 result->chain_id = 0;
2026 1 result->danger_type = DANGER;
2027 }
2028 }
2029 28 }
2030
2031 2 static int i360_target_before_execution_negative(rules_list *rule, char *file_name) {
2032 2 return i360_target_fpa_positive(rule, file_name);
2033 }
2034
2035 2 static rules_list *i360_default_recognizer_rinit(int level, unsigned int app_id, size_t enabled_group,
2036 char *file_name) {
2037 2 groups_rules_list *g_rules = parms_data_g_ptr->grp_detector;
2038
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 time.
5 while (g_rules) {
2039
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (i360_is_group_enabled(g_rules, app_id, enabled_group)) {
2040 2 rules_list_ptr *rules_ptr = g_rules->head;
2041
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 time.
8 while (rules_ptr) {
2042 7 rules_list *rule = rules_ptr->rule_ptr;
2043
2044
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (rule->level < level) {
2045 rules_ptr = rules_ptr->next;
2046 5 continue;
2047 }
2048
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 if (!(rule->target & TARGET_before_execution_negative)) {
2049 5 rules_ptr = rules_ptr->next;
2050 5 continue;
2051 }
2052
2053 2 i360_ull rule_timer = 0;
2054 2 i360_counter_saver_savetimer(&rule_timer);
2055
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (i360_target_before_execution_negative(rule, file_name)) {
2056 // Check for fp_rules without execution flow
2057
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (rule->check_fp != 1) {
2058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (rule->private_fp_list.count > 0) {
2059 if (!i360_check_fp_inner("", 0, 0, (exclude_rules_list *)&rule->private_fp_list)) {
2060 i360_counter_saver_add_rule(rule->id, rule_timer);
2061 1 return rule;
2062 }
2063 }
2064 else {
2065
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if (!i360_check_fp("", 0, 0)) {
2066 1 i360_counter_saver_add_rule(rule->id, rule_timer);
2067 1 return rule;
2068 }
2069 }
2070 }
2071 else {
2072 i360_counter_saver_add_rule(rule->id, rule_timer);
2073 return rule;
2074 }
2075 }
2076 1 i360_counter_saver_add_rule(rule->id, rule_timer);
2077
2078 1 rules_ptr = rules_ptr->next;
2079 }
2080 }
2081 3 g_rules = g_rules->next;
2082 }
2083
2084 1 return NULL;
2085 }
2086
2087 2 void i360_check_chain_rinit(chain_result *result, int logger, int level, int enabled_group, char *file_name) {
2088 2 memset(result, 0, sizeof(chain_result));
2089 2 result->danger_type = NODANGER;
2090 2 result->recognizer_id = I360_RECOGNIZER_ID_NONE;
2091
2092
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (!i360_pd_database_check_rinit(result, level, enabled_group, "", 0)) {
2093 2 rules_list *rules = i360_default_recognizer_rinit(level, i360_get_app_id(), enabled_group, file_name);
2094
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if (rules) {
2095
3/6
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
1 if ((rules->action == BLOCK_FUNC) || (rules->id >= PHP_IMUNITY_MIN_ID && rules->id <= PHP_IMUNITY_MAX_ID)) {
2096 result->block = 1;
2097 }
2098
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
1 if (rules->action != NO_ACTION && rules->check_blocked == 2) {
2099 result->block = 2;
2100 }
2101 1 result->recognizer_id = I360_RECOGNIZER_ID_COMMON;
2102 1 result->chain_id = rules->id;
2103 1 result->danger_type = DANGER;
2104 1 result->recognizer_desr = I360_RECOGNIZER_ID_COMMON_DESC;
2105 1 result->ruldescr = rules->description;
2106 }
2107 }
2108
2109
3/6
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2 if ((result->chain_id >= G_NON_LOG_RULE_ID) || (i360_is_rce_logger_log_mode() && (result->danger_type == DANGER))) {
2110 1 result->recognizer_id = I360_RECOGNIZER_ID_INTERNAL;
2111 1 result->recognizer_desr = I360_RECOGNIZER_ID_INTERNAL_DESC;
2112 }
2113
2114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (logger) {
2115 if (result->danger_type) {
2116 result->action = LOG_ONLY;
2117 }
2118 else {
2119 result->recognizer_desr = I360_RECOGNIZER_ID_LOG_DESC;
2120 result->action = LOG_ONLY;
2121 result->recognizer_id = I360_RECOGNIZER_ID_LOG;
2122 result->chain_id = 0;
2123 result->danger_type = DANGER;
2124 }
2125 }
2126 2 }
2127
2128 9 int i360_result_action(chain_result *chains, int user_action) {
2129
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (chains->recognizer_id == I360_RECOGNIZER_ID_INTERNAL) {
2130 return LOG_ONLY;
2131 }
2132 9 return user_action;
2133 }
2134
2135 4 void i360_func_foreach(void (*f)(const char *key, const char *val, int is_danger, int is_openwrite,
2136 const void *dbfunc)) {
2137
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (i360_pd_database_func_foreach(f))
2138 4 return;
2139
2140 const char *key = NULL;
2141 map_iter_t iter = map_iter(funcs);
2142 while ((key = map_next(funcs, &iter))) {
2143 char *res = (char *)map_value(funcs, &iter);
2144 if (map_get(writeloggers, key)) {
2145 f(key, res, 1, 1, 0);
2146 }
2147 else {
2148 f(key, res, 1, 0, 0);
2149 }
2150 }
2151
2152 iter = map_iter(writeloggers);
2153 while ((key = map_next(writeloggers, &iter))) {
2154 if (!map_get(funcs, key)) {
2155 f(key, NULL, 0, 1, 0);
2156 }
2157 }
2158 }
2159
2160 #ifndef UNIT_TESTING
2161 void i360_print_params(params_list *params, const char *fname, const char *dbgfile_name) {
2162 if (!params)
2163 return;
2164 if (dbgfile_name) {
2165 i360_write_debug_log(dbgfile_name, 2, "FUNC PARAMS %s:", fname);
2166 }
2167 if (params->head) {
2168 params_item *item = params->head;
2169 while (item) {
2170 if (dbgfile_name) {
2171 i360_write_debug_log(dbgfile_name, 0, "%s,", item->param);
2172 }
2173 item = item->next;
2174 }
2175 }
2176 if (dbgfile_name) {
2177 i360_write_debug_log(dbgfile_name, 3, "");
2178 }
2179 return;
2180 }
2181
2182 void i360_print_params_new(const char *fname, const char *dbgfile_name) {
2183 if (!i360_params_numb)
2184 return;
2185 if (dbgfile_name) {
2186 i360_write_debug_log(dbgfile_name, 2, "FUNC PARAMS %s:", fname);
2187 }
2188 if (i360_params_numb) {
2189 int index = 0;
2190 int len = 0;
2191 char *prm = i360_get_params_new(&index, &len);
2192 while (index != -1) {
2193 if (dbgfile_name) {
2194 i360_write_debug_log(dbgfile_name, 0, "%s,", prm);
2195 }
2196 prm = i360_get_params_new(&index, &len);
2197 }
2198 }
2199 if (dbgfile_name) {
2200 i360_write_debug_log(dbgfile_name, 3, "");
2201 }
2202 return;
2203 }
2204
2205 void i360_print_func_dict_letter() {
2206 const char *key = NULL;
2207 map_iter_t iter = map_iter(funcs);
2208 while ((key = map_next(funcs, &iter))) {
2209 char *res = (char *)map_get(funcs, key);
2210 char letter_buf[2] = {0};
2211 snprintf(letter_buf, 2, "%c", res[0]);
2212 printf("%c\t%s\n", res[0], key);
2213 }
2214 iter = map_iter(&parms_data_g_ptr->groups);
2215 while ((key = map_next(&parms_data_g_ptr->groups, &iter))) {
2216 char *res = (char *)map_get(&parms_data_g_ptr->groups, key);
2217 char *name = (char *)map_get(funcs, res);
2218 if (!name) {
2219 printf("%c\t%s\n", key[0], res);
2220 }
2221 }
2222 }
2223
2224 void i360_print_func_dict() {
2225 char letter_shown[256] = {0};
2226 const char *key = NULL;
2227 map_iter_t iter = map_iter(funcs);
2228 while ((key = map_next(funcs, &iter))) {
2229 char *res = (char *)map_get(funcs, key);
2230 uint8_t index = (uint8_t)res[0];
2231 if (!letter_shown[index]) {
2232 char letter_buf[2] = {0};
2233 snprintf(letter_buf, 2, "%c", res[0]);
2234 char *name = (char *)map_get(&parms_data_g_ptr->groups, letter_buf);
2235 printf("%c\t%s\n", res[0], name ? name : key);
2236 letter_shown[index] = 1;
2237 }
2238 }
2239 }
2240
2241 void i360_print_groups_dict() {
2242 groups_rules_list *g_rules = parms_data_g_ptr->grp_detector;
2243 while (g_rules) {
2244 if (i360_is_group_enabled(g_rules, 0, 0)) {
2245 printf("%d\t%s\n", g_rules->group_id, g_rules->group_description);
2246 }
2247 g_rules = g_rules->next;
2248 }
2249 }
2250 #endif
2251
2252 1 params_global_data *i360_get_global_data() {
2253 1 return parms_data_g_ptr;
2254 }
2255
2256 1 identifier i360_make_anyop_old(uint8_t glb, uint8_t uniq) {
2257 1 identifier tmp = {0};
2258 1 tmp.split.syscall_name = ANYOP;
2259 1 tmp.split.reserved = PHP1_RESERVED;
2260 1 tmp.split.anyop_calls = glb;
2261 1 tmp.split.anyop_dif_modif = uniq;
2262 1 return tmp;
2263 }
2264
2265 1 int i360_is_eval_in_func_list() {
2266 char buffer[G_MAX_RESULT_LEN];
2267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (!funcs)
2268 return 1;
2269 1 memset(buffer, 0, G_MAX_RESULT_LEN);
2270
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 if (i360_is_function_hooked("eval", buffer)) {
2271 1 return 1;
2272 }
2273 1 return 0;
2274 }
2275
2276 #define FILE_DEBUG_LEN 4096
2277
2278 3 int i360_write_debug_log(const char *file_name, int new_line, const char *format, ...) {
2279 char file_name_new[FILE_DEBUG_LEN];
2280 char buffer[16000];
2281 3 snprintf(file_name_new, FILE_DEBUG_LEN, "%s.%d", file_name, getpid());
2282 3 FILE *fp = fopen(file_name_new, "a");
2283
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (fp) {
2284 struct timeval tv;
2285 3 gettimeofday(&tv, NULL);
2286 va_list args;
2287 3 va_start(args, format);
2288 3 vsnprintf(buffer, 16000, format, args);
2289 3 va_end(args);
2290
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
3 if (new_line == 1) {
2291 1 fprintf(fp, "[%lld.%lld] %s\n", (long long)(tv.tv_sec), (long long)(tv.tv_usec) / 1000, buffer);
2292 }
2293
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 else if (new_line == 2) {
2294 1 fprintf(fp, "[%lld.%lld] %s", (long long)(tv.tv_sec), (long long)(tv.tv_usec) / 1000, buffer);
2295 }
2296 else {
2297
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 fprintf(fp, "%s%s", buffer, (new_line ? "\n" : ""));
2298 }
2299 3 fclose(fp);
2300 }
2301 3 return 0;
2302 }
2303
2304 static __thread int rce_logger = 0;
2305
2306 1 void i360_reset_logger_rce() {
2307 1 rce_logger = 0; // block mode
2308 1 }
2309
2310 1 void i360_set_logger_rce() {
2311 1 rce_logger = 1; // log mode
2312 1 }
2313
2314 30 int i360_is_rce_logger_log_mode() {
2315 30 return rce_logger == 1;
2316 }
2317
2318 typedef void (*iter_environ_cb)(char *s, size_t ln, void *data);
2319
2320 #if (defined(PHP_MAJOR_VERSION) && PHP_MAJOR_VERSION >= 8) || defined(UNIT_TESTING)
2321 /**
2322 * Slurp file content into memory buffer on heap.
2323 * File size is not checked, thus slurp_file() is Ok
2324 * to be used for procfs items or pipes.
2325 *
2326 * @param path
2327 * @param buf_heapptr placeholder for heap buffer pointer.
2328 * That is slurp_file() caller responsibility to free heap buffer
2329 * when the things are done.
2330 * @Return number of bytes read or -1 on error
2331 */
2332 2 static ssize_t slurp_file(const char *path, char **buf_heapptr) {
2333 2 FILE *fp = fopen(path, "rb");
2334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!fp)
2335 return -1;
2336
2337 2 size_t buf_len = 4096;
2338
2339
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (!(*buf_heapptr = malloc(buf_len))) {
2340 fclose(fp);
2341 return -1;
2342 }
2343
2344 2 size_t buf_free_capacity = buf_len;
2345 2 size_t buf_next_chunk_offset = 0;
2346 2 ssize_t retval = 0;
2347
2348 while (true) {
2349 3 size_t bytes_read = fread(*buf_heapptr + buf_next_chunk_offset, 1, buf_free_capacity, fp);
2350 3 retval += bytes_read;
2351 3 buf_free_capacity -= bytes_read;
2352
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 if (buf_free_capacity)
2353 2 break;
2354
2355 1 buf_next_chunk_offset += bytes_read;
2356 1 size_t grow_by = buf_len; // grow buf exponentially (x2)
2357 1 void *newptr = realloc(*buf_heapptr, buf_len + grow_by); // Mind possible memory leak
2358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (!(newptr)) {
2359 fclose(fp);
2360 free(*buf_heapptr);
2361 *buf_heapptr = NULL;
2362 return -1;
2363 }
2364 1 *buf_heapptr = newptr;
2365 1 buf_len += grow_by;
2366 1 buf_free_capacity += grow_by;
2367 1 }
2368
2369 2 fclose(fp);
2370 2 return retval;
2371 }
2372
2373 /**
2374 * Iterate over /proc/self/environ strings
2375 *
2376 * @param cb callback to be called for each environ string
2377 * @Return zero on success or -1 on error
2378 */
2379 #ifndef UNIT_TESTING
2380 static
2381 #endif
2382 2 int iter_proc_self_environ(iter_environ_cb cb, char *path, void *data) {
2383 char *environ_buf;
2384 2 ssize_t read = slurp_file(path, &environ_buf);
2385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (read < 0)
2386 return -1;
2387
2388 size_t ln;
2389 2 char *p = environ_buf, *q = p + read;
2390
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 2 times.
105 for (; q != p; p += ln + 1) {
2391 103 ln = strlen(p);
2392 103 cb(p, ln, data);
2393 }
2394 2 free(environ_buf);
2395 2 return 0;
2396 }
2397 #endif
2398
2399 2 static void iter_environ(iter_environ_cb cb) {
2400 2 char **s = environ;
2401
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 2 times.
74 for (; *s; ++s) {
2402 72 int ln = strlen(*s);
2403 72 cb(*s, ln, NULL);
2404 }
2405 2 }
2406
2407 #include "envfilter.c"
2408
2409 72 static void i360_init_global_server_cb(char *s, size_t ln, __attribute__((unused)) void *data) {
2410
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 70 times.
72 if (i360_need_save_env_variable(s, ln) == 1) {
2411 2 i360_add_func_param(&server_array, s, ln);
2412 }
2413 72 }
2414
2415 2 void i360_init_global_server() {
2416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (server_array.head) {
2417 i360_free_func_params(&server_array);
2418 }
2419 #if (defined(PHP_MAJOR_VERSION) && PHP_MAJOR_VERSION >= 8) || defined(UNIT_TESTING)
2420
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (environ)
2421 {
2422 2 iter_environ(i360_init_global_server_cb);
2423 }
2424 else {
2425 iter_proc_self_environ(i360_init_global_server_cb, "/proc/self/environ", NULL);
2426 }
2427 #else
2428 iter_environ(i360_init_global_server_cb);
2429 #endif
2430 2 }
2431
2432 1 void i360_init_global_server_no_env() {
2433
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (server_array.head) {
2434 1 i360_free_func_params(&server_array);
2435 }
2436 1 }
2437
2438 1 void i360_add_value_to_global_server(char *key, int len) {
2439 1 i360_add_func_param(&server_array, key, len);
2440 1 }
2441
2442 1 void i360_clean_global_server() {
2443 1 i360_free_func_params(&server_array);
2444 1 }
2445
2446 1 params_list *i360_get_global_server() {
2447 1 return (params_list *)&server_array;
2448 }
2449
2450 #define I360_PARAM_BUF_LEN_QUEUE 15
2451
2452 38 int i360_check_open_read(const char *fname, __attribute__((unused)) char short_name, int recognizer_id, int chain_id) {
2453
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 31 times.
38 if (recognizer_id != I360_RECOGNIZER_ID_COMMON)
2454 7 return 0;
2455
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 17 times.
31 if ((chain_id < PHP_IMUNITY_MIN_ID) || (chain_id > PHP_IMUNITY_MAX_ID))
2456 14 return 0;
2457
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 16 times.
17 if (!fname)
2458 1 return 0;
2459
2460
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 if (!strcmp(fname, "file_get_contents"))
2461 2 return 1;
2462
2463
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
14 if (strcmp(fname, "fopen"))
2464 2 return 0;
2465
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
12 if (i360_get_params_new_numb() < 2)
2466 2 return 0;
2467 10 int index = 1;
2468 10 int len = 0;
2469 10 char *prm = i360_get_params_index_new(&index, &len);
2470
3/6
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
10 if (!prm || len == 0 || len > 2)
2471 return 0;
2472
2473 // check is read
2474 10 char sym0 = prm[0];
2475 10 char sym1 = 0;
2476
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 if (len > 1)
2477 6 sym1 = prm[1];
2478 10 sym0 = (char)tolower((unsigned char)sym0);
2479
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
10 if (sym0 == 'r' && sym1 != '+')
2480 4 return 1;
2481 38 return 0;
2482 }
2483
2484 #define MAX_PEPARED_BUFER_LEN 4096
2485 #define MAX_PREPARED_ARRAY_LEN 100
2486 #define MIN_NEEDED_DATA 20
2487
2488 static char prepared_data_buffer[MAX_PREPARED_ARRAY_LEN][MAX_PEPARED_BUFER_LEN] = {{0}};
2489 static int last_free_in_prepared_buffer = 0;
2490 static int prepared_data_buffer_done = 0;
2491
2492 1 void i360_clear_prepared_buffer() {
2493 1 memset(prepared_data_buffer, 0, sizeof(prepared_data_buffer));
2494 1 last_free_in_prepared_buffer = 0;
2495 1 prepared_data_buffer_done = 0;
2496 1 }
2497
2498 1 void i360_fix_prepared_buffer() {
2499 1 prepared_data_buffer_done = last_free_in_prepared_buffer;
2500 1 }
2501
2502 // 1 - data added successfully
2503 // -1 - no place for new static data
2504 // 0 - no data added, data is empty
2505 83 int i360_add_prepared_buffer_req_data(char *data) {
2506
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 1 time.
83 if (data) {
2507
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 80 times.
82 if (last_free_in_prepared_buffer >= (MAX_PREPARED_ARRAY_LEN - MIN_NEEDED_DATA)) {
2508 2 return -1;
2509 }
2510 80 strncpy(prepared_data_buffer[last_free_in_prepared_buffer], data, MAX_PEPARED_BUFER_LEN - 1);
2511 80 last_free_in_prepared_buffer++;
2512 #if MIN_NEEDED_DATA == 0
2513 if (last_free_in_prepared_buffer >= MAX_PREPARED_ARRAY_LEN)
2514 last_free_in_prepared_buffer = MAX_PREPARED_ARRAY_LEN - 1;
2515 #endif
2516 80 return 1;
2517 }
2518 else {
2519 1 return 0;
2520 }
2521 return 0;
2522 }
2523
2524 1 void i360_restore_buffer_for_dynamic() {
2525 1 last_free_in_prepared_buffer = prepared_data_buffer_done;
2526 1 }
2527
2528 // 1 - data added successfully
2529 // -1 - no place for new dyn data
2530 // 0 - no data added, data is empty
2531 24 int i360_add_prepared_buffer_dyn_data(char *data) {
2532
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 1 time.
24 if (data) {
2533
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 21 times.
23 if (last_free_in_prepared_buffer >= MAX_PREPARED_ARRAY_LEN) {
2534 2 return -1;
2535 };
2536 21 strncpy(prepared_data_buffer[last_free_in_prepared_buffer], data, MAX_PEPARED_BUFER_LEN - 1);
2537 21 last_free_in_prepared_buffer++;
2538 21 return 1;
2539 }
2540 else {
2541 1 return 0;
2542 }
2543 return 0;
2544 }
2545
2546 2 int i360_is_prepared_buffer_fixed() {
2547 2 return prepared_data_buffer_done;
2548 }
2549
2550 6 int i360_prepared_buffer_length() {
2551 6 return last_free_in_prepared_buffer;
2552 }
2553
2554 2 char *i360_prepared_buffer_get(int index) {
2555
3/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
2 if (index < 0 || index >= last_free_in_prepared_buffer)
2556 1 return NULL;
2557 1 return (char *)prepared_data_buffer[index];
2558 }
2559
2560 #include "hs_runtime.h"
2561 #include "database.h"
2562
2563 static int database_fd = -1;
2564 static size_t database_size = 0;
2565 static const i360_pd_database_t *database = NULL;
2566 static hs_scratch_t *scratch = NULL;
2567
2568 4 long i360_get_current_db_sig() {
2569
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 3 times.
4 if (database)
2570 1 return (long)database->id;
2571
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
3 if (parms_data_g_ptr)
2572 1 return parms_data_g_ptr->signs;
2573 2 return 0;
2574 }
2575
2576 static inline
2577 412 const void *i360_pd_database_ptr(i360_pd_database_offset_t offset) {
2578
4/4
✓ Branch 0 taken 402 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 397 times.
✓ Branch 3 taken 5 times.
412 return (const void *)(offset != 0 && offset != UINT64_MAX ? &((const char*)database)[offset] : NULL);
2579 }
2580
2581 5 static hs_scratch_t *scratch_alloc() {
2582 const void *hs;
2583 5 hs_scratch_t *scratch = NULL;
2584 5 const i360_pd_database_offset_t *hss = i360_pd_database_ptr(database->hs);
2585
2/2
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 5 times.
30 while ((hs = i360_pd_database_ptr(*(hss++))) != NULL) {
2586
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
25 if (hs_alloc_scratch((const hs_database_t *)hs, &scratch) != HS_SUCCESS) {
2587 hs_free_scratch(scratch);
2588 return NULL;
2589 }
2590 }
2591 5 return scratch;
2592 }
2593
2594 6 void i360_pd_set_v2_database_paths(char *global_path, char *agent_path) {
2595
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (global_path) {
2596 6 v2_database_paths[0] = global_path;
2597 }
2598
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 5 times.
6 if (agent_path) {
2599 1 v2_database_paths[1] = agent_path;
2600 }
2601 6 }
2602
2603 5 int i360_pd_database_init() {
2604 struct {
2605 const char *bin_f;
2606 5 } options[] = {{v2_database_paths[0]}, {v2_database_paths[1]}}, *next = &options[1];
2607 struct stat rules_vers_st, rules_pack_st;
2608 5 int rules_ver_rc = stat(options[0].bin_f, &rules_vers_st);
2609 5 int rules_pack_rc = stat(options[1].bin_f, &rules_pack_st);
2610
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if ((rules_pack_rc == -1) && (rules_ver_rc == -1)) { // no files at all
2611 return 0;
2612 }
2613
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 else if ((!rules_ver_rc) && (rules_pack_rc == -1)) { // no global rule only agent
2614 5 next = &options[0];
2615 }
2616 else if ((!rules_ver_rc) && (rules_vers_st.st_mtime >= rules_pack_st.st_mtime)) { // global present by agents more new
2617 // or equal
2618 next = &options[0];
2619 } // by default use global. erlier set
2620 5 strncpy(current_db_path, next->bin_f, I360_PATH_BUFF-1);
2621
2622
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (hs_valid_platform() != HS_SUCCESS)
2623 return 0;
2624
2625
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (scratch) {
2626 hs_free_scratch(scratch);
2627 }
2628
2629
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (database) {
2630 munmap((void *)database, database_size);
2631 }
2632
2633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (database_fd >= 0) {
2634 close(database_fd);
2635 }
2636
2637 struct stat sb;
2638 5 int fd = open(next->bin_f, O_RDONLY);
2639
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (fd == -1)
2640 return 0;
2641
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (fstat(fd, &sb) == -1) {
2642 close(fd);
2643 return 0;
2644 }
2645 5 void *ptr = mmap((void *)database, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
2646
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ptr == MAP_FAILED) {
2647 close(fd);
2648 return 0;
2649 }
2650 5 database = (const i360_pd_database_t *)ptr;
2651
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (database->sign != I360_PD_DATABASE_SIGN || database->ver != I360_PD_DATABASE_VER) {
2652 munmap(ptr, sb.st_size);
2653 close(fd);
2654 database = NULL;
2655 return 0;
2656 }
2657 5 database_fd = fd;
2658 5 database_size = sb.st_size;
2659 5 scratch = scratch_alloc();
2660 5 return 1;
2661 }
2662
2663 59 void i360_pd_database_deinit() {
2664
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 54 times.
59 if (scratch)
2665 5 hs_free_scratch(scratch);
2666
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 54 times.
59 if (database != NULL)
2667 5 munmap((void *)database, database_size);
2668
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 54 times.
59 if (database_fd != -1)
2669 5 close(database_fd);
2670 59 scratch = NULL;
2671 59 database = NULL;
2672 59 database_fd = -1;
2673 59 database_size = 0;
2674 59 }
2675
2676 3 static int is_group_enabled(const i360_pd_database_rule_group_t *group, int app_id, int enabled_group) {
2677
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!group)
2678 return 0;
2679
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
3 if ((group->id == enabled_group) && (enabled_group))
2680 2 return 1;
2681
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (group->enabled) {
2682
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (app_id) {
2683 if (group->app_id == app_id) {
2684 return 1;
2685 }
2686 }
2687 else {
2688 1 return 1;
2689 }
2690 }
2691 return 0;
2692 }
2693
2694 struct _match_context {
2695 uint64_t *bitmap;
2696 const char *val;
2697 size_t len;
2698 };
2699
2700 static const i360_pd_database_pcre_t *database_pcre(unsigned int offset) {
2701 const i360_pd_database_offset_t *list = i360_pd_database_ptr(database->pcre);
2702 return (const i360_pd_database_pcre_t *)i360_pd_database_ptr(list[offset]);
2703 }
2704
2705 static int match_set_index(unsigned int id, __attribute__((unused)) unsigned long long from,
2706 __attribute__((unused)) unsigned long long to, __attribute__((unused)) unsigned int flags,
2707 void *context) {
2708 struct _match_context *mctx = (struct _match_context *)context;
2709 uint64_t *bitmap = mctx->bitmap;
2710 if (id >= (unsigned int)database->index_pcre) {
2711 unsigned int offset = id - (unsigned int)database->index_pcre;
2712 const i360_pd_database_pcre_t *p = database_pcre(offset);
2713 int subStrVec[30];
2714 int pcreExecRet = pcre_exec((const pcre *)p->pcre, (const pcre_extra *)i360_pd_database_ptr(p->pcre_extra),
2715 mctx->val, mctx->len, 0, PCRE_ANCHORED | PCRE_NO_START_OPTIMIZE, subStrVec, 30);
2716 id = p->index;
2717 if (pcreExecRet <= 0)
2718 return HS_SUCCESS;
2719 }
2720 I360_BITMAP_BIT_SET(bitmap, id);
2721 return HS_SUCCESS;
2722 }
2723
2724 static int match_set_index_exclude_list_args(unsigned int id, __attribute__((unused)) unsigned long long from,
2725 __attribute__((unused)) unsigned long long to,
2726 __attribute__((unused)) unsigned int flags, void *context) {
2727 struct _match_context *mctx = (struct _match_context *)context;
2728 uint64_t *bitmap = mctx->bitmap;
2729 if (id >= (unsigned int)database->index_pcre) {
2730 unsigned int offset = id - (unsigned int)database->index_pcre;
2731 const i360_pd_database_pcre_t *p = database_pcre(offset);
2732 int subStrVec[30];
2733 int pcreExecRet = pcre_exec((const pcre *)p->pcre, (const pcre_extra *)i360_pd_database_ptr(p->pcre_extra),
2734 mctx->val, mctx->len, 0, PCRE_ANCHORED | PCRE_NO_START_OPTIMIZE, subStrVec, 30);
2735 if (pcreExecRet <= 0)
2736 return HS_SUCCESS;
2737 }
2738 I360_BITMAP_BIT_SET(bitmap, I360_PD_DATABASE_EXCLUDE_LIST_ARGS_BIT);
2739 I360_BITMAP_BIT_RESET(bitmap, I360_PD_DATABASE_EXCLUDE_LIST_ARGS_NEGATIVE_BIT);
2740 return HS_SCAN_TERMINATED;
2741 }
2742
2743 static int match_set_index_exclude_list_script(unsigned int id, __attribute__((unused)) unsigned long long from,
2744 __attribute__((unused)) unsigned long long to,
2745 __attribute__((unused)) unsigned int flags, void *context) {
2746 struct _match_context *mctx = (struct _match_context *)context;
2747 uint64_t *bitmap = mctx->bitmap;
2748 if (id >= (unsigned int)database->index_pcre) {
2749 unsigned int offset = id - (unsigned int)database->index_pcre;
2750 const i360_pd_database_pcre_t *p = database_pcre(offset);
2751 int subStrVec[30];
2752 int pcreExecRet = pcre_exec((const pcre *)p->pcre, (const pcre_extra *)i360_pd_database_ptr(p->pcre_extra),
2753 mctx->val, mctx->len, 0, PCRE_ANCHORED | PCRE_NO_START_OPTIMIZE, subStrVec, 30);
2754 if (pcreExecRet <= 0)
2755 return HS_SUCCESS;
2756 }
2757 I360_BITMAP_BIT_RESET(bitmap, I360_PD_DATABASE_EXCLUDE_LIST_SCRIPT_NEGATIVE_BIT);
2758 return HS_SUCCESS;
2759 }
2760
2761 static int match_set_index_domain_blak_list_args(unsigned int id, __attribute__((unused)) unsigned long long from,
2762 __attribute__((unused)) unsigned long long to,
2763 __attribute__((unused)) unsigned int flags, void *context) {
2764 struct _match_context *mctx = (struct _match_context *)context;
2765 uint64_t *bitmap = mctx->bitmap;
2766 if (id >= (unsigned int)database->index_pcre) {
2767 unsigned int offset = id - (unsigned int)database->index_pcre;
2768 const i360_pd_database_pcre_t *p = database_pcre(offset);
2769 int subStrVec[30];
2770 int pcreExecRet = pcre_exec((const pcre *)p->pcre, (const pcre_extra *)i360_pd_database_ptr(p->pcre_extra),
2771 mctx->val, mctx->len, 0, PCRE_ANCHORED | PCRE_NO_START_OPTIMIZE, subStrVec, 30);
2772 if (pcreExecRet <= 0)
2773 return HS_SUCCESS;
2774 }
2775 I360_BITMAP_BIT_SET(bitmap, I360_PD_DATABASE_BLACK_LIST_BIT);
2776 return HS_SCAN_TERMINATED;
2777 }
2778
2779 3 static hs_error_t match_scan(i360_pd_database_offset_t offset, const char *data, unsigned int length,
2780 match_event_handler onEvent, uint64_t *bitmap) {
2781 3 const void *db = i360_pd_database_ptr(offset);
2782
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (db == NULL)
2783 return HS_INVALID;
2784 3 struct _match_context mctx = {.bitmap = bitmap, .val = data, .len = length};
2785 3 return hs_scan((const hs_database_t *)db, mctx.val, mctx.len, 0, scratch, onEvent, &mctx);
2786 }
2787
2788 3 static const i360_pd_database_rule_t *match_rules(const i360_pd_database_func_t *func, const char *queue,
2789 size_t queue_len, int level, int enabled_group,
2790 uint64_t *conditions) {
2791 3 int app_id = i360_get_app_id();
2792 3 const char *script = cur_php_fname;
2793 3 size_t script_len = 0;
2794
2795 // Rules match bitmap: 1 means rule triggered, 0 rule did not trigger
2796 3 uint64_t bitmap[database->index_size];
2797 3 memcpy(bitmap, i360_pd_database_ptr(database->index_init), database->index_size * 8);
2798
2799 3 bitmap[0] |= func->conditions & (I360_PD_DATABASE_DETECT | I360_PD_DATABASE_ARG | I360_PD_DATABASE_SCRIPT);
2800
2801
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (script)
2802 3 script_len = strlen(script);
2803
2804
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (I360_CONDITION_BIT_ISSET(func->conditions, I360_PD_DATABASE_DETECT_BIT)) {
2805 3 match_scan(func->hs_detect_re, queue, queue_len, match_set_index, bitmap);
2806 }
2807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (I360_CONDITION_BIT_ISSET(func->conditions, I360_PD_DATABASE_ARG_BIT)) {
2808 if (i360_get_params_new_numb()) {
2809 int index = 0;
2810 int len = 0;
2811 char *prm = i360_get_params_new(&index, &len);
2812 while (index != -1) {
2813 hs_error_t rv = match_scan(func->hs_args_re, prm, len, match_set_index, bitmap);
2814 if (rv != HS_SUCCESS)
2815 break;
2816 prm = i360_get_params_new(&index, &len);
2817 }
2818 }
2819 }
2820
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if (I360_CONDITION_BIT_ISSET(func->conditions, I360_PD_DATABASE_SCRIPT_BIT) && script_len) {
2821 match_scan(func->hs_script_re, script, script_len, match_set_index, bitmap);
2822 }
2823
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
3 if (I360_CONDITION_BIT_ISSET(func->conditions, I360_PD_DATABASE_FILE_OP_NAME_BIT) && i360_get_params_new_numb()) {
2824 int index = 0;
2825 int len = 0;
2826 char *prm = i360_get_params_new(&index, &len);
2827 match_scan(func->hs_file_op_name_re, prm, len, match_set_index, bitmap);
2828 }
2829
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
3 if (I360_CONDITION_BIT_ISSET(func->conditions, I360_PD_DATABASE_FILE_OP_CONTENT_BIT) && i360_get_params_new_numb() > 1) {
2830 int index = 1;
2831 int len = 0;
2832 char *prm = i360_get_params_new(&index, &len);
2833 match_scan(func->hs_file_op_content_re, prm, len, match_set_index, bitmap);
2834 }
2835
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if (I360_PD_CONDITION_INCLUDES(func->conditions, I360_PD_DATABASE_EXCLUDE_LIST_ARGS | I360_PD_DATABASE_EXCLUDE_LIST_ARGS_NEGATIVE) &&
2836 i360_get_params_new_numb()) {
2837 int index = 0;
2838 int len = 0;
2839 char *prm = i360_get_params_new(&index, &len);
2840 while (index != -1) {
2841 if (len > G_MIN_HANDLE_STRING_SIZE) {
2842 hs_error_t rv = match_scan(database->hs_exclude_list, prm, len, match_set_index_exclude_list_args, bitmap);
2843 if (rv != HS_SUCCESS) {
2844 break;
2845 }
2846 }
2847 prm = i360_get_params_new(&index, &len);
2848 }
2849 }
2850
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3 if (I360_CONDITION_BIT_ISSET(func->conditions, I360_PD_DATABASE_EXCLUDE_LIST_SCRIPT_NEGATIVE_BIT) && script &&
2851 script_len > G_MIN_HANDLE_STRING_SIZE) {
2852 match_scan(database->hs_exclude_list, script, script_len, match_set_index_exclude_list_script, bitmap);
2853 }
2854
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
3 if (I360_CONDITION_BIT_ISSET(func->conditions, I360_PD_DATABASE_BLACK_LIST_BIT) && i360_get_params_new_numb()) {
2855 char domain[MAX_DOMAIN_NAME] = {0};
2856 int index = 0;
2857 int len = 0;
2858 char *prm = i360_get_params_new(&index, &len);
2859 while (index != -1) {
2860 if (len > G_MIN_HANDLE_STRING_SIZE) {
2861 i360_extract_domain_name(prm, domain, MAX_DOMAIN_NAME);
2862 hs_error_t rv =
2863 match_scan(database->hs_black_list, domain, strlen(domain), match_set_index_domain_blak_list_args, bitmap);
2864 if (rv != HS_SUCCESS) {
2865 break;
2866 }
2867 }
2868 prm = i360_get_params_new(&index, &len);
2869 }
2870 }
2871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (I360_CONDITION_BIT_ISSET(func->conditions, I360_PD_DATABASE_MAIL_BIT)) {
2872 if (i360_check_mail_heuristic(i360_pd_database_ptr(func->name)))
2873 I360_BITMAP_BIT_SET(bitmap, I360_PD_DATABASE_MAIL_BIT);
2874 }
2875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (I360_CONDITION_BIT_ISSET(func->conditions, I360_PD_DATABASE_FOPEN_READ_NEGATIVE_BIT)) {
2876 const void *fopen = i360_pd_database_ptr(database->fopen);
2877 if (fopen && fopen == (const void *)func) {
2878 if (i360_get_params_new_numb() > 1) {
2879 int index = 1;
2880 int len = 0;
2881 char *prm = i360_get_params_new(&index, &len);
2882 if (((len == 1) && !strncmp(prm, "r", 1)) || ((len == 2) && !strncmp(prm, "rb", 2))) {
2883 I360_BITMAP_BIT_RESET(bitmap, I360_PD_DATABASE_FOPEN_READ_NEGATIVE_BIT);
2884 }
2885 }
2886 }
2887 }
2888
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (I360_PD_CONDITION_INCLUDES(func->conditions, I360_PD_DATABASE_BLOCK | I360_PD_DATABASE_BLOCK_EXCLUDE)) {
2889 if (i360_precheck_params_for_inclusion())
2890 I360_BITMAP_BIT_SET(bitmap, I360_PD_DATABASE_BLOCK_BIT);
2891 }
2892
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (I360_CONDITION_BIT_ISSET(func->conditions, I360_PD_DATABASE_BLOCK_EXCLUDE_BIT)) {
2893 if (I360_BITMAP_BIT_ISSET(bitmap, I360_PD_DATABASE_BLOCK_BIT) || i360_check_exclude_list())
2894 I360_BITMAP_BIT_SET(bitmap, I360_PD_DATABASE_BLOCK_EXCLUDE_BIT);
2895 }
2896
2897 3 const i360_pd_database_offset_t *rules = func->rules;
2898 3 const i360_pd_database_fp_rule_t *fp = (const i360_pd_database_fp_rule_t *)i360_pd_database_ptr(*rules);
2899 // False positive rules
2900
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 while (fp) {
2901 int i;
2902 int match = 1;
2903 for (i = 0; i < database->index_size; i++) {
2904 if ((bitmap[i] & fp->bitmap[i]) != fp->bitmap[i]) {
2905 match = 0;
2906 break;
2907 }
2908 }
2909 if (match) {
2910 I360_BITMAP_BIT_RESET(bitmap, I360_PD_DATABASE_FALSE_POSITIVE_BIT);
2911 I360_BITMAP_BIT_RESET(bitmap, fp->index);
2912 }
2913
2914 fp = (const i360_pd_database_fp_rule_t *)i360_pd_database_ptr(*(++rules));
2915 }
2916
2917 // Rules
2918 const i360_pd_database_rule_t *rule;
2919
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 while ((rule = (const i360_pd_database_rule_t *)i360_pd_database_ptr(*(++rules))) != NULL) {
2920
2/4
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
3 if (is_group_enabled(i360_pd_database_ptr(rule->group), app_id, enabled_group) && (rule->level >= level)) {
2921 int i;
2922 int match = 1;
2923 for (i = 0; i < database->index_size; i++) {
2924 if ((bitmap[i] & rule->bitmap[i]) != rule->bitmap[i]) {
2925 match = 0;
2926 break;
2927 }
2928 }
2929
2930 // Those files which names are whitelisted, we exclude
2931 // exclude them from regex search. Bitmask is used
2932 if (cur_wl_rules && (WHITELIST_FILE_VER3 == wl_version) &&
2933 (!((unsigned int *)cur_wl_rules)[0] ||
2934 bsearch(&(rule->id), cur_wl_rules, MAX_WHITELIST_RULES, sizeof(int), i360_wl_item_comp)))
2935 continue;
2936
2937 if (cur_wl_rules && (WHITELIST_FILE_VER4 == wl_version) && *(unsigned char *)cur_wl_rules &&
2938 (!((unsigned int *)(cur_wl_rules + 1))[0] ||
2939 bsearch(&(rule->id), cur_wl_rules + 1, *(unsigned char *)cur_wl_rules, sizeof(int), i360_wl_item_comp)))
2940 continue;
2941
2942 // Apply super-rules to every whitelist item
2943 if (super_wl_rules && (WHITELIST_FILE_VER3 == wl_version) &&
2944 bsearch(&(rule->id), super_wl_rules, MAX_WHITELIST_RULES, sizeof(int), i360_wl_item_comp))
2945 continue;
2946
2947 if (super_wl_rules && (WHITELIST_FILE_VER4 == wl_version) && super_wl_rules[0] &&
2948 bsearch(&(rule->id), super_wl_rules + 1, *(unsigned char *)super_wl_rules, sizeof(int), i360_wl_item_comp))
2949 continue;
2950
2951 if (match) {
2952 return rule;
2953 }
2954 }
2955 }
2956
2957
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (conditions)
2958 3 *conditions = bitmap[0];
2959
2960 3 return NULL;
2961 }
2962
2963 #ifndef UNIT_TESTING
2964 static inline
2965 #endif
2966 3 int i360_pd_database_is_args_requirde(const void *dbfunc) {
2967 3 const i360_pd_database_func_t *func = (const i360_pd_database_func_t *)dbfunc;
2968 3 return I360_PD_CONDITION_INCLUDES(func->conditions, I360_PD_DATABASE_ARG_BITS) ? 1 : 0;
2969 }
2970
2971 #ifndef UNIT_TESTING
2972 static inline
2973 #endif
2974 4 int i360_pd_database_is_write_log(const void *dbfunc) {
2975 4 const i360_pd_database_func_t *func = (const i360_pd_database_func_t *)dbfunc;
2976 4 return I360_CONDITION_BIT_ISSET(func->conditions, I360_PD_DATABASE_WRITE_LOG_BIT) ? 1 : 0;
2977 }
2978
2979 3 void i360_pd_database_make_info(const void *dbfunc, char *info) {
2980 3 const i360_pd_database_func_t *func = (const i360_pd_database_func_t *)dbfunc;
2981 3 info[0] = func->letter;
2982
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 info[1] = func->conditions != 0 ? 'd' : '0';
2983 3 info[2] = '0' + 16 * i360_pd_database_is_args_requirde(dbfunc) +
2984 3 16 * i360_pd_database_is_write_log(dbfunc);
2985 //if (i360_pd_database_is_args_requirde(dbfunc)) {
2986 //info[2] += 16;
2987 //}
2988 3 }
2989
2990 3 void i360_pd_database_check(chain_result *result, const void *dbfunc, const char *queue, size_t queue_len, int logger,
2991 int level, int enabled_group) {
2992 3 uint64_t conditions = 0;
2993 3 const i360_pd_database_func_t *func = (const i360_pd_database_func_t *)dbfunc;
2994 3 memset(result, 0, sizeof(chain_result));
2995 3 result->danger_type = NODANGER;
2996 3 result->recognizer_id = I360_RECOGNIZER_ID_NONE;
2997
2998 /*
2999 * rule stats from 0 to 255 shows how long rules applies to function, where function detects as number by ascii letter
3000 */
3001 3 i360_ull rule_timer = 0;
3002 3 i360_counter_saver_savetimer(&rule_timer);
3003 3 const i360_pd_database_rule_t *rule = match_rules(func, queue, queue_len, level, enabled_group, &conditions);
3004 3 i360_counter_saver_add_rule((unsigned int)((unsigned int)func->letter + STAT_SHIFTER_FUNC), rule_timer);
3005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (rule) {
3006 if (I360_PD_CONDITION_INCLUDES(rule->bitmap[0], I360_PD_DATABASE_ARG_BITS)) {
3007 // Database V1 code uppercase the letters with matching arguments. We have to do the same
3008 // to enable more sophisticated rules after a function was blocked by args
3009 i360_queue_buffer_uppercase_last();
3010 }
3011 if ((rule->action == BLOCK_FUNC) || (rule->id >= PHP_IMUNITY_MIN_ID && rule->id <= PHP_IMUNITY_MAX_ID)) {
3012 result->block = 1;
3013 }
3014 if (rule->action != NO_ACTION && I360_BITMAP_BIT_ISSET(rule->bitmap, I360_PD_DATABASE_BLOCK_EXCLUDE_BIT)) {
3015 result->block = 2;
3016 }
3017 result->recognizer_id = I360_RECOGNIZER_ID_COMMON;
3018 result->chain_id = rule->id;
3019 result->danger_type = DANGER;
3020 result->recognizer_desr = I360_RECOGNIZER_ID_COMMON_DESC;
3021 result->ruldescr = (char *)i360_pd_database_ptr(rule->description);
3022 }
3023
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 else if (I360_CONDITION_BIT_ISSET(conditions, I360_PD_DATABASE_FALSE_POSITIVE_BIT)) {
3024 3 rules_list *rules = i360_script_default_recognizer(i360_pd_database_ptr(func->name), queue, queue_len);
3025
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (rules) {
3026 if ((rules->action == BLOCK_FUNC) || (rules->id >= PHP_IMUNITY_MIN_ID && rules->id <= PHP_IMUNITY_MAX_ID)) {
3027 result->block = 1;
3028 }
3029 if (rules->action != NO_ACTION && rules->check_blocked == 2) {
3030 result->block = 2;
3031 }
3032 result->recognizer_id = I360_RECOGNIZER_ID_COMMON;
3033 result->chain_id = rules->id;
3034 result->danger_type = DANGER;
3035 result->recognizer_desr = I360_RECOGNIZER_ID_COMMON_DESC;
3036 result->ruldescr = rules->description;
3037 }
3038 }
3039
3040
2/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
3 if ((result->chain_id >= G_NON_LOG_RULE_ID) || (i360_is_rce_logger_log_mode() && (result->danger_type == DANGER))) {
3041 result->recognizer_id = I360_RECOGNIZER_ID_INTERNAL;
3042 result->recognizer_desr = I360_RECOGNIZER_ID_INTERNAL_DESC;
3043 }
3044
3045
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (logger) {
3046
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (result->danger_type) {
3047 result->action = LOG_ONLY;
3048 }
3049 else {
3050 3 result->recognizer_desr = I360_RECOGNIZER_ID_LOG_DESC;
3051 3 result->action = LOG_ONLY;
3052 3 result->recognizer_id = I360_RECOGNIZER_ID_LOG;
3053 3 result->chain_id = 0;
3054 3 result->danger_type = DANGER;
3055 }
3056 }
3057 3 }
3058
3059 2 int i360_pd_database_check_rinit(chain_result *result, int level, int enabled_group, const char *queue,
3060 size_t queue_len) {
3061
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!database)
3062 2 return 0;
3063
3064 const i360_pd_database_func_t *rinit = i360_pd_database_ptr(database->rinit);
3065
3066 if (!rinit)
3067 return 1;
3068
3069 i360_ull rule_timer = 0;
3070 i360_counter_saver_savetimer(&rule_timer);
3071 const i360_pd_database_rule_t *rule = match_rules(rinit, queue, queue_len, level, enabled_group, NULL);
3072 i360_counter_saver_add_rule((unsigned int)STAT_RINIT_RULESCHECK_TIME, rule_timer);
3073 if (rule) {
3074 if ((rule->action == BLOCK_FUNC) || (rule->id >= PHP_IMUNITY_MIN_ID && rule->id <= PHP_IMUNITY_MAX_ID)) {
3075 result->block = 1;
3076 }
3077 if (rule->action != NO_ACTION && I360_BITMAP_BIT_ISSET(rule->bitmap, I360_PD_DATABASE_BLOCK_EXCLUDE_BIT)) {
3078 result->block = 2;
3079 }
3080 result->recognizer_id = I360_RECOGNIZER_ID_COMMON;
3081 result->chain_id = rule->id;
3082 result->danger_type = DANGER;
3083 result->recognizer_desr = I360_RECOGNIZER_ID_COMMON_DESC;
3084 result->ruldescr = (char *)i360_pd_database_ptr(rule->description);
3085 }
3086
3087 2 return 1;
3088 }
3089
3090 4 int i360_pd_database_func_foreach(void (*f)(const char *key, const char *val, int is_danger, int is_openwrite,
3091 const void *dbfunc)) {
3092
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!database)
3093 return 0;
3094
3095 4 const i360_pd_database_func_t *func = i360_pd_database_ptr(database->fopen);
3096
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (func != NULL)
3097 4 f(i360_pd_database_ptr(func->name), NULL, (int)(func->letter != 0),
3098 4 I360_CONDITION_BIT_ISSET(func->conditions, I360_PD_DATABASE_WRITE_LOG_BIT), func);
3099 4 const i360_pd_database_offset_t *funcs = database->list;
3100
2/2
✓ Branch 1 taken 172 times.
✓ Branch 2 taken 4 times.
176 while ((func = i360_pd_database_ptr(*(funcs++))) != NULL)
3101 172 f(i360_pd_database_ptr(func->name), NULL, (int)(func->letter != 0),
3102 172 I360_CONDITION_BIT_ISSET(func->conditions, I360_PD_DATABASE_WRITE_LOG_BIT), func);
3103
3104 4 return 1;
3105 }
3106
3107 uint8_t i360_env_gencrc(uint8_t *data) {
3108 uint8_t crc = 0xff;
3109 size_t i, j;
3110 i = 0;
3111 while (data[i]) {
3112 crc ^= data[i];
3113 for (j = 0; j < 8; j++) {
3114 if ((crc & 0x80) != 0)
3115 crc = (uint8_t)((crc << 1) ^ 0x31);
3116 else
3117 crc <<= 1;
3118 }
3119 i++;
3120 }
3121 return crc;
3122 }
3123
3124 92 int i360_need_save_env_variable(char *variable_name, int var_len) {
3125 92 int len = var_len;
3126 92 char *fnd_eq = strchr(variable_name, '=');
3127 92 int result = 0;
3128
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 6 times.
92 if (fnd_eq) {
3129 86 len = fnd_eq - variable_name;
3130
1/2
✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
86 if (len < var_len) {
3131 86 var_len = len;
3132 }
3133 }
3134 92 result = (i360_env_filter_check(variable_name, var_len) != NULL);
3135 92 return result;
3136 }
3137
3138 static int database_version = 0;
3139 /*
3140 * 0 - old database
3141 * 1 - new hyperscan database
3142 */
3143 63 void i360_set_database_version(int db_version) {
3144 63 database_version = db_version;
3145 63 }
3146
3147 2 int i360_get_database_version() {
3148 2 return database_version;
3149 }
3150