1 /*
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2009-2021 Todd C. Miller <Todd.Miller@sudo.ws>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * This is an open source non-commercial project. Dear PVS-Studio, please check it.
21  * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
22  */
23 
24 #include <config.h>
25 
26 #include <sys/resource.h>
27 #include <sys/stat.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <pwd.h>
34 #include <signal.h>
35 #ifdef HAVE_LOGIN_CAP_H
36 # include <login_cap.h>
37 # ifndef LOGIN_SETENV
38 #  define LOGIN_SETENV  0
39 # endif
40 #endif
41 #ifdef HAVE_PROJECT_H
42 # include <project.h>
43 # include <sys/task.h>
44 #endif
45 
46 #include "sudo.h"
47 #include "sudo_exec.h"
48 #include "sudo_plugin.h"
49 #include "sudo_plugin_int.h"
50 
51 static void
close_fds(struct command_details * details,int errfd,int intercept_fd)52 close_fds(struct command_details *details, int errfd, int intercept_fd)
53 {
54     int fd, maxfd;
55     unsigned char *debug_fds;
56     debug_decl(close_fds, SUDO_DEBUG_EXEC);
57 
58     if (details->closefrom < 0)
59 	debug_return;
60 
61     /* Preserve debug fds and error pipe as needed. */
62     maxfd = sudo_debug_get_fds(&debug_fds);
63     for (fd = 0; fd <= maxfd; fd++) {
64 	if (sudo_isset(debug_fds, fd))
65 	    add_preserved_fd(&details->preserved_fds, fd);
66     }
67     if (errfd != -1)
68 	add_preserved_fd(&details->preserved_fds, errfd);
69     if (intercept_fd != -1)
70 	add_preserved_fd(&details->preserved_fds, intercept_fd);
71 
72     /* Close all fds except those explicitly preserved. */
73     closefrom_except(details->closefrom, &details->preserved_fds);
74 
75     debug_return;
76 }
77 
78 /*
79  * Setup the execution environment immediately prior to the call to execve().
80  * Group setup is performed by policy_init_session(), called earlier.
81  * Returns true on success and false on failure.
82  */
83 static bool
exec_setup(struct command_details * details,int intercept_fd,int errfd)84 exec_setup(struct command_details *details, int intercept_fd, int errfd)
85 {
86     bool ret = false;
87     debug_decl(exec_setup, SUDO_DEBUG_EXEC);
88 
89     if (details->pw != NULL) {
90 #ifdef HAVE_PROJECT_H
91 	set_project(details->pw);
92 #endif
93 #ifdef HAVE_PRIV_SET
94 	if (details->privs != NULL) {
95 	    if (setppriv(PRIV_SET, PRIV_INHERITABLE, details->privs) != 0) {
96 		sudo_warn("unable to set privileges");
97 		goto done;
98 	    }
99 	}
100 	if (details->limitprivs != NULL) {
101 	    if (setppriv(PRIV_SET, PRIV_LIMIT, details->limitprivs) != 0) {
102 		sudo_warn("unable to set limit privileges");
103 		goto done;
104 	    }
105 	} else if (details->privs != NULL) {
106 	    if (setppriv(PRIV_SET, PRIV_LIMIT, details->privs) != 0) {
107 		sudo_warn("unable to set limit privileges");
108 		goto done;
109 	    }
110 	}
111 #endif /* HAVE_PRIV_SET */
112 
113 #ifdef HAVE_GETUSERATTR
114 	if (aix_prep_user(details->pw->pw_name, details->tty) != 0) {
115 	    /* error message displayed by aix_prep_user */
116 	    goto done;
117 	}
118 #endif
119 #ifdef HAVE_LOGIN_CAP_H
120 	if (details->login_class) {
121 	    int flags;
122 	    login_cap_t *lc;
123 
124 	    /*
125 	     * We only use setusercontext() to set the nice value, rlimits
126 	     * and umask unless this is a login shell (sudo -i).
127 	     */
128 	    lc = login_getclass((char *)details->login_class);
129 	    if (!lc) {
130 		sudo_warnx(U_("unknown login class %s"), details->login_class);
131 		errno = ENOENT;
132 		goto done;
133 	    }
134 	    if (ISSET(details->flags, CD_LOGIN_SHELL)) {
135 		/* Set everything except user, group and login name. */
136 		flags = LOGIN_SETALL;
137 		CLR(flags, LOGIN_SETGROUP|LOGIN_SETLOGIN|LOGIN_SETUSER|LOGIN_SETENV|LOGIN_SETPATH);
138 	    } else {
139 		flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY|LOGIN_SETUMASK;
140 	    }
141 	    if (setusercontext(lc, details->pw, details->pw->pw_uid, flags)) {
142 		sudo_warn("%s", U_("unable to set user context"));
143 		if (details->pw->pw_uid != ROOT_UID)
144 		    goto done;
145 	    }
146 	}
147 #endif /* HAVE_LOGIN_CAP_H */
148     }
149 
150     if (ISSET(details->flags, CD_SET_GROUPS)) {
151 	/* set_user_groups() prints error message on failure. */
152 	if (!set_user_groups(details))
153 	    goto done;
154     }
155 
156     if (ISSET(details->flags, CD_SET_PRIORITY)) {
157 	if (setpriority(PRIO_PROCESS, 0, details->priority) != 0) {
158 	    sudo_warn("%s", U_("unable to set process priority"));
159 	    goto done;
160 	}
161     }
162 
163     /* Policy may override umask in PAM or login.conf. */
164     if (ISSET(details->flags, CD_OVERRIDE_UMASK))
165 	(void) umask(details->umask);
166 
167     /* Close fds before chroot (need /dev) or uid change (prlimit on Linux). */
168     close_fds(details, errfd, intercept_fd);
169 
170     if (details->chroot) {
171 	if (chroot(details->chroot) != 0 || chdir("/") != 0) {
172 	    sudo_warn(U_("unable to change root to %s"), details->chroot);
173 	    goto done;
174 	}
175     }
176 
177     /*
178      * Unlimit the number of processes since Linux's setuid() will
179      * return EAGAIN if RLIMIT_NPROC would be exceeded by the uid switch.
180      */
181     unlimit_nproc();
182 
183 #if defined(HAVE_SETRESUID)
184     if (setresuid(details->cred.uid, details->cred.euid, details->cred.euid) != 0) {
185 	sudo_warn(U_("unable to change to runas uid (%u, %u)"),
186 	    (unsigned int)details->cred.uid, (unsigned int)details->cred.euid);
187 	goto done;
188     }
189 #elif defined(HAVE_SETREUID)
190     if (setreuid(details->cred.uid, details->cred.euid) != 0) {
191 	sudo_warn(U_("unable to change to runas uid (%u, %u)"),
192 	    (unsigned int)details->cred.uid, (unsigned int)details->cred.euid);
193 	goto done;
194     }
195 #else
196     /* Cannot support real user-ID that is different from effective user-ID. */
197     if (setuid(details->cred.euid) != 0) {
198 	sudo_warn(U_("unable to change to runas uid (%u, %u)"),
199 	    (unsigned int)details->cred.euid, (unsigned int)details->cred.euid);
200 	goto done;
201     }
202 #endif /* !HAVE_SETRESUID && !HAVE_SETREUID */
203 
204     /* Restore previous value of RLIMIT_NPROC. */
205     restore_nproc();
206 
207     /*
208      * Only change cwd if we have chroot()ed or the policy modules
209      * specifies a different cwd.  Must be done after uid change.
210      */
211     if (details->cwd != NULL) {
212 	if (details->chroot != NULL || user_details.cwd == NULL ||
213 	    strcmp(details->cwd, user_details.cwd) != 0) {
214 	    /* Note: cwd is relative to the new root, if any. */
215 	    if (chdir(details->cwd) == -1) {
216 		sudo_warn(U_("unable to change directory to %s"), details->cwd);
217 		if (!details->cwd_optional)
218 		    goto done;
219 		if (details->chroot != NULL)
220 		    sudo_warnx(U_("starting from %s"), "/");
221 	    }
222 	}
223     }
224 
225     ret = true;
226 
227 done:
228     debug_return_bool(ret);
229 }
230 
231 /*
232  * Setup the execution environment and execute the command.
233  * If SELinux is enabled, run the command via sesh, otherwise
234  * execute it directly.
235  * If the exec fails, cstat is filled in with the value of errno.
236  */
237 void
exec_cmnd(struct command_details * details,int intercept_fd,int errfd)238 exec_cmnd(struct command_details *details, int intercept_fd, int errfd)
239 {
240     debug_decl(exec_cmnd, SUDO_DEBUG_EXEC);
241 
242     restore_signals();
243     if (exec_setup(details, intercept_fd, errfd) == true) {
244 	/* headed for execve() */
245 #ifdef HAVE_SELINUX
246 	if (ISSET(details->flags, CD_RBAC_ENABLED)) {
247 	    selinux_execve(details->execfd, details->command, details->argv,
248 		details->envp, ISSET(details->flags, CD_NOEXEC));
249 	} else
250 #endif
251 	{
252 	    sudo_execve(details->execfd, details->command, details->argv,
253 		details->envp, intercept_fd, details->flags);
254 	}
255     }
256     sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to exec %s: %s",
257 	details->command, strerror(errno));
258     debug_return;
259 }
260 
261 /*
262  * Check for caught signals sent to sudo before command execution.
263  * Also suspends the process if SIGTSTP was caught.
264  * Returns true if we should terminate, else false.
265  */
266 bool
sudo_terminated(struct command_status * cstat)267 sudo_terminated(struct command_status *cstat)
268 {
269     int signo;
270     bool sigtstp = false;
271     debug_decl(sudo_terminated, SUDO_DEBUG_EXEC);
272 
273     for (signo = 0; signo < NSIG; signo++) {
274 	if (signal_pending(signo)) {
275 	    switch (signo) {
276 	    case SIGCHLD:
277 		/* Ignore. */
278 		break;
279 	    case SIGTSTP:
280 		/* Suspend below if not terminated. */
281 		sigtstp = true;
282 		break;
283 	    default:
284 		/* Terminal signal, do not exec command. */
285 		cstat->type = CMD_WSTATUS;
286 		cstat->val = signo + 128;
287 		debug_return_bool(true);
288 		break;
289 	    }
290 	}
291     }
292     if (sigtstp) {
293 	struct sigaction sa;
294 	sigset_t set, oset;
295 
296 	/* Send SIGTSTP to ourselves, unblocking it if needed. */
297 	memset(&sa, 0, sizeof(sa));
298 	sigemptyset(&sa.sa_mask);
299 	sa.sa_flags = SA_RESTART;
300 	sa.sa_handler = SIG_DFL;
301 	if (sudo_sigaction(SIGTSTP, &sa, NULL) != 0)
302 	    sudo_warn(U_("unable to set handler for signal %d"), SIGTSTP);
303 	sigemptyset(&set);
304 	sigaddset(&set, SIGTSTP);
305 	sigprocmask(SIG_UNBLOCK, &set, &oset);
306 	if (kill(getpid(), SIGTSTP) != 0)
307 	    sudo_warn("kill(%d, SIGTSTP)", (int)getpid());
308 	sigprocmask(SIG_SETMASK, &oset, NULL);
309 	/* No need to restore old SIGTSTP handler. */
310     }
311     debug_return_bool(false);
312 }
313 
314 #if SUDO_API_VERSION != SUDO_API_MKVERSION(1, 17)
315 # error "Update sudo_needs_pty() after changing the plugin API"
316 #endif
317 static bool
sudo_needs_pty(struct command_details * details)318 sudo_needs_pty(struct command_details *details)
319 {
320     struct plugin_container *plugin;
321 
322     if (ISSET(details->flags, CD_USE_PTY|CD_INTERCEPT|CD_LOG_SUBCMDS))
323 	return true;
324 
325     TAILQ_FOREACH(plugin, &io_plugins, entries) {
326 	if (plugin->u.io->log_ttyin != NULL ||
327 	    plugin->u.io->log_ttyout != NULL ||
328 	    plugin->u.io->log_stdin != NULL ||
329 	    plugin->u.io->log_stdout != NULL ||
330 	    plugin->u.io->log_stderr != NULL ||
331 	    plugin->u.io->change_winsize != NULL ||
332 	    plugin->u.io->log_suspend != NULL)
333 	    return true;
334     }
335     return false;
336 }
337 
338 /*
339  * If we are not running the command in a pty, we were not invoked as
340  * sudoedit, there is no command timeout and there is no close function,
341  * sudo can exec the command directly (and not wait).
342  */
343 static bool
direct_exec_allowed(struct command_details * details)344 direct_exec_allowed(struct command_details *details)
345 {
346     struct plugin_container *plugin;
347     debug_decl(direct_exec_allowed, SUDO_DEBUG_EXEC);
348 
349     /* Assumes sudo_needs_pty() was already checked. */
350     if (ISSET(details->flags, CD_RBAC_ENABLED|CD_SET_TIMEOUT|CD_SUDOEDIT) ||
351 	    policy_plugin.u.policy->close != NULL)
352 	debug_return_bool(false);
353 
354     TAILQ_FOREACH(plugin, &audit_plugins, entries) {
355 	if (plugin->u.audit->close != NULL)
356 	    debug_return_bool(false);
357     }
358 
359     debug_return_bool(true);
360 }
361 
362 /*
363  * Execute a command, potentially in a pty with I/O logging, and
364  * wait for it to finish.
365  * This is a little bit tricky due to how POSIX job control works and
366  * we fact that we have two different controlling terminals to deal with.
367  */
368 int
sudo_execute(struct command_details * details,struct command_status * cstat)369 sudo_execute(struct command_details *details, struct command_status *cstat)
370 {
371     debug_decl(sudo_execute, SUDO_DEBUG_EXEC);
372 
373     /* If running in background mode, fork and exit. */
374     if (ISSET(details->flags, CD_BACKGROUND)) {
375 	switch (sudo_debug_fork()) {
376 	    case -1:
377 		cstat->type = CMD_ERRNO;
378 		cstat->val = errno;
379 		debug_return_int(-1);
380 	    case 0:
381 		/* child continues without controlling terminal */
382 		(void)setpgid(0, 0);
383 		break;
384 	    default:
385 		/* parent exits (but does not flush buffers) */
386 		sudo_debug_exit_int(__func__, __FILE__, __LINE__,
387 		    sudo_debug_subsys, 0);
388 		_exit(EXIT_SUCCESS);
389 	}
390     }
391 
392     /*
393      * Restore resource limits before running.
394      * We must do this *before* calling the PAM session module.
395      */
396     restore_limits();
397 
398     /*
399      * Run the command in a new pty if there is an I/O plugin or the policy
400      * has requested a pty.  If /dev/tty is unavailable and no I/O plugin
401      * is configured, this returns false and we run the command without a pty.
402      */
403     if (sudo_needs_pty(details)) {
404 	if (exec_pty(details, cstat))
405 	    goto done;
406     }
407 
408     /*
409      * If we are not running the command in a pty, we may be able to
410      * exec directly, depending on the plugins used.
411      */
412     if (direct_exec_allowed(details)) {
413 	if (!sudo_terminated(cstat)) {
414 	    exec_cmnd(details, -1, -1);
415 	    cstat->type = CMD_ERRNO;
416 	    cstat->val = errno;
417 	}
418 	goto done;
419     }
420 
421     /*
422      * Run the command in the existing tty (if any) and wait for it to finish.
423      */
424     exec_nopty(details, cstat);
425 
426 done:
427     /* The caller will run any plugin close functions. */
428     debug_return_int(cstat->type == CMD_ERRNO ? -1 : 0);
429 }
430 
431 /*
432  * Kill command with increasing urgency.
433  */
434 void
terminate_command(pid_t pid,bool use_pgrp)435 terminate_command(pid_t pid, bool use_pgrp)
436 {
437     debug_decl(terminate_command, SUDO_DEBUG_EXEC);
438 
439     /* Avoid killing more than a single process or process group. */
440     if (pid <= 0)
441 	debug_return;
442 
443     /*
444      * Note that SIGCHLD will interrupt the sleep()
445      */
446     if (use_pgrp) {
447 	sudo_debug_printf(SUDO_DEBUG_INFO, "killpg %d SIGHUP", (int)pid);
448 	killpg(pid, SIGHUP);
449 	sudo_debug_printf(SUDO_DEBUG_INFO, "killpg %d SIGTERM", (int)pid);
450 	killpg(pid, SIGTERM);
451 	sleep(2);
452 	sudo_debug_printf(SUDO_DEBUG_INFO, "killpg %d SIGKILL", (int)pid);
453 	killpg(pid, SIGKILL);
454     } else {
455 	sudo_debug_printf(SUDO_DEBUG_INFO, "kill %d SIGHUP", (int)pid);
456 	kill(pid, SIGHUP);
457 	sudo_debug_printf(SUDO_DEBUG_INFO, "kill %d SIGTERM", (int)pid);
458 	kill(pid, SIGTERM);
459 	sleep(2);
460 	sudo_debug_printf(SUDO_DEBUG_INFO, "kill %d SIGKILL", (int)pid);
461 	kill(pid, SIGKILL);
462     }
463 
464     debug_return;
465 }
466