Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F166984803
D7655.id19805.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D7655.id19805.diff
View Options
Index: usr.bin/uudecode/uudecode.c
===================================================================
--- usr.bin/uudecode/uudecode.c
+++ usr.bin/uudecode/uudecode.c
@@ -47,6 +47,7 @@
* create the specified file, decoding as you go.
* used with uuencode.
*/
+#include <sys/capsicum.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -65,21 +66,71 @@
#include <string.h>
#include <unistd.h>
-static const char *infile, *outfile;
-static FILE *infp, *outfp;
-static int base64, cflag, iflag, oflag, pflag, rflag, sflag;
+static const char *outfile;
+static FILE *outfp;
+static int base64, cflag, iflag, oflag, pflag, rflag, sflag, dirfd;
static void usage(void);
-static int decode(void);
-static int decode2(void);
-static int uu_decode(void);
-static int base64_decode(void);
+static int decode(FILE *infp, char *infile);
+static int decode2(FILE *infp, char *infile);
+static int uu_decode(FILE *infp, char *infile);
+static int base64_decode(FILE *infp, char *infile);
+
+static int
+safeoutfp(void)
+{
+ int flags, fd;
+ struct stat st;
+
+ flags = O_WRONLY | O_CREAT | O_EXCL;
+ if (lstat(outfile, &st) == 0) {
+ if (iflag) {
+ warnc(EEXIST, "%s", outfile);
+ return (0);
+ }
+ switch (st.st_mode & S_IFMT) {
+ case S_IFREG:
+ case S_IFLNK:
+ /* avoid symlink attacks */
+ if (unlink(outfile) == 0 || errno == ENOENT)
+ break;
+ warn("unlink %s", outfile);
+ return (1);
+ case S_IFDIR:
+ warnc(EISDIR, "%s", outfile);
+ return (1);
+ default:
+ if (oflag) {
+ /* trust command-line names */
+ flags &= ~O_EXCL;
+ break;
+ }
+ warnc(EEXIST, "%s", outfile);
+ return (1);
+ }
+ } else if (errno != ENOENT) {
+ warn("stat %s", outfile);
+ return (1);
+ }
+ if ((fd = open(outfile, flags, 0664)) < 0 ||
+ (outfp = fdopen(fd, "w")) == NULL) {
+ warn("open %s", outfile);
+ return (1);
+ }
+
+ return (0);
+}
int
main(int argc, char *argv[])
{
- int rval, ch;
-
+ int rval, ch, fnum, i;
+ FILE **infps;
+ char **infiles;
+
+ fnum = 0;
+ rval = 0;
+ outfp = NULL;
if (strcmp(basename(argv[0]), "b64decode") == 0)
base64 = 1;
@@ -102,6 +153,10 @@
oflag = 1; /* output to the specified file */
sflag = 1; /* do not strip pathnames for output */
outfile = optarg; /* set the output filename */
+ /* Precreate the output fd before sandboxing */
+ rval = safeoutfp();
+ if (rval != 0)
+ exit(rval);
break;
case 'p':
if (oflag)
@@ -126,27 +181,52 @@
argv += optind;
if (*argv != NULL) {
- rval = 0;
+ infps = malloc(sizeof(FILE*) * argc);
+ infiles = malloc(sizeof(char*) * argc);
+ if (infps == NULL || infiles == NULL)
+ errc(1, ENOMEM, "malloc() fds");
do {
- infp = fopen(infile = *argv, "r");
- if (infp == NULL) {
+ infps[fnum] = fopen(*argv, "r");
+ if (infps[fnum] == NULL) {
warn("%s", *argv);
rval = 1;
continue;
}
- rval |= decode();
- fclose(infp);
+ infiles[fnum] = *argv;
+ fnum++;
} while (*++argv);
} else {
- infile = "stdin";
- infp = stdin;
- rval = decode();
+ infps = malloc(sizeof(FILE*));
+ infiles = malloc(sizeof(char*));
+ if (infps == NULL || infiles == NULL)
+ errc(1, ENOMEM, "malloc() fd");
+ infps[fnum] = stdin;
+ infiles[fnum] = strdup("stdin");
+ if (infiles[fnum] == NULL)
+ errc(1, ENOMEM, "malloc()");
+ }
+
+ if ((dirfd = open(".", O_DIRECTORY)) < 0) {
+ warn("open(%s)", ".");
+ exit(1);
+ }
+
+ if (cap_enter() < 0 && errno != ENOSYS)
+ err(1, "failed to enter security sandbox");
+
+ for (i = 0; i < fnum; i++) {
+ rval |= decode(infps[i], infiles[i]);
+ fclose(infps[i]);
}
+
+ free(infps);
+ free(infiles);
+
exit(rval);
}
static int
-decode(void)
+decode(FILE *infp, char *infile)
{
int r, v;
@@ -155,17 +235,17 @@
outfile = "/dev/stdout";
outfp = stdout;
if (base64)
- return (base64_decode());
+ return (base64_decode(infp, infile));
else
- return (uu_decode());
+ return (uu_decode(infp, infile));
}
- v = decode2();
+ v = decode2(infp, infile);
if (v == EOF) {
warnx("%s: missing or bad \"begin\" line", infile);
return (1);
}
for (r = v; cflag; r |= v) {
- v = decode2();
+ v = decode2(infp, infile);
if (v == EOF)
break;
}
@@ -173,7 +253,7 @@
}
static int
-decode2(void)
+decode2(FILE *infp, char *infile)
{
int flags, fd, mode;
size_t n, m;
@@ -255,9 +335,13 @@
/* POSIX says "/dev/stdout" is a 'magic cookie' not a special file. */
if (pflag || strcmp(outfile, "/dev/stdout") == 0)
outfp = stdout;
- else {
+ else if (oflag && outfp != NULL) {
+ /* set mode of file created earlier */
+ if (fchmod(fileno(outfp), mode) != 0)
+ warn("%s: chmod %s", infile, outfile);
+ } else {
flags = O_WRONLY | O_CREAT | O_EXCL;
- if (lstat(outfile, &st) == 0) {
+ if (fstatat(dirfd, outfile, &st, AT_SYMLINK_NOFOLLOW) == 0) {
if (iflag) {
warnc(EEXIST, "%s: %s", infile, outfile);
return (0);
@@ -266,7 +350,8 @@
case S_IFREG:
case S_IFLNK:
/* avoid symlink attacks */
- if (unlink(outfile) == 0 || errno == ENOENT)
+ if (unlinkat(dirfd, outfile, 0) == 0 ||
+ errno == ENOENT)
break;
warn("%s: unlink %s", infile, outfile);
return (1);
@@ -283,24 +368,24 @@
return (1);
}
} else if (errno != ENOENT) {
- warn("%s: %s", infile, outfile);
+ warn("%s: stat %s", infile, outfile);
return (1);
}
- if ((fd = open(outfile, flags, mode)) < 0 ||
+ if ((fd = openat(dirfd, outfile, flags, mode)) < 0 ||
(outfp = fdopen(fd, "w")) == NULL) {
- warn("%s: %s", infile, outfile);
+ warn("%s: open %s", infile, outfile);
return (1);
}
}
if (base64)
- return (base64_decode());
+ return (base64_decode(infp, infile));
else
- return (uu_decode());
+ return (uu_decode(infp, infile));
}
static int
-get_line(char *buf, size_t size)
+get_line(FILE *infp, char *infile, char *buf, size_t size)
{
if (fgets(buf, size, infp) != NULL)
@@ -312,7 +397,7 @@
}
static int
-checkend(const char *ptr, const char *end, const char *msg)
+checkend(char *infile, const char *ptr, const char *end, const char *msg)
{
size_t n;
@@ -330,7 +415,7 @@
}
static int
-uu_decode(void)
+uu_decode(FILE *infp, char *infile)
{
int i, ch;
char *p;
@@ -338,7 +423,7 @@
/* for each input line */
for (;;) {
- switch (get_line(buf, sizeof(buf))) {
+ switch (get_line(infp, infile, buf, sizeof(buf))) {
case 0:
return (0);
case 1:
@@ -397,18 +482,18 @@
}
}
}
- switch (get_line(buf, sizeof(buf))) {
+ switch (get_line(infp, infile, buf, sizeof(buf))) {
case 0:
return (0);
case 1:
return (1);
default:
- return (checkend(buf, "end", "no \"end\" line"));
+ return (checkend(infile, buf, "end", "no \"end\" line"));
}
}
static int
-base64_decode(void)
+base64_decode(FILE *infp, char *infile)
{
int n, count, count4;
char inbuf[MAXPATHLEN + 1], *p;
@@ -418,7 +503,7 @@
leftover[0] = '\0';
for (;;) {
strcpy(inbuf, leftover);
- switch (get_line(inbuf + strlen(inbuf),
+ switch (get_line(infp, infile, inbuf + strlen(inbuf),
sizeof(inbuf) - strlen(inbuf))) {
case 0:
return (0);
@@ -450,7 +535,7 @@
break;
fwrite(outbuf, 1, n, outfp);
}
- return (checkend(inbuf, "====", "error decoding base64 input stream"));
+ return (checkend(infile, inbuf, "====", "error decoding base64 input stream"));
}
static void
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Aug 19, 9:42 AM (2 h, 35 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36926038
Default Alt Text
D7655.id19805.diff (7 KB)
Attached To
Mode
D7655: Capsicumize uudecode/b64decode
Attached
Detach File
Event Timeline
Log In to Comment