Lines 1-208
Link Here
|
1 |
--- plugins/sudoers/match.c Mon Jan 15 10:31:56 2018 -0700 |
|
|
2 |
+++ plugins/sudoers/match.c Tue Apr 24 09:49:28 2018 -0600 |
3 |
@@ -1,5 +1,5 @@ |
4 |
/* |
5 |
- * Copyright (c) 1996, 1998-2005, 2007-2017 |
6 |
+ * Copyright (c) 1996, 1998-2005, 2007-2018 |
7 |
* Todd C. Miller <Todd.Miller@sudo.ws> |
8 |
* |
9 |
* Permission to use, copy, modify, and distribute this software for any |
10 |
@@ -447,31 +447,20 @@ do_stat(int fd, const char *path, struct |
11 |
} |
12 |
|
13 |
/* |
14 |
- * On systems with fexecve(2), set the close-on-exec flag on the file |
15 |
- * descriptor only if the file is not a script. Because scripts need |
16 |
- * to be executed by an interpreter the fd must remain open for the |
17 |
- * interpreter to use. |
18 |
+ * Check whether the fd refers to a shell script with a "#!" shebang. |
19 |
*/ |
20 |
-static void |
21 |
-set_cloexec(int fd) |
22 |
+static bool |
23 |
+is_script(int fd) |
24 |
{ |
25 |
- bool is_script = false; |
26 |
-#ifdef HAVE_FEXECVE |
27 |
+ bool ret = false; |
28 |
char magic[2]; |
29 |
|
30 |
- /* Check for #! cookie and set is_script. */ |
31 |
if (read(fd, magic, 2) == 2) { |
32 |
if (magic[0] == '#' && magic[1] == '!') |
33 |
- is_script = true; |
34 |
+ ret = true; |
35 |
} |
36 |
(void) lseek(fd, (off_t)0, SEEK_SET); |
37 |
-#endif /* HAVE_FEXECVE */ |
38 |
- /* |
39 |
- * Shell scripts go through namei twice and so we can't set the close |
40 |
- * on exec flag on the fd for fexecve(2). |
41 |
- */ |
42 |
- if (!is_script) |
43 |
- (void)fcntl(fd, F_SETFD, FD_CLOEXEC); |
44 |
+ return ret; |
45 |
} |
46 |
|
47 |
/* |
48 |
@@ -500,16 +489,57 @@ open_cmnd(const char *path, const struct |
49 |
if (fd == -1) |
50 |
debug_return_bool(false); |
51 |
|
52 |
- set_cloexec(fd); |
53 |
+ (void)fcntl(fd, F_SETFD, FD_CLOEXEC); |
54 |
*fdp = fd; |
55 |
debug_return_bool(true); |
56 |
} |
57 |
|
58 |
+static void |
59 |
+set_cmnd_fd(int fd) |
60 |
+{ |
61 |
+ debug_decl(set_cmnd_fd, SUDOERS_DEBUG_MATCH) |
62 |
+ |
63 |
+ if (cmnd_fd != -1) |
64 |
+ close(cmnd_fd); |
65 |
+ |
66 |
+ if (fd != -1) { |
67 |
+ if (def_fdexec == never) { |
68 |
+ /* Never use fexedcve() */ |
69 |
+ close(fd); |
70 |
+ fd = -1; |
71 |
+ } else if (is_script(fd)) { |
72 |
+ char fdpath[PATH_MAX]; |
73 |
+ struct stat sb; |
74 |
+ int flags; |
75 |
+ |
76 |
+ /* We can only use fexecve() on a script if /dev/fd/N exists. */ |
77 |
+ snprintf(fdpath, sizeof(fdpath), "/dev/fd/%d", fd); |
78 |
+ if (stat(fdpath, &sb) != 0) { |
79 |
+ /* Missing /dev/fd file, can't use fexecve(). */ |
80 |
+ close(fd); |
81 |
+ fd = -1; |
82 |
+ } else { |
83 |
+ /* |
84 |
+ * Shell scripts go through namei twice so we can't have the |
85 |
+ * close on exec flag set on the fd for fexecve(2). |
86 |
+ */ |
87 |
+ flags = fcntl(fd, F_GETFD) & ~FD_CLOEXEC; |
88 |
+ (void)fcntl(fd, F_SETFD, flags); |
89 |
+ } |
90 |
+ } |
91 |
+ } |
92 |
+ |
93 |
+ cmnd_fd = fd; |
94 |
+ |
95 |
+ debug_return; |
96 |
+} |
97 |
+ |
98 |
static bool |
99 |
command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args, |
100 |
const struct sudo_digest *digest) |
101 |
{ |
102 |
struct stat sb; /* XXX - unused */ |
103 |
+ int fd = -1; |
104 |
debug_decl(command_matches_fnmatch, SUDOERS_DEBUG_MATCH) |
105 |
|
106 |
/* |
107 |
@@ -522,30 +552,22 @@ command_matches_fnmatch(const char *sudo |
108 |
if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0) |
109 |
debug_return_bool(false); |
110 |
if (command_args_match(sudoers_cmnd, sudoers_args)) { |
111 |
- if (cmnd_fd != -1) { |
112 |
- close(cmnd_fd); |
113 |
- cmnd_fd = -1; |
114 |
- } |
115 |
/* Open the file for fdexec or for digest matching. */ |
116 |
- if (!open_cmnd(user_cmnd, digest, &cmnd_fd)) |
117 |
+ if (!open_cmnd(user_cmnd, digest, &fd)) |
118 |
goto bad; |
119 |
- if (!do_stat(cmnd_fd, user_cmnd, &sb)) |
120 |
+ if (!do_stat(fd, user_cmnd, &sb)) |
121 |
goto bad; |
122 |
/* Check digest of user_cmnd since sudoers_cmnd is a pattern. */ |
123 |
- if (digest != NULL) { |
124 |
- if (!digest_matches(cmnd_fd, user_cmnd, digest)) |
125 |
- goto bad; |
126 |
- if (def_fdexec == never) { |
127 |
- close(cmnd_fd); |
128 |
- cmnd_fd = -1; |
129 |
- } |
130 |
- } |
131 |
+ if (digest != NULL && !digest_matches(fd, user_cmnd, digest)) |
132 |
+ goto bad; |
133 |
+ set_cmnd_fd(fd); |
134 |
+ |
135 |
/* No need to set safe_cmnd since user_cmnd matches sudoers_cmnd */ |
136 |
debug_return_bool(true); |
137 |
bad: |
138 |
- if (cmnd_fd != -1) { |
139 |
- close(cmnd_fd); |
140 |
- cmnd_fd = -1; |
141 |
+ if (fd != -1) { |
142 |
+ close(fd); |
143 |
+ fd = -1; |
144 |
} |
145 |
debug_return_bool(false); |
146 |
} |
147 |
@@ -673,16 +695,7 @@ done: |
148 |
if (cp != NULL) { |
149 |
if (command_args_match(sudoers_cmnd, sudoers_args)) { |
150 |
/* safe_cmnd was set above. */ |
151 |
- if (cmnd_fd != -1) { |
152 |
- close(cmnd_fd); |
153 |
- cmnd_fd = -1; |
154 |
- } |
155 |
- if (fd != -1) { |
156 |
- if (def_fdexec == never) |
157 |
- close(fd); |
158 |
- else |
159 |
- cmnd_fd = fd; |
160 |
- } |
161 |
+ set_cmnd_fd(fd); |
162 |
debug_return_bool(true); |
163 |
} |
164 |
} |
165 |
@@ -728,6 +741,7 @@ digest_matches(int fd, const char *file, |
166 |
debug_decl(digest_matches, SUDOERS_DEBUG_MATCH) |
167 |
|
168 |
file_digest = sudo_filedigest(fd, file, sd->digest_type, &digest_len); |
169 |
+ lseek(fd, SEEK_SET, (off_t)0); |
170 |
if (file_digest == NULL) { |
171 |
/* Warning (if any) printed by sudo_filedigest() */ |
172 |
goto done; |
173 |
@@ -826,16 +840,7 @@ command_matches_normal(const char *sudoe |
174 |
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); |
175 |
goto bad; |
176 |
} |
177 |
- if (cmnd_fd != -1) { |
178 |
- close(cmnd_fd); |
179 |
- cmnd_fd = -1; |
180 |
- } |
181 |
- if (fd != -1) { |
182 |
- if (def_fdexec == never) |
183 |
- close(fd); |
184 |
- else |
185 |
- cmnd_fd = fd; |
186 |
- } |
187 |
+ set_cmnd_fd(fd); |
188 |
debug_return_bool(true); |
189 |
bad: |
190 |
if (fd != -1) |
191 |
@@ -921,16 +926,7 @@ command_matches_dir(const char *sudoers_ |
192 |
closedir(dirp); |
193 |
|
194 |
if (dent != NULL) { |
195 |
- if (cmnd_fd != -1) { |
196 |
- close(cmnd_fd); |
197 |
- cmnd_fd = -1; |
198 |
- } |
199 |
- if (fd != -1) { |
200 |
- if (def_fdexec == never) |
201 |
- close(fd); |
202 |
- else |
203 |
- cmnd_fd = fd; |
204 |
- } |
205 |
+ set_cmnd_fd(fd); |
206 |
debug_return_bool(true); |
207 |
} |
208 |
if (fd != -1) |