Blame SOURCES/sudo-1.9.5-CVE-2021-23240-1.patch

15c49f
From adb4360c40df99238c17c3ecedcb1d32d76e2b2e Mon Sep 17 00:00:00 2001
15c49f
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
15c49f
Date: Fri, 17 Apr 2020 19:08:56 -0600
15c49f
Subject: [PATCH] Extend the original file before to the new size before
15c49f
 updating it. Instead of opening the original file for writing w/ tuncation,
15c49f
 we first extend the file with zeroes (by writing, not seeking), then
15c49f
 overwrite it.  This should allow sudo to fail early if the disk is out of
15c49f
 space before it overwrites the original file.
15c49f
15c49f
---
15c49f
 src/sudo_edit.c | 93 ++++++++++++++++++++++++++++++++++++++++---------
15c49f
 1 file changed, 77 insertions(+), 16 deletions(-)
15c49f
15c49f
diff --git a/src/sudo_edit.c b/src/sudo_edit.c
15c49f
index 28f6c6100..d99a5658a 100644
15c49f
--- a/src/sudo_edit.c
15c49f
+++ b/src/sudo_edit.c
15c49f
@@ -1,7 +1,7 @@
15c49f
 /*
15c49f
  * SPDX-License-Identifier: ISC
15c49f
  *
15c49f
- * Copyright (c) 2004-2008, 2010-2018 Todd C. Miller <Todd.Miller@sudo.ws>
15c49f
+ * Copyright (c) 2004-2008, 2010-2020 Todd C. Miller <Todd.Miller@sudo.ws>
15c49f
  *
15c49f
  * Permission to use, copy, modify, and distribute this software for any
15c49f
  * purpose with or without fee is hereby granted, provided that the above
15c49f
@@ -650,6 +650,51 @@ sudo_edit_create_tfiles(struct command_details *command_details,
15c49f
     debug_return_int(j);
15c49f
 }
15c49f
 
15c49f
+/*
15c49f
+ * Extend the given fd to the specified size in bytes.
15c49f
+ * We do this to allocate disk space up-front before overwriting
15c49f
+ * the original file with the temporary.  Otherwise, we could
15c49f
+ * we run out of disk space after truncating the original file.
15c49f
+ */
15c49f
+static int
15c49f
+sudo_edit_extend_file(int fd, off_t new_size)
15c49f
+{
15c49f
+    off_t old_size, size;
15c49f
+    ssize_t nwritten;
15c49f
+    char zeroes[1024] = { '\0' };
15c49f
+    debug_decl(sudo_edit_extend_file, SUDO_DEBUG_EDIT);
15c49f
+
15c49f
+    if ((old_size = lseek(fd, 0, SEEK_END)) == -1) {
15c49f
+	sudo_warn("lseek");
15c49f
+	debug_return_int(-1);
15c49f
+    }
15c49f
+    sudo_debug_printf(SUDO_DEBUG_INFO, "%s: extending file from %lld to %lld",
15c49f
+	__func__, (long long)old_size, (long long)new_size);
15c49f
+
15c49f
+    for (size = old_size; size < new_size; size += nwritten) {
15c49f
+	size_t len = new_size - size;
15c49f
+	if (len > sizeof(zeroes))
15c49f
+	    len = sizeof(zeroes);
15c49f
+	nwritten = write(fd, zeroes, len);
15c49f
+	if (nwritten == -1) {
15c49f
+	    int serrno = errno;
15c49f
+	    if (ftruncate(fd, old_size) == -1) {
15c49f
+		sudo_debug_printf(
15c49f
+		    SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
15c49f
+		    "unable to truncate to %lld", (long long)old_size);
15c49f
+	    }
15c49f
+	    errno = serrno;
15c49f
+	    debug_return_int(-1);
15c49f
+	}
15c49f
+    }
15c49f
+    if (lseek(fd, 0, SEEK_SET) == -1) {
15c49f
+	sudo_warn("lseek");
15c49f
+	debug_return_int(-1);
15c49f
+    }
15c49f
+
15c49f
+    debug_return_int(0);
15c49f
+}
15c49f
+
15c49f
 /*
15c49f
  * Copy the temporary files specified in tf to the originals.
15c49f
  * Returns the number of copy errors or 0 if completely successful.
15c49f
@@ -708,38 +753,53 @@ sudo_edit_copy_tfiles(struct command_details *command_details,
15c49f
 	switch_user(command_details->euid, command_details->egid,
15c49f
 	    command_details->ngroups, command_details->groups);
15c49f
 	oldmask = umask(command_details->umask);
15c49f
-	ofd = sudo_edit_open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT,
15c49f
+	ofd = sudo_edit_open(tf[i].ofile, O_WRONLY|O_CREAT,
15c49f
 	    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, command_details);
15c49f
 	umask(oldmask);
15c49f
 	switch_user(ROOT_UID, user_details.egid,
15c49f
 	    user_details.ngroups, user_details.groups);
15c49f
-	if (ofd == -1) {
15c49f
-	    sudo_warn(U_("unable to write to %s"), tf[i].ofile);
15c49f
-	    sudo_warnx(U_("contents of edit session left in %s"), tf[i].tfile);
15c49f
-	    close(tfd);
15c49f
-	    errors++;
15c49f
-	    continue;
15c49f
+	if (ofd == -1)
15c49f
+	    goto write_error;
15c49f
+	/* Extend the file to the new size if larger before copying. */
15c49f
+	if (tf[i].osize > 0 && sb.st_size > tf[i].osize) {
15c49f
+	    if (sudo_edit_extend_file(ofd, sb.st_size) == -1)
15c49f
+		goto write_error;
15c49f
 	}
15c49f
+	/* Overwrite the old file with the new contents. */
15c49f
 	while ((nread = read(tfd, buf, sizeof(buf))) > 0) {
15c49f
-	    if ((nwritten = write(ofd, buf, nread)) != nread) {
15c49f
+	    ssize_t off = 0;
15c49f
+	    do {
15c49f
+		nwritten = write(ofd, buf + off, nread - off);
15c49f
 		if (nwritten == -1)
15c49f
-		    sudo_warn("%s", tf[i].ofile);
15c49f
-		else
15c49f
-		    sudo_warnx(U_("%s: short write"), tf[i].ofile);
15c49f
-		break;
15c49f
-	    }
15c49f
+		    goto write_error;
15c49f
+		off += nwritten;
15c49f
+	    } while (nread > off);
15c49f
 	}
15c49f
 	if (nread == 0) {
15c49f
-	    /* success, got EOF */
15c49f
+	    /* success, read to EOF */
15c49f
+	    if (tf[i].osize > 0 && sb.st_size < tf[i].osize) {
15c49f
+		/* We don't open with O_TRUNC so must truncate manually. */
15c49f
+		if (ftruncate(ofd, sb.st_size)  == -1) {
15c49f
+		    sudo_debug_printf(
15c49f
+			SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
15c49f
+			"unable to truncate %s to %lld", tf[i].ofile,
15c49f
+			(long long)sb.st_size);
15c49f
+		    goto write_error;
15c49f
+		}
15c49f
+	    }
15c49f
 	    unlink(tf[i].tfile);
15c49f
 	} else if (nread < 0) {
15c49f
 	    sudo_warn(U_("unable to read temporary file"));
15c49f
 	    sudo_warnx(U_("contents of edit session left in %s"), tf[i].tfile);
15c49f
+	    errors++;
15c49f
 	} else {
15c49f
+write_error:
15c49f
 	    sudo_warn(U_("unable to write to %s"), tf[i].ofile);
15c49f
 	    sudo_warnx(U_("contents of edit session left in %s"), tf[i].tfile);
15c49f
+	    errors++;
15c49f
 	}
15c49f
-	close(ofd);
15c49f
+	if (ofd != -1)
15c49f
+	    close(ofd);
15c49f
 	close(tfd);
15c49f
     }
15c49f
     debug_return_int(errors);
15c49f
@@ -1065,6 +1125,7 @@ cleanup:
15c49f
 	for (i = 0; i < nfiles; i++) {
15c49f
 	    if (tf[i].tfile != NULL)
15c49f
 		unlink(tf[i].tfile);
15c49f
+	    free(tf[i].tfile);
15c49f
 	}
15c49f
     }
15c49f
     free(tf);
15c49f
-- 
15c49f
2.26.2
15c49f