Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/src/exec_common.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2009-2022 Todd C. Miller <[email protected]>
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
#include <config.h>
20
21
#include <fcntl.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <unistd.h>
26
#ifdef HAVE_PRIV_SET
27
# include <priv.h>
28
#endif
29
#include <errno.h>
30
31
#include <sudo.h>
32
#include <sudo_exec.h>
33
34
/*
35
* Disable execution of child processes in the command we are about
36
* to run. On systems with privilege sets, we can remove the exec
37
* privilege. On other systems we use LD_PRELOAD and the like.
38
*/
39
char **
40
disable_execute(char *envp[], const char *dso)
41
{
42
debug_decl(disable_execute, SUDO_DEBUG_UTIL);
43
44
#ifdef HAVE_PRIV_SET
45
/* Solaris privileges, remove PRIV_PROC_EXEC post-execve. */
46
(void)priv_set(PRIV_ON, PRIV_INHERITABLE, "PRIV_FILE_DAC_READ", NULL);
47
(void)priv_set(PRIV_ON, PRIV_INHERITABLE, "PRIV_FILE_DAC_WRITE", NULL);
48
(void)priv_set(PRIV_ON, PRIV_INHERITABLE, "PRIV_FILE_DAC_SEARCH", NULL);
49
if (priv_set(PRIV_OFF, PRIV_LIMIT, "PRIV_PROC_EXEC", NULL) == 0)
50
debug_return_ptr(envp);
51
sudo_warn("%s", U_("unable to remove PRIV_PROC_EXEC from PRIV_LIMIT"));
52
#endif /* HAVE_PRIV_SET */
53
54
#ifdef RTLD_PRELOAD_VAR
55
if (dso != NULL)
56
envp = sudo_preload_dso(envp, dso, -1);
57
#endif /* RTLD_PRELOAD_VAR */
58
59
debug_return_ptr(envp);
60
}
61
62
/*
63
* Trap execution of child processes in the command we are about to run.
64
* Uses LD_PRELOAD and the like to perform a policy check on child commands.
65
*/
66
static char **
67
enable_intercept(char *envp[], const char *dso, int intercept_fd)
68
{
69
debug_decl(enable_intercept, SUDO_DEBUG_UTIL);
70
71
if (dso != NULL) {
72
#ifdef RTLD_PRELOAD_VAR
73
if (intercept_fd == -1)
74
sudo_fatalx("%s: no intercept fd", __func__);
75
76
envp = sudo_preload_dso(envp, dso, intercept_fd);
77
#else
78
/* Intercept not supported, envp unchanged. */
79
if (intercept_fd != -1)
80
close(intercept_fd);
81
#endif /* RTLD_PRELOAD_VAR */
82
}
83
84
debug_return_ptr(envp);
85
}
86
87
/*
88
* Like execve(2) but falls back to running through /bin/sh
89
* ala execvp(3) if we get ENOEXEC.
90
*/
91
int
92
sudo_execve(int fd, const char *path, char *const argv[], char *envp[],
93
int intercept_fd, unsigned int flags)
94
{
95
debug_decl(sudo_execve, SUDO_DEBUG_UTIL);
96
97
sudo_debug_execve(SUDO_DEBUG_INFO, path, argv, envp);
98
99
/* Modify the environment as needed to trap execve(). */
100
if (ISSET(flags, CD_NOEXEC))
101
envp = disable_execute(envp, sudo_conf_noexec_path());
102
if (ISSET(flags, CD_INTERCEPT|CD_LOG_SUBCMDS)) {
103
if (!ISSET(flags, CD_USE_PTRACE)) {
104
envp = enable_intercept(envp, sudo_conf_intercept_path(),
105
intercept_fd);
106
}
107
}
108
109
#ifdef HAVE_FEXECVE
110
if (fd != -1)
111
fexecve(fd, argv, envp);
112
else
113
#endif
114
execve(path, argv, envp);
115
if (fd == -1 && errno == ENOEXEC) {
116
int argc;
117
const char **nargv;
118
119
for (argc = 0; argv[argc] != NULL; argc++)
120
continue;
121
nargv = reallocarray(NULL, (size_t)argc + 2, sizeof(char *));
122
if (nargv != NULL) {
123
nargv[0] = "sh";
124
nargv[1] = path;
125
memcpy(nargv + 2, argv + 1, (size_t)argc * sizeof(char *));
126
execve(_PATH_SUDO_BSHELL, (char **)nargv, envp);
127
free(nargv);
128
}
129
}
130
debug_return_int(-1);
131
}
132
133