xref: /optee_os/lib/libutils/ext/asan_test.c (revision d6d1731bef3d306080076b5a9be15682e353241a)
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