1 /* radare2 - LGPL - Copyright 2017-2020 - condret, MaskRay */
2
3 #include <r_io.h>
4 #include <stdlib.h>
5 #include <sdb.h>
6 #include "r_binheap.h"
7 #include "r_util.h"
8 #include "r_vector.h"
9
10 #define END_OF_MAP_IDS UT32_MAX
11
12 // Store map parts that are not covered by others into io->map_skyline
io_map_calculate_skyline(RIO * io)13 static void io_map_calculate_skyline(RIO *io) {
14 r_skyline_clear (&io->map_skyline);
15 // Last map has highest priority (it shadows previous maps)
16 void **it;
17 r_pvector_foreach (&io->maps, it) {
18 RIOMap *map = (RIOMap *)*it;
19 r_skyline_add (&io->map_skyline, map->itv, map);
20 }
21 }
22
io_map_new(RIO * io,int fd,int perm,ut64 delta,ut64 addr,ut64 size)23 RIOMap* io_map_new(RIO* io, int fd, int perm, ut64 delta, ut64 addr, ut64 size) {
24 if (!size || !io || !io->map_ids) {
25 return NULL;
26 }
27 RIOMap* map = R_NEW0 (RIOMap);
28 if (!map || !io->map_ids || !r_id_pool_grab_id (io->map_ids, &map->id)) {
29 free (map);
30 return NULL;
31 }
32 map->fd = fd;
33 map->delta = delta;
34 if ((UT64_MAX - size + 1) < addr) {
35 /// XXX: this is leaking a map!!!
36 io_map_new (io, fd, perm, delta - addr, 0LL, size + addr);
37 size = -(st64)addr;
38 }
39 // RIOMap describes an interval of addresses
40 // r_io_map_begin (map) -> r_io_map_to (map)
41 map->itv = (RInterval){ addr, size };
42 map->perm = perm;
43 map->delta = delta;
44 // new map lives on the top, being top the list's tail
45 r_pvector_push (&io->maps, map);
46 r_skyline_add (&io->map_skyline, map->itv, map);
47 return map;
48 }
49
r_io_map_new(RIO * io,int fd,int perm,ut64 delta,ut64 addr,ut64 size)50 R_API RIOMap *r_io_map_new(RIO *io, int fd, int perm, ut64 delta, ut64 addr, ut64 size) {
51 return io_map_new (io, fd, perm, delta, addr, size);
52 }
53
r_io_map_remap(RIO * io,ut32 id,ut64 addr)54 R_API bool r_io_map_remap(RIO *io, ut32 id, ut64 addr) {
55 RIOMap *map = r_io_map_resolve (io, id);
56 if (map) {
57 ut64 size = r_io_map_size (map);
58 r_io_map_set_begin (map, addr);
59 if (UT64_MAX - size + 1 < addr) {
60 r_io_map_set_size (map, -addr);
61 r_io_map_new (io, map->fd, map->perm, map->delta - addr, 0, size + addr);
62 }
63 io_map_calculate_skyline (io);
64 return true;
65 }
66 return false;
67 }
68
r_io_map_remap_fd(RIO * io,int fd,ut64 addr)69 R_API bool r_io_map_remap_fd(RIO *io, int fd, ut64 addr) {
70 RIOMap *map;
71 bool retval = false;
72 RList *maps = r_io_map_get_for_fd (io, fd);
73 if (maps) {
74 map = r_list_get_n (maps, 0);
75 if (map) {
76 retval = r_io_map_remap (io, map->id, addr);
77 }
78 r_list_free (maps);
79 }
80 return retval;
81 }
82
_map_free(void * p)83 static void _map_free(void* p) {
84 RIOMap* map = (RIOMap*) p;
85 if (map) {
86 free (map->name);
87 free (map);
88 }
89 }
90
r_io_map_init(RIO * io)91 R_API void r_io_map_init(RIO* io) {
92 r_return_if_fail (io);
93 r_pvector_init (&io->maps, _map_free);
94 if (io->map_ids) {
95 r_id_pool_free (io->map_ids);
96 }
97 io->map_ids = r_id_pool_new (1, END_OF_MAP_IDS);
98 }
99
100 // check if a map with exact the same properties exists
r_io_map_exists(RIO * io,RIOMap * map)101 R_API bool r_io_map_exists(RIO *io, RIOMap *map) {
102 r_return_val_if_fail (io && map, false);
103 void **it;
104 r_pvector_foreach (&io->maps, it) {
105 RIOMap *m = *it;
106 if (!memcmp (m, map, sizeof (RIOMap))) {
107 return true;
108 }
109 }
110 return false;
111 }
112
113 // check if a map with specified id exists
r_io_map_exists_for_id(RIO * io,ut32 id)114 R_API bool r_io_map_exists_for_id(RIO* io, ut32 id) {
115 return r_io_map_resolve (io, id) != NULL;
116 }
117
r_io_map_resolve(RIO * io,ut32 id)118 R_API RIOMap* r_io_map_resolve(RIO *io, ut32 id) {
119 r_return_val_if_fail (io && id, false);
120 void **it;
121 r_pvector_foreach (&io->maps, it) {
122 RIOMap *map = *it;
123 if (map->id == id) {
124 return map;
125 }
126 }
127 return NULL;
128 }
129
io_map_add(RIO * io,int fd,int perm,ut64 delta,ut64 addr,ut64 size)130 RIOMap* io_map_add(RIO* io, int fd, int perm, ut64 delta, ut64 addr, ut64 size) {
131 //check if desc exists
132 RIODesc* desc = r_io_desc_get (io, fd);
133 if (desc) {
134 //a map cannot have higher permissions than the desc belonging to it
135 return io_map_new (io, fd, (perm & desc->perm) | (perm & R_PERM_X),
136 delta, addr, size);
137 }
138 return NULL;
139 }
140
r_io_map_add(RIO * io,int fd,int perm,ut64 delta,ut64 addr,ut64 size)141 R_API RIOMap *r_io_map_add(RIO *io, int fd, int perm, ut64 delta, ut64 addr, ut64 size) {
142 return io_map_add (io, fd, perm, delta, addr, size);
143 }
144
r_io_map_add_batch(RIO * io,int fd,int perm,ut64 delta,ut64 addr,ut64 size)145 R_API RIOMap *r_io_map_add_batch(RIO *io, int fd, int perm, ut64 delta, ut64 addr, ut64 size) {
146 return io_map_add (io, fd, perm, delta, addr, size);
147 }
148
r_io_update(RIO * io)149 R_API void r_io_update(RIO *io) {
150 io_map_calculate_skyline (io);
151 }
152
r_io_map_get_paddr(RIO * io,ut64 paddr)153 R_API RIOMap* r_io_map_get_paddr(RIO* io, ut64 paddr) {
154 r_return_val_if_fail (io, NULL);
155 void **it;
156 r_pvector_foreach_prev (&io->maps, it) {
157 RIOMap *map = *it;
158 if (map->delta <= paddr && paddr < map->delta + r_io_map_size (map)) {
159 return map;
160 }
161 }
162 return NULL;
163 }
164
165 // gets first map where addr fits in
r_io_map_get(RIO * io,ut64 addr)166 R_API RIOMap *r_io_map_get(RIO* io, ut64 addr) {
167 r_return_val_if_fail (io, NULL);
168 return r_skyline_get (&io->map_skyline, addr);
169 }
170
r_io_map_is_mapped(RIO * io,ut64 addr)171 R_API bool r_io_map_is_mapped(RIO* io, ut64 addr) {
172 r_return_val_if_fail (io, false);
173 return (bool)r_io_map_get (io, addr);
174 }
175
r_io_map_reset(RIO * io)176 R_API void r_io_map_reset(RIO* io) {
177 r_io_map_fini (io);
178 r_io_map_init (io);
179 io_map_calculate_skyline (io);
180 }
181
r_io_map_del(RIO * io,ut32 id)182 R_API bool r_io_map_del(RIO *io, ut32 id) {
183 r_return_val_if_fail (io, false);
184 size_t i;
185 for (i = 0; i < r_pvector_len (&io->maps); i++) {
186 RIOMap *map = r_pvector_at (&io->maps, i);
187 if (map->id == id) {
188 r_pvector_remove_at (&io->maps, i);
189 _map_free (map);
190 r_id_pool_kick_id (io->map_ids, id);
191 io_map_calculate_skyline (io);
192 return true;
193 }
194 }
195 return false;
196 }
197
198 //delete all maps with specified fd
r_io_map_del_for_fd(RIO * io,int fd)199 R_API bool r_io_map_del_for_fd(RIO* io, int fd) {
200 r_return_val_if_fail (io, false);
201 bool ret = false;
202 size_t i;
203 for (i = 0; i < r_pvector_len (&io->maps);) {
204 RIOMap *map = r_pvector_at (&io->maps, i);
205 if (!map) {
206 r_pvector_remove_at (&io->maps, i);
207 } else if (map->fd == fd) {
208 r_id_pool_kick_id (io->map_ids, map->id);
209 //delete iter and map
210 r_pvector_remove_at (&io->maps, i);
211 _map_free (map);
212 ret = true;
213 } else {
214 i++;
215 }
216 }
217 if (ret) {
218 io_map_calculate_skyline (io);
219 }
220 return ret;
221 }
222
223 //brings map with specified id to the tail of of the list
224 //return a boolean denoting whether is was possible to priorized
r_io_map_priorize(RIO * io,ut32 id)225 R_API bool r_io_map_priorize(RIO* io, ut32 id) {
226 r_return_val_if_fail (io, false);
227 size_t i;
228 for (i = 0; i < r_pvector_len (&io->maps); i++) {
229 RIOMap *map = r_pvector_at (&io->maps, i);
230 // search for iter with the correct map
231 if (map->id == id) {
232 r_pvector_remove_at (&io->maps, i);
233 r_pvector_push (&io->maps, map);
234 io_map_calculate_skyline (io);
235 return true;
236 }
237 }
238 return false;
239 }
240
r_io_map_depriorize(RIO * io,ut32 id)241 R_API bool r_io_map_depriorize(RIO* io, ut32 id) {
242 r_return_val_if_fail (io, false);
243 size_t i;
244 for (i = 0; i < r_pvector_len (&io->maps); i++) {
245 RIOMap *map = r_pvector_at (&io->maps, i);
246 // search for iter with the correct map
247 if (map->id == id) {
248 r_pvector_remove_at (&io->maps, i);
249 r_pvector_push_front (&io->maps, map);
250 io_map_calculate_skyline (io);
251 return true;
252 }
253 }
254 return false;
255 }
256
r_io_map_priorize_for_fd(RIO * io,int fd)257 R_API bool r_io_map_priorize_for_fd(RIO *io, int fd) {
258 r_return_val_if_fail (io, false);
259 //we need a clean list for this, or this becomes a segfault-field
260 r_io_map_cleanup (io);
261 RPVector temp;
262 r_pvector_init (&temp, NULL);
263 size_t i;
264 for (i = 0; i < r_pvector_len (&io->maps);) {
265 RIOMap *map = r_pvector_at (&io->maps, i);
266 if (map->fd == fd) {
267 r_pvector_push (&temp, map);
268 r_pvector_remove_at (&io->maps, i);
269 continue;
270 }
271 i++;
272 }
273 r_pvector_insert_range (&io->maps, r_pvector_len (&io->maps), temp.v.a, r_pvector_len (&temp));
274 r_pvector_clear (&temp);
275 io_map_calculate_skyline (io);
276 return true;
277 }
278
279 //may fix some inconsistencies in io->maps
r_io_map_cleanup(RIO * io)280 R_API void r_io_map_cleanup(RIO* io) {
281 r_return_if_fail (io);
282 //remove all maps if no descs exist
283 if (!io->files) {
284 r_io_map_fini (io);
285 r_io_map_init (io);
286 return;
287 }
288 bool del = false;
289 size_t i;
290 for (i = 0; i < r_pvector_len (&io->maps);) {
291 RIOMap *map = r_pvector_at (&io->maps, i);
292 if (!map) {
293 // remove iter if the map is a null-ptr, this may fix some segfaults. This should never happen.
294 r_warn_if_reached ();
295 r_pvector_remove_at (&io->maps, i);
296 del = true;
297 } else if (!r_io_desc_get (io, map->fd)) {
298 //delete map and iter if no desc exists for map->fd in io->files
299 r_id_pool_kick_id (io->map_ids, map->id);
300 map = r_pvector_remove_at (&io->maps, i);
301 _map_free (map);
302 del = true;
303 } else {
304 i++;
305 }
306 }
307 if (del) {
308 io_map_calculate_skyline (io);
309 }
310 }
311
r_io_map_fini(RIO * io)312 R_API void r_io_map_fini(RIO* io) {
313 r_return_if_fail (io);
314 r_pvector_clear (&io->maps);
315 r_id_pool_free (io->map_ids);
316 io->map_ids = NULL;
317 r_skyline_clear (&io->map_skyline);
318 }
319
r_io_map_set_name(RIOMap * map,const char * name)320 R_API void r_io_map_set_name(RIOMap* map, const char* name) {
321 r_return_if_fail (map && name);
322 free (map->name);
323 map->name = strdup (name);
324 }
325
r_io_map_del_name(RIOMap * map)326 R_API void r_io_map_del_name(RIOMap* map) {
327 if (map) {
328 R_FREE (map->name);
329 }
330 }
331
332 // TODO: very similar to r_io_map_next_address, decide which one to use
r_io_map_next_available(RIO * io,ut64 addr,ut64 size,ut64 load_align)333 R_API ut64 r_io_map_next_available(RIO* io, ut64 addr, ut64 size, ut64 load_align) {
334 if (load_align == 0) {
335 load_align = 1;
336 }
337 ut64 next_addr = addr,
338 end_addr = next_addr + size;
339 void **it;
340 r_pvector_foreach (&io->maps, it) {
341 RIOMap *map = *it;
342 ut64 to = r_io_map_end (map);
343 next_addr = R_MAX (next_addr, to + (load_align - (to % load_align)) % load_align);
344 // XXX - This does not handle when file overflow 0xFFFFFFFF000 -> 0x00000FFF
345 // adding the check for the map's fd to see if this removes contention for
346 // memory mapping with multiple files. infinite loop ahead?
347 if ((r_io_map_begin (map) <= next_addr && next_addr < to) || r_io_map_contain (map, end_addr)) {
348 next_addr = to + (load_align - (to % load_align)) % load_align;
349 return r_io_map_next_available (io, next_addr, size, load_align);
350 }
351 break;
352 }
353 return next_addr;
354 }
355
356 // TODO: very similar to r_io_map_next_available. decide which one to use
r_io_map_next_address(RIO * io,ut64 addr)357 R_API ut64 r_io_map_next_address(RIO* io, ut64 addr) {
358 ut64 lowest = UT64_MAX;
359 void **it;
360 r_pvector_foreach (&io->maps, it) {
361 RIOMap *map = *it;
362 ut64 from = r_io_map_begin (map);
363 if (from > addr && addr < lowest) {
364 lowest = from;
365 }
366 ut64 to = r_io_map_end (map);
367 if (to > addr && to < lowest) {
368 lowest = to;
369 }
370 }
371 return lowest;
372 }
373
r_io_map_get_for_fd(RIO * io,int fd)374 R_API RList* r_io_map_get_for_fd(RIO* io, int fd) {
375 RList* map_list = r_list_newf (NULL);
376 if (!map_list) {
377 return NULL;
378 }
379 void **it;
380 r_pvector_foreach (&io->maps, it) {
381 RIOMap *map = *it;
382 if (map && map->fd == fd) {
383 r_list_append (map_list, map);
384 }
385 }
386 return map_list;
387 }
388
r_io_map_resize(RIO * io,ut32 id,ut64 newsize)389 R_API bool r_io_map_resize(RIO *io, ut32 id, ut64 newsize) {
390 RIOMap *map;
391 if (!newsize || !(map = r_io_map_resolve (io, id))) {
392 return false;
393 }
394 ut64 addr = r_io_map_begin (map);
395 if (UT64_MAX - newsize + 1 < addr) {
396 r_io_map_set_size (map, -addr);
397 r_io_map_new (io, map->fd, map->perm, map->delta - addr, 0, newsize + addr);
398 return true;
399 }
400 r_io_map_set_size (map, newsize);
401 io_map_calculate_skyline (io);
402 return true;
403 }
404
405 // find a location that can hold enough bytes without overlapping
406 // XXX this function is buggy and doesnt works as expected, but i need it for a PoC for now
r_io_map_location(RIO * io,ut64 size)407 R_API ut64 r_io_map_location(RIO *io, ut64 size) {
408 ut64 base = (io->bits == 64)? 0x60000000000LL: 0x60000000;
409 while (r_io_map_get (io, base)) {
410 base += 0x200000;
411 }
412 return base;
413 }
414