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