summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/recipes-extended/sudo/files/CVE-2021-23240.patch419
-rw-r--r--meta/recipes-extended/sudo/sudo_1.9.3.bb1
2 files changed, 420 insertions, 0 deletions
diff --git a/meta/recipes-extended/sudo/files/CVE-2021-23240.patch b/meta/recipes-extended/sudo/files/CVE-2021-23240.patch
new file mode 100644
index 0000000000..740a13cd90
--- /dev/null
+++ b/meta/recipes-extended/sudo/files/CVE-2021-23240.patch
@@ -0,0 +1,419 @@
1Upstream-Status: Backport [https://www.sudo.ws/repos/sudo/rev/8fcb36ef422a]
2Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
3CVE: CVE-2021-23240
4
5# HG changeset patch
6# User Todd C. Miller <Todd.Miller@sudo.ws>
7# Date 1609953360 25200
8# Node ID 8fcb36ef422a251fe33738a347551439944a4a37
9# Parent ea19d0073c02951bbbf35342dd63304da83edce8
10Add security checks before using temp files for SELinux RBAC sudoedit.
11Otherwise, it may be possible for the user running sudoedit to
12replace the newly-created temporary files with a symbolic link and
13have sudoedit set the owner of an arbitrary file.
14Problem reported by Matthias Gerstner of SUSE.
15
16diff -r ea19d0073c02 -r 8fcb36ef422a src/copy_file.c
17--- a/src/copy_file.c Wed Jan 06 10:16:00 2021 -0700
18+++ b/src/copy_file.c Wed Jan 06 10:16:00 2021 -0700
19@@ -1,7 +1,7 @@
20 /*
21 * SPDX-License-Identifier: ISC
22 *
23- * Copyright (c) 2020 Todd C. Miller <Todd.Miller@sudo.ws>
24+ * Copyright (c) 2020-2021 Todd C. Miller <Todd.Miller@sudo.ws>
25 *
26 * Permission to use, copy, modify, and distribute this software for any
27 * purpose with or without fee is hereby granted, provided that the above
28@@ -23,6 +23,8 @@
29
30 #include <config.h>
31
32+#include <sys/stat.h>
33+
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <errno.h>
37@@ -134,3 +136,34 @@
38 sudo_warn(U_("unable to write to %s"), dst);
39 debug_return_int(-1);
40 }
41+
42+#ifdef HAVE_SELINUX
43+bool
44+sudo_check_temp_file(int tfd, const char *tfile, uid_t uid, struct stat *sb)
45+{
46+ struct stat sbuf;
47+ debug_decl(sudo_check_temp_file, SUDO_DEBUG_UTIL);
48+
49+ if (sb == NULL)
50+ sb = &sbuf;
51+
52+ if (fstat(tfd, sb) == -1) {
53+ sudo_warn(U_("unable to stat %s"), tfile);
54+ debug_return_bool(false);
55+ }
56+ if (!S_ISREG(sb->st_mode)) {
57+ sudo_warnx(U_("%s: not a regular file"), tfile);
58+ debug_return_bool(false);
59+ }
60+ if ((sb->st_mode & ALLPERMS) != (S_IRUSR|S_IWUSR)) {
61+ sudo_warnx(U_("%s: bad file mode: 0%o"), tfile, sb->st_mode & ALLPERMS);
62+ debug_return_bool(false);
63+ }
64+ if (sb->st_uid != uid) {
65+ sudo_warnx(U_("%s is owned by uid %u, should be %u"),
66+ tfile, (unsigned int)sb->st_uid, (unsigned int)uid);
67+ debug_return_bool(false);
68+ }
69+ debug_return_bool(true);
70+}
71+#endif /* SELINUX */
72diff -r ea19d0073c02 -r 8fcb36ef422a src/sesh.c
73--- a/src/sesh.c Wed Jan 06 10:16:00 2021 -0700
74+++ b/src/sesh.c Wed Jan 06 10:16:00 2021 -0700
75@@ -1,7 +1,7 @@
76 /*
77 * SPDX-License-Identifier: ISC
78 *
79- * Copyright (c) 2008, 2010-2018, 2020 Todd C. Miller <Todd.Miller@sudo.ws>
80+ * Copyright (c) 2008, 2010-2018, 2020-2021 Todd C. Miller <Todd.Miller@sudo.ws>
81 *
82 * Permission to use, copy, modify, and distribute this software for any
83 * purpose with or without fee is hereby granted, provided that the above
84@@ -132,7 +132,7 @@
85 static int
86 sesh_sudoedit(int argc, char *argv[])
87 {
88- int i, oflags_dst, post, ret = SESH_ERR_FAILURE;
89+ int i, oflags_src, oflags_dst, post, ret = SESH_ERR_FAILURE;
90 int fd_src = -1, fd_dst = -1, follow = 0;
91 struct stat sb;
92 struct timespec times[2];
93@@ -174,10 +174,12 @@
94 debug_return_int(SESH_ERR_BAD_PATHS);
95
96 /*
97- * Use O_EXCL if we are not in the post editing stage
98- * so that it's ensured that the temporary files are
99- * created by us and that we are not opening any symlinks.
100+ * In the pre-editing stage, use O_EXCL to ensure that the temporary
101+ * files are created by us and that we are not opening any symlinks.
102+ * In the post-editing stage, use O_NOFOLLOW so we don't follow symlinks
103+ * when opening the temporary files.
104 */
105+ oflags_src = O_RDONLY|(post ? O_NONBLOCK|O_NOFOLLOW : follow);
106 oflags_dst = O_WRONLY|O_CREAT|(post ? follow : O_EXCL);
107 for (i = 0; i < argc - 1; i += 2) {
108 const char *path_src = argv[i];
109@@ -187,7 +189,7 @@
110 * doesn't exist, that's OK, we'll create an empty
111 * destination file.
112 */
113- if ((fd_src = open(path_src, O_RDONLY|follow, S_IRUSR|S_IWUSR)) < 0) {
114+ if ((fd_src = open(path_src, oflags_src, S_IRUSR|S_IWUSR)) < 0) {
115 if (errno != ENOENT) {
116 sudo_warn("%s", path_src);
117 if (post) {
118@@ -197,6 +199,14 @@
119 goto cleanup_0;
120 }
121 }
122+ if (post) {
123+ /* Make sure the temporary file is safe and has the proper owner. */
124+ if (!sudo_check_temp_file(fd_src, path_src, geteuid(), &sb)) {
125+ ret = SESH_ERR_SOME_FILES;
126+ goto nocleanup;
127+ }
128+ fcntl(fd_src, F_SETFL, fcntl(fd_src, F_GETFL, 0) & ~O_NONBLOCK);
129+ }
130
131 if ((fd_dst = open(path_dst, oflags_dst, post ?
132 (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) : (S_IRUSR|S_IWUSR))) < 0) {
133@@ -214,10 +224,7 @@
134 off_t len_dst = -1;
135
136 if (post) {
137- if (fstat(fd_src, &sb) != 0) {
138- ret = SESH_ERR_SOME_FILES;
139- goto nocleanup;
140- }
141+ /* sudo_check_temp_file() filled in sb for us. */
142 len_src = sb.st_size;
143 if (fstat(fd_dst, &sb) != 0) {
144 ret = SESH_ERR_SOME_FILES;
145diff -r ea19d0073c02 -r 8fcb36ef422a src/sudo_edit.c
146--- a/src/sudo_edit.c Wed Jan 06 10:16:00 2021 -0700
147+++ b/src/sudo_edit.c Wed Jan 06 10:16:00 2021 -0700
148@@ -1,7 +1,7 @@
149 /*
150 * SPDX-License-Identifier: ISC
151 *
152- * Copyright (c) 2004-2008, 2010-2020 Todd C. Miller <Todd.Miller@sudo.ws>
153+ * Copyright (c) 2004-2008, 2010-2021 Todd C. Miller <Todd.Miller@sudo.ws>
154 *
155 * Permission to use, copy, modify, and distribute this software for any
156 * purpose with or without fee is hereby granted, provided that the above
157@@ -259,8 +259,10 @@
158 } else {
159 len = asprintf(tfile, "%s/%s.XXXXXXXX", edit_tmpdir, cp);
160 }
161- if (len == -1)
162- sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
163+ if (len == -1) {
164+ sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
165+ debug_return_int(-1);
166+ }
167 tfd = mkstemps(*tfile, suff ? strlen(suff) : 0);
168 sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
169 "%s -> %s, fd %d", ofile, *tfile, tfd);
170@@ -735,7 +737,8 @@
171
172 #ifdef HAVE_SELINUX
173 static int
174-selinux_run_helper(char *argv[], char *envp[])
175+selinux_run_helper(uid_t uid, gid_t gid, int ngroups, GETGROUPS_T *groups,
176+ char *const argv[], char *const envp[])
177 {
178 int status, ret = SESH_ERR_FAILURE;
179 const char *sesh;
180@@ -755,8 +758,10 @@
181 break;
182 case 0:
183 /* child runs sesh in new context */
184- if (selinux_setcon() == 0)
185+ if (selinux_setcon() == 0) {
186+ switch_user(uid, gid, ngroups, groups);
187 execve(sesh, argv, envp);
188+ }
189 _exit(SESH_ERR_FAILURE);
190 default:
191 /* parent waits */
192@@ -775,7 +780,7 @@
193 struct tempfile *tf, char *files[], int nfiles)
194 {
195 char **sesh_args, **sesh_ap;
196- int i, rc, sesh_nargs;
197+ int i, error, sesh_nargs, ret = -1;
198 struct stat sb;
199 debug_decl(selinux_edit_create_tfiles, SUDO_DEBUG_EDIT);
200
201@@ -787,7 +792,7 @@
202 sesh_args = sesh_ap = reallocarray(NULL, sesh_nargs, sizeof(char *));
203 if (sesh_args == NULL) {
204 sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
205- debug_return_int(-1);
206+ goto done;
207 }
208 *sesh_ap++ = "sesh";
209 *sesh_ap++ = "-e";
210@@ -795,7 +800,6 @@
211 *sesh_ap++ = "-h";
212 *sesh_ap++ = "0";
213
214- /* XXX - temp files should be created with user's context */
215 for (i = 0; i < nfiles; i++) {
216 char *tfile, *ofile = files[i];
217 int tfd;
218@@ -813,8 +817,7 @@
219 if (tfd == -1) {
220 sudo_warn("mkstemps");
221 free(tfile);
222- free(sesh_args);
223- debug_return_int(-1);
224+ goto done;
225 }
226 /* Helper will re-create temp file with proper security context. */
227 close(tfd);
228@@ -825,8 +828,10 @@
229 *sesh_ap = NULL;
230
231 /* Run sesh -e [-h] 0 <o1> <t1> ... <on> <tn> */
232- rc = selinux_run_helper(sesh_args, command_details->envp);
233- switch (rc) {
234+ error = selinux_run_helper(command_details->uid, command_details->gid,
235+ command_details->ngroups, command_details->groups, sesh_args,
236+ command_details->envp);
237+ switch (error) {
238 case SESH_SUCCESS:
239 break;
240 case SESH_ERR_BAD_PATHS:
241@@ -836,21 +841,35 @@
242 case SESH_ERR_KILLED:
243 sudo_fatalx("%s", U_("sesh: killed by a signal"));
244 default:
245- sudo_fatalx(U_("sesh: unknown error %d"), rc);
246+ sudo_warnx(U_("sesh: unknown error %d"), error);
247+ goto done;
248 }
249
250- /* Chown to user's UID so they can edit the temporary files. */
251 for (i = 0; i < nfiles; i++) {
252- if (chown(tf[i].tfile, user_details.uid, user_details.gid) != 0) {
253+ int tfd = open(tf[i].tfile, O_RDONLY|O_NONBLOCK|O_NOFOLLOW);
254+ if (tfd == -1) {
255+ sudo_warn(U_("unable to open %s"), tf[i].tfile);
256+ goto done;
257+ }
258+ if (!sudo_check_temp_file(tfd, tf[i].tfile, command_details->uid, NULL)) {
259+ close(tfd);
260+ goto done;
261+ }
262+ if (fchown(tfd, user_details.uid, user_details.gid) != 0) {
263 sudo_warn("unable to chown(%s) to %d:%d for editing",
264 tf[i].tfile, user_details.uid, user_details.gid);
265+ close(tfd);
266+ goto done;
267 }
268+ close(tfd);
269 }
270+ ret = nfiles;
271
272+done:
273 /* Contents of tf will be freed by caller. */
274 free(sesh_args);
275
276- return (nfiles);
277+ debug_return_int(ret);
278 }
279
280 static int
281@@ -858,7 +877,8 @@
282 struct tempfile *tf, int nfiles, struct timespec *times)
283 {
284 char **sesh_args, **sesh_ap;
285- int i, rc, sesh_nargs, ret = 1;
286+ int i, error, sesh_nargs, ret = 1;
287+ int tfd = -1;
288 struct timespec ts;
289 struct stat sb;
290 debug_decl(selinux_edit_copy_tfiles, SUDO_DEBUG_EDIT);
291@@ -879,33 +899,43 @@
292
293 /* Construct args for sesh -e 1 */
294 for (i = 0; i < nfiles; i++) {
295- if (stat(tf[i].tfile, &sb) == 0) {
296- mtim_get(&sb, ts);
297- if (tf[i].osize == sb.st_size && sudo_timespeccmp(&tf[i].omtim, &ts, ==)) {
298- /*
299- * If mtime and size match but the user spent no measurable
300- * time in the editor we can't tell if the file was changed.
301- */
302- if (sudo_timespeccmp(&times[0], &times[1], !=)) {
303- sudo_warnx(U_("%s unchanged"), tf[i].ofile);
304- unlink(tf[i].tfile);
305- continue;
306- }
307+ if (tfd != -1)
308+ close(tfd);
309+ if ((tfd = open(tf[i].tfile, O_RDONLY|O_NONBLOCK|O_NOFOLLOW)) == -1) {
310+ sudo_warn(U_("unable to open %s"), tf[i].tfile);
311+ continue;
312+ }
313+ if (!sudo_check_temp_file(tfd, tf[i].tfile, user_details.uid, &sb))
314+ continue;
315+ mtim_get(&sb, ts);
316+ if (tf[i].osize == sb.st_size && sudo_timespeccmp(&tf[i].omtim, &ts, ==)) {
317+ /*
318+ * If mtime and size match but the user spent no measurable
319+ * time in the editor we can't tell if the file was changed.
320+ */
321+ if (sudo_timespeccmp(&times[0], &times[1], !=)) {
322+ sudo_warnx(U_("%s unchanged"), tf[i].ofile);
323+ unlink(tf[i].tfile);
324+ continue;
325 }
326 }
327 *sesh_ap++ = tf[i].tfile;
328 *sesh_ap++ = tf[i].ofile;
329- if (chown(tf[i].tfile, command_details->uid, command_details->gid) != 0) {
330+ if (fchown(tfd, command_details->uid, command_details->gid) != 0) {
331 sudo_warn("unable to chown(%s) back to %d:%d", tf[i].tfile,
332 command_details->uid, command_details->gid);
333 }
334 }
335 *sesh_ap = NULL;
336+ if (tfd != -1)
337+ close(tfd);
338
339 if (sesh_ap - sesh_args > 3) {
340 /* Run sesh -e 1 <t1> <o1> ... <tn> <on> */
341- rc = selinux_run_helper(sesh_args, command_details->envp);
342- switch (rc) {
343+ error = selinux_run_helper(command_details->uid, command_details->gid,
344+ command_details->ngroups, command_details->groups, sesh_args,
345+ command_details->envp);
346+ switch (error) {
347 case SESH_SUCCESS:
348 ret = 0;
349 break;
350@@ -921,7 +951,7 @@
351 sudo_warnx("%s", U_("sesh: killed by a signal"));
352 break;
353 default:
354- sudo_warnx(U_("sesh: unknown error %d"), rc);
355+ sudo_warnx(U_("sesh: unknown error %d"), error);
356 break;
357 }
358 if (ret != 0)
359@@ -943,7 +973,7 @@
360 {
361 struct command_details saved_command_details;
362 char **nargv = NULL, **ap, **files = NULL;
363- int errors, i, ac, nargc, rc;
364+ int errors, i, ac, nargc, ret;
365 int editor_argc = 0, nfiles = 0;
366 struct timespec times[2];
367 struct tempfile *tf = NULL;
368@@ -1038,7 +1068,7 @@
369 command_details->ngroups = user_details.ngroups;
370 command_details->groups = user_details.groups;
371 command_details->argv = nargv;
372- rc = run_command(command_details);
373+ ret = run_command(command_details);
374 if (sudo_gettime_real(&times[1]) == -1) {
375 sudo_warn("%s", U_("unable to read the clock"));
376 goto cleanup;
377@@ -1062,14 +1092,14 @@
378 errors = sudo_edit_copy_tfiles(command_details, tf, nfiles, times);
379 if (errors) {
380 /* Preserve the edited temporary files. */
381- rc = W_EXITCODE(1, 0);
382+ ret = W_EXITCODE(1, 0);
383 }
384
385 for (i = 0; i < nfiles; i++)
386 free(tf[i].tfile);
387 free(tf);
388 free(nargv);
389- debug_return_int(rc);
390+ debug_return_int(ret);
391
392 cleanup:
393 /* Clean up temp files and return. */
394diff -r ea19d0073c02 -r 8fcb36ef422a src/sudo_exec.h
395--- a/src/sudo_exec.h Wed Jan 06 10:16:00 2021 -0700
396+++ b/src/sudo_exec.h Wed Jan 06 10:16:00 2021 -0700
397@@ -1,7 +1,7 @@
398 /*
399 * SPDX-License-Identifier: ISC
400 *
401- * Copyright (c) 2010-2016 Todd C. Miller <Todd.Miller@sudo.ws>
402+ * Copyright (c) 2010-2017, 2020-2021 Todd C. Miller <Todd.Miller@sudo.ws>
403 *
404 * Permission to use, copy, modify, and distribute this software for any
405 * purpose with or without fee is hereby granted, provided that the above
406@@ -84,9 +84,11 @@
407 */
408 struct command_details;
409 struct command_status;
410+struct stat;
411
412 /* copy_file.c */
413 int sudo_copy_file(const char *src, int src_fd, off_t src_len, const char *dst, int dst_fd, off_t dst_len);
414+bool sudo_check_temp_file(int tfd, const char *tname, uid_t uid, struct stat *sb);
415
416 /* exec.c */
417 void exec_cmnd(struct command_details *details, int errfd);
418
419
diff --git a/meta/recipes-extended/sudo/sudo_1.9.3.bb b/meta/recipes-extended/sudo/sudo_1.9.3.bb
index 132d9a8cb9..4edcbfc607 100644
--- a/meta/recipes-extended/sudo/sudo_1.9.3.bb
+++ b/meta/recipes-extended/sudo/sudo_1.9.3.bb
@@ -4,6 +4,7 @@ SRC_URI = "https://www.sudo.ws/dist/sudo-${PV}.tar.gz \
4 ${@bb.utils.contains('DISTRO_FEATURES', 'pam', '${PAM_SRC_URI}', '', d)} \ 4 ${@bb.utils.contains('DISTRO_FEATURES', 'pam', '${PAM_SRC_URI}', '', d)} \
5 file://0001-sudo.conf.in-fix-conflict-with-multilib.patch \ 5 file://0001-sudo.conf.in-fix-conflict-with-multilib.patch \
6 file://CVE-2021-23239.patch \ 6 file://CVE-2021-23239.patch \
7 file://CVE-2021-23240.patch \
7 " 8 "
8 9
9PAM_SRC_URI = "file://sudo.pam" 10PAM_SRC_URI = "file://sudo.pam"