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