diff options
author | fanf <fanf@FreeBSD.org> | 2002-11-01 00:58:00 +0000 |
---|---|---|
committer | fanf <fanf@FreeBSD.org> | 2002-11-01 00:58:00 +0000 |
commit | c46715077793ed90d5eaf4f4ce3ebd59fe491d56 (patch) | |
tree | 1e19d098d93d0e38d464197e6b665f2c43de5abb /usr.bin | |
parent | 760e63e6f7c93856411ba0045221c7e278044c92 (diff) | |
download | FreeBSD-src-c46715077793ed90d5eaf4f4ce3ebd59fe491d56.zip FreeBSD-src-c46715077793ed90d5eaf4f4ce3ebd59fe491d56.tar.gz |
Be much more paranoid about where uudecode writes its output, especially
when the filename comes from the untrusted input. This is a work-around
for careless people who don't routinely check the begin line of the file
or run uudecode -i and instead report "vulnerabilities" to CERT.
http://www.kb.cert.org/vuls/id/336083
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/uudecode/uudecode.c | 43 |
1 files changed, 36 insertions, 7 deletions
diff --git a/usr.bin/uudecode/uudecode.c b/usr.bin/uudecode/uudecode.c index d6cae1d..95046ae 100644 --- a/usr.bin/uudecode/uudecode.c +++ b/usr.bin/uudecode/uudecode.c @@ -59,6 +59,8 @@ __FBSDID("$FreeBSD$"); #include <netinet/in.h> #include <err.h> +#include <errno.h> +#include <fcntl.h> #include <pwd.h> #include <resolv.h> #include <stdio.h> @@ -231,14 +233,41 @@ decode2(void) return (1); } - if (!pflag) { - if (iflag && !access(buffn, F_OK)) { - warnx("not overwritten: %s", buffn); - return (0); + if (pflag) + outfp = stdout; + else { + int 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 ((outfp = fopen(buffn, "w")) == NULL || - stat(buffn, &st) < 0 || (S_ISREG(st.st_mode) && - fchmod(fileno(outfp), getmode(mode, 0) & 0666) < 0)) { + if ((i = open(buffn, flags, getmode(mode, 0) & 0666)) < 0 || + (outfp = fdopen(i, "w")) == NULL) { warn("%s: %s", filename, buffn); return (1); } |