import sudo-1.8.29-7.el8
This commit is contained in:
parent
777d690e00
commit
d13292b8f6
61
SOURCES/sudo-1.9.5-CVE-2021-23239.patch
Normal file
61
SOURCES/sudo-1.9.5-CVE-2021-23239.patch
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
From db1f27c0350e9e437c93780ffe88648ae1984467 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
|
||||||
|
Date: Wed, 6 Jan 2021 10:16:00 -0700
|
||||||
|
Subject: [PATCH] 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.
|
||||||
|
|
||||||
|
---
|
||||||
|
src/sudo_edit.c | 29 ++++++++++++++++++++++++-----
|
||||||
|
1 file changed, 24 insertions(+), 5 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/sudo_edit.c b/src/sudo_edit.c
|
||||||
|
index 82e04a71b..5502b7bd9 100644
|
||||||
|
--- a/src/sudo_edit.c
|
||||||
|
+++ b/src/sudo_edit.c
|
||||||
|
@@ -541,14 +541,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;
|
||||||
|
--
|
||||||
|
2.26.2
|
||||||
|
|
158
SOURCES/sudo-1.9.5-CVE-2021-23240-1.patch
Normal file
158
SOURCES/sudo-1.9.5-CVE-2021-23240-1.patch
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
From adb4360c40df99238c17c3ecedcb1d32d76e2b2e Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
|
||||||
|
Date: Fri, 17 Apr 2020 19:08:56 -0600
|
||||||
|
Subject: [PATCH] Extend the original file before to the new size before
|
||||||
|
updating it. Instead of opening the original file for writing w/ tuncation,
|
||||||
|
we first extend the file with zeroes (by writing, not seeking), then
|
||||||
|
overwrite it. This should allow sudo to fail early if the disk is out of
|
||||||
|
space before it overwrites the original file.
|
||||||
|
|
||||||
|
---
|
||||||
|
src/sudo_edit.c | 93 ++++++++++++++++++++++++++++++++++++++++---------
|
||||||
|
1 file changed, 77 insertions(+), 16 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/sudo_edit.c b/src/sudo_edit.c
|
||||||
|
index 28f6c6100..d99a5658a 100644
|
||||||
|
--- a/src/sudo_edit.c
|
||||||
|
+++ b/src/sudo_edit.c
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: ISC
|
||||||
|
*
|
||||||
|
- * Copyright (c) 2004-2008, 2010-2018 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
|
+ * Copyright (c) 2004-2008, 2010-2020 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
|
||||||
|
@@ -650,6 +650,51 @@ sudo_edit_create_tfiles(struct command_details *command_details,
|
||||||
|
debug_return_int(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Extend the given fd to the specified size in bytes.
|
||||||
|
+ * We do this to allocate disk space up-front before overwriting
|
||||||
|
+ * the original file with the temporary. Otherwise, we could
|
||||||
|
+ * we run out of disk space after truncating the original file.
|
||||||
|
+ */
|
||||||
|
+static int
|
||||||
|
+sudo_edit_extend_file(int fd, off_t new_size)
|
||||||
|
+{
|
||||||
|
+ off_t old_size, size;
|
||||||
|
+ ssize_t nwritten;
|
||||||
|
+ char zeroes[1024] = { '\0' };
|
||||||
|
+ debug_decl(sudo_edit_extend_file, SUDO_DEBUG_EDIT);
|
||||||
|
+
|
||||||
|
+ if ((old_size = lseek(fd, 0, SEEK_END)) == -1) {
|
||||||
|
+ sudo_warn("lseek");
|
||||||
|
+ debug_return_int(-1);
|
||||||
|
+ }
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_INFO, "%s: extending file from %lld to %lld",
|
||||||
|
+ __func__, (long long)old_size, (long long)new_size);
|
||||||
|
+
|
||||||
|
+ for (size = old_size; size < new_size; size += nwritten) {
|
||||||
|
+ size_t len = new_size - size;
|
||||||
|
+ if (len > sizeof(zeroes))
|
||||||
|
+ len = sizeof(zeroes);
|
||||||
|
+ nwritten = write(fd, zeroes, len);
|
||||||
|
+ if (nwritten == -1) {
|
||||||
|
+ int serrno = errno;
|
||||||
|
+ if (ftruncate(fd, old_size) == -1) {
|
||||||
|
+ sudo_debug_printf(
|
||||||
|
+ SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
|
+ "unable to truncate to %lld", (long long)old_size);
|
||||||
|
+ }
|
||||||
|
+ errno = serrno;
|
||||||
|
+ debug_return_int(-1);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (lseek(fd, 0, SEEK_SET) == -1) {
|
||||||
|
+ sudo_warn("lseek");
|
||||||
|
+ debug_return_int(-1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ debug_return_int(0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Copy the temporary files specified in tf to the originals.
|
||||||
|
* Returns the number of copy errors or 0 if completely successful.
|
||||||
|
@@ -708,38 +753,53 @@ sudo_edit_copy_tfiles(struct command_details *command_details,
|
||||||
|
switch_user(command_details->euid, command_details->egid,
|
||||||
|
command_details->ngroups, command_details->groups);
|
||||||
|
oldmask = umask(command_details->umask);
|
||||||
|
- ofd = sudo_edit_open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT,
|
||||||
|
+ ofd = sudo_edit_open(tf[i].ofile, O_WRONLY|O_CREAT,
|
||||||
|
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, command_details);
|
||||||
|
umask(oldmask);
|
||||||
|
switch_user(ROOT_UID, user_details.egid,
|
||||||
|
user_details.ngroups, user_details.groups);
|
||||||
|
- if (ofd == -1) {
|
||||||
|
- sudo_warn(U_("unable to write to %s"), tf[i].ofile);
|
||||||
|
- sudo_warnx(U_("contents of edit session left in %s"), tf[i].tfile);
|
||||||
|
- close(tfd);
|
||||||
|
- errors++;
|
||||||
|
- continue;
|
||||||
|
+ if (ofd == -1)
|
||||||
|
+ goto write_error;
|
||||||
|
+ /* Extend the file to the new size if larger before copying. */
|
||||||
|
+ if (tf[i].osize > 0 && sb.st_size > tf[i].osize) {
|
||||||
|
+ if (sudo_edit_extend_file(ofd, sb.st_size) == -1)
|
||||||
|
+ goto write_error;
|
||||||
|
}
|
||||||
|
+ /* Overwrite the old file with the new contents. */
|
||||||
|
while ((nread = read(tfd, buf, sizeof(buf))) > 0) {
|
||||||
|
- if ((nwritten = write(ofd, buf, nread)) != nread) {
|
||||||
|
+ ssize_t off = 0;
|
||||||
|
+ do {
|
||||||
|
+ nwritten = write(ofd, buf + off, nread - off);
|
||||||
|
if (nwritten == -1)
|
||||||
|
- sudo_warn("%s", tf[i].ofile);
|
||||||
|
- else
|
||||||
|
- sudo_warnx(U_("%s: short write"), tf[i].ofile);
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
+ goto write_error;
|
||||||
|
+ off += nwritten;
|
||||||
|
+ } while (nread > off);
|
||||||
|
}
|
||||||
|
if (nread == 0) {
|
||||||
|
- /* success, got EOF */
|
||||||
|
+ /* success, read to EOF */
|
||||||
|
+ if (tf[i].osize > 0 && sb.st_size < tf[i].osize) {
|
||||||
|
+ /* We don't open with O_TRUNC so must truncate manually. */
|
||||||
|
+ if (ftruncate(ofd, sb.st_size) == -1) {
|
||||||
|
+ sudo_debug_printf(
|
||||||
|
+ SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
|
+ "unable to truncate %s to %lld", tf[i].ofile,
|
||||||
|
+ (long long)sb.st_size);
|
||||||
|
+ goto write_error;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
unlink(tf[i].tfile);
|
||||||
|
} else if (nread < 0) {
|
||||||
|
sudo_warn(U_("unable to read temporary file"));
|
||||||
|
sudo_warnx(U_("contents of edit session left in %s"), tf[i].tfile);
|
||||||
|
+ errors++;
|
||||||
|
} else {
|
||||||
|
+write_error:
|
||||||
|
sudo_warn(U_("unable to write to %s"), tf[i].ofile);
|
||||||
|
sudo_warnx(U_("contents of edit session left in %s"), tf[i].tfile);
|
||||||
|
+ errors++;
|
||||||
|
}
|
||||||
|
- close(ofd);
|
||||||
|
+ if (ofd != -1)
|
||||||
|
+ close(ofd);
|
||||||
|
close(tfd);
|
||||||
|
}
|
||||||
|
debug_return_int(errors);
|
||||||
|
@@ -1065,6 +1125,7 @@ cleanup:
|
||||||
|
for (i = 0; i < nfiles; i++) {
|
||||||
|
if (tf[i].tfile != NULL)
|
||||||
|
unlink(tf[i].tfile);
|
||||||
|
+ free(tf[i].tfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(tf);
|
||||||
|
--
|
||||||
|
2.26.2
|
||||||
|
|
431
SOURCES/sudo-1.9.5-CVE-2021-23240-2.patch
Normal file
431
SOURCES/sudo-1.9.5-CVE-2021-23240-2.patch
Normal file
@ -0,0 +1,431 @@
|
|||||||
|
diff -up ./src/copy_file.c.symbolic-link-attack-2 ./src/copy_file.c
|
||||||
|
--- ./src/copy_file.c.symbolic-link-attack-2 2021-02-02 15:31:20.555340446 +0100
|
||||||
|
+++ ./src/copy_file.c 2021-02-02 15:31:20.555340446 +0100
|
||||||
|
@@ -0,0 +1,128 @@
|
||||||
|
+/*
|
||||||
|
+ * SPDX-License-Identifier: ISC
|
||||||
|
+ *
|
||||||
|
+ * Copyright (c) 2020 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
|
||||||
|
+ * copyright notice and this permission notice appear in all copies.
|
||||||
|
+ *
|
||||||
|
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||||
|
+ * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <config.h>
|
||||||
|
+
|
||||||
|
+#include <sys/types.h>
|
||||||
|
+
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
+#include <errno.h>
|
||||||
|
+
|
||||||
|
+#include "sudo.h"
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Extend the given fd to the specified size in bytes.
|
||||||
|
+ * We do this to allocate disk space up-front before overwriting
|
||||||
|
+ * the original file with the temporary. Otherwise, we could
|
||||||
|
+ * we run out of disk space after truncating the original file.
|
||||||
|
+ */
|
||||||
|
+static int
|
||||||
|
+sudo_extend_file(int fd, const char *name, off_t new_size)
|
||||||
|
+{
|
||||||
|
+ off_t old_size, size;
|
||||||
|
+ ssize_t nwritten;
|
||||||
|
+ char zeroes[BUFSIZ] = { '\0' };
|
||||||
|
+ debug_decl(sudo_extend_file, SUDO_DEBUG_UTIL);
|
||||||
|
+
|
||||||
|
+ if ((old_size = lseek(fd, 0, SEEK_END)) == -1) {
|
||||||
|
+ sudo_warn("lseek");
|
||||||
|
+ debug_return_int(-1);
|
||||||
|
+ }
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_INFO, "%s: extending %s from %lld to %lld",
|
||||||
|
+ __func__, name, (long long)old_size, (long long)new_size);
|
||||||
|
+
|
||||||
|
+ for (size = old_size; size < new_size; size += nwritten) {
|
||||||
|
+ size_t len = new_size - size;
|
||||||
|
+ if (len > sizeof(zeroes))
|
||||||
|
+ len = sizeof(zeroes);
|
||||||
|
+ nwritten = write(fd, zeroes, len);
|
||||||
|
+ if (nwritten == -1) {
|
||||||
|
+ int serrno = errno;
|
||||||
|
+ if (ftruncate(fd, old_size) == -1) {
|
||||||
|
+ sudo_debug_printf(
|
||||||
|
+ SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
|
+ "unable to truncate %s to %lld", name, (long long)old_size);
|
||||||
|
+ }
|
||||||
|
+ errno = serrno;
|
||||||
|
+ debug_return_int(-1);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (lseek(fd, 0, SEEK_SET) == -1) {
|
||||||
|
+ sudo_warn("lseek");
|
||||||
|
+ debug_return_int(-1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ debug_return_int(0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Copy the contents of src_fd into dst_fd.
|
||||||
|
+ * Returns 0 on success or -1 on error.
|
||||||
|
+ */
|
||||||
|
+int
|
||||||
|
+sudo_copy_file(const char *src, int src_fd, off_t src_len, const char *dst,
|
||||||
|
+ int dst_fd, off_t dst_len)
|
||||||
|
+{
|
||||||
|
+ char buf[BUFSIZ];
|
||||||
|
+ ssize_t nwritten, nread;
|
||||||
|
+ debug_decl(sudo_copy_file, SUDO_DEBUG_UTIL);
|
||||||
|
+
|
||||||
|
+ /* Extend the file to the new size if larger before copying. */
|
||||||
|
+ if (dst_len > 0 && src_len > dst_len) {
|
||||||
|
+ if (sudo_extend_file(dst_fd, dst, src_len) == -1)
|
||||||
|
+ goto write_error;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Overwrite the old file with the new contents. */
|
||||||
|
+ while ((nread = read(src_fd, buf, sizeof(buf))) > 0) {
|
||||||
|
+ ssize_t off = 0;
|
||||||
|
+ do {
|
||||||
|
+ nwritten = write(dst_fd, buf + off, nread - off);
|
||||||
|
+ if (nwritten == -1)
|
||||||
|
+ goto write_error;
|
||||||
|
+ off += nwritten;
|
||||||
|
+ } while (nread > off);
|
||||||
|
+ }
|
||||||
|
+ if (nread == 0) {
|
||||||
|
+ /* success, read to EOF */
|
||||||
|
+ if (src_len < dst_len) {
|
||||||
|
+ /* We don't open with O_TRUNC so must truncate manually. */
|
||||||
|
+ if (ftruncate(dst_fd, src_len) == -1) {
|
||||||
|
+ sudo_debug_printf(
|
||||||
|
+ SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
|
+ "unable to truncate %s to %lld", dst, (long long)src_len);
|
||||||
|
+ goto write_error;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ debug_return_int(0);
|
||||||
|
+ } else if (nread < 0) {
|
||||||
|
+ sudo_warn(U_("unable to read from %s"), src);
|
||||||
|
+ debug_return_int(-1);
|
||||||
|
+ } else {
|
||||||
|
+write_error:
|
||||||
|
+ sudo_warn(U_("unable to write to %s"), dst);
|
||||||
|
+ debug_return_int(-1);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff -up ./src/Makefile.in.symbolic-link-attack-2 ./src/Makefile.in
|
||||||
|
--- ./src/Makefile.in.symbolic-link-attack-2 2019-10-28 13:28:54.000000000 +0100
|
||||||
|
+++ ./src/Makefile.in 2021-02-02 15:31:20.555340446 +0100
|
||||||
|
@@ -120,16 +120,17 @@ SHELL = @SHELL@
|
||||||
|
|
||||||
|
PROGS = @PROGS@
|
||||||
|
|
||||||
|
-OBJS = conversation.o env_hooks.o exec.o exec_common.o exec_monitor.o \
|
||||||
|
- exec_nopty.o exec_pty.o get_pty.o hooks.o limits.o load_plugins.o \
|
||||||
|
- net_ifs.o parse_args.o preserve_fds.o signal.o sudo.o sudo_edit.o \
|
||||||
|
- tcsetpgrp_nobg.o tgetpass.o ttyname.o utmp.o @SUDO_OBJS@
|
||||||
|
+OBJS = conversation.o copy_file.o env_hooks.o exec.o exec_common.o \
|
||||||
|
+ exec_monitor.o exec_nopty.o exec_pty.o get_pty.o hooks.o \
|
||||||
|
+ limits.o load_plugins.o net_ifs.o parse_args.o preserve_fds.o \
|
||||||
|
+ signal.o sudo.o sudo_edit.o tcsetpgrp_nobg.o tgetpass.o \
|
||||||
|
+ ttyname.o utmp.o @SUDO_OBJS@
|
||||||
|
|
||||||
|
IOBJS = $(OBJS:.o=.i) sesh.i
|
||||||
|
|
||||||
|
POBJS = $(IOBJS:.i=.plog)
|
||||||
|
|
||||||
|
-SESH_OBJS = sesh.o exec_common.o
|
||||||
|
+SESH_OBJS = copy_file.o exec_common.o sesh.o
|
||||||
|
|
||||||
|
CHECK_NOEXEC_OBJS = check_noexec.o exec_common.o
|
||||||
|
|
||||||
|
@@ -335,6 +336,22 @@ conversation.i: $(srcdir)/conversation.c
|
||||||
|
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||||
|
conversation.plog: conversation.i
|
||||||
|
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/conversation.c --i-file $< --output-file $@
|
||||||
|
+copy_file.o: $(srcdir)/copy_file.c $(incdir)/compat/stdbool.h \
|
||||||
|
+ $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
|
||||||
|
+ $(incdir)/sudo_debug.h $(incdir)/sudo_event.h \
|
||||||
|
+ $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||||
|
+ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/sudo.h \
|
||||||
|
+ $(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||||
|
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/copy_file.c
|
||||||
|
+copy_file.i: $(srcdir)/copy_file.c $(incdir)/compat/stdbool.h \
|
||||||
|
+ $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
|
||||||
|
+ $(incdir)/sudo_debug.h $(incdir)/sudo_event.h \
|
||||||
|
+ $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||||
|
+ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/sudo.h \
|
||||||
|
+ $(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||||
|
+ $(CC) -E -o $@ $(CPPFLAGS) $<
|
||||||
|
+copy_file.plog: copy_file.i
|
||||||
|
+ rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/copy_file.c --i-file $< --output-file $@
|
||||||
|
env_hooks.o: $(srcdir)/env_hooks.c $(incdir)/compat/stdbool.h \
|
||||||
|
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
|
||||||
|
$(incdir)/sudo_debug.h $(incdir)/sudo_dso.h \
|
||||||
|
diff -up ./src/sesh.c.symbolic-link-attack-2 ./src/sesh.c
|
||||||
|
--- ./src/sesh.c.symbolic-link-attack-2 2019-10-28 13:28:52.000000000 +0100
|
||||||
|
+++ ./src/sesh.c 2021-02-02 15:31:20.555340446 +0100
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: ISC
|
||||||
|
*
|
||||||
|
- * Copyright (c) 2008, 2010-2018 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
|
+ * Copyright (c) 2008, 2010-2018, 2020 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
|
||||||
|
@@ -182,7 +182,7 @@ sesh_sudoedit(int argc, char *argv[])
|
||||||
|
* so that it's ensured that the temporary files are
|
||||||
|
* created by us and that we are not opening any symlinks.
|
||||||
|
*/
|
||||||
|
- oflags_dst = O_WRONLY|O_TRUNC|O_CREAT|(post ? follow : O_EXCL);
|
||||||
|
+ oflags_dst = O_WRONLY|O_CREAT|(post ? follow : O_EXCL);
|
||||||
|
for (i = 0; i < argc - 1; i += 2) {
|
||||||
|
const char *path_src = argv[i];
|
||||||
|
const char *path_dst = argv[i + 1];
|
||||||
|
@@ -214,14 +214,29 @@ sesh_sudoedit(int argc, char *argv[])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd_src != -1) {
|
||||||
|
- while ((nread = read(fd_src, buf, sizeof(buf))) > 0) {
|
||||||
|
- if ((nwritten = write(fd_dst, buf, nread)) != nread) {
|
||||||
|
- sudo_warn("%s", path_src);
|
||||||
|
- if (post) {
|
||||||
|
- ret = SESH_ERR_SOME_FILES;
|
||||||
|
- goto nocleanup;
|
||||||
|
- } else
|
||||||
|
- goto cleanup_0;
|
||||||
|
+ off_t len_src = -1;
|
||||||
|
+ off_t len_dst = -1;
|
||||||
|
+
|
||||||
|
+ if (post) {
|
||||||
|
+ if (fstat(fd_src, &sb) != 0) {
|
||||||
|
+ ret = SESH_ERR_SOME_FILES;
|
||||||
|
+ goto nocleanup;
|
||||||
|
+ }
|
||||||
|
+ len_src = sb.st_size;
|
||||||
|
+ if (fstat(fd_dst, &sb) != 0) {
|
||||||
|
+ ret = SESH_ERR_SOME_FILES;
|
||||||
|
+ goto nocleanup;
|
||||||
|
+ }
|
||||||
|
+ len_dst = sb.st_size;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (sudo_copy_file(path_src, fd_src, len_src, path_dst, fd_dst,
|
||||||
|
+ len_dst) == -1) {
|
||||||
|
+ if (post) {
|
||||||
|
+ ret = SESH_ERR_SOME_FILES;
|
||||||
|
+ goto nocleanup;
|
||||||
|
+ } else {
|
||||||
|
+ goto cleanup_0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff -up ./src/sudo_edit.c.symbolic-link-attack-2 ./src/sudo_edit.c
|
||||||
|
--- ./src/sudo_edit.c.symbolic-link-attack-2 2021-02-02 15:31:20.554340459 +0100
|
||||||
|
+++ ./src/sudo_edit.c 2021-02-02 15:31:54.355884326 +0100
|
||||||
|
@@ -42,7 +42,6 @@
|
||||||
|
#include <grp.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
-#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "sudo.h"
|
||||||
|
@@ -551,8 +550,6 @@ sudo_edit_create_tfiles(struct command_d
|
||||||
|
struct tempfile *tf, char *files[], int nfiles)
|
||||||
|
{
|
||||||
|
int i, j, tfd, ofd, rc;
|
||||||
|
- char buf[BUFSIZ];
|
||||||
|
- ssize_t nwritten, nread;
|
||||||
|
struct timespec times[2];
|
||||||
|
struct stat sb;
|
||||||
|
debug_decl(sudo_edit_create_tfiles, SUDO_DEBUG_EDIT)
|
||||||
|
@@ -648,18 +645,7 @@ sudo_edit_create_tfiles(struct command_d
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
||||||
|
if (ofd != -1) {
|
||||||
|
- while ((nread = read(ofd, buf, sizeof(buf))) > 0) {
|
||||||
|
- if ((nwritten = write(tfd, buf, nread)) != nread) {
|
||||||
|
- if (nwritten == -1)
|
||||||
|
- sudo_warn("%s", tf[j].tfile);
|
||||||
|
- else
|
||||||
|
- sudo_warnx(U_("%s: short write"), tf[j].tfile);
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- if (nread != 0) {
|
||||||
|
- if (nread < 0)
|
||||||
|
- sudo_warn("%s", files[i]);
|
||||||
|
+ if (sudo_copy_file(tf[j].ofile, ofd, tf[j].osize, tf[j].tfile, tfd, -1) == -1) {
|
||||||
|
close(ofd);
|
||||||
|
close(tfd);
|
||||||
|
debug_return_int(-1);
|
||||||
|
@@ -689,51 +675,6 @@ sudo_edit_create_tfiles(struct command_d
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
- * Extend the given fd to the specified size in bytes.
|
||||||
|
- * We do this to allocate disk space up-front before overwriting
|
||||||
|
- * the original file with the temporary. Otherwise, we could
|
||||||
|
- * we run out of disk space after truncating the original file.
|
||||||
|
- */
|
||||||
|
-static int
|
||||||
|
-sudo_edit_extend_file(int fd, off_t new_size)
|
||||||
|
-{
|
||||||
|
- off_t old_size, size;
|
||||||
|
- ssize_t nwritten;
|
||||||
|
- char zeroes[1024] = { '\0' };
|
||||||
|
- debug_decl(sudo_edit_extend_file, SUDO_DEBUG_EDIT);
|
||||||
|
-
|
||||||
|
- if ((old_size = lseek(fd, 0, SEEK_END)) == -1) {
|
||||||
|
- sudo_warn("lseek");
|
||||||
|
- debug_return_int(-1);
|
||||||
|
- }
|
||||||
|
- sudo_debug_printf(SUDO_DEBUG_INFO, "%s: extending file from %lld to %lld",
|
||||||
|
- __func__, (long long)old_size, (long long)new_size);
|
||||||
|
-
|
||||||
|
- for (size = old_size; size < new_size; size += nwritten) {
|
||||||
|
- size_t len = new_size - size;
|
||||||
|
- if (len > sizeof(zeroes))
|
||||||
|
- len = sizeof(zeroes);
|
||||||
|
- nwritten = write(fd, zeroes, len);
|
||||||
|
- if (nwritten == -1) {
|
||||||
|
- int serrno = errno;
|
||||||
|
- if (ftruncate(fd, old_size) == -1) {
|
||||||
|
- sudo_debug_printf(
|
||||||
|
- SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
|
- "unable to truncate to %lld", (long long)old_size);
|
||||||
|
- }
|
||||||
|
- errno = serrno;
|
||||||
|
- debug_return_int(-1);
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- if (lseek(fd, 0, SEEK_SET) == -1) {
|
||||||
|
- sudo_warn("lseek");
|
||||||
|
- debug_return_int(-1);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- debug_return_int(0);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/*
|
||||||
|
* Copy the temporary files specified in tf to the originals.
|
||||||
|
* Returns the number of copy errors or 0 if completely successful.
|
||||||
|
*/
|
||||||
|
@@ -741,9 +682,7 @@ static int
|
||||||
|
sudo_edit_copy_tfiles(struct command_details *command_details,
|
||||||
|
struct tempfile *tf, int nfiles, struct timespec *times)
|
||||||
|
{
|
||||||
|
- int i, tfd, ofd, rc, errors = 0;
|
||||||
|
- char buf[BUFSIZ];
|
||||||
|
- ssize_t nwritten, nread;
|
||||||
|
+ int i, tfd, ofd, errors = 0;
|
||||||
|
struct timespec ts;
|
||||||
|
struct stat sb;
|
||||||
|
mode_t oldmask;
|
||||||
|
@@ -751,7 +690,7 @@ sudo_edit_copy_tfiles(struct command_det
|
||||||
|
|
||||||
|
/* Copy contents of temp files to real ones. */
|
||||||
|
for (i = 0; i < nfiles; i++) {
|
||||||
|
- rc = -1;
|
||||||
|
+ int rc = -1;
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||||
|
"seteuid(%u)", (unsigned int)user_details.uid);
|
||||||
|
if (seteuid(user_details.uid) != 0)
|
||||||
|
@@ -764,8 +703,8 @@ sudo_edit_copy_tfiles(struct command_det
|
||||||
|
"seteuid(%u)", ROOT_UID);
|
||||||
|
if (seteuid(ROOT_UID) != 0)
|
||||||
|
sudo_fatal("seteuid(ROOT_UID)");
|
||||||
|
- if (rc || !S_ISREG(sb.st_mode)) {
|
||||||
|
- if (rc)
|
||||||
|
+ if (rc == -1 || !S_ISREG(sb.st_mode)) {
|
||||||
|
+ if (rc == -1)
|
||||||
|
sudo_warn("%s", tf[i].tfile);
|
||||||
|
else
|
||||||
|
sudo_warnx(U_("%s: not a regular file"), tf[i].tfile);
|
||||||
|
@@ -796,46 +735,19 @@ sudo_edit_copy_tfiles(struct command_det
|
||||||
|
umask(oldmask);
|
||||||
|
switch_user(ROOT_UID, user_details.egid,
|
||||||
|
user_details.ngroups, user_details.groups);
|
||||||
|
- if (ofd == -1)
|
||||||
|
- goto write_error;
|
||||||
|
- /* Extend the file to the new size if larger before copying. */
|
||||||
|
- if (tf[i].osize > 0 && sb.st_size > tf[i].osize) {
|
||||||
|
- if (sudo_edit_extend_file(ofd, sb.st_size) == -1)
|
||||||
|
- goto write_error;
|
||||||
|
+ if (ofd == -1) {
|
||||||
|
+ sudo_warn(U_("unable to write to %s"), tf[i].ofile);
|
||||||
|
+ goto bad;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
/* Overwrite the old file with the new contents. */
|
||||||
|
- while ((nread = read(tfd, buf, sizeof(buf))) > 0) {
|
||||||
|
- ssize_t off = 0;
|
||||||
|
- do {
|
||||||
|
- nwritten = write(ofd, buf + off, nread - off);
|
||||||
|
- if (nwritten == -1)
|
||||||
|
- goto write_error;
|
||||||
|
- off += nwritten;
|
||||||
|
- } while (nread > off);
|
||||||
|
- }
|
||||||
|
- if (nread == 0) {
|
||||||
|
- /* success, read to EOF */
|
||||||
|
- if (tf[i].osize > 0 && sb.st_size < tf[i].osize) {
|
||||||
|
- /* We don't open with O_TRUNC so must truncate manually. */
|
||||||
|
- if (ftruncate(ofd, sb.st_size) == -1) {
|
||||||
|
- sudo_debug_printf(
|
||||||
|
- SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
|
- "unable to truncate %s to %lld", tf[i].ofile,
|
||||||
|
- (long long)sb.st_size);
|
||||||
|
- goto write_error;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- unlink(tf[i].tfile);
|
||||||
|
- } else if (nread < 0) {
|
||||||
|
- sudo_warn(U_("unable to read temporary file"));
|
||||||
|
- sudo_warnx(U_("contents of edit session left in %s"), tf[i].tfile);
|
||||||
|
- errors++;
|
||||||
|
- } else {
|
||||||
|
-write_error:
|
||||||
|
- sudo_warn(U_("unable to write to %s"), tf[i].ofile);
|
||||||
|
+ if (sudo_copy_file(tf[i].tfile, tfd, sb.st_size, tf[i].ofile, ofd,
|
||||||
|
+ tf[i].osize) == -1) {
|
||||||
|
+bad:
|
||||||
|
sudo_warnx(U_("contents of edit session left in %s"), tf[i].tfile);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
if (ofd != -1)
|
||||||
|
close(ofd);
|
||||||
|
close(tfd);
|
||||||
|
diff -up ./src/sudo_exec.h.symbolic-link-attack-2 ./src/sudo_exec.h
|
||||||
|
--- ./src/sudo_exec.h.symbolic-link-attack-2 2019-10-28 13:27:39.000000000 +0100
|
||||||
|
+++ ./src/sudo_exec.h 2021-02-02 15:31:20.556340432 +0100
|
||||||
|
@@ -84,6 +84,9 @@
|
||||||
|
struct command_details;
|
||||||
|
struct command_status;
|
||||||
|
|
||||||
|
+/* copy_file.c */
|
||||||
|
+int sudo_copy_file(const char *src, int src_fd, off_t src_len, const char *dst, int dst_fd, off_t dst_len);
|
||||||
|
+
|
||||||
|
/* exec.c */
|
||||||
|
void exec_cmnd(struct command_details *details, int errfd);
|
||||||
|
void terminate_command(pid_t pid, bool use_pgrp);
|
345
SOURCES/sudo-1.9.5-CVE-2021-23240-3.patch
Normal file
345
SOURCES/sudo-1.9.5-CVE-2021-23240-3.patch
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
diff -up ./src/exec_monitor.c.symbolic-link-attack-3 ./src/exec_monitor.c
|
||||||
|
--- ./src/exec_monitor.c.symbolic-link-attack-3 2019-10-28 13:27:39.000000000 +0100
|
||||||
|
+++ ./src/exec_monitor.c 2021-02-02 17:11:32.382020407 +0100
|
||||||
|
@@ -613,7 +613,7 @@ exec_monitor(struct command_details *det
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
if (ISSET(details->flags, CD_RBAC_ENABLED)) {
|
||||||
|
if (selinux_setup(details->selinux_role, details->selinux_type,
|
||||||
|
- details->tty, io_fds[SFD_SLAVE]) == -1)
|
||||||
|
+ details->tty, io_fds[SFD_SLAVE], true) == -1)
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
diff -up ./src/exec_nopty.c.symbolic-link-attack-3 ./src/exec_nopty.c
|
||||||
|
--- ./src/exec_nopty.c.symbolic-link-attack-3 2019-10-28 13:27:39.000000000 +0100
|
||||||
|
+++ ./src/exec_nopty.c 2021-02-02 17:11:32.382020407 +0100
|
||||||
|
@@ -381,7 +381,7 @@ exec_nopty(struct command_details *detai
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
if (ISSET(details->flags, CD_RBAC_ENABLED)) {
|
||||||
|
if (selinux_setup(details->selinux_role, details->selinux_type,
|
||||||
|
- details->tty, -1) == -1) {
|
||||||
|
+ details->tty, -1, true) == -1) {
|
||||||
|
cstat->type = CMD_ERRNO;
|
||||||
|
cstat->val = errno;
|
||||||
|
debug_return;
|
||||||
|
diff -up ./src/selinux.c.symbolic-link-attack-3 ./src/selinux.c
|
||||||
|
--- ./src/selinux.c.symbolic-link-attack-3 2019-10-28 13:27:39.000000000 +0100
|
||||||
|
+++ ./src/selinux.c 2021-02-02 17:11:32.382020407 +0100
|
||||||
|
@@ -363,7 +363,7 @@ bad:
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
selinux_setup(const char *role, const char *type, const char *ttyn,
|
||||||
|
- int ptyfd)
|
||||||
|
+ int ptyfd, bool label_tty)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
debug_decl(selinux_setup, SUDO_DEBUG_SELINUX)
|
||||||
|
@@ -392,7 +392,7 @@ selinux_setup(const char *role, const ch
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: new context %s", __func__,
|
||||||
|
se_state.new_context);
|
||||||
|
|
||||||
|
- if (relabel_tty(ttyn, ptyfd) == -1) {
|
||||||
|
+ if (label_tty && relabel_tty(ttyn, ptyfd) == -1) {
|
||||||
|
sudo_warn(U_("unable to set tty context to %s"), se_state.new_context);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
@@ -408,6 +408,28 @@ done:
|
||||||
|
debug_return_int(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
+int
|
||||||
|
+selinux_setcon(void)
|
||||||
|
+{
|
||||||
|
+ debug_decl(selinux_setcon, SUDO_DEBUG_SELINUX);
|
||||||
|
+
|
||||||
|
+ if (setexeccon(se_state.new_context)) {
|
||||||
|
+ sudo_warn(U_("unable to set exec context to %s"), se_state.new_context);
|
||||||
|
+ if (se_state.enforcing)
|
||||||
|
+ debug_return_int(-1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+#ifdef HAVE_SETKEYCREATECON
|
||||||
|
+ if (setkeycreatecon(se_state.new_context)) {
|
||||||
|
+ sudo_warn(U_("unable to set key creation context to %s"), se_state.new_context);
|
||||||
|
+ if (se_state.enforcing)
|
||||||
|
+ debug_return_int(-1);
|
||||||
|
+ }
|
||||||
|
+#endif /* HAVE_SETKEYCREATECON */
|
||||||
|
+
|
||||||
|
+ debug_return_int(0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void
|
||||||
|
selinux_execve(int fd, const char *path, char *const argv[], char *envp[],
|
||||||
|
bool noexec)
|
||||||
|
@@ -424,19 +446,9 @@ selinux_execve(int fd, const char *path,
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (setexeccon(se_state.new_context)) {
|
||||||
|
- sudo_warn(U_("unable to set exec context to %s"), se_state.new_context);
|
||||||
|
- if (se_state.enforcing)
|
||||||
|
- debug_return;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
-#ifdef HAVE_SETKEYCREATECON
|
||||||
|
- if (setkeycreatecon(se_state.new_context)) {
|
||||||
|
- sudo_warn(U_("unable to set key creation context to %s"), se_state.new_context);
|
||||||
|
- if (se_state.enforcing)
|
||||||
|
- debug_return;
|
||||||
|
- }
|
||||||
|
-#endif /* HAVE_SETKEYCREATECON */
|
||||||
|
+ /* Set SELinux exec and keycreate contexts. */
|
||||||
|
+ if (selinux_setcon() == -1)
|
||||||
|
+ debug_return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build new argv with sesh as argv[0].
|
||||||
|
diff -up ./src/sudo.c.symbolic-link-attack-3 ./src/sudo.c
|
||||||
|
--- ./src/sudo.c.symbolic-link-attack-3 2021-02-02 17:12:32.773182386 +0100
|
||||||
|
+++ ./src/sudo.c 2021-02-02 17:12:48.510964009 +0100
|
||||||
|
@@ -971,10 +971,6 @@ run_command(struct command_details *deta
|
||||||
|
case CMD_WSTATUS:
|
||||||
|
/* Command ran, exited or was killed. */
|
||||||
|
status = cstat.val;
|
||||||
|
-#ifdef HAVE_SELINUX
|
||||||
|
- if (ISSET(details->flags, CD_SUDOEDIT_COPY))
|
||||||
|
- break;
|
||||||
|
-#endif
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_DEBUG,
|
||||||
|
"calling policy close with wait status %d", status);
|
||||||
|
policy_close(&policy_plugin, status, 0);
|
||||||
|
diff -up ./src/sudo_edit.c.symbolic-link-attack-3 ./src/sudo_edit.c
|
||||||
|
--- ./src/sudo_edit.c.symbolic-link-attack-3 2021-02-02 17:11:32.380020435 +0100
|
||||||
|
+++ ./src/sudo_edit.c 2021-02-02 17:11:32.382020407 +0100
|
||||||
|
@@ -757,28 +757,54 @@ bad:
|
||||||
|
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
static int
|
||||||
|
+selinux_run_helper(char *argv[], char *envp[])
|
||||||
|
+{
|
||||||
|
+ int status, ret = SESH_ERR_FAILURE;
|
||||||
|
+ const char *sesh;
|
||||||
|
+ pid_t child, pid;
|
||||||
|
+ debug_decl(selinux_run_helper, SUDO_DEBUG_EDIT);
|
||||||
|
+
|
||||||
|
+ sesh = sudo_conf_sesh_path();
|
||||||
|
+ if (sesh == NULL) {
|
||||||
|
+ sudo_warnx("internal error: sesh path not set");
|
||||||
|
+ debug_return_int(-1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ child = sudo_debug_fork();
|
||||||
|
+ switch (child) {
|
||||||
|
+ case -1:
|
||||||
|
+ sudo_warn(U_("unable to fork"));
|
||||||
|
+ break;
|
||||||
|
+ case 0:
|
||||||
|
+ /* child runs sesh in new context */
|
||||||
|
+ if (selinux_setcon() == 0)
|
||||||
|
+ execve(sesh, argv, envp);
|
||||||
|
+ _exit(SESH_ERR_FAILURE);
|
||||||
|
+ default:
|
||||||
|
+ /* parent waits */
|
||||||
|
+ do {
|
||||||
|
+ pid = waitpid(child, &status, 0);
|
||||||
|
+ } while (pid == -1 && errno == EINTR);
|
||||||
|
+
|
||||||
|
+ ret = WIFSIGNALED(status) ? SESH_ERR_KILLED : WEXITSTATUS(status);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ debug_return_int(ret);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
selinux_edit_create_tfiles(struct command_details *command_details,
|
||||||
|
struct tempfile *tf, char *files[], int nfiles)
|
||||||
|
{
|
||||||
|
char **sesh_args, **sesh_ap;
|
||||||
|
int i, rc, sesh_nargs;
|
||||||
|
struct stat sb;
|
||||||
|
- struct command_details saved_command_details;
|
||||||
|
debug_decl(selinux_edit_create_tfiles, SUDO_DEBUG_EDIT)
|
||||||
|
-
|
||||||
|
- /* Prepare selinux stuff (setexeccon) */
|
||||||
|
- if (selinux_setup(command_details->selinux_role,
|
||||||
|
- command_details->selinux_type, NULL, -1) != 0)
|
||||||
|
- debug_return_int(-1);
|
||||||
|
|
||||||
|
if (nfiles < 1)
|
||||||
|
debug_return_int(0);
|
||||||
|
|
||||||
|
/* Construct common args for sesh */
|
||||||
|
- memcpy(&saved_command_details, command_details, sizeof(struct command_details));
|
||||||
|
- command_details->command = _PATH_SUDO_SESH;
|
||||||
|
- command_details->flags |= CD_SUDOEDIT_COPY;
|
||||||
|
-
|
||||||
|
sesh_nargs = 4 + (nfiles * 2) + 1;
|
||||||
|
sesh_args = sesh_ap = reallocarray(NULL, sesh_nargs, sizeof(char *));
|
||||||
|
if (sesh_args == NULL) {
|
||||||
|
@@ -791,6 +817,7 @@ selinux_edit_create_tfiles(struct comman
|
||||||
|
*sesh_ap++ = "-h";
|
||||||
|
*sesh_ap++ = "0";
|
||||||
|
|
||||||
|
+ /* XXX - temp files should be created with user's context */
|
||||||
|
for (i = 0; i < nfiles; i++) {
|
||||||
|
char *tfile, *ofile = files[i];
|
||||||
|
int tfd;
|
||||||
|
@@ -820,8 +847,7 @@ selinux_edit_create_tfiles(struct comman
|
||||||
|
*sesh_ap = NULL;
|
||||||
|
|
||||||
|
/* Run sesh -e [-h] 0 <o1> <t1> ... <on> <tn> */
|
||||||
|
- command_details->argv = sesh_args;
|
||||||
|
- rc = run_command(command_details);
|
||||||
|
+ rc = selinux_run_helper(sesh_args, command_details->envp);
|
||||||
|
switch (rc) {
|
||||||
|
case SESH_SUCCESS:
|
||||||
|
break;
|
||||||
|
@@ -829,15 +855,12 @@ selinux_edit_create_tfiles(struct comman
|
||||||
|
sudo_fatalx(U_("sesh: internal error: odd number of paths"));
|
||||||
|
case SESH_ERR_NO_FILES:
|
||||||
|
sudo_fatalx(U_("sesh: unable to create temporary files"));
|
||||||
|
+ case SESH_ERR_KILLED:
|
||||||
|
+ sudo_fatalx(U_("sesh: killed by a signal"));
|
||||||
|
default:
|
||||||
|
sudo_fatalx(U_("sesh: unknown error %d"), rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* Restore saved command_details. */
|
||||||
|
- command_details->command = saved_command_details.command;
|
||||||
|
- command_details->flags = saved_command_details.flags;
|
||||||
|
- command_details->argv = saved_command_details.argv;
|
||||||
|
-
|
||||||
|
/* Chown to user's UID so they can edit the temporary files. */
|
||||||
|
for (i = 0; i < nfiles; i++) {
|
||||||
|
if (chown(tf[i].tfile, user_details.uid, user_details.gid) != 0) {
|
||||||
|
@@ -858,24 +881,14 @@ selinux_edit_copy_tfiles(struct command_
|
||||||
|
{
|
||||||
|
char **sesh_args, **sesh_ap;
|
||||||
|
int i, rc, sesh_nargs, ret = 1;
|
||||||
|
- struct command_details saved_command_details;
|
||||||
|
struct timespec ts;
|
||||||
|
struct stat sb;
|
||||||
|
debug_decl(selinux_edit_copy_tfiles, SUDO_DEBUG_EDIT)
|
||||||
|
-
|
||||||
|
- /* Prepare selinux stuff (setexeccon) */
|
||||||
|
- if (selinux_setup(command_details->selinux_role,
|
||||||
|
- command_details->selinux_type, NULL, -1) != 0)
|
||||||
|
- debug_return_int(1);
|
||||||
|
|
||||||
|
if (nfiles < 1)
|
||||||
|
debug_return_int(0);
|
||||||
|
|
||||||
|
/* Construct common args for sesh */
|
||||||
|
- memcpy(&saved_command_details, command_details, sizeof(struct command_details));
|
||||||
|
- command_details->command = _PATH_SUDO_SESH;
|
||||||
|
- command_details->flags |= CD_SUDOEDIT_COPY;
|
||||||
|
-
|
||||||
|
sesh_nargs = 3 + (nfiles * 2) + 1;
|
||||||
|
sesh_args = sesh_ap = reallocarray(NULL, sesh_nargs, sizeof(char *));
|
||||||
|
if (sesh_args == NULL) {
|
||||||
|
@@ -913,32 +926,29 @@ selinux_edit_copy_tfiles(struct command_
|
||||||
|
|
||||||
|
if (sesh_ap - sesh_args > 3) {
|
||||||
|
/* Run sesh -e 1 <t1> <o1> ... <tn> <on> */
|
||||||
|
- command_details->argv = sesh_args;
|
||||||
|
- rc = run_command(command_details);
|
||||||
|
+ rc = selinux_run_helper(sesh_args, command_details->envp);
|
||||||
|
switch (rc) {
|
||||||
|
case SESH_SUCCESS:
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
case SESH_ERR_NO_FILES:
|
||||||
|
sudo_warnx(U_("unable to copy temporary files back to their original location"));
|
||||||
|
- sudo_warnx(U_("contents of edit session left in %s"), edit_tmpdir);
|
||||||
|
break;
|
||||||
|
case SESH_ERR_SOME_FILES:
|
||||||
|
sudo_warnx(U_("unable to copy some of the temporary files back to their original location"));
|
||||||
|
- sudo_warnx(U_("contents of edit session left in %s"), edit_tmpdir);
|
||||||
|
+ break;
|
||||||
|
+ case SESH_ERR_KILLED:
|
||||||
|
+ sudo_warnx(U_("sesh: killed by a signal"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sudo_warnx(U_("sesh: unknown error %d"), rc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
+ if (ret != 0)
|
||||||
|
+ sudo_warnx(U_("contents of edit session left in %s"), edit_tmpdir);
|
||||||
|
}
|
||||||
|
free(sesh_args);
|
||||||
|
|
||||||
|
- /* Restore saved command_details. */
|
||||||
|
- command_details->command = saved_command_details.command;
|
||||||
|
- command_details->flags = saved_command_details.flags;
|
||||||
|
- command_details->argv = saved_command_details.argv;
|
||||||
|
-
|
||||||
|
debug_return_int(ret);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_SELINUX */
|
||||||
|
@@ -990,6 +1000,15 @@ sudo_edit(struct command_details *comman
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
+#ifdef HAVE_SELINUX
|
||||||
|
+ /* Compute new SELinux security context. */
|
||||||
|
+ if (ISSET(command_details->flags, CD_RBAC_ENABLED)) {
|
||||||
|
+ if (selinux_setup(command_details->selinux_role,
|
||||||
|
+ command_details->selinux_type, NULL, -1, false) != 0)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/* Copy editor files to temporaries. */
|
||||||
|
tf = calloc(nfiles, sizeof(*tf));
|
||||||
|
if (tf == NULL) {
|
||||||
|
@@ -1025,6 +1044,7 @@ sudo_edit(struct command_details *comman
|
||||||
|
/*
|
||||||
|
* Run the editor with the invoking user's creds,
|
||||||
|
* keeping track of the time spent in the editor.
|
||||||
|
+ * XXX - should run editor with user's context
|
||||||
|
*/
|
||||||
|
if (sudo_gettime_real(×[0]) == -1) {
|
||||||
|
sudo_warn(U_("unable to read the clock"));
|
||||||
|
diff -up ./src/sudo_exec.h.symbolic-link-attack-3 ./src/sudo_exec.h
|
||||||
|
--- ./src/sudo_exec.h.symbolic-link-attack-3 2021-02-02 17:11:32.380020435 +0100
|
||||||
|
+++ ./src/sudo_exec.h 2021-02-02 17:11:32.382020407 +0100
|
||||||
|
@@ -73,6 +73,7 @@
|
||||||
|
*/
|
||||||
|
#define SESH_SUCCESS 0 /* successful operation */
|
||||||
|
#define SESH_ERR_FAILURE 1 /* unspecified error */
|
||||||
|
+#define SESH_ERR_KILLED 2 /* killed by a signal */
|
||||||
|
#define SESH_ERR_INVALID 30 /* invalid -e arg value */
|
||||||
|
#define SESH_ERR_BAD_PATHS 31 /* odd number of paths */
|
||||||
|
#define SESH_ERR_NO_FILES 32 /* copy error, no files copied */
|
||||||
|
diff -up ./src/sudo.h.symbolic-link-attack-3 ./src/sudo.h
|
||||||
|
--- ./src/sudo.h.symbolic-link-attack-3 2019-10-28 13:28:52.000000000 +0100
|
||||||
|
+++ ./src/sudo.h 2021-02-02 17:11:32.382020407 +0100
|
||||||
|
@@ -135,12 +135,11 @@ struct user_details {
|
||||||
|
#define CD_USE_PTY 0x001000
|
||||||
|
#define CD_SET_UTMP 0x002000
|
||||||
|
#define CD_EXEC_BG 0x004000
|
||||||
|
-#define CD_SUDOEDIT_COPY 0x008000
|
||||||
|
-#define CD_SUDOEDIT_FOLLOW 0x010000
|
||||||
|
-#define CD_SUDOEDIT_CHECKDIR 0x020000
|
||||||
|
-#define CD_SET_GROUPS 0x040000
|
||||||
|
-#define CD_LOGIN_SHELL 0x080000
|
||||||
|
-#define CD_OVERRIDE_UMASK 0x100000
|
||||||
|
+#define CD_SUDOEDIT_FOLLOW 0x008000
|
||||||
|
+#define CD_SUDOEDIT_CHECKDIR 0x010000
|
||||||
|
+#define CD_SET_GROUPS 0x020000
|
||||||
|
+#define CD_LOGIN_SHELL 0x040000
|
||||||
|
+#define CD_OVERRIDE_UMASK 0x080000
|
||||||
|
|
||||||
|
struct preserved_fd {
|
||||||
|
TAILQ_ENTRY(preserved_fd) entries;
|
||||||
|
@@ -240,7 +239,8 @@ int os_init_openbsd(int argc, char *argv
|
||||||
|
/* selinux.c */
|
||||||
|
int selinux_restore_tty(void);
|
||||||
|
int selinux_setup(const char *role, const char *type, const char *ttyn,
|
||||||
|
- int ttyfd);
|
||||||
|
+ int ttyfd, bool label_tty);
|
||||||
|
+int selinux_setcon(void);
|
||||||
|
void selinux_execve(int fd, const char *path, char *const argv[],
|
||||||
|
char *envp[], bool noexec);
|
||||||
|
|
380
SOURCES/sudo-1.9.5-CVE-2021-23240-4.patch
Normal file
380
SOURCES/sudo-1.9.5-CVE-2021-23240-4.patch
Normal file
@ -0,0 +1,380 @@
|
|||||||
|
diff -up ./src/copy_file.c.symbolic-link-attack-4 ./src/copy_file.c
|
||||||
|
--- ./src/copy_file.c.symbolic-link-attack-4 2021-02-02 16:35:18.453036846 +0100
|
||||||
|
+++ ./src/copy_file.c 2021-02-02 16:38:09.430731749 +0100
|
||||||
|
@@ -23,6 +23,7 @@
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
+#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
@@ -126,3 +127,35 @@ write_error:
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+#ifdef HAVE_SELINUX
|
||||||
|
+bool
|
||||||
|
+sudo_check_temp_file(int tfd, const char *tfile, uid_t uid, struct stat *sb)
|
||||||
|
+{
|
||||||
|
+ struct stat sbuf;
|
||||||
|
+ debug_decl(sudo_check_temp_file, SUDO_DEBUG_UTIL);
|
||||||
|
+
|
||||||
|
+ if (sb == NULL)
|
||||||
|
+ sb = &sbuf;
|
||||||
|
+
|
||||||
|
+ if (fstat(tfd, sb) == -1) {
|
||||||
|
+ sudo_warn(U_("unable to stat %s"), tfile);
|
||||||
|
+ debug_return_bool(false);
|
||||||
|
+ }
|
||||||
|
+ if (!S_ISREG(sb->st_mode)) {
|
||||||
|
+ sudo_warnx(U_("%s: not a regular file"), tfile);
|
||||||
|
+ debug_return_bool(false);
|
||||||
|
+ }
|
||||||
|
+ if ((sb->st_mode & ALLPERMS) != (S_IRUSR|S_IWUSR)) {
|
||||||
|
+ sudo_warnx(U_("%s: bad file mode: 0%o"), tfile,
|
||||||
|
+ (unsigned int)(sb->st_mode & ALLPERMS));
|
||||||
|
+ debug_return_bool(false);
|
||||||
|
+ }
|
||||||
|
+ if (sb->st_uid != uid) {
|
||||||
|
+ sudo_warnx(U_("%s is owned by uid %u, should be %u"),
|
||||||
|
+ tfile, (unsigned int)sb->st_uid, (unsigned int)uid);
|
||||||
|
+ debug_return_bool(false);
|
||||||
|
+ }
|
||||||
|
+ debug_return_bool(true);
|
||||||
|
+}
|
||||||
|
+#endif /* SELINUX */
|
||||||
|
diff -up ./src/sesh.c.symbolic-link-attack-4 ./src/sesh.c
|
||||||
|
--- ./src/sesh.c.symbolic-link-attack-4 2021-02-02 16:35:18.450036887 +0100
|
||||||
|
+++ ./src/sesh.c 2021-02-02 16:38:52.907146897 +0100
|
||||||
|
@@ -134,7 +134,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;
|
||||||
|
ssize_t nread, nwritten;
|
||||||
|
struct stat sb;
|
||||||
|
@@ -178,10 +178,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];
|
||||||
|
@@ -191,7 +193,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) {
|
||||||
|
@@ -201,6 +203,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) {
|
||||||
|
@@ -218,10 +228,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;
|
||||||
|
diff -up ./src/sudo_edit.c.symbolic-link-attack-4 ./src/sudo_edit.c
|
||||||
|
--- ./src/sudo_edit.c.symbolic-link-attack-4 2021-02-02 16:35:18.452036860 +0100
|
||||||
|
+++ ./src/sudo_edit.c 2021-02-02 16:54:25.943429580 +0100
|
||||||
|
@@ -253,8 +253,10 @@ sudo_edit_mktemp(const char *ofile, char
|
||||||
|
} else {
|
||||||
|
len = asprintf(tfile, "%s/%s.XXXXXXXX", edit_tmpdir, cp);
|
||||||
|
}
|
||||||
|
- if (len == -1)
|
||||||
|
- sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||||
|
+ if (len == -1) {
|
||||||
|
+ sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||||
|
+ debug_return_int(-1);
|
||||||
|
+ }
|
||||||
|
tfd = mkstemps(*tfile, suff ? strlen(suff) : 0);
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||||
|
"%s -> %s, fd %d", ofile, *tfile, tfd);
|
||||||
|
@@ -757,7 +759,8 @@ bad:
|
||||||
|
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
static int
|
||||||
|
-selinux_run_helper(char *argv[], char *envp[])
|
||||||
|
+selinux_run_helper(uid_t uid, gid_t gid, int ngroups, GETGROUPS_T *groups,
|
||||||
|
+ char *const argv[], char *const envp[])
|
||||||
|
{
|
||||||
|
int status, ret = SESH_ERR_FAILURE;
|
||||||
|
const char *sesh;
|
||||||
|
@@ -777,8 +780,10 @@ selinux_run_helper(char *argv[], char *e
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
/* child runs sesh in new context */
|
||||||
|
- if (selinux_setcon() == 0)
|
||||||
|
+ if (selinux_setcon() == 0) {
|
||||||
|
+ switch_user(uid, gid, ngroups, groups);
|
||||||
|
execve(sesh, argv, envp);
|
||||||
|
+ }
|
||||||
|
_exit(SESH_ERR_FAILURE);
|
||||||
|
default:
|
||||||
|
/* parent waits */
|
||||||
|
@@ -797,7 +802,7 @@ selinux_edit_create_tfiles(struct comman
|
||||||
|
struct tempfile *tf, char *files[], int nfiles)
|
||||||
|
{
|
||||||
|
char **sesh_args, **sesh_ap;
|
||||||
|
- int i, rc, sesh_nargs;
|
||||||
|
+ int i, rc, error, sesh_nargs, ret = -1;
|
||||||
|
struct stat sb;
|
||||||
|
debug_decl(selinux_edit_create_tfiles, SUDO_DEBUG_EDIT)
|
||||||
|
|
||||||
|
@@ -809,7 +814,7 @@ selinux_edit_create_tfiles(struct comman
|
||||||
|
sesh_args = sesh_ap = reallocarray(NULL, sesh_nargs, sizeof(char *));
|
||||||
|
if (sesh_args == NULL) {
|
||||||
|
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||||
|
- debug_return_int(-1);
|
||||||
|
+ goto done;
|
||||||
|
}
|
||||||
|
*sesh_ap++ = "sesh";
|
||||||
|
*sesh_ap++ = "-e";
|
||||||
|
@@ -817,7 +822,6 @@ selinux_edit_create_tfiles(struct comman
|
||||||
|
*sesh_ap++ = "-h";
|
||||||
|
*sesh_ap++ = "0";
|
||||||
|
|
||||||
|
- /* XXX - temp files should be created with user's context */
|
||||||
|
for (i = 0; i < nfiles; i++) {
|
||||||
|
char *tfile, *ofile = files[i];
|
||||||
|
int tfd;
|
||||||
|
@@ -835,8 +839,7 @@ selinux_edit_create_tfiles(struct comman
|
||||||
|
if (tfd == -1) {
|
||||||
|
sudo_warn("mkstemps");
|
||||||
|
free(tfile);
|
||||||
|
- free(sesh_args);
|
||||||
|
- debug_return_int(-1);
|
||||||
|
+ goto done;
|
||||||
|
}
|
||||||
|
/* Helper will re-create temp file with proper security context. */
|
||||||
|
close(tfd);
|
||||||
|
@@ -847,8 +850,10 @@ selinux_edit_create_tfiles(struct comman
|
||||||
|
*sesh_ap = NULL;
|
||||||
|
|
||||||
|
/* Run sesh -e [-h] 0 <o1> <t1> ... <on> <tn> */
|
||||||
|
- rc = selinux_run_helper(sesh_args, command_details->envp);
|
||||||
|
- switch (rc) {
|
||||||
|
+ error = selinux_run_helper(command_details->uid, command_details->gid,
|
||||||
|
+ command_details->ngroups, command_details->groups, sesh_args,
|
||||||
|
+ command_details->envp);
|
||||||
|
+ switch (error) {
|
||||||
|
case SESH_SUCCESS:
|
||||||
|
break;
|
||||||
|
case SESH_ERR_BAD_PATHS:
|
||||||
|
@@ -858,21 +863,34 @@ selinux_edit_create_tfiles(struct comman
|
||||||
|
case SESH_ERR_KILLED:
|
||||||
|
sudo_fatalx(U_("sesh: killed by a signal"));
|
||||||
|
default:
|
||||||
|
- sudo_fatalx(U_("sesh: unknown error %d"), rc);
|
||||||
|
+ sudo_fatalx(U_("sesh: unknown error %d"), error);
|
||||||
|
+ goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* Chown to user's UID so they can edit the temporary files. */
|
||||||
|
for (i = 0; i < nfiles; i++) {
|
||||||
|
- if (chown(tf[i].tfile, user_details.uid, user_details.gid) != 0) {
|
||||||
|
- sudo_warn("unable to chown(%s) to %d:%d for editing",
|
||||||
|
- tf[i].tfile, user_details.uid, user_details.gid);
|
||||||
|
- }
|
||||||
|
+ int tfd = open(tf[i].tfile, O_RDONLY|O_NONBLOCK|O_NOFOLLOW);
|
||||||
|
+ if (tfd == -1) {
|
||||||
|
+ sudo_warn(U_("unable to open %s"), tf[i].tfile);
|
||||||
|
+ goto done;
|
||||||
|
+ }
|
||||||
|
+ if (!sudo_check_temp_file(tfd, tf[i].tfile, command_details->uid, NULL)) {
|
||||||
|
+ close(tfd);
|
||||||
|
+ goto done;
|
||||||
|
+ }
|
||||||
|
+ if (fchown(tfd, user_details.uid, user_details.gid) != 0) {
|
||||||
|
+ sudo_warn("unable to chown(%s) to %d:%d for editing",
|
||||||
|
+ tf[i].tfile, user_details.uid, user_details.gid);
|
||||||
|
+ close(tfd);
|
||||||
|
+ goto done;
|
||||||
|
+ }
|
||||||
|
+ close(tfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
+done:
|
||||||
|
/* Contents of tf will be freed by caller. */
|
||||||
|
free(sesh_args);
|
||||||
|
|
||||||
|
- return (nfiles);
|
||||||
|
+ debug_return_int(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
@@ -880,7 +898,8 @@ selinux_edit_copy_tfiles(struct command_
|
||||||
|
struct tempfile *tf, int nfiles, struct timespec *times)
|
||||||
|
{
|
||||||
|
char **sesh_args, **sesh_ap;
|
||||||
|
- int i, rc, sesh_nargs, ret = 1;
|
||||||
|
+ int i, rc, error, sesh_nargs, ret = 1;
|
||||||
|
+ int tfd = -1;
|
||||||
|
struct timespec ts;
|
||||||
|
struct stat sb;
|
||||||
|
debug_decl(selinux_edit_copy_tfiles, SUDO_DEBUG_EDIT)
|
||||||
|
@@ -901,33 +920,43 @@ selinux_edit_copy_tfiles(struct command_
|
||||||
|
|
||||||
|
/* Construct args for sesh -e 1 */
|
||||||
|
for (i = 0; i < nfiles; i++) {
|
||||||
|
- if (stat(tf[i].tfile, &sb) == 0) {
|
||||||
|
- mtim_get(&sb, ts);
|
||||||
|
- if (tf[i].osize == sb.st_size && sudo_timespeccmp(&tf[i].omtim, &ts, ==)) {
|
||||||
|
- /*
|
||||||
|
- * If mtime and size match but the user spent no measurable
|
||||||
|
- * time in the editor we can't tell if the file was changed.
|
||||||
|
- */
|
||||||
|
- if (sudo_timespeccmp(×[0], ×[1], !=)) {
|
||||||
|
- sudo_warnx(U_("%s unchanged"), tf[i].ofile);
|
||||||
|
- unlink(tf[i].tfile);
|
||||||
|
- continue;
|
||||||
|
- }
|
||||||
|
+ if (tfd != -1)
|
||||||
|
+ close(tfd);
|
||||||
|
+ if ((tfd = open(tf[i].tfile, O_RDONLY|O_NONBLOCK|O_NOFOLLOW)) == -1) {
|
||||||
|
+ sudo_warn(U_("unable to open %s"), tf[i].tfile);
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ if (!sudo_check_temp_file(tfd, tf[i].tfile, user_details.uid, &sb))
|
||||||
|
+ continue;
|
||||||
|
+ mtim_get(&sb, ts);
|
||||||
|
+ if (tf[i].osize == sb.st_size && sudo_timespeccmp(&tf[i].omtim, &ts, ==)) {
|
||||||
|
+ /*
|
||||||
|
+ * If mtime and size match but the user spent no measurable
|
||||||
|
+ * time in the editor we can't tell if the file was changed.
|
||||||
|
+ */
|
||||||
|
+ if (sudo_timespeccmp(×[0], ×[1], !=)) {
|
||||||
|
+ sudo_warnx(U_("%s unchanged"), tf[i].ofile);
|
||||||
|
+ unlink(tf[i].tfile);
|
||||||
|
+ continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*sesh_ap++ = tf[i].tfile;
|
||||||
|
*sesh_ap++ = tf[i].ofile;
|
||||||
|
- if (chown(tf[i].tfile, command_details->uid, command_details->gid) != 0) {
|
||||||
|
+ if (fchown(tfd, command_details->uid, command_details->gid) != 0) {
|
||||||
|
sudo_warn("unable to chown(%s) back to %d:%d", tf[i].tfile,
|
||||||
|
command_details->uid, command_details->gid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*sesh_ap = NULL;
|
||||||
|
+ if (tfd != -1)
|
||||||
|
+ close(tfd);
|
||||||
|
|
||||||
|
if (sesh_ap - sesh_args > 3) {
|
||||||
|
/* Run sesh -e 1 <t1> <o1> ... <tn> <on> */
|
||||||
|
- rc = selinux_run_helper(sesh_args, command_details->envp);
|
||||||
|
- switch (rc) {
|
||||||
|
+ error = selinux_run_helper(command_details->uid, command_details->gid,
|
||||||
|
+ command_details->ngroups, command_details->groups, sesh_args,
|
||||||
|
+ command_details->envp);
|
||||||
|
+ switch (error) {
|
||||||
|
case SESH_SUCCESS:
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
@@ -941,7 +970,7 @@ selinux_edit_copy_tfiles(struct command_
|
||||||
|
sudo_warnx(U_("sesh: killed by a signal"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
- sudo_warnx(U_("sesh: unknown error %d"), rc);
|
||||||
|
+ sudo_warnx(U_("sesh: unknown error %d"), error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret != 0)
|
||||||
|
@@ -963,7 +992,7 @@ sudo_edit(struct command_details *comman
|
||||||
|
{
|
||||||
|
struct command_details saved_command_details;
|
||||||
|
char **nargv = NULL, **ap, **files = NULL;
|
||||||
|
- int errors, i, ac, nargc, rc;
|
||||||
|
+ int errors, i, ac, nargc, ret;
|
||||||
|
int editor_argc = 0, nfiles = 0;
|
||||||
|
struct timespec times[2];
|
||||||
|
struct tempfile *tf = NULL;
|
||||||
|
@@ -1058,7 +1087,7 @@ sudo_edit(struct command_details *comman
|
||||||
|
command_details->ngroups = user_details.ngroups;
|
||||||
|
command_details->groups = user_details.groups;
|
||||||
|
command_details->argv = nargv;
|
||||||
|
- rc = run_command(command_details);
|
||||||
|
+ ret = run_command(command_details);
|
||||||
|
if (sudo_gettime_real(×[1]) == -1) {
|
||||||
|
sudo_warn(U_("unable to read the clock"));
|
||||||
|
goto cleanup;
|
||||||
|
@@ -1080,14 +1109,16 @@ sudo_edit(struct command_details *comman
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
errors = sudo_edit_copy_tfiles(command_details, tf, nfiles, times);
|
||||||
|
- if (errors)
|
||||||
|
- goto cleanup;
|
||||||
|
+ if (errors) {
|
||||||
|
+ /* Preserve the edited temporary files. */
|
||||||
|
+ ret = W_EXITCODE(1, 0);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
for (i = 0; i < nfiles; i++)
|
||||||
|
free(tf[i].tfile);
|
||||||
|
free(tf);
|
||||||
|
free(nargv);
|
||||||
|
- debug_return_int(rc);
|
||||||
|
+ debug_return_int(ret);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
/* Clean up temp files and return. */
|
||||||
|
diff -up ./src/sudo_exec.h.symbolic-link-attack-4 ./src/sudo_exec.h
|
||||||
|
--- ./src/sudo_exec.h.symbolic-link-attack-4 2021-02-02 16:35:18.452036860 +0100
|
||||||
|
+++ ./src/sudo_exec.h 2021-02-02 16:35:18.454036833 +0100
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: ISC
|
||||||
|
*
|
||||||
|
- * Copyright (c) 2010-2016 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
|
+ * Copyright (c) 2010-2017, 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
|
||||||
|
@@ -84,9 +84,11 @@
|
||||||
|
*/
|
||||||
|
struct command_details;
|
||||||
|
struct command_status;
|
||||||
|
+struct stat;
|
||||||
|
|
||||||
|
/* copy_file.c */
|
||||||
|
int sudo_copy_file(const char *src, int src_fd, off_t src_len, const char *dst, int dst_fd, off_t dst_len);
|
||||||
|
+bool sudo_check_temp_file(int tfd, const char *tname, uid_t uid, struct stat *sb);
|
||||||
|
|
||||||
|
/* exec.c */
|
||||||
|
void exec_cmnd(struct command_details *details, int errfd);
|
47
SOURCES/sudo-1.9.5-CVE-2021-23240-5.patch
Normal file
47
SOURCES/sudo-1.9.5-CVE-2021-23240-5.patch
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
diff -up ./src/copy_file.c.symbolic-link-attack-5 ./src/copy_file.c
|
||||||
|
--- ./src/copy_file.c.symbolic-link-attack-5 2021-02-02 17:18:05.355567274 +0100
|
||||||
|
+++ ./src/copy_file.c 2021-02-02 17:19:09.904671563 +0100
|
||||||
|
@@ -128,7 +128,6 @@ write_error:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-#ifdef HAVE_SELINUX
|
||||||
|
bool
|
||||||
|
sudo_check_temp_file(int tfd, const char *tfile, uid_t uid, struct stat *sb)
|
||||||
|
{
|
||||||
|
@@ -158,4 +157,3 @@ sudo_check_temp_file(int tfd, const char
|
||||||
|
}
|
||||||
|
debug_return_bool(true);
|
||||||
|
}
|
||||||
|
-#endif /* SELINUX */
|
||||||
|
diff -up ./src/sudo_edit.c.symbolic-link-attack-5 ./src/sudo_edit.c
|
||||||
|
--- ./src/sudo_edit.c.symbolic-link-attack-5 2021-02-02 17:18:05.355567274 +0100
|
||||||
|
+++ ./src/sudo_edit.c 2021-02-02 17:18:05.356567260 +0100
|
||||||
|
@@ -692,24 +692,17 @@ sudo_edit_copy_tfiles(struct command_det
|
||||||
|
|
||||||
|
/* Copy contents of temp files to real ones. */
|
||||||
|
for (i = 0; i < nfiles; i++) {
|
||||||
|
- int rc = -1;
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||||
|
"seteuid(%u)", (unsigned int)user_details.uid);
|
||||||
|
if (seteuid(user_details.uid) != 0)
|
||||||
|
sudo_fatal("seteuid(%u)", (unsigned int)user_details.uid);
|
||||||
|
tfd = sudo_edit_open(tf[i].tfile, O_RDONLY,
|
||||||
|
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, NULL);
|
||||||
|
- if (tfd != -1)
|
||||||
|
- rc = fstat(tfd, &sb);
|
||||||
|
- sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||||
|
- "seteuid(%u)", ROOT_UID);
|
||||||
|
if (seteuid(ROOT_UID) != 0)
|
||||||
|
sudo_fatal("seteuid(ROOT_UID)");
|
||||||
|
- if (rc == -1 || !S_ISREG(sb.st_mode)) {
|
||||||
|
- if (rc == -1)
|
||||||
|
- sudo_warn("%s", tf[i].tfile);
|
||||||
|
- else
|
||||||
|
- sudo_warnx(U_("%s: not a regular file"), tf[i].tfile);
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||||
|
+ "seteuid(%u)", ROOT_UID);
|
||||||
|
+ if (tfd == -1 || !sudo_check_temp_file(tfd, tf[i].tfile, user_details.uid, &sb)) {
|
||||||
|
sudo_warnx(U_("%s left unmodified"), tf[i].ofile);
|
||||||
|
if (tfd != -1)
|
||||||
|
close(tfd);
|
@ -1,10 +1,10 @@
|
|||||||
Summary: Allows restricted root access for specified users
|
Summary: Allows restricted root access for specified users
|
||||||
Name: sudo
|
Name: sudo
|
||||||
Version: 1.8.29
|
Version: 1.8.29
|
||||||
Release: 6%{?dist}.1
|
Release: 7%{?dist}
|
||||||
License: ISC
|
License: ISC
|
||||||
Group: Applications/System
|
Group: Applications/System
|
||||||
URL: http://www.courtesan.com/sudo/
|
URL: https://www.sudo.ws/
|
||||||
|
|
||||||
Source0: https://www.sudo.ws/dist/%{name}-%{version}.tar.gz
|
Source0: https://www.sudo.ws/dist/%{name}-%{version}.tar.gz
|
||||||
Source1: sudoers
|
Source1: sudoers
|
||||||
@ -56,8 +56,16 @@ Patch9: sudo-1.8.29-CVE-2019-18634.patch
|
|||||||
Patch10: sudo-1.8.29-expired-password-part1.patch
|
Patch10: sudo-1.8.29-expired-password-part1.patch
|
||||||
Patch11: sudo-1.8.29-expired-password-part2.patch
|
Patch11: sudo-1.8.29-expired-password-part2.patch
|
||||||
|
|
||||||
# 1917732 - EMBARGOED CVE-2021-3156 sudo: Heap-buffer overflow in argument parsing [rhel-8.3.0.z]
|
# 1917734 - EMBARGOED CVE-2021-3156 sudo: Heap-buffer overflow in argument parsing [rhel-8.4.0]
|
||||||
Patch12: sudo-1.8.31-CVE-2021-3156.patch
|
Patch12: sudo-1.8.31-CVE-2021-3156.patch
|
||||||
|
# 1916434 - CVE-2021-23239 sudo: possible directory existence test due to race condition in sudoedit [rhel-8]
|
||||||
|
Patch13: sudo-1.9.5-CVE-2021-23239.patch
|
||||||
|
# 1917038 - CVE-2021-23240 sudo: symbolic link attack in SELinux-enabled sudoedit [rhel-8]
|
||||||
|
Patch14: sudo-1.9.5-CVE-2021-23240-1.patch
|
||||||
|
Patch15: sudo-1.9.5-CVE-2021-23240-2.patch
|
||||||
|
Patch16: sudo-1.9.5-CVE-2021-23240-3.patch
|
||||||
|
Patch17: sudo-1.9.5-CVE-2021-23240-4.patch
|
||||||
|
Patch18: sudo-1.9.5-CVE-2021-23240-5.patch
|
||||||
|
|
||||||
%description
|
%description
|
||||||
Sudo (superuser do) allows a system administrator to give certain
|
Sudo (superuser do) allows a system administrator to give certain
|
||||||
@ -97,6 +105,14 @@ plugins that use %{name}.
|
|||||||
|
|
||||||
%patch12 -p1 -b .heap-buffer
|
%patch12 -p1 -b .heap-buffer
|
||||||
|
|
||||||
|
%patch13 -p1 -b .sudoedit-race
|
||||||
|
|
||||||
|
%patch14 -p1 -b .symbolic-link-attack-1
|
||||||
|
%patch15 -p1 -b .symbolic-link-attack-2
|
||||||
|
%patch16 -p1 -b .symbolic-link-attack-3
|
||||||
|
%patch17 -p1 -b .symbolic-link-attack-4
|
||||||
|
%patch18 -p1 -b .symbolic-link-attack-5
|
||||||
|
|
||||||
%build
|
%build
|
||||||
# Remove bundled copy of zlib
|
# Remove bundled copy of zlib
|
||||||
rm -rf zlib/
|
rm -rf zlib/
|
||||||
@ -255,10 +271,16 @@ rm -rf $RPM_BUILD_ROOT
|
|||||||
%{_mandir}/man8/sudo_plugin.8*
|
%{_mandir}/man8/sudo_plugin.8*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Wed Jan 20 2021 Radovan Sroka <rsroka@redhat.com> - 1.8.29-6.1
|
* Tue Feb 02 2021 Radovan Sroka <rsroka@redhat.com> - 1.8.29-7
|
||||||
- RHEL 8.3.Z ERRATUM
|
- RHEL 8.4 ERRATUM
|
||||||
- CVE-2021-3156
|
- CVE-2021-3156
|
||||||
Resolves: rhbz#1917732
|
Resolves: rhbz#1917734
|
||||||
|
- CVE-2021-23239 sudo: possible directory existence test due to race condition in sudoedit
|
||||||
|
Resolves: rhzb#1916434
|
||||||
|
- CVE-2021-23240 sudo: symbolic link attack in SELinux-enabled sudoedit
|
||||||
|
Resolves: rhbz#1917038
|
||||||
|
- updated upstream url
|
||||||
|
Resolves: rhbz#1923825
|
||||||
|
|
||||||
* Tue Apr 28 2020 Radovan Sroka <rsroka@redhat.com> - 1.8.29-6
|
* Tue Apr 28 2020 Radovan Sroka <rsroka@redhat.com> - 1.8.29-6
|
||||||
- RHEL 8.3 ERRATUM
|
- RHEL 8.3 ERRATUM
|
||||||
|
Loading…
Reference in New Issue
Block a user