summaryrefslogtreecommitdiffstats
path: root/meta/recipes-extended/sudo/files/CVE-2021-23239.patch
blob: e16baecd5a1ba621ef0b00534dbc2df16c81cf83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# HG changeset patch
# User Todd C. Miller <Todd.Miller@sudo.ws>
# Date 1609953360 25200
# Node ID ea19d0073c02951bbbf35342dd63304da83edce8
# Parent  f1ca39a0d87089d005b78a2556e2b1a2dc17f672
Fix potential directory existing info leak in sudoedit.
When creating a new file, sudoedit checks to make sure the parent
directory exists so it can provide the user with a sensible error
message.  However, this could be used to test for the existence of
directories not normally accessible to the user by pointing to them
with a symbolic link when the parent directory is controlled by the
user.  Problem reported by Matthias Gerstner of SUSE.

Upstream-Status: Backport [https://www.sudo.ws/repos/sudo/rev/ea19d0073c02]
CVE: CVE-2021-23239
Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>

diff -r f1ca39a0d870 -r ea19d0073c02 src/sudo_edit.c
--- a/src/sudo_edit.c	Wed Jan 06 10:16:00 2021 -0700
+++ b/src/sudo_edit.c	Wed Jan 06 10:16:00 2021 -0700
@@ -541,14 +541,33 @@
 	    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, command_details);
 	if (ofd != -1 || errno == ENOENT) {
 	    if (ofd == -1) {
-		/* New file, verify parent dir exists unless in cwd. */
+		/*
+		 * New file, verify parent dir exists unless in cwd.
+		 * This fails early so the user knows ahead of time if the
+		 * edit won't succeed.  Additional checks are performed
+		 * when copying the temporary file back to the origin.
+		 */
 		char *slash = strrchr(files[i], '/');
 		if (slash != NULL && slash != files[i]) {
-		    int serrno = errno;
+		    const int sflags = command_details->flags;
+		    const int serrno = errno;
+		    int dfd;
+
+		    /*
+		     * The parent directory is allowed to be a symbolic
+		     * link as long as *its* parent is not writable.
+		     */
 		    *slash = '\0';
-		    if (stat(files[i], &sb) == 0 && S_ISDIR(sb.st_mode)) {
-			memset(&sb, 0, sizeof(sb));
-			rc = 0;
+		    SET(command_details->flags, CD_SUDOEDIT_FOLLOW);
+		    dfd = sudo_edit_open(files[i], DIR_OPEN_FLAGS,
+			S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, command_details);
+		    command_details->flags = sflags;
+		    if (dfd != -1) {
+			if (fstat(dfd, &sb) == 0 && S_ISDIR(sb.st_mode)) {
+			    memset(&sb, 0, sizeof(sb));
+			    rc = 0;
+			}
+			close(dfd);
 		    }
 		    *slash = '/';
 		    errno = serrno;