/src/fluent-bit/tests/internal/fuzzers/log_cache_fuzzer.c
Line | Count | Source |
1 | | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* Fluent Bit |
4 | | * ========== |
5 | | * Copyright (C) 2015-2026 The Fluent Bit Authors |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | #include <limits.h> |
21 | | #include <stdint.h> |
22 | | #include <stdlib.h> |
23 | | #include <string.h> |
24 | | |
25 | | #include <fluent-bit/flb_log.h> |
26 | | #include <fluent-bit/flb_mem.h> |
27 | | |
28 | 281 | #define MAX_CACHE_ENTRIES 8 |
29 | | |
30 | | #ifdef FLB_HAVE_TESTS_OSSFUZZ |
31 | | static void silence_expected_allocation_errors(void) |
32 | 281 | { |
33 | 281 | static struct flb_log log; |
34 | 281 | static struct flb_worker worker; |
35 | | |
36 | 281 | log.level = FLB_LOG_OFF; |
37 | 281 | worker.log_ctx = &log; |
38 | | |
39 | 281 | FLB_TLS_INIT(flb_worker_ctx); |
40 | 281 | FLB_TLS_SET(flb_worker_ctx, &worker); |
41 | 281 | } |
42 | | |
43 | | static void reset_fuzz_allocator(void) |
44 | 3.53k | { |
45 | 3.53k | flb_malloc_p = 0; |
46 | 3.53k | flb_malloc_mod = INT_MAX; |
47 | 3.53k | } |
48 | | |
49 | | static void exercise_cache_create_allocation_failures(int timeout, int entries) |
50 | 281 | { |
51 | 281 | int i; |
52 | 281 | int allocation_count; |
53 | 281 | struct flb_log_cache *cache; |
54 | | |
55 | | /* The cache and each entry and its buffer require one allocation each. */ |
56 | 281 | allocation_count = 1 + (entries * 2); |
57 | | |
58 | 3.25k | for (i = 1; i <= allocation_count; i++) { |
59 | 2.97k | flb_malloc_mod = allocation_count + 1; |
60 | 2.97k | flb_malloc_p = flb_malloc_mod - i; |
61 | | |
62 | 2.97k | cache = flb_log_cache_create(timeout, entries); |
63 | | |
64 | 2.97k | reset_fuzz_allocator(); |
65 | 2.97k | if (cache != NULL) { |
66 | 0 | flb_log_cache_destroy(cache); |
67 | 0 | abort(); |
68 | 0 | } |
69 | 2.97k | } |
70 | 281 | } |
71 | | |
72 | | static void exercise_message_allocation_failure(struct flb_log_cache *cache, |
73 | | uint8_t value) |
74 | 281 | { |
75 | 281 | char message[FLB_LOG_CACHE_TEXT_BUF_SIZE + 1]; |
76 | 281 | struct flb_log_cache_entry *entry; |
77 | | |
78 | 281 | memset(message, value, sizeof(message)); |
79 | | |
80 | | /* Force the next allocation, used to grow the message buffer, to fail. */ |
81 | 281 | flb_malloc_mod = 2; |
82 | 281 | flb_malloc_p = 1; |
83 | 281 | flb_log_cache_check_suppress(cache, message, sizeof(message)); |
84 | 281 | reset_fuzz_allocator(); |
85 | | |
86 | 281 | entry = flb_log_cache_exists(cache, message, sizeof(message)); |
87 | 281 | if (entry != NULL) { |
88 | 0 | abort(); |
89 | 0 | } |
90 | | |
91 | | /* A failed growth must leave the cache entry valid for a later retry. */ |
92 | 281 | flb_log_cache_check_suppress(cache, message, sizeof(message)); |
93 | 281 | entry = flb_log_cache_exists(cache, message, sizeof(message)); |
94 | 281 | if (entry == NULL) { |
95 | 0 | abort(); |
96 | 0 | } |
97 | 281 | } |
98 | | #endif |
99 | | |
100 | | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
101 | 281 | { |
102 | 281 | int entries; |
103 | 281 | int timeout; |
104 | 281 | struct flb_log_cache *cache; |
105 | | |
106 | 281 | if (size == 0) { |
107 | 0 | return 0; |
108 | 0 | } |
109 | | |
110 | 281 | entries = (data[0] % MAX_CACHE_ENTRIES) + 1; |
111 | 281 | timeout = data[0]; |
112 | | |
113 | 281 | #ifdef FLB_HAVE_TESTS_OSSFUZZ |
114 | 281 | silence_expected_allocation_errors(); |
115 | 281 | exercise_cache_create_allocation_failures(timeout, entries); |
116 | 281 | reset_fuzz_allocator(); |
117 | 281 | #endif |
118 | | |
119 | 281 | cache = flb_log_cache_create(timeout, entries); |
120 | 281 | if (cache == NULL) { |
121 | 0 | return 0; |
122 | 0 | } |
123 | | |
124 | 281 | #ifdef FLB_HAVE_TESTS_OSSFUZZ |
125 | 281 | exercise_message_allocation_failure(cache, data[0]); |
126 | 281 | #endif |
127 | | |
128 | 281 | if (size > 1) { |
129 | 274 | flb_log_cache_check_suppress(cache, (char *) &data[1], size - 1); |
130 | 274 | flb_log_cache_check_suppress(cache, (char *) &data[1], size - 1); |
131 | 274 | } |
132 | | |
133 | 281 | #if SIZE_MAX > INT_MAX |
134 | 281 | flb_log_cache_check_suppress(cache, (char *) data, (size_t) INT_MAX + 1); |
135 | 281 | #endif |
136 | | |
137 | 281 | flb_log_cache_destroy(cache); |
138 | 281 | return 0; |
139 | 281 | } |