1 /* Unit test for _dl_addr_inside_object.
2 Copyright (C) 2016-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <link.h>
22 #include <elf.h>
23 #include <libc-symbols.h>
24
25 extern int _dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr);
26
27 static int
do_test(void)28 do_test (void)
29 {
30 int ret, err = 0;
31 ElfW(Addr) addr;
32 struct link_map map;
33 ElfW(Phdr) header;
34 map.l_phdr = &header;
35 map.l_phnum = 1;
36 map.l_addr = 0x0;
37 /* Segment spans 0x2000 -> 0x4000. */
38 header.p_vaddr = 0x2000;
39 header.p_memsz = 0x2000;
40 header.p_type = PT_LOAD;
41 /* Address is above the segment e.g. > 0x4000. */
42 addr = 0x5000;
43 ret = _dl_addr_inside_object (&map, addr);
44 switch (ret)
45 {
46 case 0:
47 printf ("PASS: Above: Address is detected as outside the segment.\n");
48 break;
49 case 1:
50 printf ("FAIL: Above: Address is detected as inside the segment.\n");
51 err++;
52 break;
53 default:
54 printf ("FAIL: Above: Invalid return value.\n");
55 exit (1);
56 }
57 /* Address is inside the segment e.g. 0x2000 < addr < 0x4000. */
58 addr = 0x3000;
59 ret = _dl_addr_inside_object (&map, addr);
60 switch (ret)
61 {
62 case 0:
63 printf ("FAIL: Inside: Address is detected as outside the segment.\n");
64 err++;
65 break;
66 case 1:
67 printf ("PASS: Inside: Address is detected as inside the segment.\n");
68 break;
69 default:
70 printf ("FAIL: Inside: Invalid return value.\n");
71 exit (1);
72 }
73 /* Address is below the segment e.g. < 0x2000. */
74 addr = 0x1000;
75 ret = _dl_addr_inside_object (&map, addr);
76 switch (ret)
77 {
78 case 0:
79 printf ("PASS: Below: Address is detected as outside the segment.\n");
80 break;
81 case 1:
82 printf ("FAIL: Below: Address is detected as inside the segment.\n");
83 err++;
84 break;
85 default:
86 printf ("FAIL: Below: Invalid return value.\n");
87 exit (1);
88 }
89 /* Address is in the segment and addr == p_vaddr. */
90 addr = 0x2000;
91 ret = _dl_addr_inside_object (&map, addr);
92 switch (ret)
93 {
94 case 0:
95 printf ("FAIL: At p_vaddr: Address is detected as outside the segment.\n");
96 err++;
97 break;
98 case 1:
99 printf ("PASS: At p_vaddr: Address is detected as inside the segment.\n");
100 break;
101 default:
102 printf ("FAIL: At p_vaddr: Invalid return value.\n");
103 exit (1);
104 }
105 /* Address is in the segment and addr == p_vaddr + p_memsz - 1. */
106 addr = 0x2000 + 0x2000 - 0x1;
107 ret = _dl_addr_inside_object (&map, addr);
108 switch (ret)
109 {
110 case 0:
111 printf ("FAIL: At p_memsz-1: Address is detected as outside the segment.\n");
112 err++;
113 break;
114 case 1:
115 printf ("PASS: At p_memsz-1: Address is detected as inside the segment.\n");
116 break;
117 default:
118 printf ("FAIL: At p_memsz-1: Invalid return value.\n");
119 exit (1);
120 }
121 /* Address is outside the segment and addr == p_vaddr + p_memsz. */
122 addr = 0x2000 + 0x2000;
123 ret = _dl_addr_inside_object (&map, addr);
124 switch (ret)
125 {
126 case 0:
127 printf ("PASS: At p_memsz: Address is detected as outside the segment.\n");
128 break;
129 case 1:
130 printf ("FAIL: At p_memsz: Address is detected as inside the segment.\n");
131 err++;
132 break;
133 default:
134 printf ("FAIL: At p_memsz: Invalid return value.\n");
135 exit (1);
136 }
137 /* Address is outside the segment and p_vaddr at maximum address. */
138 addr = 0x0 - 0x2;
139 header.p_vaddr = 0x0 - 0x1;
140 header.p_memsz = 0x1;
141 ret = _dl_addr_inside_object (&map, addr);
142 switch (ret)
143 {
144 case 0:
145 printf ("PASS: At max: Address is detected as outside the segment.\n");
146 break;
147 case 1:
148 printf ("FAIL: At max: Address is detected as inside the segment.\n");
149 err++;
150 break;
151 default:
152 printf ("FAIL: At max: Invalid return value.\n");
153 exit (1);
154 }
155 /* Address is outside the segment and p_vaddr at minimum address. */
156 addr = 0x1;
157 header.p_vaddr = 0x0;
158 header.p_memsz = 0x1;
159 ret = _dl_addr_inside_object (&map, addr);
160 switch (ret)
161 {
162 case 0:
163 printf ("PASS: At min: Address is detected as outside the segment.\n");
164 break;
165 case 1:
166 printf ("FAIL: At min: Address is detected as inside the segment.\n");
167 err++;
168 break;
169 default:
170 printf ("FAIL: At min: Invalid return value.\n");
171 exit (1);
172 }
173 /* Address is always inside the segment with p_memsz at max. */
174 addr = 0x0;
175 header.p_vaddr = 0x0;
176 header.p_memsz = 0x0 - 0x1;
177 ret = _dl_addr_inside_object (&map, addr);
178 switch (ret)
179 {
180 case 0:
181 printf ("FAIL: At maxmem: Address is detected as outside the segment.\n");
182 err++;
183 break;
184 case 1:
185 printf ("PASS: At maxmem: Address is detected as inside the segment.\n");
186 break;
187 default:
188 printf ("FAIL: At maxmem: Invalid return value.\n");
189 exit (1);
190 }
191 /* Attempt to wrap addr into the segment.
192 Pick a load address in the middle of the address space.
193 Place the test address at 0x0 so it wraps to the middle again. */
194 map.l_addr = 0x0 - 0x1;
195 map.l_addr = map.l_addr / 2;
196 addr = 0;
197 /* Setup a segment covering 1/2 the address space. */
198 header.p_vaddr = 0x0;
199 header.p_memsz = 0x0 - 0x1 - map.l_addr;
200 /* No matter where you place addr everything is shifted modulo l_addr
201 and even with this underflow you're always 1 byte away from being
202 in the range. */
203 ret = _dl_addr_inside_object (&map, addr);
204 switch (ret)
205 {
206 case 0:
207 printf ("PASS: Underflow: Address is detected as outside the segment.\n");
208 break;
209 case 1:
210 printf ("FAIL: Underflow: Address is detected as inside the segment.\n");
211 err++;
212 break;
213 default:
214 printf ("FAIL: Underflow: Invalid return value.\n");
215 exit (1);
216 }
217
218 return err;
219 }
220
221 #include <support/test-driver.c>
222