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