1 /* radare - LGPL - Copyright 2009-2020 - pancake */
2 
3 #include <r_userconf.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #if defined(__NetBSD__)
7 # include <sys/param.h>
8 # include <sys/sysctl.h>
9 # if __NetBSD_Prereq__(7,0,0)
10 #  define NETBSD_WITH_BACKTRACE
11 # endif
12 #endif
13 #if defined(__FreeBSD__)
14 # include <sys/param.h>
15 # include <sys/sysctl.h>
16 # if __FreeBSD_version >= 1000000
17 #  define FREEBSD_WITH_BACKTRACE
18 # endif
19 #endif
20 #if defined(__DragonFly__)
21 # include <sys/param.h>
22 # include <sys/sysctl.h>
23 #endif
24 #if defined(__HAIKU__)
25 # include <kernel/image.h>
26 # include <sys/param.h>
27 #endif
28 #include <sys/types.h>
29 #include <r_types.h>
30 #include <r_util.h>
31 #include <r_lib.h>
32 
33 static char** env = NULL;
34 
35 #if (__linux__ && __GNU_LIBRARY__) || defined(NETBSD_WITH_BACKTRACE) || \
36   defined(FREEBSD_WITH_BACKTRACE) || __DragonFly__ || __sun || __HAIKU__
37 # include <execinfo.h>
38 #endif
39 #if __APPLE__
40 #include <errno.h>
41 #ifdef __MAC_10_8
42 #define HAVE_ENVIRON 1
43 #else
44 #define HAVE_ENVIRON 0
45 #endif
46 
47 #if HAVE_ENVIRON
48 #include <execinfo.h>
49 #endif
50 // iOS don't have this we can't hardcode
51 // #include <crt_externs.h>
52 extern char ***_NSGetEnviron(void);
53 # ifndef PROC_PIDPATHINFO_MAXSIZE
54 #  define PROC_PIDPATHINFO_MAXSIZE 1024
55 int proc_pidpath(int pid, void * buffer, ut32 buffersize);
56 //#  include <libproc.h>
57 # endif
58 #endif
59 #if __UNIX__
60 # include <sys/utsname.h>
61 # include <sys/wait.h>
62 # include <sys/stat.h>
63 # include <errno.h>
64 # include <signal.h>
65 extern char **environ;
66 
67 #ifdef __HAIKU__
68 # define Sleep sleep
69 #endif
70 #endif
71 #if __WINDOWS__
72 # include <io.h>
73 # include <winbase.h>
74 # include <signal.h>
75 #define TMP_BUFSIZE	4096
76 #ifdef _MSC_VER
77 #include <psapi.h>
78 #include <process.h>  // to allow getpid under windows msvc compilation
79 #include <direct.h>  // to allow getcwd under windows msvc compilation
80 #endif
81 #endif
82 
83 R_LIB_VERSION(r_util);
84 
85 #ifdef __x86_64__
86 # ifdef _MSC_VER
87 #  define R_SYS_ASM_START_ROP() \
88 	 eprintf ("r_sys_run_rop: Unsupported arch\n");
89 # else
90 #  define R_SYS_ASM_START_ROP() \
91 	 __asm__ __volatile__ ("leaq %0, %%rsp; ret" \
92 				: \
93 				: "m" (*bufptr));
94 # endif
95 #elif __i386__
96 # ifdef _MSC_VER
97 #  define R_SYS_ASM_START_ROP() \
98 	__asm \
99 	{ \
100 		__asm lea esp, bufptr\
101 		__asm ret\
102 	}
103 # else
104 #  define R_SYS_ASM_START_ROP() \
105 	__asm__ __volatile__ ("leal %0, %%esp; ret" \
106 				: \
107 				: "m" (*bufptr));
108 # endif
109 #else
110 # define R_SYS_ASM_START_ROP() \
111 	eprintf ("r_sys_run_rop: Unsupported arch\n");
112 #endif
113 
114 static const struct {const char* name; ut64 bit;} arch_bit_array[] = {
115     {"x86", R_SYS_ARCH_X86},
116     {"arm", R_SYS_ARCH_ARM},
117     {"ppc", R_SYS_ARCH_PPC},
118     {"m68k", R_SYS_ARCH_M68K},
119     {"java", R_SYS_ARCH_JAVA},
120     {"mips", R_SYS_ARCH_MIPS},
121     {"sparc", R_SYS_ARCH_SPARC},
122     {"xap", R_SYS_ARCH_XAP},
123     {"tms320", R_SYS_ARCH_TMS320},
124     {"msil", R_SYS_ARCH_MSIL},
125     {"objd", R_SYS_ARCH_OBJD},
126     {"bf", R_SYS_ARCH_BF},
127     {"sh", R_SYS_ARCH_SH},
128     {"avr", R_SYS_ARCH_AVR},
129     {"dalvik", R_SYS_ARCH_DALVIK},
130     {"z80", R_SYS_ARCH_Z80},
131     {"arc", R_SYS_ARCH_ARC},
132     {"i8080", R_SYS_ARCH_I8080},
133     {"rar", R_SYS_ARCH_RAR},
134     {"lm32", R_SYS_ARCH_LM32},
135     {"v850", R_SYS_ARCH_V850},
136     {NULL, 0}
137 };
138 
r_sys_fork(void)139 R_API int r_sys_fork(void) {
140 #if HAVE_FORK
141 #if __WINDOWS__
142 	return -1;
143 #else
144 	return fork ();
145 #endif
146 #else
147 	return -1;
148 #endif
149 }
150 
151 #if __WINDOWS__
r_sys_sigaction(int * sig,void (* handler)(int))152 R_API int r_sys_sigaction(int *sig, void (*handler) (int)) {
153 	return -1;
154 }
155 #elif HAVE_SIGACTION
r_sys_sigaction(int * sig,void (* handler)(int))156 R_API int r_sys_sigaction(int *sig, void (*handler) (int)) {
157 	struct sigaction sigact = { };
158 	int ret, i;
159 
160 	if (!sig) {
161 		return -EINVAL;
162 	}
163 
164 	sigact.sa_handler = handler;
165 	sigemptyset (&sigact.sa_mask);
166 
167 	for (i = 0; sig[i] != 0; i++) {
168 		sigaddset (&sigact.sa_mask, sig[i]);
169 	}
170 
171 	for (i = 0; sig[i] != 0; i++) {
172 		ret = sigaction (sig[i], &sigact, NULL);
173 		if (ret) {
174 			eprintf ("Failed to set signal handler for signal '%d': %s\n", sig[i], strerror(errno));
175 			return ret;
176 		}
177 	}
178 	return 0;
179 }
180 #else
r_sys_sigaction(int * sig,void (* handler)(int))181 R_API int r_sys_sigaction(int *sig, void (*handler)(int)) {
182 	if (!sig) {
183 		return -EINVAL;
184 	}
185 	size_t i;
186 	for (i = 0; sig[i] != 0; i++) {
187 		void (*ret)(int) = signal (sig[i], handler);
188 		if (ret == SIG_ERR) {
189 			eprintf ("Failed to set signal handler for signal '%d': %s\n", sig[i], strerror(errno));
190 			return -1;
191 		}
192 	}
193 	return 0;
194 }
195 #endif
196 
r_sys_signal(int sig,void (* handler)(int))197 R_API int r_sys_signal(int sig, void (*handler) (int)) {
198 	int s[2] = { sig, 0 };
199 	return r_sys_sigaction (s, handler);
200 }
201 
r_sys_exit(int status,bool nocleanup)202 R_API void r_sys_exit(int status, bool nocleanup) {
203 	if (nocleanup) {
204 		_exit (status);
205 	} else {
206 		exit (status);
207 	}
208 }
209 
r_sys_truncate(const char * file,int sz)210 R_API int r_sys_truncate(const char *file, int sz) {
211 #if __WINDOWS__
212 	int fd = r_sandbox_open (file, O_RDWR, 0644);
213 	if (fd == -1) {
214 		return false;
215 	}
216 #ifdef _MSC_VER
217 	int r = _chsize (fd, sz);
218 #else
219 	int r = ftruncate (fd, sz);
220 #endif
221 	if (r != 0) {
222 		eprintf ("Could not resize '%s' file\n", file);
223 		close (fd);
224 		return false;
225 	}
226 	close (fd);
227 	return true;
228 #else
229 	if (r_sandbox_enable (0)) {
230 		return false;
231 	}
232 	return truncate (file, sz) == 0;
233 #endif
234 }
235 
r_sys_dir(const char * path)236 R_API RList *r_sys_dir(const char *path) {
237 	RList *list = NULL;
238 #if __WINDOWS__
239 	WIN32_FIND_DATAW entry;
240 	char *cfname;
241 	HANDLE fh = r_sandbox_opendir (path, &entry);
242 	if (fh == INVALID_HANDLE_VALUE) {
243 		//IFDGB eprintf ("Cannot open directory %ls\n", wcpath);
244 		return list;
245 	}
246 	list = r_list_newf (free);
247 	if (list) {
248 		do {
249 			if ((cfname = r_utf16_to_utf8 (entry.cFileName))) {
250 				r_list_append (list, strdup (cfname));
251 				free (cfname);
252 			}
253 		} while (FindNextFileW (fh, &entry));
254 	}
255 	FindClose (fh);
256 #else
257 	struct dirent *entry;
258 	DIR *dir = r_sandbox_opendir (path);
259 	if (dir) {
260 		list = r_list_new ();
261 		if (list) {
262 			list->free = free;
263 			while ((entry = readdir (dir))) {
264 				r_list_append (list, strdup (entry->d_name));
265 			}
266 		}
267 		closedir (dir);
268 	}
269 #endif
270 	return list;
271 }
272 
r_sys_cmd_strf(const char * fmt,...)273 R_API char *r_sys_cmd_strf(const char *fmt, ...) {
274 	char *ret, cmd[4096];
275 	va_list ap;
276 	va_start (ap, fmt);
277 	vsnprintf (cmd, sizeof (cmd), fmt, ap);
278 	ret = r_sys_cmd_str (cmd, NULL, NULL);
279 	va_end (ap);
280 	return ret;
281 }
282 
283 #ifdef __MAC_10_7
284 #define APPLE_WITH_BACKTRACE 1
285 #endif
286 #ifdef __IPHONE_4_0
287 #define APPLE_WITH_BACKTRACE 1
288 #endif
289 
290 #if (__linux__ && __GNU_LIBRARY__) || (__APPLE__ && APPLE_WITH_BACKTRACE) || \
291   defined(NETBSD_WITH_BACKTRACE) || defined(FREEBSD_WITH_BACKTRACE) || \
292   __DragonFly__ || __sun || __HAIKU__
293 #define HAVE_BACKTRACE 1
294 #endif
295 
r_sys_backtrace(void)296 R_API void r_sys_backtrace(void) {
297 #ifdef HAVE_BACKTRACE
298 	void *array[10];
299 	size_t size = backtrace (array, 10);
300 	eprintf ("Backtrace %zd stack frames.\n", size);
301 	backtrace_symbols_fd (array, size, 2);
302 #elif __APPLE__
303 	void **fp = (void **) __builtin_frame_address (0);
304 	void *saved_pc = __builtin_return_address (0);
305 	void *saved_fp = __builtin_frame_address (1);
306 	int depth = 0;
307 
308 	printf ("[%d] pc == %p fp == %p\n", depth++, saved_pc, saved_fp);
309 	fp = saved_fp;
310 	while (fp) {
311 		saved_fp = *fp;
312 		fp = saved_fp;
313 		if (!*fp) {
314 			break;
315 		}
316 		saved_pc = *(fp + 2);
317 		printf ("[%d] pc == %p fp == %p\n", depth++, saved_pc, saved_fp);
318 	}
319 #else
320 #ifdef _MSC_VER
321 #pragma message ("TODO: r_sys_bt : unimplemented")
322 #else
323 #warning TODO: r_sys_bt : unimplemented
324 #endif
325 #endif
326 }
327 
r_sys_sleep(int secs)328 R_API int r_sys_sleep(int secs) {
329 #if HAS_CLOCK_NANOSLEEP
330 	struct timespec rqtp;
331 	rqtp.tv_sec = secs;
332 	rqtp.tv_nsec = 0;
333 	return clock_nanosleep (CLOCK_MONOTONIC, 0, &rqtp, NULL);
334 #elif __UNIX__
335 	return sleep (secs);
336 #else
337 	Sleep (secs * 1000); // W32
338 	return 0;
339 #endif
340 }
341 
r_sys_usleep(int usecs)342 R_API int r_sys_usleep(int usecs) {
343 #if HAS_CLOCK_NANOSLEEP
344 	struct timespec rqtp;
345 	rqtp.tv_sec = usecs / 1000000;
346 	rqtp.tv_nsec = (usecs - (rqtp.tv_sec * 1000000)) * 1000;
347 	return clock_nanosleep (CLOCK_MONOTONIC, 0, &rqtp, NULL);
348 #elif __UNIX__
349 #if defined(__GLIBC__) && defined(__GLIBC_MINOR__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)
350 	// Old versions of GNU libc return void for usleep
351 	usleep (usecs);
352 	return 0;
353 #else
354 	return usleep (usecs);
355 #endif
356 #else
357 	// w32 api uses milliseconds
358 	usecs /= 1000;
359 	Sleep (usecs); // W32
360 	return 0;
361 #endif
362 }
363 
r_sys_clearenv(void)364 R_API int r_sys_clearenv(void) {
365 #if __UNIX__
366 #if __APPLE__ && !HAVE_ENVIRON
367 	/* do nothing */
368 	if (!env) {
369 		r_sys_env_init ();
370 		return 0;
371 	}
372 	char **e = env;
373 	while (*e) {
374 		*e++ = NULL;
375 	}
376 #else
377 	if (!environ) {
378 		return 0;
379 	}
380 	while (*environ) {
381 		*environ++ = NULL;
382 	}
383 #endif
384 	return 0;
385 #else
386 #ifdef _MSC_VER
387 #pragma message ("r_sys_clearenv : unimplemented for this platform")
388 #else
389 #warning r_sys_clearenv : unimplemented for this platform
390 #endif
391 	return 0;
392 #endif
393 }
394 
r_sys_setenv(const char * key,const char * value)395 R_API int r_sys_setenv(const char *key, const char *value) {
396 	if (!key) {
397 		return 0;
398 	}
399 #if __UNIX__
400 	if (!value) {
401 		unsetenv (key);
402 		return 0;
403 	}
404 	return setenv (key, value, 1);
405 #elif __WINDOWS__
406 	LPTSTR key_ = r_sys_conv_utf8_to_win (key);
407 	LPTSTR value_ = r_sys_conv_utf8_to_win (value);
408 	int ret = SetEnvironmentVariable (key_, value_);
409 	if (!ret) {
410 		r_sys_perror ("r_sys_setenv/SetEnvironmentVariable");
411 	}
412 	free (key_);
413 	free (value_);
414 	return ret ? 0 : -1;
415 #else
416 #warning r_sys_setenv : unimplemented for this platform
417 	return 0;
418 #endif
419 }
420 
421 #if __UNIX__
422 static char *crash_handler_cmd = NULL;
423 
signal_handler(int signum)424 static void signal_handler(int signum) {
425 	char cmd[1024];
426 	if (!crash_handler_cmd) {
427 		return;
428 	}
429 	snprintf (cmd, sizeof(cmd) - 1, crash_handler_cmd, getpid ());
430 	r_sys_backtrace ();
431 	exit (r_sys_cmd (cmd));
432 }
433 
checkcmd(const char * c)434 static int checkcmd(const char *c) {
435 	char oc = 0;
436 	for (;*c;c++) {
437 		if (oc == '%') {
438 			if (*c != 'd' && *c != '%') {
439 				return 0;
440 			}
441 		}
442 		oc = *c;
443 	}
444 	return 1;
445 }
446 #endif
447 
r_sys_crash_handler(const char * cmd)448 R_API int r_sys_crash_handler(const char *cmd) {
449 #ifndef __WINDOWS__
450 	int sig[] = { SIGINT, SIGSEGV, SIGBUS, SIGQUIT, SIGHUP, 0 };
451 
452 	if (!checkcmd (cmd)) {
453 		return false;
454 	}
455 #ifdef HAVE_BACKTRACE
456 	void *array[1];
457 	/* call this outside of the signal handler to init it safely */
458 	backtrace (array, 1);
459 #endif
460 
461 	free (crash_handler_cmd);
462 	crash_handler_cmd = strdup (cmd);
463 
464 	r_sys_sigaction (sig, signal_handler);
465 #else
466 #pragma message ("r_sys_crash_handler : unimplemented for this platform")
467 #endif
468 	return true;
469 }
470 
r_sys_getenv(const char * key)471 R_API char *r_sys_getenv(const char *key) {
472 #if __WINDOWS__
473 	DWORD dwRet;
474 	LPTSTR envbuf = NULL, key_ = NULL, tmp_ptr;
475 	char *val = NULL;
476 
477 	if (!key) {
478 		return NULL;
479 	}
480 	envbuf = (LPTSTR)malloc (sizeof (TCHAR) * TMP_BUFSIZE);
481 	if (!envbuf) {
482 		goto err_r_sys_get_env;
483 	}
484 	key_ = r_sys_conv_utf8_to_win (key);
485 	dwRet = GetEnvironmentVariable (key_, envbuf, TMP_BUFSIZE);
486 	if (dwRet == 0) {
487 		if (GetLastError () == ERROR_ENVVAR_NOT_FOUND) {
488 			goto err_r_sys_get_env;
489 		}
490 	} else if (TMP_BUFSIZE < dwRet) {
491 		tmp_ptr = (LPTSTR)realloc (envbuf, dwRet * sizeof (TCHAR));
492 		if (!tmp_ptr) {
493 			goto err_r_sys_get_env;
494 		}
495 		envbuf = tmp_ptr;
496 		dwRet = GetEnvironmentVariable (key_, envbuf, dwRet);
497 		if (!dwRet) {
498 			goto err_r_sys_get_env;
499 		}
500 	}
501 	val = r_sys_conv_win_to_utf8_l (envbuf, (int)dwRet);
502 err_r_sys_get_env:
503 	free (key_);
504 	free (envbuf);
505 	return val;
506 #else
507 	char *b;
508 	if (!key) {
509 		return NULL;
510 	}
511 	b = getenv (key);
512 	return b? strdup (b): NULL;
513 #endif
514 }
515 
r_sys_getenv_asbool(const char * key)516 R_API bool r_sys_getenv_asbool(const char *key) {
517 	char *env = r_sys_getenv (key);
518 	const bool res = (env && *env == '1');
519 	free (env);
520 	return res;
521 }
522 
r_sys_getdir(void)523 R_API char *r_sys_getdir(void) {
524 #if __WINDOWS__
525 	return _getcwd (NULL, 0);
526 #else
527 	return getcwd (NULL, 0);
528 #endif
529 }
530 
r_sys_chdir(const char * s)531 R_API int r_sys_chdir(const char *s) {
532 	return r_sandbox_chdir (s)==0;
533 }
534 
r_sys_aslr(int val)535 R_API bool r_sys_aslr(int val) {
536 	bool ret = true;
537 #if __linux__
538 	const char *rva = "/proc/sys/kernel/randomize_va_space";
539 	char buf[3] = {0};
540 	snprintf(buf, sizeof (buf), "%d\n", val != 0 ? 2 : 0);
541 	int fd = r_sandbox_open (rva, O_WRONLY, 0644);
542 	if (fd != -1) {
543 		if (r_sandbox_write (fd, (ut8 *)buf, sizeof (buf)) != sizeof (buf)) {
544 			eprintf ("Failed to set RVA\n");
545 			ret = false;
546 		}
547 		close (fd);
548 	}
549 #elif __FreeBSD__ && __FreeBSD_version >= 1300000
550 	size_t vlen = sizeof (val);
551 	if (sysctlbyname ("kern.elf32.aslr.enable", NULL, 0, &val, vlen) == -1) {
552 		eprintf ("Failed to set RVA 32 bits\n");
553 		return false;
554 	}
555 
556 #if __LP64__
557 	if (sysctlbyname ("kern.elf64.aslr.enable", NULL, 0, &val, vlen) == -1) {
558 		eprintf ("Failed to set RVA 64 bits\n");
559 		ret = false;
560 	}
561 #endif
562 #elif __NetBSD__
563 	size_t vlen = sizeof (val);
564 	if (sysctlbyname ("security.pax.aslr.enabled", NULL, 0, &val, vlen) == -1) {
565 		eprintf ("Failed to set RVA\n");
566 		ret = false;
567 	}
568 #elif __DragonFly__
569 	size_t vlen = sizeof (val);
570 	if (sysctlbyname ("vm.randomize_mmap", NULL, 0, &val, vlen) == -1) {
571 		eprintf ("Failed to set RVA\n");
572 		ret = false;
573 	}
574 #elif __DragonFly__
575 #endif
576 	return ret;
577 }
578 
r_sys_thp_mode(void)579 R_API int r_sys_thp_mode(void) {
580 #if __linux__
581 	const char *thp = "/sys/kernel/mm/transparent_hugepage/enabled";
582 	int ret = 0;
583 	char *val = r_file_slurp (thp, NULL);
584 	if (val) {
585 		if (strstr (val, "[madvise]")) {
586 			ret = 1;
587 		} else if (strstr (val, "[always]")) {
588 			ret = 2;
589 		}
590 		free (val);
591 	}
592 
593 	return ret;
594 #else
595   return 0;
596 #endif
597 }
598 
599 #if __UNIX__
r_sys_cmd_str_full(const char * cmd,const char * input,char ** output,int * len,char ** sterr)600 R_API int r_sys_cmd_str_full(const char *cmd, const char *input, char **output, int *len, char **sterr) {
601 	char *mysterr = NULL;
602 	if (!sterr) {
603 		sterr = &mysterr;
604 	}
605 	char buffer[1024], *outputptr = NULL;
606 	char *inputptr = (char *)input;
607 	int pid, bytes = 0, status;
608 	int sh_in[2], sh_out[2], sh_err[2];
609 
610 	if (len) {
611 		*len = 0;
612 	}
613 	if (pipe (sh_in)) {
614 		return false;
615 	}
616 	if (output) {
617 		if (pipe (sh_out)) {
618 			close (sh_in[0]);
619 			close (sh_in[1]);
620 			close (sh_out[0]);
621 			close (sh_out[1]);
622 			return false;
623 		}
624 	}
625 	if (pipe (sh_err)) {
626 		close (sh_in[0]);
627 		close (sh_in[1]);
628 		return false;
629 	}
630 
631 	switch ((pid = r_sys_fork ())) {
632 	case -1:
633 		return false;
634 	case 0:
635 		dup2 (sh_in[0], 0);
636 		close (sh_in[0]);
637 		close (sh_in[1]);
638 		if (output) {
639 			dup2 (sh_out[1], 1);
640 			close (sh_out[0]);
641 			close (sh_out[1]);
642 		}
643 		if (sterr) {
644 			dup2 (sh_err[1], 2);
645 		} else {
646 			close (2);
647 		}
648 		close (sh_err[0]);
649 		close (sh_err[1]);
650 		exit (r_sandbox_system (cmd, 0));
651 	default:
652 		outputptr = strdup ("");
653 		if (!outputptr) {
654 			return false;
655 		}
656 		if (sterr) {
657 			*sterr = strdup ("");
658 			if (!*sterr) {
659 				free (outputptr);
660 				return false;
661 			}
662 		}
663 		if (output) {
664 			close (sh_out[1]);
665 		}
666 		close (sh_err[1]);
667 		close (sh_in[0]);
668 		if (!inputptr || !*inputptr) {
669 			close (sh_in[1]);
670 		}
671 		// we should handle broken pipes somehow better
672 		r_sys_signal (SIGPIPE, SIG_IGN);
673 		size_t err_len = 0, out_len = 0;
674 		for (;;) {
675 			fd_set rfds, wfds;
676 			int nfd;
677 			FD_ZERO (&rfds);
678 			FD_ZERO (&wfds);
679 			if (output) {
680 				FD_SET (sh_out[0], &rfds);
681 			}
682 			if (sterr) {
683 				FD_SET (sh_err[0], &rfds);
684 			}
685 			if (inputptr && *inputptr) {
686 				FD_SET (sh_in[1], &wfds);
687 			}
688 			memset (buffer, 0, sizeof (buffer));
689 			nfd = select (sh_err[0] + 1, &rfds, &wfds, NULL, NULL);
690 			if (nfd < 0) {
691 				break;
692 			}
693 			if (output && FD_ISSET (sh_out[0], &rfds)) {
694 				if ((bytes = read (sh_out[0], buffer, sizeof (buffer))) < 1) {
695 					break;
696 				}
697 				char *tmp = realloc (outputptr, out_len + bytes + 1);
698 				if (!tmp) {
699 					R_FREE (outputptr);
700 					break;
701 				}
702 				outputptr = tmp;
703 				memcpy (outputptr + out_len, buffer, bytes);
704 				out_len += bytes;
705 			} else if (FD_ISSET (sh_err[0], &rfds) && sterr) {
706 				if ((bytes = read (sh_err[0], buffer, sizeof (buffer))) < 1) {
707 					break;
708 				}
709 				char *tmp = realloc (*sterr, err_len + bytes + 1);
710 				if (!tmp) {
711 					R_FREE (*sterr);
712 					break;
713 				}
714 				*sterr = tmp;
715 				memcpy (*sterr + err_len, buffer, bytes);
716 				err_len += bytes;
717 			} else if (FD_ISSET (sh_in[1], &wfds) && inputptr && *inputptr) {
718 				int inputptr_len = strlen (inputptr);
719 				bytes = write (sh_in[1], inputptr, inputptr_len);
720 				if (bytes != inputptr_len) {
721 					break;
722 				}
723 				inputptr += bytes;
724 				if (!*inputptr) {
725 					close (sh_in[1]);
726 					/* If neither stdout nor stderr should be captured,
727 					 * abort now - nothing more to do for select(). */
728 					if (!output && !sterr) {
729 						break;
730 					}
731 				}
732 			}
733 		}
734 		if (output) {
735 			close (sh_out[0]);
736 		}
737 		close (sh_err[0]);
738 		close (sh_in[1]);
739 		waitpid (pid, &status, 0);
740 		bool ret = true;
741 		if (status) {
742 			// char *escmd = r_str_escape (cmd);
743 			// eprintf ("error code %d (%s): %s\n", WEXITSTATUS (status), escmd, *sterr);
744 			// eprintf ("(%s)\n", output);
745 			// eprintf ("%s: failed command '%s'\n", __func__, escmd);
746 			// free (escmd);
747 			ret = false;
748 		}
749 
750 		if (len) {
751 			*len = out_len;
752 		}
753 		if (*sterr) {
754 			(*sterr)[err_len] = 0;
755 		}
756 		if (outputptr) {
757 			outputptr[out_len] = 0;
758 		}
759 		if (output) {
760 			*output = outputptr;
761 		} else {
762 			free (outputptr);
763 		}
764 		free (mysterr);
765 		return ret;
766 	}
767 	return false;
768 }
769 #elif __WINDOWS__
r_sys_cmd_str_full(const char * cmd,const char * input,char ** output,int * len,char ** sterr)770 R_API int r_sys_cmd_str_full(const char *cmd, const char *input, char **output, int *len, char **sterr) {
771 	return r_sys_cmd_str_full_w32 (cmd, input, output, len, sterr);
772 }
773 #else
r_sys_cmd_str_full(const char * cmd,const char * input,char ** output,int * len,char ** sterr)774 R_API int r_sys_cmd_str_full(const char *cmd, const char *input, char **output, int *len, char **sterr) {
775 	eprintf ("r_sys_cmd_str: not yet implemented for this platform\n");
776 	return false;
777 }
778 #endif
779 
r_sys_cmdf(const char * fmt,...)780 R_API int r_sys_cmdf(const char *fmt, ...) {
781 	int ret;
782 	char cmd[4096];
783 	va_list ap;
784 	va_start(ap, fmt);
785 	vsnprintf (cmd, sizeof (cmd), fmt, ap);
786 	ret = r_sys_cmd (cmd);
787 	va_end (ap);
788 	return ret;
789 }
790 
r_sys_cmdbg(const char * str)791 R_API int r_sys_cmdbg (const char *str) {
792 #if __UNIX__
793 	int ret, pid = r_sys_fork ();
794 	if (pid == -1) {
795 		return -1;
796 	}
797 	if (pid) {
798 		return pid;
799 	}
800 	ret = r_sandbox_system (str, 0);
801 	eprintf ("{exit: %d, pid: %d, cmd: \"%s\"}", ret, pid, str);
802 	exit (0);
803 	return -1;
804 #else
805 #ifdef _MSC_VER
806 #pragma message ("r_sys_cmdbg is not implemented for this platform")
807 #else
808 #warning r_sys_cmdbg is not implemented for this platform
809 #endif
810 	return -1;
811 #endif
812 }
813 
r_sys_cmd(const char * str)814 R_API int r_sys_cmd(const char *str) {
815 	if (r_sandbox_enable (0)) {
816 		return false;
817 	}
818 	return r_sandbox_system (str, 1);
819 }
820 
r_sys_cmd_str(const char * cmd,const char * input,int * len)821 R_API char *r_sys_cmd_str(const char *cmd, const char *input, int *len) {
822 	char *output = NULL;
823 	if (r_sys_cmd_str_full (cmd, input, &output, len, NULL)) {
824 		return output;
825 	}
826 	free (output);
827 	return NULL;
828 }
829 
r_sys_mkdir(const char * dir)830 R_API bool r_sys_mkdir(const char *dir) {
831 	bool ret;
832 
833 	if (r_sandbox_enable (0)) {
834 		return false;
835 	}
836 #if __WINDOWS__
837 	LPTSTR dir_ = r_sys_conv_utf8_to_win (dir);
838 
839 	ret = CreateDirectory (dir_, NULL) != 0;
840 	free (dir_);
841 #else
842 	ret = mkdir (dir, 0755) != -1;
843 #endif
844 	return ret;
845 }
846 
r_sys_mkdirp(const char * dir)847 R_API bool r_sys_mkdirp(const char *dir) {
848 	bool ret = true;
849 	char slash = R_SYS_DIR[0];
850 	char *path = strdup (dir), *ptr = path;
851 	if (!path) {
852 		eprintf ("r_sys_mkdirp: Unable to allocate memory\n");
853 		return false;
854 	}
855 	if (*ptr == slash) {
856 		ptr++;
857 	}
858 #if __WINDOWS__
859 	{
860 		char *p = strstr (ptr, ":\\");
861 		if (p) {
862 			ptr = p + 3;
863 		}
864 	}
865 #endif
866 	for (;;) {
867 		// find next slash
868 		for (; *ptr; ptr++) {
869 			if (*ptr == '/' || *ptr == '\\') {
870 				slash = *ptr;
871 				break;
872 			}
873 		}
874 		if (!*ptr) {
875 			break;
876 		}
877 		*ptr = 0;
878 		if (!r_sys_mkdir (path) && r_sys_mkdir_failed ()) {
879 			eprintf ("r_sys_mkdirp: fail '%s' of '%s'\n", path, dir);
880 			free (path);
881 			return false;
882 		}
883 		*ptr = slash;
884 		ptr++;
885 	}
886 	if (!r_sys_mkdir (path) && r_sys_mkdir_failed ()) {
887 		ret = false;
888 	}
889 	free (path);
890 	return ret;
891 }
892 
r_sys_perror_str(const char * fun)893 R_API void r_sys_perror_str(const char *fun) {
894 #if __UNIX__
895 #pragma push_macro("perror")
896 #undef perror
897 	perror (fun);
898 #pragma pop_macro("perror")
899 #elif __WINDOWS__
900 	LPTSTR lpMsgBuf;
901 	DWORD dw = GetLastError();
902 
903 	if (FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER |
904 			FORMAT_MESSAGE_FROM_SYSTEM |
905 			FORMAT_MESSAGE_IGNORE_INSERTS,
906 			NULL,
907 			dw,
908 			MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
909 			(LPTSTR)&lpMsgBuf,
910 			0, NULL )) {
911 		char *err = r_sys_conv_win_to_utf8 (lpMsgBuf);
912 		if (err) {
913 			eprintf ("%s: (%#lx) %s%s", fun, dw, err,
914 			         r_str_endswith (err, "\n") ? "" : "\n");
915 			free (err);
916 		}
917 		LocalFree (lpMsgBuf);
918 	} else {
919 		eprintf ("%s\n", fun);
920 	}
921 #endif
922 }
923 
r_sys_arch_match(const char * archstr,const char * arch)924 R_API bool r_sys_arch_match(const char *archstr, const char *arch) {
925 	char *ptr;
926 	if (!archstr || !arch || !*archstr || !*arch) {
927 		return true;
928 	}
929 	if (!strcmp (archstr, "*") || !strcmp (archstr, "any")) {
930 		return true;
931 	}
932 	if (!strcmp (archstr, arch)) {
933 		return true;
934 	}
935 	if ((ptr = strstr (archstr, arch))) {
936 		char p = ptr[strlen (arch)];
937 		if (!p || p==',') {
938 			return true;
939 		}
940 	}
941 	return false;
942 }
943 
r_sys_arch_id(const char * arch)944 R_API int r_sys_arch_id(const char *arch) {
945 	int i;
946 	for (i = 0; arch_bit_array[i].name; i++) {
947 		if (!strcmp (arch, arch_bit_array[i].name)) {
948 			return arch_bit_array[i].bit;
949 		}
950 	}
951 	return 0;
952 }
953 
r_sys_arch_str(int arch)954 R_API const char *r_sys_arch_str(int arch) {
955 	int i;
956 	for (i = 0; arch_bit_array[i].name; i++) {
957 		if (arch & arch_bit_array[i].bit) {
958 			return arch_bit_array[i].name;
959 		}
960 	}
961 	return "none";
962 }
963 
964 #define USE_FORK 0
r_sys_run(const ut8 * buf,int len)965 R_API int r_sys_run(const ut8 *buf, int len) {
966 	const int sz = 4096;
967 	int pdelta, ret, (*cb)();
968 #if USE_FORK
969 	int st, pid;
970 #endif
971 // TODO: define R_SYS_ALIGN_FORWARD in r_util.h
972 	ut8 *ptr, *p = malloc ((sz + len) << 1);
973 	ptr = p;
974 	pdelta = ((size_t)(p)) & (4096 - 1);
975 	if (pdelta) {
976 		ptr += (4096 - pdelta);
977 	}
978 	if (!ptr || !buf) {
979 		eprintf ("r_sys_run: Cannot run empty buffer\n");
980 		free (p);
981 		return false;
982 	}
983 	memcpy (ptr, buf, len);
984 	r_mem_protect (ptr, sz, "rx");
985 	//r_mem_protect (ptr, sz, "rwx"); // try, ignore if fail
986 	cb = (int (*)())ptr;
987 #if USE_FORK
988 #if __UNIX__
989 	pid = r_sys_fork ();
990 #else
991 	pid = -1;
992 #endif
993 	if (pid < 0) {
994 		return cb ();
995 	}
996 	if (!pid) {
997 		ret = cb ();
998 		exit (ret);
999 		return ret;
1000 	}
1001 	st = 0;
1002 	waitpid (pid, &st, 0);
1003 	if (WIFSIGNALED (st)) {
1004 		int num = WTERMSIG(st);
1005 		eprintf ("Got signal %d\n", num);
1006 		ret = num;
1007 	} else {
1008 		ret = WEXITSTATUS (st);
1009 	}
1010 #else
1011 	ret = (*cb) ();
1012 #endif
1013 	free (p);
1014 	return ret;
1015 }
1016 
r_sys_run_rop(const ut8 * buf,int len)1017 R_API int r_sys_run_rop(const ut8 *buf, int len) {
1018 #if USE_FORK
1019 	int st;
1020 #endif
1021 	// TODO: define R_SYS_ALIGN_FORWARD in r_util.h
1022 	ut8 *bufptr = malloc (len);
1023 	if (!bufptr) {
1024 		eprintf ("r_sys_run_rop: Cannot allocate buffer\n");
1025 		return false;
1026 	}
1027 
1028 	if (!buf) {
1029 		eprintf ("r_sys_run_rop: Cannot execute empty rop chain\n");
1030 		free (bufptr);
1031 		return false;
1032 	}
1033 	memcpy (bufptr, buf, len);
1034 #if USE_FORK
1035 #if __UNIX__
1036 	pid_t pid = r_sys_fork ();
1037 #else
1038 	pid = -1;
1039 #endif
1040 	if (pid < 0) {
1041 		R_SYS_ASM_START_ROP ();
1042 	} else {
1043 		R_SYS_ASM_START_ROP ();
1044 		exit (0);
1045                 return 0;
1046 	}
1047 	st = 0;
1048 	if (waitpid (pid, &st, 0) == -1) {
1049             eprintf ("r_sys_run_rop: waitpid failed\n");
1050             free (bufptr);
1051             return -1;
1052         }
1053 	if (WIFSIGNALED (st)) {
1054 		int num = WTERMSIG (st);
1055 		eprintf ("Got signal %d\n", num);
1056 		ret = num;
1057 	} else {
1058 		ret = WEXITSTATUS (st);
1059 	}
1060 #else
1061 	R_SYS_ASM_START_ROP ();
1062 #endif
1063 	free (bufptr);
1064 	return 0;
1065 }
1066 
r_sys_pid_to_path(int pid)1067 R_API char *r_sys_pid_to_path(int pid) {
1068 #if __WINDOWS__
1069 	// TODO: add maximum path length support
1070 	HANDLE processHandle;
1071 	const DWORD maxlength = MAX_PATH;
1072 	TCHAR filename[MAX_PATH];
1073 	char *result = NULL;
1074 
1075 	processHandle = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
1076 	if (!processHandle) {
1077 		eprintf ("r_sys_pid_to_path: Cannot open process.\n");
1078 		return NULL;
1079 	}
1080 	DWORD length = GetModuleFileNameEx (processHandle, NULL, filename, maxlength);
1081 	if (length == 0) {
1082 		// Upon failure fallback to GetProcessImageFileName
1083 		length = GetProcessImageFileName (processHandle, filename, maxlength);
1084 		CloseHandle (processHandle);
1085 		if (length == 0) {
1086 			eprintf ("r_sys_pid_to_path: Error calling GetProcessImageFileName\n");
1087 			return NULL;
1088 		}
1089 		// Convert NT path to win32 path
1090 		char *name = r_sys_conv_win_to_utf8 (filename);
1091 		if (!name) {
1092 			eprintf ("r_sys_pid_to_path: Error converting to utf8\n");
1093 			return NULL;
1094 		}
1095 		char *tmp = strchr (name + 1, '\\');
1096 		if (!tmp) {
1097 			free (name);
1098 			eprintf ("r_sys_pid_to_path: Malformed NT path\n");
1099 			return NULL;
1100 		}
1101 		tmp = strchr (tmp + 1, '\\');
1102 		if (!tmp) {
1103 			free (name);
1104 			eprintf ("r_sys_pid_to_path: Malformed NT path\n");
1105 			return NULL;
1106 		}
1107 		length = tmp - name;
1108 		tmp = malloc (length + 1);
1109 		if (!tmp) {
1110 			free (name);
1111 			eprintf ("r_sys_pid_to_path: Error allocating memory\n");
1112 			return NULL;
1113 		}
1114 		strncpy (tmp, name, length);
1115 		tmp[length] = '\0';
1116 		TCHAR device[MAX_PATH];
1117 		for (TCHAR drv[] = TEXT("A:"); drv[0] <= TEXT('Z'); drv[0]++) {
1118 			if (QueryDosDevice (drv, device, maxlength) > 0) {
1119 				char *dvc = r_sys_conv_win_to_utf8 (device);
1120 				if (!dvc) {
1121 					free (name);
1122 					free (tmp);
1123 					eprintf ("r_sys_pid_to_path: Error converting to utf8\n");
1124 					return NULL;
1125 				}
1126 				if (!strcmp (tmp, dvc)) {
1127 					free (tmp);
1128 					free (dvc);
1129 					char *d = r_sys_conv_win_to_utf8 (drv);
1130 					if (!d) {
1131 						free (name);
1132 						eprintf ("r_sys_pid_to_path: Error converting to utf8\n");
1133 						return NULL;
1134 					}
1135 					tmp = r_str_newf ("%s%s", d, &name[length]);
1136 					free (d);
1137 					if (!tmp) {
1138 						free (name);
1139 						eprintf ("r_sys_pid_to_path: Error calling r_str_newf\n");
1140 						return NULL;
1141 					}
1142 					result = strdup (tmp);
1143 					break;
1144 				}
1145 				free (dvc);
1146 			}
1147 		}
1148 		free (name);
1149 		free (tmp);
1150 	} else {
1151 		CloseHandle (processHandle);
1152 		result = r_sys_conv_win_to_utf8 (filename);
1153 	}
1154 	return result;
1155 #elif __APPLE__
1156 #if __POWERPC__
1157 #warning TODO getpidproc
1158 	return NULL;
1159 #else
1160 	char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
1161 	pathbuf[0] = 0;
1162 	int ret = proc_pidpath (pid, pathbuf, sizeof (pathbuf));
1163 	if (ret <= 0) {
1164 		return NULL;
1165 	}
1166 	return strdup (pathbuf);
1167 #endif
1168 #else
1169 	int ret;
1170 #if __FreeBSD__ || __DragonFly__
1171 	char pathbuf[PATH_MAX];
1172 	size_t pathbufl = sizeof (pathbuf);
1173 	int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid};
1174 	ret = sysctl (mib, 4, pathbuf, &pathbufl, NULL, 0);
1175 	if (ret != 0) {
1176 		return NULL;
1177 	}
1178 #elif __HAIKU__
1179 	char pathbuf[MAXPATHLEN];
1180 	int32_t group = 0;
1181 	image_info ii;
1182 
1183 	while (get_next_image_info ((team_id)pid, &group, &ii) == B_OK) {
1184 		if (ii.type == B_APP_IMAGE) {
1185 			break;
1186 		}
1187 	}
1188 
1189 	if (ii.type == B_APP_IMAGE) {
1190 		r_str_ncpy (pathbuf, ii.name, MAXPATHLEN);
1191 	} else {
1192 		pathbuf[0] = '\0';
1193 	}
1194 #else
1195 	char buf[128], pathbuf[1024];
1196 	snprintf (buf, sizeof (buf), "/proc/%d/exe", pid);
1197 	ret = readlink (buf, pathbuf, sizeof (pathbuf)-1);
1198 	if (ret < 1) {
1199 		return NULL;
1200 	}
1201 	pathbuf[ret] = 0;
1202 #endif
1203 	return strdup (pathbuf);
1204 #endif
1205 }
1206 
r_sys_env_init(void)1207 R_API void r_sys_env_init(void) {
1208 	char **envp = r_sys_get_environ ();
1209 	if (envp) {
1210 		r_sys_set_environ (envp);
1211 	}
1212 }
1213 
r_sys_get_environ(void)1214 R_API char **r_sys_get_environ(void) {
1215 #if __APPLE__ && !HAVE_ENVIRON
1216 	env = *_NSGetEnviron();
1217 #else
1218 	env = environ;
1219 #endif
1220 	// return environ if available??
1221 	if (!env) {
1222 		env = r_lib_dl_sym (NULL, "environ");
1223 	}
1224 	return env;
1225 }
1226 
r_sys_set_environ(char ** e)1227 R_API void r_sys_set_environ(char **e) {
1228 	env = e;
1229 }
1230 
r_sys_whoami(void)1231 R_API char *r_sys_whoami(void) {
1232 	char buf[32];
1233 #if __WINDOWS__
1234 	DWORD buf_sz = sizeof (buf);
1235 	if (!GetUserName(buf, (LPDWORD)&buf_sz) ) {
1236 		return strdup ("?");
1237 	}
1238 #else
1239 	int uid = getuid ();
1240 	snprintf (buf, sizeof (buf), "uid%d", uid);
1241 #endif
1242 	return strdup (buf);
1243 }
1244 
r_sys_getpid(void)1245 R_API int r_sys_getpid(void) {
1246 #if __UNIX__
1247 	return getpid ();
1248 #elif __WINDOWS__
1249 	return GetCurrentProcessId();
1250 #else
1251 #warning r_sys_getpid not implemented for this platform
1252 	return -1;
1253 #endif
1254 }
1255 
r_sys_tts(const char * txt,bool bg)1256 R_API bool r_sys_tts(const char *txt, bool bg) {
1257 	int i;
1258 	r_return_val_if_fail (txt, false);
1259 	const char *says[] = {
1260 		"say", "termux-tts-speak", NULL
1261 	};
1262 	for (i = 0; says[i]; i++) {
1263 		char *sayPath = r_file_path (says[i]);
1264 		if (sayPath) {
1265 			char *line = r_str_replace (strdup (txt), "'", "\"", 1);
1266 			r_sys_cmdf ("\"%s\" '%s'%s", sayPath, line, bg? " &": "");
1267 			free (line);
1268 			free (sayPath);
1269 			return true;
1270 		}
1271 	}
1272 	return false;
1273 }
1274 
r_sys_prefix(const char * pfx)1275 R_API const char *r_sys_prefix(const char *pfx) {
1276 	static char *prefix = NULL;
1277 	if (!prefix) {
1278 #if __WINDOWS__
1279 		prefix = r_sys_get_src_dir_w32 ();
1280 		if (!prefix) {
1281 			prefix = strdup (R2_PREFIX);
1282 		}
1283 #else
1284 		prefix = strdup (R2_PREFIX);
1285 #endif
1286 	}
1287 	if (pfx) {
1288 		free (prefix);
1289 		prefix = strdup (pfx);
1290 	}
1291 	return prefix;
1292 }
1293 
r_sys_info(void)1294 R_API RSysInfo *r_sys_info(void) {
1295 #if __UNIX__
1296 	struct utsname un = {{0}};
1297 	if (uname (&un) != -1) {
1298 		RSysInfo *si = R_NEW0 (RSysInfo);
1299 		if (si) {
1300 			si->sysname  = strdup (un.sysname);
1301 			si->nodename = strdup (un.nodename);
1302 			si->release  = strdup (un.release);
1303 			si->version  = strdup (un.version);
1304 			si->machine  = strdup (un.machine);
1305 			return si;
1306 		}
1307 	}
1308 #elif __WINDOWS__
1309 	HKEY key;
1310 	DWORD type;
1311 	DWORD size;
1312 	DWORD major;
1313 	DWORD minor;
1314 	char tmp[256] = {0};
1315 	RSysInfo *si = R_NEW0 (RSysInfo);
1316 	if (!si) {
1317 		return NULL;
1318 	}
1319 
1320 	if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0,
1321 		KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) {
1322 		r_sys_perror ("r_sys_info/RegOpenKeyExA");
1323 		r_sys_info_free (si);
1324 		return NULL;
1325 	}
1326 
1327 	size = sizeof (tmp);
1328 	if (RegQueryValueExA (key, "ProductName", NULL, &type,
1329 		(LPBYTE)&tmp, &size) != ERROR_SUCCESS
1330 		|| type != REG_SZ) {
1331 		goto beach;
1332 	}
1333 	si->sysname = strdup (tmp);
1334 
1335 	size = sizeof (major);
1336 	if (RegQueryValueExA (key, "CurrentMajorVersionNumber", NULL, &type,
1337 		(LPBYTE)&major, &size) != ERROR_SUCCESS
1338 		|| type != REG_DWORD) {
1339 		goto beach;
1340 	}
1341 	size = sizeof (minor);
1342 	if (RegQueryValueExA (key, "CurrentMinorVersionNumber", NULL, &type,
1343 		(LPBYTE)&minor, &size) != ERROR_SUCCESS
1344 		|| type != REG_DWORD) {
1345 		goto beach;
1346 	}
1347 
1348 	size = sizeof (tmp);
1349 	if (RegQueryValueExA (key, "CurrentBuild", NULL, &type,
1350 		(LPBYTE)&tmp, &size) != ERROR_SUCCESS
1351 		|| type != REG_SZ) {
1352 		goto beach;
1353 	}
1354 	si->version = r_str_newf ("%lu.%lu.%s", major, minor, tmp);
1355 
1356 	size = sizeof (tmp);
1357 	if (RegQueryValueExA (key, "ReleaseId", NULL, &type,
1358 		(LPBYTE)tmp, &size) != ERROR_SUCCESS
1359 		|| type != REG_SZ) {
1360 		goto beach;
1361 	}
1362 	si->release = strdup (tmp);
1363 beach:
1364 	RegCloseKey (key);
1365 	return si;
1366 #endif
1367 	return NULL;
1368 }
1369 
r_sys_info_free(RSysInfo * si)1370 R_API void r_sys_info_free(RSysInfo *si) {
1371 	free (si->sysname);
1372 	free (si->nodename);
1373 	free (si->release);
1374 	free (si->version);
1375 	free (si->machine);
1376 	free (si);
1377 }
1378