Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 29 Oct 2002 04:06:16 +0000
From:      Tony Finch <dot@dotat.at>
To:        freebsd-audit@freebsd.org
Cc:        dot@dotat.at
Subject:   uudecode paranoia
Message-ID:  <20021029040616.A3802@chiark.greenend.org.uk>

next in thread | raw e-mail | index | archive | help
Following on from http://www.kb.cert.org/vuls/id/336083 here is a
candidate patch to make FreeBSD's uudecode paranoid about less-trusted
filenames. Comments and suggestions are welcome, especially regarding
the evil freopen hack.

Tony.
-- 
f.a.n.finch  <dot@dotat.at>  http://dotat.at/
WEST SOLE: SOUTHERLY VEERING NORTHEASTERLY 5 TO 7. RAIN THEN SHOWERS. MODERATE
BECOMING GOOD.


--- uudecode.c	11 Sep 2002 04:26:09 -0000	1.40
+++ uudecode.c	29 Oct 2002 04:01:06 -0000
@@ -59,6 +59,8 @@
 #include <netinet/in.h>
 
 #include <err.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <pwd.h>
 #include <resolv.h>
 #include <stdio.h>
@@ -152,7 +154,7 @@
 int
 decode2(void)
 {
-	int base64, i;
+	int base64, i, flags;
 	size_t n;
 	char ch, *p, *q;
 	void *mode;
@@ -228,13 +230,42 @@
 	}
 
 	if (!pflag) {
-		if (iflag && !access(buffn, F_OK)) {
-			warnx("not overwritten: %s", buffn);
-			return (0);
+		flags = O_WRONLY|O_CREAT|O_EXCL;
+		if (lstat(buffn, &st) == 0) {
+			if (iflag) {
+				warnc(EEXIST, "%s: %s", filename, buffn);
+				return (0);
+			}
+			switch (st.st_mode & S_IFMT) {
+			case S_IFREG:
+			case S_IFLNK:
+				/* avoid symlink attacks */
+				if (unlink(buffn) == 0 || errno == ENOENT)
+					break;
+				warn("%s: unlink %s", filename, buffn);
+				return (1);
+			case S_IFDIR:
+				warnc(EISDIR, "%s: %s", filename, buffn);
+				return (1);
+			default:
+				if (oflag) {
+					/* trust command-line names */
+					flags &= ~O_EXCL;
+					break;
+				}
+				warnc(EEXIST, "%s: %s", filename, buffn);
+				return (1);
+			}
+		} else if (errno != ENOENT) {
+			warn("%s: %s", filename, buffn);
+			return (1);
 		}
-		if (freopen(buffn, "w", stdout) == NULL ||
-		    stat(buffn, &st) < 0 || (S_ISREG(st.st_mode) &&
-		    fchmod(fileno(stdout), getmode(mode, 0) & 0666) < 0)) {
+		if (fclose(stdout) != 0)
+			warn("problem writing output");
+		/* Bah! there is no fdreopen or O_EXCL flag for fopen */
+		i = open(buffn, flags, getmode(mode, 0) & 0666);
+		if (i < 0 || dup2(i, 1) < 0 ||
+		    freopen("/dev/stdout", "w", stdout) == NULL) {
 			warn("%s: %s", filename, buffn);
 			return (1);
 		}

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-audit" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20021029040616.A3802>