/src/llama.cpp/fuzzers/fuzz_structured.cpp
Line | Count | Source |
1 | | /* Copyright 2024 Google LLC |
2 | | Licensed under the Apache License, Version 2.0 (the "License"); |
3 | | you may not use this file except in compliance with the License. |
4 | | You may obtain a copy of the License at |
5 | | http://www.apache.org/licenses/LICENSE-2.0 |
6 | | Unless required by applicable law or agreed to in writing, software |
7 | | distributed under the License is distributed on an "AS IS" BASIS, |
8 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
9 | | See the License for the specific language governing permissions and |
10 | | limitations under the License. |
11 | | */ |
12 | | |
13 | | #include "llama.h" |
14 | | #include <iostream> |
15 | | #include <string> |
16 | | #include <vector> |
17 | | |
18 | | #include <setjmp.h> |
19 | | #include <unistd.h> |
20 | | |
21 | | #include <fuzzer/FuzzedDataProvider.h> |
22 | | #include <string.h> |
23 | | |
24 | | jmp_buf fuzzing_jmp_buf; |
25 | | |
26 | 50 | #define NUM_OVERRIDES 75 |
27 | | struct llama_model_kv_override fuzz_kv_overrides[NUM_OVERRIDES + 1]; |
28 | | |
29 | | llama_model_kv_override_type arrayed_enums[4] = { |
30 | | LLAMA_KV_OVERRIDE_TYPE_INT, LLAMA_KV_OVERRIDE_TYPE_FLOAT, |
31 | | LLAMA_KV_OVERRIDE_TYPE_BOOL, LLAMA_KV_OVERRIDE_TYPE_STR}; |
32 | | |
33 | | std::vector<std::string> possible_keys = { |
34 | | "general.type", |
35 | | "general.quantization_version", |
36 | | "general.alignment", |
37 | | "general.name", |
38 | | "general.author", |
39 | | "general.version", |
40 | | "general.url", |
41 | | "general.description", |
42 | | "general.license", |
43 | | "general.source.url", |
44 | | "general.source.huggingface.repository", |
45 | | "split.no", |
46 | | "split.count", |
47 | | "split.tensors.count", |
48 | | "tokenizer.ggml.model", |
49 | | "tokenizer.ggml.pre", |
50 | | "tokenizer.ggml.tokens", |
51 | | "tokenizer.ggml.token_type", |
52 | | "tokenizer.ggml.token_type_count", |
53 | | "tokenizer.ggml.scores", |
54 | | "tokenizer.ggml.merges", |
55 | | "tokenizer.ggml.bos_token_id", |
56 | | "tokenizer.ggml.eos_token_id", |
57 | | "tokenizer.ggml.unknown_token_id", |
58 | | "tokenizer.ggml.seperator_token_id", |
59 | | "tokenizer.ggml.padding_token_id", |
60 | | "tokenizer.ggml.cls_token_id", |
61 | | "tokenizer.ggml.mask_token_id", |
62 | | "tokenizer.ggml.add_bos_token", |
63 | | "tokenizer.ggml.add_eos_token", |
64 | | "tokenizer.ggml.add_space_prefix", |
65 | | "tokenizer.ggml.remove_extra_whitespaces", |
66 | | "tokenizer.ggml.precompiled_charsmap", |
67 | | "tokenizer.huggingface.json", |
68 | | "tokenizer.rwkv.world", |
69 | | "tokenizer.ggml.prefix_token_id", |
70 | | "tokenizer.ggml.suffix_token_id", |
71 | | "tokenizer.ggml.middle_token_id", |
72 | | "tokenizer.ggml.eot_token_id", |
73 | | "tokenizer.ggml.eom_token_id", |
74 | | "adapter.type", |
75 | | "adapter.lora.alpha", |
76 | | |
77 | | }; |
78 | | |
79 | | std::vector<std::string> possible_architectures = { |
80 | | "llama", "falcon", "grok", "gpt2", "gptj", "gptneox", |
81 | | "mpt", "baichuan", "starcoder", "refact", "bert", "nomic-bert", |
82 | | "jina-bert-v2", "bloom", "stablelm", "qwen", "qwen2", |
83 | | }; |
84 | | |
85 | | std::vector<std::string> possible_prefix_keys = { |
86 | | ".vocab_size", |
87 | | ".context_length", |
88 | | ".embedding_length", |
89 | | ".block_count", |
90 | | ".leading_dense_block_count", |
91 | | ".feed_forward_length", |
92 | | ".expert_feed_forward_length", |
93 | | ".expert_shared_feed_forward_length", |
94 | | ".use_parallel_residual", |
95 | | ".tensor_data_layout", |
96 | | ".expert_count", |
97 | | ".expert_used_count", |
98 | | ".expert_shared_count", |
99 | | ".expert_weights_scale", |
100 | | ".pooling_type", |
101 | | ".logit_scale", |
102 | | ".decoder_start_token_id", |
103 | | ".attn_logit_softcapping", |
104 | | ".final_logit_softcapping", |
105 | | ".rescale_every_n_layers", |
106 | | ".time_mix_extra_dim", |
107 | | ".time_decay_extra_dim", |
108 | | ".attention.head_count", |
109 | | ".attention.head_count_kv", |
110 | | ".attention.max_alibi_bias", |
111 | | ".attention.clamp_kqv", |
112 | | ".attention.key_length", |
113 | | ".attention.value_length", |
114 | | ".attention.layer_norm_epsilon", |
115 | | ".attention.layer_norm_rms_epsilon", |
116 | | ".attention.causal", |
117 | | ".attention.q_lora_rank", |
118 | | ".attention.kv_lora_rank", |
119 | | ".attention.relative_buckets_count", |
120 | | ".attention.sliding_window", |
121 | | ".rope.dimension_count", |
122 | | ".rope.freq_base", |
123 | | ".rope.scale_linear", |
124 | | ".rope.scaling.type", |
125 | | ".rope.scaling.factor", |
126 | | ".rope.scaling.attn_factor", |
127 | | ".rope.scaling.original_context_length", |
128 | | ".rope.scaling.finetuned", |
129 | | ".rope.scaling.yarn_log_multiplier", |
130 | | ".ssm.conv_kernel", |
131 | | ".ssm.inner_size", |
132 | | ".ssm.state_size", |
133 | | ".ssm.time_step_rank", |
134 | | ".ssm.dt_b_c_rms", |
135 | | ".wkv.head_size", |
136 | | }; |
137 | | |
138 | 0 | extern "C" void __wrap_abort(void) { longjmp(fuzzing_jmp_buf, 1); } |
139 | | |
140 | 70 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
141 | 70 | if (size < 256) { |
142 | 14 | return 0; |
143 | 14 | } |
144 | 56 | llama_backend_init(); |
145 | 56 | FuzzedDataProvider fdp(data, size); |
146 | | |
147 | 56 | auto params = llama_model_params{}; |
148 | 56 | memset(¶ms, 0x0, sizeof(struct llama_model_params)); |
149 | 56 | params.use_mmap = false; |
150 | 56 | params.progress_callback = [](float progress, void *ctx) { |
151 | 0 | (void)ctx; |
152 | 0 | return progress > 0.50; |
153 | 0 | }; |
154 | | |
155 | 56 | int overwrite_idx = 0; |
156 | | |
157 | | // set the architecture |
158 | 56 | std::string arch_key = "general.architecture"; |
159 | 56 | uint8_t arch_index = |
160 | 56 | fdp.ConsumeIntegralInRange<uint8_t>(0, possible_architectures.size() - 1); |
161 | | |
162 | 56 | std::string arch_val = std::string(possible_architectures[arch_index]); |
163 | 56 | fuzz_kv_overrides[overwrite_idx].tag = LLAMA_KV_OVERRIDE_TYPE_STR; |
164 | 56 | strcpy(fuzz_kv_overrides[overwrite_idx].key, arch_key.c_str()); |
165 | 56 | strcpy(fuzz_kv_overrides[overwrite_idx].val_str, arch_val.c_str()); |
166 | 56 | overwrite_idx++; |
167 | | |
168 | 2.85k | for (int i = 0; i < possible_prefix_keys.size(); i++) { |
169 | 2.80k | std::string key; |
170 | 2.80k | std::string val; |
171 | | |
172 | | // Get the key |
173 | 2.80k | key = arch_val + possible_prefix_keys[i]; |
174 | 2.80k | val = fdp.ConsumeRandomLengthString(32); |
175 | | |
176 | | // Copy the data into the overrides array |
177 | 2.80k | fuzz_kv_overrides[overwrite_idx].tag = fdp.PickValueInArray(arrayed_enums); |
178 | 2.80k | strcpy(fuzz_kv_overrides[overwrite_idx].key, key.c_str()); |
179 | 2.80k | strcpy(fuzz_kv_overrides[overwrite_idx].val_str, val.c_str()); |
180 | 2.80k | overwrite_idx++; |
181 | 2.80k | } |
182 | | |
183 | | // Create the model |
184 | 56 | std::string model_payload = fdp.ConsumeRandomLengthString(); |
185 | 56 | if (model_payload.size() < 10) { |
186 | 54 | return 0; |
187 | 54 | } |
188 | 2 | model_payload[0] = 'G'; |
189 | 2 | model_payload[1] = 'G'; |
190 | 2 | model_payload[2] = 'U'; |
191 | 2 | model_payload[3] = 'F'; |
192 | | |
193 | 2 | char filename[256]; |
194 | 2 | sprintf(filename, "/tmp/libfuzzer.%d", getpid()); |
195 | | |
196 | 2 | FILE *fp = fopen(filename, "wb"); |
197 | 2 | if (!fp) { |
198 | 0 | return 0; |
199 | 0 | } |
200 | 2 | fwrite(model_payload.data(), model_payload.size(), 1, fp); |
201 | 2 | fclose(fp); |
202 | | |
203 | | // Override an arbitrary set of arguments |
204 | 50 | for (int i = overwrite_idx; i < NUM_OVERRIDES; i++) { |
205 | 48 | std::string key; |
206 | 48 | std::string val; |
207 | | |
208 | | // Get the key |
209 | 48 | if (fdp.ConsumeProbability<float>() > 0.90) { |
210 | 0 | key = fdp.ConsumeRandomLengthString(20); |
211 | 48 | } else { |
212 | 48 | int i = fdp.ConsumeIntegralInRange<int>(0, possible_keys.size() - 1); |
213 | 48 | key = possible_keys[i]; |
214 | 48 | } |
215 | 48 | val = fdp.ConsumeRandomLengthString(30); |
216 | | |
217 | | // Copy the data into the overrides array |
218 | 48 | fuzz_kv_overrides[i].tag = fdp.PickValueInArray(arrayed_enums); |
219 | 48 | strcpy(fuzz_kv_overrides[i].key, key.c_str()); |
220 | 48 | strcpy(fuzz_kv_overrides[i].val_str, val.c_str()); |
221 | 48 | } |
222 | | |
223 | | // For debugging |
224 | | // std::cout << "--- overwrote ---\n"; |
225 | | // for (int m = 0; m < NUM_OVERRIDES-1; m++) { |
226 | | // std::cout << "=== " << fuzz_kv_overrides[m].key << "\n"; |
227 | | //} |
228 | | // std::cout << "#############\n"; |
229 | | |
230 | 2 | params.kv_overrides = |
231 | 2 | (const struct llama_model_kv_override *)fuzz_kv_overrides; |
232 | | |
233 | 2 | if (setjmp(fuzzing_jmp_buf) == 0) { |
234 | 2 | auto *model = llama_load_model_from_file(filename, params); |
235 | 2 | if (model != nullptr) { |
236 | 0 | llama_free_model(model); |
237 | 0 | } |
238 | 2 | } |
239 | 2 | llama_backend_free(); |
240 | | |
241 | | // close any open descriptors. |
242 | 2.04k | for (int i = 3; i < 1024; i++) { |
243 | 2.04k | close(i); |
244 | 2.04k | } |
245 | | |
246 | 2 | unlink(filename); |
247 | 2 | return 0; |
248 | 2 | } |