1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2026, Linutronix GmbH
4 */
5
6 #include <asan.h>
7 #include <asan_test.h>
8 #include <setjmp.h>
9 #include <malloc.h>
10 #include <config.h>
11 #include <util.h>
12 #include <trace.h>
13
14 #define ASAN_TEST_SUCCESS 1
15 #define ASAN_TEST_BUF_SIZE 15
16
17 static char asan_test_sgbuf[ASAN_TEST_BUF_SIZE];
18 char asan_test_gbuf[ASAN_TEST_BUF_SIZE];
19 static const char asan_test_sgbuf_ro[ASAN_TEST_BUF_SIZE + 1];
20
21 static jmp_buf asan_test_jmp;
22
asan_out_of_bounds_write(char * buf,size_t pos,char value)23 static void asan_out_of_bounds_write(char *buf, size_t pos,
24 char value)
25 {
26 buf[pos] = value;
27 }
28
asan_out_of_bounds_read(char * buf,size_t pos)29 static char asan_out_of_bounds_read(char *buf, size_t pos)
30 {
31 return buf[pos];
32 }
33
asan_out_of_bounds_memcpy(void * __restrict dst,const void * __restrict src,size_t size)34 static void *asan_out_of_bounds_memcpy(void *__restrict dst,
35 const void *__restrict src,
36 size_t size)
37 {
38 return memcpy(dst, src, size);
39 }
40
asan_out_of_bounds_memset(void * buf,int val,size_t size)41 static void *asan_out_of_bounds_memset(void *buf, int val, size_t size)
42 {
43 return memset(buf, val, size);
44 }
45
asan_panic_test(void)46 static void asan_panic_test(void)
47 {
48 longjmp(asan_test_jmp, ASAN_TEST_SUCCESS);
49 }
50
asan_test_cleanup(struct asan_test_ctx * ctx)51 static void asan_test_cleanup(struct asan_test_ctx *ctx)
52 {
53 unsigned int i = 0;
54
55 free(ctx->pmalloc1);
56
57 for (; i < ARRAY_SIZE(ctx->pmalloc2); i++)
58 free(ctx->pmalloc2[i]);
59 }
60
asan_test_stack(struct asan_test_ctx * ctx)61 void asan_test_stack(struct asan_test_ctx *ctx)
62 {
63 char buf[ASAN_TEST_BUF_SIZE] = {0};
64
65 ctx->write_func(buf, ASAN_TEST_BUF_SIZE, ctx->write_value);
66 }
67
asan_test_global_stat(struct asan_test_ctx * ctx)68 void asan_test_global_stat(struct asan_test_ctx *ctx)
69 {
70 ctx->write_func(asan_test_sgbuf, ASAN_TEST_BUF_SIZE,
71 ctx->write_value);
72 }
73
asan_test_global_ro(struct asan_test_ctx * ctx)74 void asan_test_global_ro(struct asan_test_ctx *ctx)
75 {
76 ctx->read_func((char *)asan_test_sgbuf_ro,
77 ASAN_TEST_BUF_SIZE + 1);
78 }
79
asan_test_global(struct asan_test_ctx * ctx)80 void asan_test_global(struct asan_test_ctx *ctx)
81 {
82 ctx->write_func(asan_test_gbuf, ASAN_TEST_BUF_SIZE,
83 ctx->write_value);
84 }
85
asan_test_malloc(struct asan_test_ctx * ctx)86 void asan_test_malloc(struct asan_test_ctx *ctx)
87 {
88 ctx->pmalloc1 = malloc(ASAN_TEST_BUF_SIZE);
89
90 if (ctx->pmalloc1)
91 ctx->write_func(ctx->pmalloc1, ASAN_TEST_BUF_SIZE,
92 ctx->write_value);
93 }
94
asan_test_malloc2(struct asan_test_ctx * ctx)95 void asan_test_malloc2(struct asan_test_ctx *ctx)
96 {
97 size_t aligned_size = ROUNDUP(ASAN_TEST_BUF_SIZE, 8);
98 unsigned int i = 0;
99 char *p = NULL;
100
101 for (; i < ARRAY_SIZE(ctx->pmalloc2); i++) {
102 ctx->pmalloc2[i] = malloc(aligned_size);
103 if (!ctx->pmalloc2[i])
104 return;
105 }
106 p = ctx->pmalloc2[1];
107 ctx->write_func(p, aligned_size, ctx->write_value);
108 }
109
asan_test_use_after_free(struct asan_test_ctx * ctx)110 void asan_test_use_after_free(struct asan_test_ctx *ctx)
111 {
112 char *a = malloc(ASAN_TEST_BUF_SIZE);
113
114 if (a) {
115 ctx->free_func(a);
116 ctx->write_func(a, 0, ctx->write_value);
117 }
118 }
119
asan_test_memcpy_dst(struct asan_test_ctx * ctx)120 void asan_test_memcpy_dst(struct asan_test_ctx *ctx)
121 {
122 static char b[ASAN_TEST_BUF_SIZE + 1];
123 static char a[ASAN_TEST_BUF_SIZE];
124
125 ctx->memcpy_func(a, b, sizeof(b));
126 }
127
asan_test_memcpy_src(struct asan_test_ctx * ctx)128 void asan_test_memcpy_src(struct asan_test_ctx *ctx)
129 {
130 static char a[ASAN_TEST_BUF_SIZE + 1];
131 static char b[ASAN_TEST_BUF_SIZE];
132
133 ctx->memcpy_func(a, b, sizeof(a));
134 }
135
asan_test_memset(struct asan_test_ctx * ctx)136 void asan_test_memset(struct asan_test_ctx *ctx)
137 {
138 static char b[ASAN_TEST_BUF_SIZE];
139
140 ctx->memset_func(b, ctx->write_value, ASAN_TEST_BUF_SIZE + 1);
141 }
142
asan_test_free(void * ptr)143 static void asan_test_free(void *ptr)
144 {
145 free(ptr);
146 }
147
asan_test_init(struct asan_test_ctx * ctx)148 void asan_test_init(struct asan_test_ctx *ctx)
149 {
150 ctx->write_value = 0xab;
151 ctx->write_func = asan_out_of_bounds_write;
152 ctx->read_func = asan_out_of_bounds_read;
153 ctx->memcpy_func = asan_out_of_bounds_memcpy;
154 ctx->memset_func = asan_out_of_bounds_memset;
155 ctx->free_func = asan_test_free;
156
157 asan_set_panic_cb(asan_panic_test);
158 }
159
asan_test_deinit(struct asan_test_ctx * ctx)160 void asan_test_deinit(struct asan_test_ctx *ctx)
161 {
162 asan_test_cleanup(ctx);
163 asan_set_panic_cb(asan_panic);
164 }
165
asan_call_test(struct asan_test_ctx * ctx,void (* test)(struct asan_test_ctx * ctx),const char __unused * desc)166 int asan_call_test(struct asan_test_ctx *ctx,
167 void (*test)(struct asan_test_ctx *ctx),
168 const char __unused *desc)
169 {
170 int ret = 0;
171
172 ret = setjmp(asan_test_jmp);
173 if (ret == 0) {
174 test(ctx);
175 ret = -1;
176 } else if (ret == ASAN_TEST_SUCCESS) {
177 ret = 0;
178 } else {
179 asan_panic();
180 }
181 IMSG(" => [asan] test %s: %s", desc, !ret ? "ok" : "FAILED");
182
183 return ret;
184 }
185