Add security checks before using temp files for SELinux RBAC sudoedit.

Otherwise, it may be possible for the user running sudoedit to
replace the newly-created temporary files with a symbolic link and
have sudoedit set the owner of an arbitrary file.
Problem reported by Matthias Gerstner of SUSE.
This commit is contained in:
Todd C. Miller
2021-01-06 10:16:00 -07:00
parent db1f27c035
commit 7cd36222e7
4 changed files with 121 additions and 49 deletions

View File

@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2008, 2010-2018, 2020 Todd C. Miller <Todd.Miller@sudo.ws>
* Copyright (c) 2008, 2010-2018, 2020-2021 Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -132,7 +132,7 @@ main(int argc, char *argv[], char *envp[])
static int
sesh_sudoedit(int argc, char *argv[])
{
int i, oflags_dst, post, ret = SESH_ERR_FAILURE;
int i, oflags_src, oflags_dst, post, ret = SESH_ERR_FAILURE;
int fd_src = -1, fd_dst = -1, follow = 0;
struct stat sb;
struct timespec times[2];
@@ -174,10 +174,12 @@ sesh_sudoedit(int argc, char *argv[])
debug_return_int(SESH_ERR_BAD_PATHS);
/*
* Use O_EXCL if we are not in the post editing stage
* so that it's ensured that the temporary files are
* created by us and that we are not opening any symlinks.
* In the pre-editing stage, use O_EXCL to ensure that the temporary
* files are created by us and that we are not opening any symlinks.
* In the post-editing stage, use O_NOFOLLOW so we don't follow symlinks
* when opening the temporary files.
*/
oflags_src = O_RDONLY|(post ? O_NONBLOCK|O_NOFOLLOW : follow);
oflags_dst = O_WRONLY|O_CREAT|(post ? follow : O_EXCL);
for (i = 0; i < argc - 1; i += 2) {
const char *path_src = argv[i];
@@ -187,7 +189,7 @@ sesh_sudoedit(int argc, char *argv[])
* doesn't exist, that's OK, we'll create an empty
* destination file.
*/
if ((fd_src = open(path_src, O_RDONLY|follow, S_IRUSR|S_IWUSR)) < 0) {
if ((fd_src = open(path_src, oflags_src, S_IRUSR|S_IWUSR)) < 0) {
if (errno != ENOENT) {
sudo_warn("%s", path_src);
if (post) {
@@ -197,6 +199,14 @@ sesh_sudoedit(int argc, char *argv[])
goto cleanup_0;
}
}
if (post) {
/* Make sure the temporary file is safe and has the proper owner. */
if (!sudo_check_temp_file(fd_src, path_src, geteuid(), &sb)) {
ret = SESH_ERR_SOME_FILES;
goto nocleanup;
}
fcntl(fd_src, F_SETFL, fcntl(fd_src, F_GETFL, 0) & ~O_NONBLOCK);
}
if ((fd_dst = open(path_dst, oflags_dst, post ?
(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) : (S_IRUSR|S_IWUSR))) < 0) {
@@ -214,10 +224,7 @@ sesh_sudoedit(int argc, char *argv[])
off_t len_dst = -1;
if (post) {
if (fstat(fd_src, &sb) != 0) {
ret = SESH_ERR_SOME_FILES;
goto nocleanup;
}
/* sudo_check_temp_file() filled in sb for us. */
len_src = sb.st_size;
if (fstat(fd_dst, &sb) != 0) {
ret = SESH_ERR_SOME_FILES;