1 /* radare - LGPL - Copyright 2014-2020 - pancake */
2 
3 /* this helper api is here because it depends on r_util and r_socket */
4 /* we should find a better place for it. r_io? */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <fcntl.h>
9 #include <r_socket.h>
10 #include <r_util.h>
11 #include <r_lib.h>
12 #include <r_cons.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 
16 #if __APPLE__ && LIBC_HAVE_FORK
17 #if !__POWERPC__
18 #include <spawn.h>
19 #endif
20 #include <sys/wait.h>
21 #include <mach/exception_types.h>
22 #include <mach/mach_init.h>
23 #include <mach/mach_port.h>
24 #include <mach/mach_traps.h>
25 #include <mach/task.h>
26 #include <mach/task_info.h>
27 #include <mach/thread_act.h>
28 #include <mach/thread_info.h>
29 #include <mach/vm_map.h>
30 #include <mach-o/loader.h>
31 #include <mach-o/nlist.h>
32 #endif
33 
34 #if __UNIX__
35 #include <sys/ioctl.h>
36 #include <sys/resource.h>
37 #include <grp.h>
38 #include <errno.h>
39 #if defined(__sun)
40 #include <sys/filio.h>
41 #endif
42 #if __linux__ && !__ANDROID__
43 #include <sys/personality.h>
44 #include <pty.h>
45 #include <utmp.h>
46 #endif
47 #if defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__)
48 #include <util.h>
49 #elif defined(__FreeBSD__) || defined(__DragonFly__)
50 #include <sys/sysctl.h>
51 #include <libutil.h>
52 #endif
53 #endif
54 #ifdef _MSC_VER
55 #include <direct.h>   // to compile chdir in msvc windows
56 #include <process.h>  // to compile execv in msvc windows
57 #define pid_t int
58 #endif
59 
60 #if EMSCRIPTEN
61 #undef HAVE_PTY
62 #define HAVE_PTY 0
63 #else
64 #define HAVE_PTY __UNIX__ && !__ANDROID__ && LIBC_HAVE_FORK && !__sun
65 #endif
66 
67 
68 #if HAVE_PTY
69 static int (*dyn_openpty)(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp) = NULL;
70 static int (*dyn_login_tty)(int fd) = NULL;
71 static id_t (*dyn_forkpty)(int *amaster, char *name, struct termios *termp, struct winsize *winp) = NULL;
dyn_init(void)72 static void dyn_init(void) {
73 	if (!dyn_openpty) {
74 		dyn_openpty = r_lib_dl_sym (NULL, "openpty");
75 	}
76 	if (!dyn_login_tty) {
77 		dyn_openpty = r_lib_dl_sym (NULL, "login_tty");
78 	}
79 	if (!dyn_forkpty) {
80 		dyn_openpty = r_lib_dl_sym (NULL, "forkpty");
81 	}
82 }
83 
84 #endif
85 
r_run_new(const char * str)86 R_API RRunProfile *r_run_new(const char *str) {
87 	RRunProfile *p = R_NEW0 (RRunProfile);
88 	if (p) {
89 		r_run_reset (p);
90 		if (str) {
91 			r_run_parsefile (p, str);
92 		}
93 	}
94 	return p;
95 }
96 
r_run_reset(RRunProfile * p)97 R_API void r_run_reset(RRunProfile *p) {
98 	r_return_if_fail (p);
99 	memset (p, 0, sizeof (RRunProfile));
100 	p->_aslr = -1;
101 }
102 
r_run_parse(RRunProfile * pf,const char * profile)103 R_API bool r_run_parse(RRunProfile *pf, const char *profile) {
104 	r_return_val_if_fail (pf && profile, false);
105 	char *p, *o, *str = strdup (profile);
106 	if (!str) {
107 		return false;
108 	}
109 	r_str_replace_char (str, '\r',0);
110 	p = str;
111 	while (p) {
112 		if ((o = strchr (p, '\n'))) {
113 			*o++ = 0;
114 		}
115 		r_run_parseline (pf, p);
116 		p = o;
117 	}
118 	free (str);
119 	return true;
120 }
121 
r_run_free(RRunProfile * r)122 R_API void r_run_free(RRunProfile *r) {
123 	if (r) {
124 		free (r->_system);
125 		free (r->_program);
126 		free (r->_runlib);
127 		free (r->_runlib_fcn);
128 		free (r->_stdio);
129 		free (r->_stdin);
130 		free (r->_stdout);
131 		free (r->_stderr);
132 		free (r->_chgdir);
133 		free (r->_chroot);
134 		free (r->_libpath);
135 		free (r->_preload);
136 		free (r);
137 	}
138 }
139 
140 #if __UNIX__
set_limit(int n,int a,ut64 b)141 static void set_limit(int n, int a, ut64 b) {
142 	if (n) {
143 		struct rlimit cl = {b, b};
144 		setrlimit (RLIMIT_CORE, &cl);
145 	} else {
146 		struct rlimit cl = {0, 0};
147 		setrlimit (a, &cl);
148 	}
149 }
150 #endif
151 
getstr(const char * src)152 static char *getstr(const char *src) {
153 	int len;
154 	char *ret = NULL;
155 
156 	switch (*src) {
157 	case '\'':
158 		ret = strdup (src+1);
159 		if (ret) {
160 			len = strlen (ret);
161 			if (len > 0) {
162 				len--;
163 				if (ret[len] == '\'') {
164 					ret[len] = 0;
165 					return ret;
166 				}
167 				eprintf ("Missing \"\n");
168 			}
169 			free (ret);
170 		}
171 		return NULL;
172 	case '"':
173 		ret = strdup (src + 1);
174 		if (ret) {
175 			len = strlen (ret);
176 			if (len > 0) {
177 				len--;
178 				if (ret[len] == '"') {
179 					ret[len] = 0;
180 					r_str_unescape (ret);
181 					return ret;
182 				}
183 				eprintf ("Missing \"\n");
184 			}
185 			free (ret);
186 		}
187 		return NULL;
188 	case '@':
189 		{
190 			char *pat = strchr (src + 1, '@');
191 			if (pat) {
192 				size_t len;
193 				long i, rep;
194 				*pat++ = 0;
195 				rep = strtol (src + 1, NULL, 10);
196 				len = strlen (pat);
197 				if (rep > 0) {
198 					char *buf = malloc (rep);
199 					if (buf) {
200 						for (i = 0; i < rep; i++) {
201 							buf[i] = pat[i % len];
202 						}
203 					}
204 					return buf;
205 				}
206 			}
207 			// slurp file
208 			return r_file_slurp (src + 1, NULL);
209 		}
210 	case '`':
211 		{
212 		char *msg = strdup (src + 1);
213 		int msg_len = strlen (msg);
214 		if (msg_len > 0) {
215 			msg [msg_len - 1] = 0;
216 			char *ret = r_sys_cmd_str (msg, NULL, NULL);
217 			r_str_trim_tail (ret);
218 			free (msg);
219 			return ret;
220 		}
221 		free (msg);
222 		return strdup ("");
223 		}
224 	case '!':
225 		{
226 		char *a = r_sys_cmd_str (src + 1, NULL, NULL);
227 		r_str_trim_tail (a);
228 		return a;
229 		}
230 	case ':':
231 		if (src[1] == '!') {
232 			ret = r_sys_cmd_str (src + 1, NULL, NULL);
233 			r_str_trim_tail (ret); // why no head :?
234 		} else {
235 			ret = strdup (src);
236 		}
237 		len = r_hex_str2bin (src + 1, (ut8*)ret);
238 		if (len > 0) {
239 			ret[len] = 0;
240 			return ret;
241 		}
242 		eprintf ("Invalid hexpair string\n");
243 		free (ret);
244 		return NULL;
245 	}
246 	r_str_unescape ((ret = strdup (src)));
247 	return ret;
248 }
249 
parseBool(const char * e)250 static int parseBool(const char *e) {
251 	return (strcmp (e, "yes")?
252 		(strcmp (e, "on")?
253 		(strcmp (e, "true")?
254 		(strcmp (e, "1")?
255 		0: 1): 1): 1): 1);
256 }
257 
258 // TODO: move into r_util? r_run_... ? with the rest of funcs?
setASLR(RRunProfile * r,int enabled)259 static void setASLR(RRunProfile *r, int enabled) {
260 #if __linux__
261 	r_sys_aslr (enabled);
262 #if HAVE_DECL_ADDR_NO_RANDOMIZE && !__ANDROID__
263 	if (personality (ADDR_NO_RANDOMIZE) == -1) {
264 #endif
265 		r_sys_aslr (0);
266 #if HAVE_DECL_ADDR_NO_RANDOMIZE && !__ANDROID__
267 	}
268 #endif
269 #elif __APPLE__
270 	// TOO OLD setenv ("DYLD_NO_PIE", "1", 1);
271 	// disable this because its
272 	const char *argv0 = r->_system ? r->_system
273 		: r->_program ? r->_program
274 		: r->_args[0] ? r->_args[0]
275 		: "/path/to/exec";
276 	eprintf ("To disable aslr patch mach0.hdr.flags with:\n"
277 		"r2 -qwnc 'wx 000000 @ 0x18' %s\n", argv0);
278 	// f MH_PIE=0x00200000; wB-MH_PIE @ 24\n");
279 	// for osxver>=10.7
280 	// "unset the MH_PIE bit in an already linked executable" with --no-pie flag of the script
281 	// the right way is to disable the aslr bit in the spawn call
282 #elif __FreeBSD__ || __NetBSD__ || __DragonFly__
283 	r_sys_aslr (enabled);
284 #else
285 	// not supported for this platform
286 #endif
287 }
288 
289 #if __APPLE__ && !__POWERPC__
290 #else
291 #if HAVE_PTY
restore_saved_fd(int saved,bool restore,int fd)292 static void restore_saved_fd(int saved, bool restore, int fd) {
293 	if (saved == -1) {
294 		return;
295 	}
296 	if (restore) {
297 		dup2 (saved, fd);
298 	}
299 	close (saved);
300 }
301 #endif
302 
handle_redirection_proc(const char * cmd,bool in,bool out,bool err)303 static int handle_redirection_proc(const char *cmd, bool in, bool out, bool err) {
304 #if HAVE_PTY
305 	if (!dyn_forkpty) {
306 		// No forkpty api found, maybe we should fallback to just fork without any pty allocated
307 		return -1;
308 	}
309 	// use PTY to redirect I/O because pipes can be problematic in
310 	// case of interactive programs.
311 	int saved_stdin = dup (STDIN_FILENO);
312 	if (saved_stdin == -1) {
313 		return -1;
314 	}
315 	int saved_stdout = dup (STDOUT_FILENO);
316 	if (saved_stdout == -1) {
317 		close (saved_stdin);
318 		return -1;
319 	}
320 
321 	int fdm, pid = dyn_forkpty (&fdm, NULL, NULL, NULL);
322 	if (pid == -1) {
323 		close (saved_stdin);
324 		close (saved_stdout);
325 		return -1;
326 	}
327 	const char *tn = ttyname (fdm);
328 	if (!tn) {
329 		close (saved_stdin);
330 		close (saved_stdout);
331 		return -1;
332 	}
333 	int fds = open (tn, O_RDWR);
334 	if (fds == -1) {
335 		close (saved_stdin);
336 		close (saved_stdout);
337 		return -1;
338 	}
339 	if (pid == 0) {
340 		close (fdm);
341 		// child process
342 		if (in) {
343 			dup2 (fds, STDIN_FILENO);
344 		}
345 		if (out) {
346 			dup2 (fds, STDOUT_FILENO);
347 		}
348 		// child - program to run
349 
350 		// necessary because otherwise you can read the same thing you
351 		// wrote on fdm.
352 		struct termios t;
353 		tcgetattr (fds, &t);
354 		cfmakeraw (&t);
355 		tcsetattr (fds, TCSANOW, &t);
356 
357 		int code = r_sys_cmd (cmd);
358 		restore_saved_fd (saved_stdin, in, STDIN_FILENO);
359 		restore_saved_fd (saved_stdout, out, STDOUT_FILENO);
360 		exit (code);
361 	} else {
362 		close (fds);
363 		if (in) {
364 			dup2 (fdm, STDIN_FILENO);
365 		}
366 		if (out) {
367 			dup2 (fdm, STDOUT_FILENO);
368 		}
369 		// parent process
370 		int status;
371 		waitpid (pid, &status, 0);
372 	}
373 
374 	// parent
375 	close (saved_stdin);
376 	close (saved_stdout);
377 	return 0;
378 #else
379 #ifdef _MSC_VER
380 #pragma message ("TODO: handle_redirection_proc: Not implemented for this platform")
381 #else
382 #warning handle_redirection_proc : unimplemented for this platform
383 #endif
384 	return -1;
385 #endif
386 }
387 #endif
388 
handle_redirection(const char * cmd,bool in,bool out,bool err)389 static int handle_redirection(const char *cmd, bool in, bool out, bool err) {
390 #if __APPLE__ && !__POWERPC__
391 	//XXX handle this in other layer since things changes a little bit
392 	//this seems like a really good place to refactor stuff
393 	return 0;
394 #else
395 	if (!cmd || !*cmd) {
396 		return 0;
397 	}
398 	if (cmd[0] == '"') {
399 #if __UNIX__
400 		if (in) {
401 			int pipes[2];
402 			if (pipe (pipes) != -1) {
403 				size_t cmdl = strlen (cmd)-2;
404 				if (write (pipes[1], cmd + 1, cmdl) != cmdl) {
405 					eprintf ("[ERROR] rarun2: Cannot write to the pipe\n");
406 					close (0);
407 					return 1;
408 				}
409 				if (write (pipes[1], "\n", 1) != 1) {
410 					eprintf ("[ERROR] rarun2: Cannot write to the pipe\n");
411 					close (0);
412 					return 1;
413 				}
414 				close (0);
415 				dup2 (pipes[0], 0);
416 			} else {
417 				eprintf ("[ERROR] rarun2: Cannot create pipe\n");
418 			}
419 		}
420 #else
421 #ifdef _MSC_VER
422 #pragma message ("string redirection handle not yet done")
423 #else
424 #warning quoted string redirection handle not yet done
425 #endif
426 #endif
427 	} else if (cmd[0] == '!') {
428 		// redirection to a process
429 		return handle_redirection_proc (cmd + 1, in, out, err);
430 	} else {
431 		// redirection to a file
432 		int f, flag = 0, mode = 0;
433 		flag |= in ? O_RDONLY : 0;
434 		flag |= out ? O_WRONLY | O_CREAT : 0;
435 		flag |= err ? O_WRONLY | O_CREAT : 0;
436 #ifdef __WINDOWS__
437 		mode = _S_IREAD | _S_IWRITE;
438 #else
439 		mode = S_IRUSR | S_IWUSR;
440 #endif
441 		f = open (cmd, flag, mode);
442 		if (f < 0) {
443 			eprintf ("[ERROR] rarun2: Cannot open: %s\n", cmd);
444 			return 1;
445 		}
446 #define DUP(x) { close(x); dup2(f,x); }
447 		if (in) {
448 			DUP(0);
449 		}
450 		if (out) {
451 			DUP(1);
452 		}
453 		if (err) {
454 			DUP(2);
455 		}
456 		close (f);
457 	}
458 	return 0;
459 #endif
460 }
461 
r_run_parsefile(RRunProfile * p,const char * b)462 R_API bool r_run_parsefile(RRunProfile *p, const char *b) {
463 	r_return_val_if_fail (p && b, false);
464 	char *s = r_file_slurp (b, NULL);
465 	if (s) {
466 		bool ret = r_run_parse (p, s);
467 		free (s);
468 		return ret;
469 	}
470 	return 0;
471 }
472 
r_run_parseline(RRunProfile * p,const char * b)473 R_API bool r_run_parseline(RRunProfile *p, const char *b) {
474 	int must_free = false;
475 	char *e = strchr (b, '=');
476 	if (!e || *b == '#') {
477 		return 0;
478 	}
479 	*e++ = 0;
480 	if (*e == '$') {
481 		must_free = true;
482 		e = r_sys_getenv (e);
483 	}
484 	if (!e) {
485 		return 0;
486 	}
487 	if (!strcmp (b, "program")) {
488 		p->_args[0] = p->_program = strdup (e);
489 	} else if (!strcmp (b, "daemon")) {
490 		p->_daemon = true;
491 	} else if (!strcmp (b, "system")) {
492 		p->_system = strdup (e);
493 	} else if (!strcmp (b, "runlib")) {
494 		p->_runlib = strdup (e);
495 	} else if (!strcmp (b, "runlib.fcn")) {
496 		p->_runlib_fcn = strdup (e);
497 	} else if (!strcmp (b, "aslr")) {
498 		p->_aslr = parseBool (e);
499 	} else if (!strcmp (b, "pid")) {
500 		p->_pid = atoi (e);
501 	} else if (!strcmp (b, "pidfile")) {
502 		p->_pidfile = strdup (e);
503 	} else if (!strcmp (b, "connect")) {
504 		p->_connect = strdup (e);
505 	} else if (!strcmp (b, "listen")) {
506 		p->_listen = strdup (e);
507 	} else if (!strcmp (b, "pty")) {
508 		p->_pty = parseBool (e);
509 	} else if (!strcmp (b, "stdio")) {
510 		if (e[0] == '!') {
511 			p->_stdio = strdup (e);
512 		} else {
513 			p->_stdout = strdup (e);
514 			p->_stderr = strdup (e);
515 			p->_stdin = strdup (e);
516 		}
517 	} else if (!strcmp (b, "stdout")) {
518 		p->_stdout = strdup (e);
519 	} else if (!strcmp (b, "stdin")) {
520 		p->_stdin = strdup (e);
521 	} else if (!strcmp (b, "stderr")) {
522 		p->_stderr = strdup (e);
523 	} else if (!strcmp (b, "input")) {
524 		p->_input = strdup (e);
525 	} else if (!strcmp (b, "chdir")) {
526 		p->_chgdir = strdup (e);
527 	} else if (!strcmp (b, "core")) {
528 		p->_docore = parseBool (e);
529 	} else if (!strcmp (b, "fork")) {
530 		p->_dofork = parseBool (e);
531 	} else if (!strcmp (b, "sleep")) {
532 		p->_r2sleep = atoi (e);
533 	} else if (!strcmp (b, "maxstack")) {
534 		p->_maxstack = atoi (e);
535 	} else if (!strcmp (b, "maxproc")) {
536 		p->_maxproc = atoi (e);
537 	} else if (!strcmp (b, "maxfd")) {
538 		p->_maxfd = atoi (e);
539 	} else if (!strcmp (b, "bits")) {
540 		p->_bits = atoi (e);
541 	} else if (!strcmp (b, "chroot")) {
542 		p->_chroot = strdup (e);
543 	} else if (!strcmp (b, "libpath")) {
544 		p->_libpath = strdup (e);
545 	} else if (!strcmp (b, "preload")) {
546 		p->_preload = strdup (e);
547 	} else if (!strcmp (b, "r2preload")) {
548 		p->_r2preload = parseBool (e);
549 	} else if (!strcmp (b, "r2preweb")) {
550 		r_sys_setenv ("RARUN2_WEB", "yes");
551 	} else if (!strcmp (b, "setuid")) {
552 		p->_setuid = strdup (e);
553 	} else if (!strcmp (b, "seteuid")) {
554 		p->_seteuid = strdup (e);
555 	} else if (!strcmp (b, "setgid")) {
556 		p->_setgid = strdup (e);
557 	} else if (!strcmp (b, "setegid")) {
558 		p->_setegid = strdup (e);
559 	} else if (!strcmp (b, "nice")) {
560 		p->_nice = atoi (e);
561 	} else if (!strcmp (b, "timeout")) {
562 		p->_timeout = atoi (e);
563 	} else if (!strcmp (b, "timeoutsig")) {
564 		p->_timeout_sig = r_signal_from_string (e);
565 	} else if (!memcmp (b, "arg", 3)) {
566 		int n = atoi (b + 3);
567 		if (n >= 0 && n < R_RUN_PROFILE_NARGS) {
568 			p->_args[n] = getstr (e);
569 			p->_argc++;
570 		} else {
571 			eprintf ("Out of bounds args index: %d\n", n);
572 		}
573 	} else if (!strcmp (b, "envfile")) {
574 		char *p, buf[1024];
575 		size_t len;
576 		FILE *fd = r_sandbox_fopen (e, "r");
577 		if (!fd) {
578 			eprintf ("Cannot open '%s'\n", e);
579 			if (must_free == true) {
580 				free (e);
581 			}
582 			return false;
583 		}
584 		for (;;) {
585 			if (!fgets (buf, sizeof (buf), fd)) {
586 				break;
587 			}
588 			if (feof (fd)) {
589 				break;
590 			}
591 			p = strchr (buf, '=');
592 			if (p) {
593 				*p++ = 0;
594 				len = strlen (p);
595 				if (len > 0 && p[len - 1] == '\n') {
596 					p[len - 1] = 0;
597 				}
598 				if (len > 1 && p[len - 2] == '\r') {
599 					p[len - 2] = 0;
600 				}
601 				r_sys_setenv (buf, p);
602 			}
603 		}
604 		fclose (fd);
605 	} else if (!strcmp (b, "unsetenv")) {
606 		r_sys_setenv (e, NULL);
607 	} else if (!strcmp (b, "setenv")) {
608 		char *V, *v = strchr (e, '=');
609 		if (v) {
610 			*v++ = 0;
611 			V = getstr (v);
612 			r_sys_setenv (e, V);
613 			free (V);
614 		}
615 	} else if (!strcmp(b, "clearenv")) {
616 		r_sys_clearenv ();
617 	}
618 	if (must_free == true) {
619 		free (e);
620 	}
621 	return true;
622 }
623 
r_run_help(void)624 R_API const char *r_run_help(void) {
625 	return
626 	"program=/bin/ls\n"
627 	"arg1=/bin\n"
628 	"# arg2=hello\n"
629 	"# arg3=\"hello\\nworld\"\n"
630 	"# arg4=:048490184058104849\n"
631 	"# arg5=:!ragg2 -p n50 -d 10:0x8048123\n"
632 	"# arg6=@arg.txt\n"
633 	"# arg7=@300@ABCD # 300 chars filled with ABCD pattern\n"
634 	"# system=r2 -\n"
635 	"# daemon=false\n"
636 	"# aslr=no\n"
637 	"setenv=FOO=BAR\n"
638 	"# unsetenv=FOO\n"
639 	"# clearenv=true\n"
640 	"# envfile=environ.txt\n"
641 	"timeout=3\n"
642 	"# timeoutsig=SIGTERM # or 15\n"
643 	"# connect=localhost:8080\n"
644 	"# listen=8080\n"
645 	"# pty=false\n"
646 	"# fork=true\n"
647 	"# bits=32\n"
648 	"# pid=0\n"
649 	"# pidfile=/tmp/foo.pid\n"
650 	"# #sleep=0\n"
651 	"# #maxfd=0\n"
652 	"# #execve=false\n"
653 	"# #maxproc=0\n"
654 	"# #maxstack=0\n"
655 	"# #core=false\n"
656 	"# #stdio=blah.txt\n"
657 	"# #stderr=foo.txt\n"
658 	"# stdout=foo.txt\n"
659 	"# stdin=input.txt # or !program to redirect input from another program\n"
660 	"# input=input.txt\n"
661 	"# chdir=/\n"
662 	"# chroot=/mnt/chroot\n"
663 	"# libpath=$PWD:/tmp/lib\n"
664 	"# r2preload=yes\n"
665 	"# preload=/lib/libfoo.so\n"
666 	"# setuid=2000\n"
667 	"# seteuid=2000\n"
668 	"# setgid=2001\n"
669 	"# setegid=2001\n"
670 	"# nice=5\n";
671 }
672 
673 #if HAVE_PTY
fd_forward(int in_fd,int out_fd,char ** buff)674 static int fd_forward(int in_fd, int out_fd, char **buff) {
675 	int size = 0;
676 
677 	if (ioctl (in_fd, FIONREAD, &size) == -1) {
678 		perror ("ioctl");
679 		return -1;
680 	}
681 	if (!size) { // child process exited or socket is closed
682 		return -1;
683 	}
684 
685 	char *new_buff = realloc (*buff, size);
686 	if (!new_buff) {
687 		eprintf ("Failed to allocate buffer for redirection");
688 		return -1;
689 	}
690 	*buff = new_buff;
691 	if (read (in_fd, *buff, size) != size) {
692 		perror ("read");
693 		return -1;
694 	}
695 	if (write (out_fd, *buff, size) != size) {
696 		perror ("write");
697 		return -1;
698 	}
699 
700 	return 0;
701 }
702 #endif
703 
redirect_socket_to_stdio(RSocket * sock)704 static int redirect_socket_to_stdio(RSocket *sock) {
705 	close (0);
706 	close (1);
707 	close (2);
708 
709 	dup2 (sock->fd, 0);
710 	dup2 (sock->fd, 1);
711 	dup2 (sock->fd, 2);
712 
713 	return 0;
714 }
715 
716 #if __WINDOWS__
exit_process(RThread * th)717 static RThreadFunctionRet exit_process(RThread *th) {
718 	// eprintf ("\nrarun2: Interrupted by timeout\n");
719 	exit (0);
720 }
721 #endif
722 
redirect_socket_to_pty(RSocket * sock)723 static int redirect_socket_to_pty(RSocket *sock) {
724 #if HAVE_PTY
725 	// directly duplicating the fds using dup2() creates problems
726 	// in case of interactive applications
727 	int fdm = -1, fds = -1;
728 
729 	if (dyn_openpty && dyn_openpty (&fdm, &fds, NULL, NULL, NULL) == -1) {
730 		perror ("opening pty");
731 		return -1;
732 	}
733 
734 	pid_t child_pid = r_sys_fork ();
735 
736 	if (child_pid == -1) {
737 		eprintf ("cannot fork\n");
738 		if (fdm != -1) {
739 			close (fdm);
740 		}
741 		if (fds != -1) {
742 			close (fds);
743 		}
744 		return -1;
745 	}
746 
747 	if (child_pid == 0) {
748 		// child process
749 		close (fds);
750 
751 		char *buff = NULL;
752 		int sockfd = sock->fd;
753 		int max_fd = fdm > sockfd ? fdm : sockfd;
754 
755 		while (true) {
756 			fd_set readfds;
757 			FD_ZERO (&readfds);
758 			FD_SET (fdm, &readfds);
759 			FD_SET (sockfd, &readfds);
760 
761 			if (select (max_fd + 1, &readfds, NULL, NULL, NULL) == -1) {
762 				perror ("select error");
763 				break;
764 			}
765 
766 			if (FD_ISSET (fdm, &readfds)) {
767 				if (fd_forward (fdm, sockfd, &buff) != 0) {
768 					break;
769 				}
770 			}
771 
772 			if (FD_ISSET (sockfd, &readfds)) {
773 				if (fd_forward (sockfd, fdm, &buff) != 0) {
774 					break;
775 				}
776 			}
777 		}
778 
779 		free (buff);
780 		if (fdm != -1) {
781 			close (fdm);
782 			fdm = -1;
783 		}
784 		r_socket_free (sock);
785 		exit (0);
786 	}
787 
788 	// parent
789 	r_socket_close_fd (sock);
790 	if (dyn_login_tty) {
791 		dyn_login_tty (fds);
792 	}
793 	if (fdm != -1) {
794 		close (fdm);
795 	}
796 
797 	// disable the echo on slave stdin
798 	struct termios t;
799 	tcgetattr (0, &t);
800 	cfmakeraw (&t);
801 	tcsetattr (0, TCSANOW, &t);
802 
803 	return 0;
804 #else
805 	// Fallback to socket to I/O redirection
806 	return redirect_socket_to_stdio (sock);
807 #endif
808 }
809 
r_run_config_env(RRunProfile * p)810 R_API int r_run_config_env(RRunProfile *p) {
811 	int ret;
812 
813 #if HAVE_PTY
814 	dyn_init ();
815 #endif
816 
817 	if (!p->_program && !p->_system && !p->_runlib) {
818 		eprintf ("No program, system or runlib rule defined\n");
819 		return 1;
820 	}
821 	// when IO is redirected to a process, handle them together
822 	if (handle_redirection (p->_stdio, true, true, false) != 0) {
823 		return 1;
824 	}
825 	if (handle_redirection (p->_stdin, true, false, false) != 0) {
826 		return 1;
827 	}
828 	if (handle_redirection (p->_stdout, false, true, false) != 0) {
829 		return 1;
830 	}
831 	if (handle_redirection (p->_stderr, false, false, true) != 0) {
832 		return 1;
833 	}
834 	if (p->_aslr != -1) {
835 		setASLR (p, p->_aslr);
836 	}
837 #if __UNIX__
838 	set_limit (p->_docore, RLIMIT_CORE, RLIM_INFINITY);
839 	if (p->_maxfd) {
840 		set_limit (p->_maxfd, RLIMIT_NOFILE, p->_maxfd);
841 	}
842 #ifdef RLIMIT_NPROC
843 	if (p->_maxproc) {
844 		set_limit (p->_maxproc, RLIMIT_NPROC, p->_maxproc);
845 	}
846 #endif
847 	if (p->_maxstack) {
848 		set_limit (p->_maxstack, RLIMIT_STACK, p->_maxstack);
849 	}
850 #else
851 	if (p->_docore || p->_maxfd || p->_maxproc || p->_maxstack)
852 		eprintf ("Warning: setrlimits not supported for this platform\n");
853 #endif
854 	if (p->_connect) {
855 		char *q = strchr (p->_connect, ':');
856 		if (q) {
857 			RSocket *fd = r_socket_new (0);
858 			*q = 0;
859 			if (!r_socket_connect_tcp (fd, p->_connect, q+1, 30)) {
860 				eprintf ("Cannot connect\n");
861 				return 1;
862 			}
863 			if (p->_pty) {
864 				if (redirect_socket_to_pty (fd) != 0) {
865 					eprintf ("socket redirection failed\n");
866 					r_socket_free (fd);
867 					return 1;
868 				}
869 			} else {
870 				redirect_socket_to_stdio (fd);
871 			}
872 		} else {
873 			eprintf ("Invalid format for connect. missing ':'\n");
874 			return 1;
875 		}
876 	}
877 	if (p->_listen) {
878 		RSocket *child, *fd = r_socket_new (0);
879 		bool is_child = false;
880 		if (!r_socket_listen (fd, p->_listen, NULL)) {
881 			eprintf ("rarun2: cannot listen\n");
882 			r_socket_free (fd);
883 			return 1;
884 		}
885 		while (true) {
886 			child = r_socket_accept (fd);
887 			if (child) {
888 				is_child = true;
889 
890 				if (p->_dofork && !p->_dodebug) {
891 					pid_t child_pid = r_sys_fork ();
892 					if (child_pid == -1) {
893 						eprintf("rarun2: cannot fork\n");
894 						r_socket_free (child);
895 						r_socket_free (fd);
896 						return 1;
897 					} else if (child_pid != 0){
898 						// parent code
899 						is_child = false;
900 					}
901 				}
902 
903 				if (is_child) {
904 					r_socket_close_fd (fd);
905 					eprintf ("connected\n");
906 					if (p->_pty) {
907 						if (redirect_socket_to_pty (child) != 0) {
908 							eprintf ("socket redirection failed\n");
909 							r_socket_free (child);
910 							r_socket_free (fd);
911 							return 1;
912 						}
913 					} else {
914 						redirect_socket_to_stdio (child);
915 					}
916 					break;
917 				} else {
918 					r_socket_close_fd (child);
919 				}
920 			}
921 		}
922 		if (!is_child) {
923 			r_socket_free (child);
924 		}
925 		r_socket_free (fd);
926 	}
927 	if (p->_r2sleep != 0) {
928 		r_sys_sleep (p->_r2sleep);
929 	}
930 #if __UNIX__
931 	if (p->_chroot) {
932 		if (chdir (p->_chroot) == -1) {
933 			eprintf ("Cannot chdir to chroot in %s\n", p->_chroot);
934 			return 1;
935 		} else {
936 			if (chroot (".") == -1) {
937 				eprintf ("Cannot chroot to %s\n", p->_chroot);
938 				return 1;
939 			} else {
940 				// Silenting pedantic meson flags...
941 				if (chdir ("/") == -1) {
942 					eprintf ("Cannot chdir to /\n");
943 					return 1;
944 				}
945 				if (p->_chgdir) {
946 					if (chdir (p->_chgdir) == -1) {
947 						eprintf ("Cannot chdir after chroot to %s\n", p->_chgdir);
948 						return 1;
949 					}
950 				}
951 			}
952 		}
953 	} else if (p->_chgdir) {
954 		if (chdir (p->_chgdir) == -1) {
955 			eprintf ("Cannot chdir after chroot to %s\n", p->_chgdir);
956 			return 1;
957 		}
958 	}
959 #else
960 	if (p->_chgdir) {
961 		ret = chdir (p->_chgdir);
962 		if (ret < 0) {
963 			return 1;
964 		}
965 	}
966 	if (p->_chroot) {
967 		ret = chdir (p->_chroot);
968 		if (ret < 0) {
969 			return 1;
970 		}
971 	}
972 #endif
973 #if __UNIX__
974 	if (p->_setuid) {
975 		ret = setgroups (0, NULL);
976 		if (ret < 0) {
977 			return 1;
978 		}
979 		ret = setuid (atoi (p->_setuid));
980 		if (ret < 0) {
981 			return 1;
982 		}
983 	}
984 	if (p->_seteuid) {
985 		ret = seteuid (atoi (p->_seteuid));
986 		if (ret < 0) {
987 			return 1;
988 		}
989 	}
990 	if (p->_setgid) {
991 		ret = setgid (atoi (p->_setgid));
992 		if (ret < 0) {
993 			return 1;
994 		}
995 	}
996 	if (p->_input) {
997 		char *inp;
998 		int f2[2];
999 		if (pipe (f2) != -1) {
1000 			close (0);
1001 			dup2 (f2[0], 0);
1002 		} else {
1003 			eprintf ("[ERROR] rarun2: Cannot create pipe\n");
1004 			return 1;
1005 		}
1006 		inp = getstr (p->_input);
1007 		if (inp) {
1008 			size_t inpl = strlen (inp);
1009 			if  (write (f2[1], inp, inpl) != inpl) {
1010 				eprintf ("[ERROR] rarun2: Cannot write to the pipe\n");
1011 			}
1012 			close (f2[1]);
1013 			free (inp);
1014 		} else {
1015 			eprintf ("Invalid input\n");
1016 		}
1017 	}
1018 #endif
1019 	if (p->_r2preload) {
1020 		if (p->_preload) {
1021 			eprintf ("WARNING: Only one library can be opened at a time\n");
1022 		}
1023 #ifdef __WINDOWS__
1024 		p->_preload = r_str_r2_prefix (R_JOIN_2_PATHS (R2_LIBDIR, "libr2."R_LIB_EXT));
1025 #else
1026 		p->_preload = strdup (R2_LIBDIR"/libr2."R_LIB_EXT);
1027 #endif
1028 	}
1029 	if (p->_libpath) {
1030 #if __WINDOWS__
1031 		eprintf ("rarun2: libpath unsupported for this platform\n");
1032 #elif __HAIKU__
1033 		r_sys_setenv ("LIBRARY_PATH", p->_libpath);
1034 #elif __APPLE__
1035 		r_sys_setenv ("DYLD_LIBRARY_PATH", p->_libpath);
1036 #else
1037 		r_sys_setenv ("LD_LIBRARY_PATH", p->_libpath);
1038 #endif
1039 	}
1040 	if (p->_preload) {
1041 #if __APPLE__
1042 		// 10.6
1043 #ifndef __MAC_10_7
1044 		r_sys_setenv ("DYLD_PRELOAD", p->_preload);
1045 #endif
1046 		r_sys_setenv ("DYLD_INSERT_LIBRARIES", p->_preload);
1047 		// 10.8
1048 		r_sys_setenv ("DYLD_FORCE_FLAT_NAMESPACE", "1");
1049 #else
1050 		r_sys_setenv ("LD_PRELOAD", p->_preload);
1051 #endif
1052 	}
1053 	if (p->_timeout) {
1054 #if __UNIX__
1055 		int mypid = getpid ();
1056 		if (!r_sys_fork ()) {
1057 			int use_signal = p->_timeout_sig;
1058 			if (use_signal < 1) {
1059 				use_signal = SIGKILL;
1060 			}
1061 			sleep (p->_timeout);
1062 			if (!kill (mypid, 0)) {
1063 				// eprintf ("\nrarun2: Interrupted by timeout\n");
1064 			}
1065 			kill (mypid, use_signal);
1066 			exit (0);
1067 		}
1068 #else
1069 		if (p->_timeout_sig < 1 || p->_timeout_sig == 9) {
1070 			r_th_new (exit_process, NULL, p->_timeout);
1071 		} else {
1072 			eprintf ("timeout with signal not supported for this platform\n");
1073 		}
1074 #endif
1075 	}
1076 	return 0;
1077 }
1078 
1079 // NOTE: return value is like in unix return code (0 = ok, 1 = not ok)
r_run_start(RRunProfile * p)1080 R_API int r_run_start(RRunProfile *p) {
1081 #if LIBC_HAVE_FORK
1082 	if (p->_execve) {
1083 		exit (execv (p->_program, (char* const*)p->_args));
1084 	}
1085 #endif
1086 #if __APPLE__ && !__POWERPC__ && LIBC_HAVE_FORK
1087 	posix_spawnattr_t attr = {0};
1088 	pid_t pid = -1;
1089 	int ret;
1090 	posix_spawnattr_init (&attr);
1091 	if (p->_args[0]) {
1092 		char **envp = r_sys_get_environ();
1093 		ut32 spflags = 0; //POSIX_SPAWN_START_SUSPENDED;
1094 		spflags |= POSIX_SPAWN_SETEXEC;
1095 		if (p->_aslr == 0) {
1096 #define _POSIX_SPAWN_DISABLE_ASLR 0x0100
1097 			spflags |= _POSIX_SPAWN_DISABLE_ASLR;
1098 		}
1099 		(void)posix_spawnattr_setflags (&attr, spflags);
1100 		if (p->_bits) {
1101 			size_t copied = 1;
1102 			cpu_type_t cpu;
1103 #if __i386__ || __x86_64__
1104 			cpu = CPU_TYPE_I386;
1105 			if (p->_bits == 64) {
1106 				cpu |= CPU_ARCH_ABI64;
1107 			}
1108 #else
1109 			cpu = CPU_TYPE_ANY;
1110 #endif
1111 			posix_spawnattr_setbinpref_np (
1112 					&attr, 1, &cpu, &copied);
1113 		}
1114 		ret = posix_spawnp (&pid, p->_args[0],
1115 			NULL, &attr, p->_args, envp);
1116 		switch (ret) {
1117 		case 0:
1118 			break;
1119 		case 22:
1120 			eprintf ("posix_spawnp: Invalid argument\n");
1121 			break;
1122 		case 86:
1123 			eprintf ("posix_spawnp: Unsupported architecture\n");
1124 			break;
1125 		default:
1126 			eprintf ("posix_spawnp: unknown error %d\n", ret);
1127 			perror ("posix_spawnp");
1128 			break;
1129 		}
1130 		exit (ret);
1131 	}
1132 #endif
1133 	if (p->_system) {
1134 		if (p->_pid) {
1135 			eprintf ("PID: Cannot determine pid with 'system' directive. Use 'program'.\n");
1136 		}
1137 		if (p->_daemon) {
1138 #if __WINDOWS__
1139 	//		eprintf ("PID: Cannot determine pid with 'system' directive. Use 'program'.\n");
1140 #else
1141 			pid_t child = r_sys_fork ();
1142 			if (child == -1) {
1143 				perror ("fork");
1144 				exit (1);
1145 			}
1146 			if (child) {
1147 				if (p->_pidfile) {
1148 					char pidstr[32];
1149 					snprintf (pidstr, sizeof (pidstr), "%d\n", child);
1150 					r_file_dump (p->_pidfile,
1151 							(const ut8*)pidstr,
1152 							strlen (pidstr), 0);
1153 				}
1154 				exit (0);
1155 			}
1156 			setsid ();
1157 			if (p->_timeout) {
1158 #if __UNIX__
1159 				int mypid = getpid ();
1160 				if (!r_sys_fork ()) {
1161 					int use_signal = p->_timeout_sig;
1162 					if (use_signal < 1) {
1163 						use_signal = SIGKILL;
1164 					}
1165 					sleep (p->_timeout);
1166 					if (!kill (mypid, 0)) {
1167 						// eprintf ("\nrarun2: Interrupted by timeout\n");
1168 					}
1169 					kill (mypid, use_signal);
1170 					exit (0);
1171 				}
1172 #else
1173 				eprintf ("timeout not supported for this platform\n");
1174 #endif
1175 			}
1176 #endif
1177 #if __UNIX__
1178 			close(0);
1179 			close(1);
1180 			exit (execl ("/bin/sh","/bin/sh", "-c", p->_system, NULL));
1181 #else
1182 			exit (r_sys_cmd (p->_system));
1183 #endif
1184 		} else {
1185 			if (p->_pidfile) {
1186 				eprintf ("Warning: pidfile doesnt work with 'system'.\n");
1187 			}
1188 			exit (r_sys_cmd (p->_system));
1189 		}
1190 	}
1191 	if (p->_program) {
1192 		if (!r_file_exists (p->_program)) {
1193 			char *progpath = r_file_path (p->_program);
1194 			if (progpath && *progpath) {
1195 				free (p->_program);
1196 				p->_program = progpath;
1197 			} else {
1198 				free (progpath);
1199 				eprintf ("rarun2: %s: file not found\n", p->_program);
1200 				return 1;
1201 			}
1202 		}
1203 #if __UNIX__
1204 		// XXX HACK close all non-tty fds
1205 		{ int i;
1206 			for (i = 3; i < 1024; i++) {
1207 				close (i);
1208 			}
1209 		}
1210 		// TODO: use posix_spawn
1211 		if (p->_setgid) {
1212 			int ret = setgid (atoi (p->_setgid));
1213 			if (ret < 0) {
1214 				return 1;
1215 			}
1216 		}
1217 		if (p->_pid) {
1218 			eprintf ("PID: %d\n", getpid ());
1219 		}
1220 		if (p->_pidfile) {
1221 			char pidstr[32];
1222 			snprintf (pidstr, sizeof (pidstr), "%d\n", getpid ());
1223 			r_file_dump (p->_pidfile,
1224 				(const ut8*)pidstr,
1225 				strlen (pidstr), 0);
1226 		}
1227 #endif
1228 
1229 		if (p->_nice) {
1230 #if __UNIX__ && !defined(__HAIKU__)
1231 			if (nice (p->_nice) == -1) {
1232 				return 1;
1233 			}
1234 #else
1235 			eprintf ("nice not supported for this platform\n");
1236 #endif
1237 		}
1238 		if (p->_daemon) {
1239 #if __WINDOWS__
1240 			eprintf ("PID: Cannot determine pid with 'system' directive. Use 'program'.\n");
1241 #else
1242 			pid_t child = r_sys_fork ();
1243 			if (child == -1) {
1244 				perror ("fork");
1245 				exit (1);
1246 			}
1247 			if (child) {
1248 				if (p->_pidfile) {
1249 					char pidstr[32];
1250 					snprintf (pidstr, sizeof (pidstr), "%d\n", child);
1251 					r_file_dump (p->_pidfile,
1252 							(const ut8*)pidstr,
1253 							strlen (pidstr), 0);
1254 					exit (0);
1255 				}
1256 			}
1257 			setsid ();
1258 #if !LIBC_HAVE_FORK
1259 		exit (execv (p->_program, (char* const*)p->_args));
1260 #endif
1261 #endif
1262 		}
1263 // TODO: must be HAVE_EXECVE
1264 #if LIBC_HAVE_FORK
1265 		exit (execv (p->_program, (char* const*)p->_args));
1266 #endif
1267 	}
1268 	if (p->_runlib) {
1269 		if (!p->_runlib_fcn) {
1270 			eprintf ("No function specified. Please set runlib.fcn\n");
1271 			return 1;
1272 		}
1273 		void *addr = r_lib_dl_open (p->_runlib);
1274 		if (!addr) {
1275 			eprintf ("Could not load the library '%s'\n", p->_runlib);
1276 			return 1;
1277 		}
1278 		void (*fcn)(void) = r_lib_dl_sym (addr, p->_runlib_fcn);
1279 		if (!fcn) {
1280 			eprintf ("Could not find the function '%s'\n", p->_runlib_fcn);
1281 			return 1;
1282 		}
1283 		switch (p->_argc) {
1284 		case 0:
1285 			fcn ();
1286 			break;
1287 		case 1:
1288 			r_run_call1 (fcn, p->_args[1]);
1289 			break;
1290 		case 2:
1291 			r_run_call2 (fcn, p->_args[1], p->_args[2]);
1292 			break;
1293 		case 3:
1294 			r_run_call3 (fcn, p->_args[1], p->_args[2], p->_args[3]);
1295 			break;
1296 		case 4:
1297 			r_run_call4 (fcn, p->_args[1], p->_args[2], p->_args[3], p->_args[4]);
1298 			break;
1299 		case 5:
1300 			r_run_call5 (fcn, p->_args[1], p->_args[2], p->_args[3], p->_args[4],
1301 				p->_args[5]);
1302 			break;
1303 		case 6:
1304 			r_run_call6 (fcn, p->_args[1], p->_args[2], p->_args[3], p->_args[4],
1305 				p->_args[5], p->_args[6]);
1306 			break;
1307 		case 7:
1308 			r_run_call7 (fcn, p->_args[1], p->_args[2], p->_args[3], p->_args[4],
1309 				p->_args[5], p->_args[6], p->_args[7]);
1310 			break;
1311 		case 8:
1312 			r_run_call8 (fcn, p->_args[1], p->_args[2], p->_args[3], p->_args[4],
1313 				p->_args[5], p->_args[6], p->_args[7], p->_args[8]);
1314 			break;
1315 		case 9:
1316 			r_run_call9 (fcn, p->_args[1], p->_args[2], p->_args[3], p->_args[4],
1317 				p->_args[5], p->_args[6], p->_args[7], p->_args[8], p->_args[9]);
1318 			break;
1319 		case 10:
1320 			r_run_call10 (fcn, p->_args[1], p->_args[2], p->_args[3], p->_args[4],
1321 				p->_args[5], p->_args[6], p->_args[7], p->_args[8], p->_args[9], p->_args[10]);
1322 			break;
1323 		default:
1324 			eprintf ("Too many arguments.\n");
1325 			return 1;
1326 		}
1327 		r_lib_dl_close (addr);
1328 	}
1329 	return 0;
1330 }
1331 
r_run_get_environ_profile(char ** env)1332 R_API char *r_run_get_environ_profile(char **env) {
1333 	if (!env) {
1334 		return NULL;
1335 	}
1336 	RStrBuf *sb = r_strbuf_new (NULL);
1337 	while (*env) {
1338 		char *k = strdup (*env);
1339 		char *v = strchr (k, '=');
1340 		if (v) {
1341 			*v++ = 0;
1342 			v = r_str_escape_latin1 (v, false, true, true);
1343 			if (v) {
1344 				r_strbuf_appendf (sb, "setenv=%s=\"%s\"\n", k, v);
1345 				free (v);
1346 			}
1347 		}
1348 		free (k);
1349 		env++;
1350 	}
1351 	return r_strbuf_drain (sb);
1352 }
1353