Annotation of embedaddon/sudo/src/exec.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 2009-2011 Todd C. Miller <Todd.Miller@courtesan.com>
3: *
4: * Permission to use, copy, modify, and distribute this software for any
5: * purpose with or without fee is hereby granted, provided that the above
6: * copyright notice and this permission notice appear in all copies.
7: *
8: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15: */
16:
17: #include <config.h>
18:
19: #include <sys/types.h>
20: #include <sys/param.h>
21: #ifdef HAVE_SYS_SYSMACROS_H
22: # include <sys/sysmacros.h>
23: #endif
24: #include <sys/socket.h>
25: #include <sys/stat.h>
26: #include <sys/time.h>
27: #include <sys/wait.h>
28: #include <sys/ioctl.h>
29: #ifdef HAVE_SYS_SELECT_H
30: # include <sys/select.h>
31: #endif /* HAVE_SYS_SELECT_H */
32: #include <stdio.h>
33: #ifdef STDC_HEADERS
34: # include <stdlib.h>
35: # include <stddef.h>
36: #else
37: # ifdef HAVE_STDLIB_H
38: # include <stdlib.h>
39: # endif
40: #endif /* STDC_HEADERS */
41: #ifdef HAVE_STRING_H
42: # include <string.h>
43: #endif /* HAVE_STRING_H */
44: #ifdef HAVE_STRINGS_H
45: # include <strings.h>
46: #endif /* HAVE_STRINGS_H */
47: #ifdef HAVE_UNISTD_H
48: # include <unistd.h>
49: #endif /* HAVE_UNISTD_H */
50: #if TIME_WITH_SYS_TIME
51: # include <time.h>
52: #endif
53: #ifdef HAVE_SETLOCALE
54: # include <locale.h>
55: #endif
56: #include <errno.h>
57: #include <fcntl.h>
58: #include <signal.h>
59: #include <termios.h>
60:
61: #include "sudo.h"
62: #include "sudo_exec.h"
63: #include "sudo_plugin.h"
64: #include "sudo_plugin_int.h"
65:
66: /* Shared with exec_pty.c for use with handler(). */
67: int signal_pipe[2];
68:
69: /* We keep a tailq of signals to forward to child. */
70: struct sigforward {
71: struct sigforward *prev, *next;
72: int signo;
73: };
74: TQ_DECLARE(sigforward)
75: static struct sigforward_list sigfwd_list;
76:
77: static int handle_signals(int fd, pid_t child, int log_io,
78: struct command_status *cstat);
79: static void forward_signals(int fd);
80: static void schedule_signal(int signo);
81:
82: /*
83: * Like execve(2) but falls back to running through /bin/sh
84: * ala execvp(3) if we get ENOEXEC.
85: */
86: int
87: my_execve(const char *path, char *const argv[], char *const envp[])
88: {
89: execve(path, argv, envp);
90: if (errno == ENOEXEC) {
91: int argc;
92: char **nargv;
93:
94: for (argc = 0; argv[argc] != NULL; argc++)
95: continue;
96: nargv = emalloc2(argc + 2, sizeof(char *));
97: nargv[0] = "sh";
98: nargv[1] = (char *)path;
99: memcpy(nargv + 2, argv + 1, argc * sizeof(char *));
100: execve(_PATH_BSHELL, nargv, envp);
101: efree(nargv);
102: }
103: return -1;
104: }
105:
106: /*
107: * Fork and execute a command, returns the child's pid.
108: * Sends errno back on sv[1] if execve() fails.
109: */
110: static int fork_cmnd(struct command_details *details, int sv[2])
111: {
112: struct command_status cstat;
113: sigaction_t sa;
114: pid_t child;
115:
116: zero_bytes(&sa, sizeof(sa));
117: sigemptyset(&sa.sa_mask);
118: sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
119: sa.sa_handler = handler;
120: sigaction(SIGCONT, &sa, NULL);
121:
122: child = fork();
123: switch (child) {
124: case -1:
125: error(1, _("unable to fork"));
126: break;
127: case 0:
128: /* child */
129: close(sv[0]);
130: close(signal_pipe[0]);
131: close(signal_pipe[1]);
132: fcntl(sv[1], F_SETFD, FD_CLOEXEC);
133: restore_signals();
134: if (exec_setup(details, NULL, -1) == TRUE) {
135: /* headed for execve() */
136: if (details->closefrom >= 0)
137: closefrom(details->closefrom);
138: #ifdef HAVE_SELINUX
139: if (ISSET(details->flags, CD_RBAC_ENABLED))
140: selinux_execve(details->command, details->argv, details->envp);
141: else
142: #endif
143: my_execve(details->command, details->argv, details->envp);
144: }
145: cstat.type = CMD_ERRNO;
146: cstat.val = errno;
147: send(sv[1], &cstat, sizeof(cstat), 0);
148: _exit(1);
149: }
150: return child;
151: }
152:
153: static struct signal_state {
154: int signo;
155: sigaction_t sa;
156: } saved_signals[] = {
157: { SIGALRM },
158: { SIGCHLD },
159: { SIGCONT },
160: { SIGHUP },
161: { SIGINT },
162: { SIGPIPE },
163: { SIGQUIT },
164: { SIGTERM },
165: { SIGTSTP },
166: { SIGTTIN },
167: { SIGTTOU },
168: { SIGUSR1 },
169: { SIGUSR2 },
170: { -1 }
171: };
172:
173: /*
174: * Save signal handler state so it can be restored before exec.
175: */
176: void
177: save_signals(void)
178: {
179: struct signal_state *ss;
180:
181: for (ss = saved_signals; ss->signo != -1; ss++)
182: sigaction(ss->signo, NULL, &ss->sa);
183: }
184:
185: /*
186: * Restore signal handlers to initial state.
187: */
188: void
189: restore_signals(void)
190: {
191: struct signal_state *ss;
192:
193: for (ss = saved_signals; ss->signo != -1; ss++)
194: sigaction(ss->signo, &ss->sa, NULL);
195: }
196:
197: /*
198: * Execute a command, potentially in a pty with I/O loggging.
199: * This is a little bit tricky due to how POSIX job control works and
200: * we fact that we have two different controlling terminals to deal with.
201: */
202: int
203: sudo_execve(struct command_details *details, struct command_status *cstat)
204: {
205: int maxfd, n, nready, sv[2], log_io = FALSE;
206: const char *utmp_user = NULL;
207: fd_set *fdsr, *fdsw;
208: sigaction_t sa;
209: pid_t child;
210:
211: /* If running in background mode, fork and exit. */
212: if (ISSET(details->flags, CD_BACKGROUND)) {
213: switch (fork()) {
214: case -1:
215: cstat->type = CMD_ERRNO;
216: cstat->val = errno;
217: return -1;
218: case 0:
219: /* child continues without controlling terminal */
220: (void)setpgid(0, 0);
221: break;
222: default:
223: /* parent exits (but does not flush buffers) */
224: _exit(0);
225: }
226: }
227:
228: /*
229: * If we have an I/O plugin or the policy plugin has requested one, we
230: * need to allocate a pty. It is OK to set log_io in the pty-only case
231: * as the io plugin tailqueue will be empty and no I/O logging will occur.
232: */
233: if (!tq_empty(&io_plugins) || ISSET(details->flags, CD_USE_PTY)) {
234: log_io = TRUE;
235: if (ISSET(details->flags, CD_SET_UTMP))
236: utmp_user = details->utmp_user ? details->utmp_user : user_details.username;
237: sudo_debug(8, "allocate pty for I/O logging");
238: pty_setup(details->euid, user_details.tty, utmp_user);
239: }
240:
241: /*
242: * We communicate with the child over a bi-directional pair of sockets.
243: * Parent sends signal info to child and child sends back wait status.
244: */
245: if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1)
246: error(1, _("unable to create sockets"));
247:
248: /*
249: * We use a pipe to atomically handle signal notification within
250: * the select() loop.
251: */
252: if (pipe_nonblock(signal_pipe) != 0)
253: error(1, _("unable to create pipe"));
254:
255: zero_bytes(&sa, sizeof(sa));
256: sigemptyset(&sa.sa_mask);
257:
258: /*
259: * Signals for forward to the child process (excluding SIGALRM and SIGCHLD).
260: * Note: HP-UX select() will not be interrupted if SA_RESTART set.
261: */
262: sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
263: sa.sa_handler = handler;
264: sigaction(SIGALRM, &sa, NULL);
265: sigaction(SIGCHLD, &sa, NULL);
266: sigaction(SIGHUP, &sa, NULL);
267: sigaction(SIGINT, &sa, NULL);
268: sigaction(SIGPIPE, &sa, NULL);
269: sigaction(SIGQUIT, &sa, NULL);
270: sigaction(SIGTERM, &sa, NULL);
271: sigaction(SIGUSR1, &sa, NULL);
272: sigaction(SIGUSR2, &sa, NULL);
273:
274: /* Max fd we will be selecting on. */
275: maxfd = MAX(sv[0], signal_pipe[0]);
276:
277: /*
278: * Child will run the command in the pty, parent will pass data
279: * to and from pty. Adjusts maxfd as needed.
280: */
281: if (log_io)
282: child = fork_pty(details, sv, &maxfd);
283: else
284: child = fork_cmnd(details, sv);
285: close(sv[1]);
286:
287: /* Set command timeout if specified. */
288: if (ISSET(details->flags, CD_SET_TIMEOUT))
289: alarm(details->timeout);
290:
291: #ifdef HAVE_SETLOCALE
292: /*
293: * I/O logging must be in the C locale for floating point numbers
294: * to be logged consistently.
295: */
296: setlocale(LC_ALL, "C");
297: #endif
298:
299: /*
300: * In the event loop we pass input from user tty to master
301: * and pass output from master to stdout and IO plugin.
302: */
303: fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
304: fdsw = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
305: for (;;) {
306: zero_bytes(fdsw, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
307: zero_bytes(fdsr, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
308:
309: FD_SET(signal_pipe[0], fdsr);
310: FD_SET(sv[0], fdsr);
311: if (!tq_empty(&sigfwd_list))
312: FD_SET(sv[0], fdsw);
313: if (log_io)
314: fd_set_iobs(fdsr, fdsw); /* XXX - better name */
315: nready = select(maxfd + 1, fdsr, fdsw, NULL, NULL);
316: if (nready == -1) {
317: if (errno == EINTR)
318: continue;
319: error(1, _("select failed"));
320: }
321: if (FD_ISSET(sv[0], fdsw)) {
322: forward_signals(sv[0]);
323: }
324: if (FD_ISSET(signal_pipe[0], fdsr)) {
325: n = handle_signals(signal_pipe[0], child, log_io, cstat);
326: if (n == 0) {
327: /* Child has exited, cstat is set, we are done. */
328: goto done;
329: }
330: if (n == -1) {
331: /* Error reading signal_pipe[0], should not happen. */
332: break;
333: }
334: /* Restart event loop so signals get sent to child immediately. */
335: continue;
336: }
337: if (FD_ISSET(sv[0], fdsr)) {
338: /* read child status */
339: n = recv(sv[0], cstat, sizeof(*cstat), 0);
340: if (n == -1) {
341: if (errno == EINTR)
342: continue;
343: /*
344: * If not logging I/O we will receive ECONNRESET when
345: * the command is executed. It is safe to ignore this.
346: */
347: if (log_io && errno != EAGAIN) {
348: cstat->type = CMD_ERRNO;
349: cstat->val = errno;
350: break;
351: }
352: }
353: if (cstat->type == CMD_WSTATUS) {
354: if (WIFSTOPPED(cstat->val)) {
355: /* Suspend parent and tell child how to resume on return. */
356: sudo_debug(8, "child stopped, suspending parent");
357: n = suspend_parent(WSTOPSIG(cstat->val));
358: schedule_signal(n);
359: continue;
360: } else {
361: /* Child exited or was killed, either way we are done. */
362: break;
363: }
364: } else if (cstat->type == CMD_ERRNO) {
365: /* Child was unable to execute command or broken pipe. */
366: break;
367: }
368: }
369:
370: if (perform_io(fdsr, fdsw, cstat) != 0) {
371: /* I/O error, kill child if still alive and finish. */
372: schedule_signal(SIGKILL);
373: forward_signals(sv[0]);
374: break;
375: }
376: }
377:
378: if (log_io) {
379: /* Flush any remaining output and free pty-related memory. */
380: pty_close(cstat);
381: }
382:
383: #ifdef HAVE_SELINUX
384: if (ISSET(details->flags, CD_RBAC_ENABLED)) {
385: /* This is probably not needed in log_io mode. */
386: if (selinux_restore_tty() != 0)
387: warningx(_("unable to restore tty label"));
388: }
389: #endif
390:
391: done:
392: efree(fdsr);
393: efree(fdsw);
394: while (!tq_empty(&sigfwd_list)) {
395: struct sigforward *sigfwd = tq_first(&sigfwd_list);
396: tq_remove(&sigfwd_list, sigfwd);
397: efree(sigfwd);
398: }
399:
400: return cstat->type == CMD_ERRNO ? -1 : 0;
401: }
402:
403: /*
404: * Read signals on fd written to by handler().
405: * Returns -1 on error, 0 on child exit, else 1.
406: */
407: static int
408: handle_signals(int fd, pid_t child, int log_io, struct command_status *cstat)
409: {
410: unsigned char signo;
411: ssize_t nread;
412: int status;
413: pid_t pid;
414:
415: for (;;) {
416: /* read signal pipe */
417: nread = read(signal_pipe[0], &signo, sizeof(signo));
418: if (nread <= 0) {
419: /* It should not be possible to get EOF but just in case. */
420: if (nread == 0)
421: errno = ECONNRESET;
422: /* Restart if interrupted by signal so the pipe doesn't fill. */
423: if (errno == EINTR)
424: continue;
425: /* If pipe is empty, we are done. */
426: if (errno == EAGAIN)
427: break;
428: sudo_debug(9, "error reading signal pipe %s", strerror(errno));
429: cstat->type = CMD_ERRNO;
430: cstat->val = errno;
431: return -1;
432: }
433: sudo_debug(9, "received signal %d", signo);
434: if (signo == SIGCHLD) {
435: /*
436: * If logging I/O, child is the intermediate process,
437: * otherwise it is the command itself.
438: */
439: do {
440: pid = waitpid(child, &status, WUNTRACED|WNOHANG);
441: } while (pid == -1 && errno == EINTR);
442: if (pid == child) {
443: /* If not logging I/O and child has exited we are done. */
444: if (!log_io) {
445: if (WIFSTOPPED(status)) {
446: /*
447: * Save the controlling terminal's process group
448: * so we can restore it after we resume.
449: */
450: pid_t saved_pgrp = (pid_t)-1;
451: int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
452: if (fd != -1)
453: saved_pgrp = tcgetpgrp(fd);
454: if (kill(getpid(), WSTOPSIG(status)) != 0) {
455: warning("kill(%d, %d)", (int)getpid(),
456: WSTOPSIG(status));
457: }
458: if (fd != -1) {
459: if (saved_pgrp != (pid_t)-1)
460: (void)tcsetpgrp(fd, saved_pgrp);
461: close(fd);
462: }
463: } else {
464: /* Child has exited, we are done. */
465: cstat->type = CMD_WSTATUS;
466: cstat->val = status;
467: return 0;
468: }
469: }
470: /* Else we get ECONNRESET on sv[0] if child dies. */
471: }
472: } else {
473: if (log_io) {
474: /* Schedule signo to be forwared to the child. */
475: schedule_signal(signo);
476: } else {
477: /* Nothing listening on sv[0], send directly. */
478: if (signo == SIGALRM)
479: terminate_child(child, FALSE);
480: else if (kill(child, signo) != 0)
481: warning("kill(%d, %d)", (int)child, signo);
482: }
483: }
484: }
485: return 1;
486: }
487:
488: /*
489: * Forward signals in sigfwd_list to child listening on fd.
490: */
491: static void
492: forward_signals(int sock)
493: {
494: struct sigforward *sigfwd;
495: struct command_status cstat;
496: ssize_t nsent;
497:
498: while (!tq_empty(&sigfwd_list)) {
499: sigfwd = tq_first(&sigfwd_list);
500: sudo_debug(9, "sending signal %d to child over backchannel",
501: sigfwd->signo);
502: cstat.type = CMD_SIGNO;
503: cstat.val = sigfwd->signo;
504: do {
505: nsent = send(sock, &cstat, sizeof(cstat), 0);
506: } while (nsent == -1 && errno == EINTR);
507: tq_remove(&sigfwd_list, sigfwd);
508: efree(sigfwd);
509: if (nsent != sizeof(cstat)) {
510: if (errno == EPIPE) {
511: /* Other end of socket gone, empty out sigfwd_list. */
512: while (!tq_empty(&sigfwd_list)) {
513: sigfwd = tq_first(&sigfwd_list);
514: tq_remove(&sigfwd_list, sigfwd);
515: efree(sigfwd);
516: }
517: }
518: break;
519: }
520: }
521: }
522:
523: /*
524: * Schedule a signal to be forwared.
525: */
526: static void
527: schedule_signal(int signo)
528: {
529: struct sigforward *sigfwd;
530:
531: sigfwd = emalloc(sizeof(*sigfwd));
532: sigfwd->prev = sigfwd;
533: sigfwd->next = NULL;
534: sigfwd->signo = signo;
535: tq_append(&sigfwd_list, sigfwd);
536: }
537:
538: /*
539: * Generic handler for signals passed from parent -> child.
540: * The other end of signal_pipe is checked in the main event loop.
541: */
542: void
543: handler(int s)
544: {
545: unsigned char signo = (unsigned char)s;
546:
547: /*
548: * The pipe is non-blocking, if we overflow the kernel's pipe
549: * buffer we drop the signal. This is not a problem in practice.
550: */
551: if (write(signal_pipe[1], &signo, sizeof(signo)) == -1)
552: /* shut up glibc */;
553: }
554:
555: /*
556: * Open a pipe and make both ends non-blocking.
557: * Returns 0 on success and -1 on error.
558: */
559: int
560: pipe_nonblock(int fds[2])
561: {
562: int flags, rval;
563:
564: rval = pipe(fds);
565: if (rval != -1) {
566: flags = fcntl(fds[0], F_GETFL, 0);
567: if (flags != -1 && !ISSET(flags, O_NONBLOCK))
568: rval = fcntl(fds[0], F_SETFL, flags | O_NONBLOCK);
569: if (rval != -1) {
570: flags = fcntl(fds[1], F_GETFL, 0);
571: if (flags != -1 && !ISSET(flags, O_NONBLOCK))
572: rval = fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
573: }
574: if (rval == -1) {
575: close(fds[0]);
576: close(fds[1]);
577: }
578: }
579:
580: return rval;
581: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>