/src/yara/libyara/rules.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Copyright (c) 2013. The YARA Authors. All Rights Reserved. |
3 | | |
4 | | Redistribution and use in source and binary forms, with or without modification, |
5 | | are permitted provided that the following conditions are met: |
6 | | |
7 | | 1. Redistributions of source code must retain the above copyright notice, this |
8 | | list of conditions and the following disclaimer. |
9 | | |
10 | | 2. Redistributions in binary form must reproduce the above copyright notice, |
11 | | this list of conditions and the following disclaimer in the documentation and/or |
12 | | other materials provided with the distribution. |
13 | | |
14 | | 3. Neither the name of the copyright holder nor the names of its contributors |
15 | | may be used to endorse or promote products derived from this software without |
16 | | specific prior written permission. |
17 | | |
18 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
19 | | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
20 | | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
21 | | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
22 | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
23 | | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
24 | | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
25 | | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
27 | | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | | */ |
29 | | |
30 | | #include <assert.h> |
31 | | #include <ctype.h> |
32 | | #include <string.h> |
33 | | #include <yara/compiler.h> |
34 | | #include <yara/error.h> |
35 | | #include <yara/filemap.h> |
36 | | #include <yara/globals.h> |
37 | | #include <yara/mem.h> |
38 | | #include <yara/proc.h> |
39 | | #include <yara/rules.h> |
40 | | #include <yara/scan.h> |
41 | | #include <yara/scanner.h> |
42 | | #include <yara/utils.h> |
43 | | |
44 | | YR_API int yr_rules_define_integer_variable( |
45 | | YR_RULES* rules, |
46 | | const char* identifier, |
47 | | int64_t value) |
48 | 0 | { |
49 | 0 | YR_EXTERNAL_VARIABLE* external; |
50 | |
|
51 | 0 | if (identifier == NULL) |
52 | 0 | return ERROR_INVALID_ARGUMENT; |
53 | | |
54 | 0 | external = rules->ext_vars_table; |
55 | |
|
56 | 0 | while (!EXTERNAL_VARIABLE_IS_NULL(external)) |
57 | 0 | { |
58 | 0 | if (strcmp(external->identifier, identifier) == 0) |
59 | 0 | { |
60 | 0 | if (external->type != EXTERNAL_VARIABLE_TYPE_INTEGER) |
61 | 0 | return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; |
62 | | |
63 | 0 | external->value.i = value; |
64 | 0 | return ERROR_SUCCESS; |
65 | 0 | } |
66 | | |
67 | 0 | external++; |
68 | 0 | } |
69 | | |
70 | 0 | return ERROR_INVALID_ARGUMENT; |
71 | 0 | } |
72 | | |
73 | | YR_API int yr_rules_define_boolean_variable( |
74 | | YR_RULES* rules, |
75 | | const char* identifier, |
76 | | int value) |
77 | 0 | { |
78 | 0 | YR_EXTERNAL_VARIABLE* external; |
79 | |
|
80 | 0 | if (identifier == NULL) |
81 | 0 | return ERROR_INVALID_ARGUMENT; |
82 | | |
83 | 0 | external = rules->ext_vars_table; |
84 | |
|
85 | 0 | while (!EXTERNAL_VARIABLE_IS_NULL(external)) |
86 | 0 | { |
87 | 0 | if (strcmp(external->identifier, identifier) == 0) |
88 | 0 | { |
89 | 0 | if (external->type != EXTERNAL_VARIABLE_TYPE_BOOLEAN) |
90 | 0 | return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; |
91 | | |
92 | 0 | external->value.i = value; |
93 | 0 | return ERROR_SUCCESS; |
94 | 0 | } |
95 | | |
96 | 0 | external++; |
97 | 0 | } |
98 | | |
99 | 0 | return ERROR_INVALID_ARGUMENT; |
100 | 0 | } |
101 | | |
102 | | YR_API int yr_rules_define_float_variable( |
103 | | YR_RULES* rules, |
104 | | const char* identifier, |
105 | | double value) |
106 | 0 | { |
107 | 0 | YR_EXTERNAL_VARIABLE* external; |
108 | |
|
109 | 0 | if (identifier == NULL) |
110 | 0 | return ERROR_INVALID_ARGUMENT; |
111 | | |
112 | 0 | external = rules->ext_vars_table; |
113 | |
|
114 | 0 | while (!EXTERNAL_VARIABLE_IS_NULL(external)) |
115 | 0 | { |
116 | 0 | if (strcmp(external->identifier, identifier) == 0) |
117 | 0 | { |
118 | 0 | if (external->type != EXTERNAL_VARIABLE_TYPE_FLOAT) |
119 | 0 | return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; |
120 | | |
121 | 0 | external->value.f = value; |
122 | 0 | return ERROR_SUCCESS; |
123 | 0 | } |
124 | | |
125 | 0 | external++; |
126 | 0 | } |
127 | | |
128 | 0 | return ERROR_INVALID_ARGUMENT; |
129 | 0 | } |
130 | | |
131 | | YR_API int yr_rules_define_string_variable( |
132 | | YR_RULES* rules, |
133 | | const char* identifier, |
134 | | const char* value) |
135 | 0 | { |
136 | 0 | YR_EXTERNAL_VARIABLE* external; |
137 | |
|
138 | 0 | if (identifier == NULL || value == NULL) |
139 | 0 | return ERROR_INVALID_ARGUMENT; |
140 | | |
141 | 0 | external = rules->ext_vars_table; |
142 | |
|
143 | 0 | while (!EXTERNAL_VARIABLE_IS_NULL(external)) |
144 | 0 | { |
145 | 0 | if (strcmp(external->identifier, identifier) == 0) |
146 | 0 | { |
147 | 0 | if (external->type != EXTERNAL_VARIABLE_TYPE_STRING && |
148 | 0 | external->type != EXTERNAL_VARIABLE_TYPE_MALLOC_STRING) |
149 | 0 | return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; |
150 | | |
151 | 0 | if (external->type == EXTERNAL_VARIABLE_TYPE_MALLOC_STRING && |
152 | 0 | external->value.s != NULL) |
153 | 0 | { |
154 | 0 | yr_free(external->value.s); |
155 | 0 | } |
156 | |
|
157 | 0 | external->type = EXTERNAL_VARIABLE_TYPE_MALLOC_STRING; |
158 | 0 | external->value.s = yr_strdup(value); |
159 | |
|
160 | 0 | if (external->value.s == NULL) |
161 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
162 | 0 | else |
163 | 0 | return ERROR_SUCCESS; |
164 | 0 | } |
165 | | |
166 | 0 | external++; |
167 | 0 | } |
168 | | |
169 | 0 | return ERROR_INVALID_ARGUMENT; |
170 | 0 | } |
171 | | |
172 | | YR_API int yr_rules_scan_mem_blocks( |
173 | | YR_RULES* rules, |
174 | | YR_MEMORY_BLOCK_ITERATOR* iterator, |
175 | | int flags, |
176 | | YR_CALLBACK_FUNC callback, |
177 | | void* user_data, |
178 | | int timeout) |
179 | 0 | { |
180 | 0 | YR_SCANNER* scanner; |
181 | 0 | int result; |
182 | |
|
183 | 0 | FAIL_ON_ERROR(yr_scanner_create(rules, &scanner)); |
184 | |
|
185 | 0 | yr_scanner_set_callback(scanner, callback, user_data); |
186 | 0 | yr_scanner_set_timeout(scanner, timeout); |
187 | 0 | yr_scanner_set_flags(scanner, flags); |
188 | |
|
189 | 0 | result = yr_scanner_scan_mem_blocks(scanner, iterator); |
190 | |
|
191 | 0 | yr_scanner_destroy(scanner); |
192 | |
|
193 | 0 | return result; |
194 | 0 | } |
195 | | |
196 | | YR_API int yr_rules_scan_mem( |
197 | | YR_RULES* rules, |
198 | | const uint8_t* buffer, |
199 | | size_t buffer_size, |
200 | | int flags, |
201 | | YR_CALLBACK_FUNC callback, |
202 | | void* user_data, |
203 | | int timeout) |
204 | 7.62k | { |
205 | 7.62k | YR_DEBUG_FPRINTF( |
206 | 7.62k | 2, |
207 | 7.62k | stderr, |
208 | 7.62k | "+ %s(buffer=%p buffer_size=%zu timeout=%d) {\n", |
209 | 7.62k | __FUNCTION__, |
210 | 7.62k | buffer, |
211 | 7.62k | buffer_size, |
212 | 7.62k | timeout); |
213 | | |
214 | 7.62k | YR_SCANNER* scanner; |
215 | 7.62k | int result = ERROR_INTERNAL_FATAL_ERROR; |
216 | | |
217 | 7.62k | GOTO_EXIT_ON_ERROR(yr_scanner_create(rules, &scanner)); |
218 | | |
219 | 7.62k | yr_scanner_set_callback(scanner, callback, user_data); |
220 | 7.62k | yr_scanner_set_timeout(scanner, timeout); |
221 | 7.62k | yr_scanner_set_flags(scanner, flags); |
222 | | |
223 | 7.62k | result = yr_scanner_scan_mem(scanner, buffer, buffer_size); |
224 | | |
225 | 7.62k | yr_scanner_destroy(scanner); |
226 | | |
227 | 7.62k | _exit: |
228 | | |
229 | 7.62k | YR_DEBUG_FPRINTF( |
230 | 7.62k | 2, |
231 | 7.62k | stderr, |
232 | 7.62k | "" |
233 | 7.62k | "} = %d AKA %s // %s()\n", |
234 | 7.62k | result, |
235 | 7.62k | yr_debug_error_as_string(result), |
236 | 7.62k | __FUNCTION__); |
237 | | |
238 | 7.62k | return result; |
239 | 7.62k | } |
240 | | |
241 | | YR_API int yr_rules_scan_file( |
242 | | YR_RULES* rules, |
243 | | const char* filename, |
244 | | int flags, |
245 | | YR_CALLBACK_FUNC callback, |
246 | | void* user_data, |
247 | | int timeout) |
248 | 0 | { |
249 | 0 | YR_MAPPED_FILE mfile; |
250 | |
|
251 | 0 | int result = yr_filemap_map(filename, &mfile); |
252 | |
|
253 | 0 | if (result == ERROR_SUCCESS) |
254 | 0 | { |
255 | 0 | result = yr_rules_scan_mem( |
256 | 0 | rules, mfile.data, mfile.size, flags, callback, user_data, timeout); |
257 | |
|
258 | 0 | yr_filemap_unmap(&mfile); |
259 | 0 | } |
260 | |
|
261 | 0 | return result; |
262 | 0 | } |
263 | | |
264 | | YR_API int yr_rules_scan_fd( |
265 | | YR_RULES* rules, |
266 | | YR_FILE_DESCRIPTOR fd, |
267 | | int flags, |
268 | | YR_CALLBACK_FUNC callback, |
269 | | void* user_data, |
270 | | int timeout) |
271 | 0 | { |
272 | 0 | YR_MAPPED_FILE mfile; |
273 | |
|
274 | 0 | int result = yr_filemap_map_fd(fd, 0, 0, &mfile); |
275 | |
|
276 | 0 | if (result == ERROR_SUCCESS) |
277 | 0 | { |
278 | 0 | result = yr_rules_scan_mem( |
279 | 0 | rules, mfile.data, mfile.size, flags, callback, user_data, timeout); |
280 | |
|
281 | 0 | yr_filemap_unmap_fd(&mfile); |
282 | 0 | } |
283 | |
|
284 | 0 | return result; |
285 | 0 | } |
286 | | |
287 | | YR_API int yr_rules_scan_proc( |
288 | | YR_RULES* rules, |
289 | | int pid, |
290 | | int flags, |
291 | | YR_CALLBACK_FUNC callback, |
292 | | void* user_data, |
293 | | int timeout) |
294 | 0 | { |
295 | 0 | YR_DEBUG_FPRINTF( |
296 | 0 | 2, stderr, "+ %s(pid=%d timeout=%d) {\n", __FUNCTION__, pid, timeout); |
297 | |
|
298 | 0 | YR_MEMORY_BLOCK_ITERATOR iterator; |
299 | |
|
300 | 0 | int result = yr_process_open_iterator(pid, &iterator); |
301 | |
|
302 | 0 | if (result == ERROR_SUCCESS) |
303 | 0 | { |
304 | 0 | result = yr_rules_scan_mem_blocks( |
305 | 0 | rules, |
306 | 0 | &iterator, |
307 | 0 | flags | SCAN_FLAGS_PROCESS_MEMORY, |
308 | 0 | callback, |
309 | 0 | user_data, |
310 | 0 | timeout); |
311 | |
|
312 | 0 | yr_process_close_iterator(&iterator); |
313 | 0 | } |
314 | |
|
315 | 0 | YR_DEBUG_FPRINTF( |
316 | 0 | 2, |
317 | 0 | stderr, |
318 | 0 | "} = %d AKA %s // %s()\n", |
319 | 0 | result, |
320 | 0 | yr_debug_error_as_string(result), |
321 | 0 | __FUNCTION__); |
322 | |
|
323 | 0 | return result; |
324 | 0 | } |
325 | | |
326 | | int yr_rules_from_arena(YR_ARENA* arena, YR_RULES** rules) |
327 | 2 | { |
328 | 2 | YR_SUMMARY* summary = (YR_SUMMARY*) yr_arena_get_ptr( |
329 | 2 | arena, YR_SUMMARY_SECTION, 0); |
330 | | |
331 | 2 | if (summary == NULL) |
332 | 0 | return ERROR_CORRUPT_FILE; |
333 | | |
334 | 2 | YR_RULES* new_rules = (YR_RULES*) yr_malloc(sizeof(YR_RULES)); |
335 | | |
336 | 2 | if (new_rules == NULL) |
337 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
338 | | |
339 | 2 | new_rules->no_required_strings = (YR_BITMASK*) yr_calloc( |
340 | 2 | sizeof(YR_BITMASK), YR_BITMASK_SIZE(summary->num_rules)); |
341 | | |
342 | 2 | if (new_rules->no_required_strings == NULL) |
343 | 0 | { |
344 | 0 | yr_free(new_rules); |
345 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
346 | 0 | } |
347 | | |
348 | | // Now YR_RULES relies on this arena, let's increment the arena's |
349 | | // reference count so that if the original owner of the arena calls |
350 | | // yr_arena_destroy the arena is not destroyed. |
351 | 2 | yr_arena_acquire(arena); |
352 | | |
353 | 2 | new_rules->arena = arena; |
354 | 2 | new_rules->num_rules = summary->num_rules; |
355 | 2 | new_rules->num_strings = summary->num_strings; |
356 | 2 | new_rules->num_namespaces = summary->num_namespaces; |
357 | | |
358 | 2 | new_rules->rules_table = yr_arena_get_ptr(arena, YR_RULES_TABLE, 0); |
359 | | |
360 | 2 | new_rules->strings_table = yr_arena_get_ptr(arena, YR_STRINGS_TABLE, 0); |
361 | | |
362 | 2 | new_rules->ext_vars_table = yr_arena_get_ptr( |
363 | 2 | arena, YR_EXTERNAL_VARIABLES_TABLE, 0); |
364 | | |
365 | 2 | new_rules->ac_transition_table = yr_arena_get_ptr( |
366 | 2 | arena, YR_AC_TRANSITION_TABLE, 0); |
367 | | |
368 | 2 | new_rules->ac_match_table = yr_arena_get_ptr( |
369 | 2 | arena, YR_AC_STATE_MATCHES_TABLE, 0); |
370 | | |
371 | 2 | new_rules->ac_match_pool = yr_arena_get_ptr( |
372 | 2 | arena, YR_AC_STATE_MATCHES_POOL, 0); |
373 | | |
374 | 2 | new_rules->code_start = yr_arena_get_ptr(arena, YR_CODE_SECTION, 0); |
375 | | |
376 | | // If a rule has no required_strings, this means that the condition might |
377 | | // evaluate to true without any matching strings, and we therefore have to |
378 | | // mark it as "to be evaluated" from the beginning. |
379 | 4 | for (int i = 0; i < new_rules->num_rules; i++) |
380 | 2 | { |
381 | 2 | if (new_rules->rules_table[i].required_strings == 0) |
382 | 2 | yr_bitmask_set(new_rules->no_required_strings, i); |
383 | 2 | } |
384 | | |
385 | 2 | *rules = new_rules; |
386 | | |
387 | 2 | return ERROR_SUCCESS; |
388 | 2 | } |
389 | | |
390 | | YR_API int yr_rules_load_stream(YR_STREAM* stream, YR_RULES** rules) |
391 | 0 | { |
392 | 0 | YR_ARENA* arena; |
393 | | |
394 | | // Load the arena's data the stream. We are the owners of the arena. |
395 | 0 | FAIL_ON_ERROR(yr_arena_load_stream(stream, &arena)); |
396 | | |
397 | | // Create the YR_RULES object from the arena, this makes YR_RULES owner |
398 | | // of the arena too. |
399 | 0 | FAIL_ON_ERROR(yr_rules_from_arena(arena, rules)); |
400 | | |
401 | | // Release our ownership so that YR_RULES is the single owner. This way the |
402 | | // arena is destroyed when YR_RULES is destroyed. |
403 | 0 | yr_arena_release(arena); |
404 | |
|
405 | 0 | return ERROR_SUCCESS; |
406 | 0 | } |
407 | | |
408 | | YR_API int yr_rules_load(const char* filename, YR_RULES** rules) |
409 | 0 | { |
410 | 0 | int result; |
411 | |
|
412 | 0 | YR_STREAM stream; |
413 | 0 | FILE* fh = fopen(filename, "rb"); |
414 | |
|
415 | 0 | if (fh == NULL) |
416 | 0 | return ERROR_COULD_NOT_OPEN_FILE; |
417 | | |
418 | 0 | stream.user_data = fh; |
419 | 0 | stream.read = (YR_STREAM_READ_FUNC) fread; |
420 | |
|
421 | 0 | result = yr_rules_load_stream(&stream, rules); |
422 | |
|
423 | 0 | fclose(fh); |
424 | 0 | return result; |
425 | 0 | } |
426 | | |
427 | | YR_API int yr_rules_save_stream(YR_RULES* rules, YR_STREAM* stream) |
428 | 0 | { |
429 | 0 | return yr_arena_save_stream(rules->arena, stream); |
430 | 0 | } |
431 | | |
432 | | YR_API int yr_rules_save(YR_RULES* rules, const char* filename) |
433 | 0 | { |
434 | 0 | int result; |
435 | |
|
436 | 0 | YR_STREAM stream; |
437 | 0 | FILE* fh = fopen(filename, "wb"); |
438 | |
|
439 | 0 | if (fh == NULL) |
440 | 0 | return ERROR_COULD_NOT_OPEN_FILE; |
441 | | |
442 | 0 | stream.user_data = fh; |
443 | 0 | stream.write = (YR_STREAM_WRITE_FUNC) fwrite; |
444 | |
|
445 | 0 | result = yr_rules_save_stream(rules, &stream); |
446 | |
|
447 | 0 | fclose(fh); |
448 | 0 | return result; |
449 | 0 | } |
450 | | |
451 | | static int _uint32_cmp(const void* a, const void* b) |
452 | 0 | { |
453 | 0 | return (*(uint32_t*) a - *(uint32_t*) b); |
454 | 0 | } |
455 | | |
456 | | YR_API int yr_rules_get_stats(YR_RULES* rules, YR_RULES_STATS* stats) |
457 | 0 | { |
458 | 0 | memset(stats, 0, sizeof(YR_RULES_STATS)); |
459 | |
|
460 | 0 | stats->ac_tables_size = yr_arena_get_current_offset( |
461 | 0 | rules->arena, YR_AC_TRANSITION_TABLE) / |
462 | 0 | sizeof(YR_AC_TRANSITION); |
463 | |
|
464 | 0 | uint32_t* match_list_lengths = (uint32_t*) yr_malloc( |
465 | 0 | sizeof(uint32_t) * stats->ac_tables_size); |
466 | |
|
467 | 0 | if (match_list_lengths == NULL) |
468 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
469 | | |
470 | 0 | stats->num_rules = rules->num_rules; |
471 | 0 | stats->num_strings = rules->num_strings; |
472 | |
|
473 | 0 | float match_list_length_sum = 0; |
474 | 0 | int c = 0; |
475 | |
|
476 | 0 | for (uint32_t i = 0; i < stats->ac_tables_size; i++) |
477 | 0 | { |
478 | 0 | int match_list_length = 0; |
479 | |
|
480 | 0 | if (rules->ac_match_table[i] != 0) |
481 | 0 | { |
482 | 0 | YR_AC_MATCH* m = &rules->ac_match_pool[rules->ac_match_table[i] - 1]; |
483 | |
|
484 | 0 | while (m != NULL) |
485 | 0 | { |
486 | 0 | match_list_length++; |
487 | 0 | stats->ac_matches++; |
488 | 0 | m = m->next; |
489 | 0 | } |
490 | 0 | } |
491 | |
|
492 | 0 | if (i == 0) |
493 | 0 | stats->ac_root_match_list_length = match_list_length; |
494 | |
|
495 | 0 | match_list_length_sum += match_list_length; |
496 | |
|
497 | 0 | if (match_list_length > 0) |
498 | 0 | { |
499 | 0 | match_list_lengths[c] = match_list_length; |
500 | 0 | c++; |
501 | 0 | } |
502 | 0 | } |
503 | |
|
504 | 0 | if (c == 0) |
505 | 0 | { |
506 | 0 | yr_free(match_list_lengths); |
507 | 0 | return ERROR_SUCCESS; |
508 | 0 | } |
509 | | |
510 | | // sort match_list_lengths in increasing order for computing percentiles. |
511 | 0 | qsort(match_list_lengths, c, sizeof(match_list_lengths[0]), _uint32_cmp); |
512 | |
|
513 | 0 | for (int i = 0; i < 100; i++) |
514 | 0 | { |
515 | 0 | if (i < c) |
516 | 0 | stats->top_ac_match_list_lengths[i] = match_list_lengths[c - i - 1]; |
517 | 0 | else |
518 | 0 | stats->top_ac_match_list_lengths[i] = 0; |
519 | 0 | } |
520 | |
|
521 | 0 | stats->ac_average_match_list_length = match_list_length_sum / c; |
522 | 0 | stats->ac_match_list_length_pctls[0] = match_list_lengths[0]; |
523 | 0 | stats->ac_match_list_length_pctls[100] = match_list_lengths[c - 1]; |
524 | |
|
525 | 0 | for (int i = 1; i < 100; i++) |
526 | 0 | stats->ac_match_list_length_pctls[i] = match_list_lengths[(c * i) / 100]; |
527 | |
|
528 | 0 | yr_free(match_list_lengths); |
529 | |
|
530 | 0 | return ERROR_SUCCESS; |
531 | 0 | } |
532 | | |
533 | | YR_API int yr_rules_destroy(YR_RULES* rules) |
534 | 0 | { |
535 | 0 | YR_EXTERNAL_VARIABLE* external = rules->ext_vars_table; |
536 | |
|
537 | 0 | while (!EXTERNAL_VARIABLE_IS_NULL(external)) |
538 | 0 | { |
539 | 0 | if (external->type == EXTERNAL_VARIABLE_TYPE_MALLOC_STRING) |
540 | 0 | yr_free(external->value.s); |
541 | |
|
542 | 0 | external++; |
543 | 0 | } |
544 | |
|
545 | 0 | yr_free(rules->no_required_strings); |
546 | 0 | yr_arena_release(rules->arena); |
547 | 0 | yr_free(rules); |
548 | |
|
549 | 0 | return ERROR_SUCCESS; |
550 | 0 | } |
551 | | |
552 | | YR_API void yr_rule_disable(YR_RULE* rule) |
553 | 0 | { |
554 | 0 | YR_STRING* string; |
555 | |
|
556 | 0 | rule->flags |= RULE_FLAGS_DISABLED; |
557 | |
|
558 | 0 | yr_rule_strings_foreach(rule, string) |
559 | 0 | { |
560 | 0 | string->flags |= STRING_FLAGS_DISABLED; |
561 | 0 | } |
562 | 0 | } |
563 | | |
564 | | YR_API void yr_rule_enable(YR_RULE* rule) |
565 | 0 | { |
566 | 0 | YR_STRING* string; |
567 | |
|
568 | 0 | rule->flags &= ~RULE_FLAGS_DISABLED; |
569 | |
|
570 | 0 | yr_rule_strings_foreach(rule, string) |
571 | 0 | { |
572 | 0 | string->flags &= ~STRING_FLAGS_DISABLED; |
573 | 0 | } |
574 | 0 | } |