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