diff options
author | Todd C. Miller <Todd.Miller@sudo.ws> | 2021-01-06 10:16:00 -0700 |
---|---|---|
committer | Todd C. Miller <Todd.Miller@sudo.ws> | 2021-01-06 10:16:00 -0700 |
commit | bf495920acd628a6a7feb46b3fdb5a64d708afdf (patch) | |
tree | 08d5d8bc2dfb0d063baf6ba446ebe78bcb88b437 | |
parent | 8c9f04a74824f1999e5c6afa16b3c872667fcb25 (diff) | |
download | sudo-bf495920acd628a6a7feb46b3fdb5a64d708afdf.tar.gz |
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.
-rw-r--r-- | src/sudo_edit.c | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/src/sudo_edit.c b/src/sudo_edit.c index 15f0aff76..7dda881d8 100644 --- a/src/sudo_edit.c +++ b/src/sudo_edit.c @@ -578,14 +578,33 @@ sudo_edit_create_tfiles(struct command_details *command_details, 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; |