From 3b1701b0a563dc40721dbe947a754093740bf1f5 Mon Sep 17 00:00:00 2001 From: dholland Date: Wed, 1 Jul 2015 06:48:25 +0000 Subject: [PATCH] Repair accidental regression in -r1.49: for -a mode, don't allow calendars to be other than regular files unless the -x option is in effect. (If not in -a mode, we're running purely as the user whose calendar it is and if they want to DoS themselves with named pipes it's their own lookout.) --- usr.bin/calendar/calendar.c | 78 +++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 4 deletions(-) diff --git a/usr.bin/calendar/calendar.c b/usr.bin/calendar/calendar.c index fa0f216b02cc..cddcb1fef5a6 100644 --- a/usr.bin/calendar/calendar.c +++ b/usr.bin/calendar/calendar.c @@ -1,4 +1,4 @@ -/* $NetBSD: calendar.c,v 1.51 2015/07/01 06:45:51 dholland Exp $ */ +/* $NetBSD: calendar.c,v 1.52 2015/07/01 06:48:25 dholland Exp $ */ /* * Copyright (c) 1989, 1993, 1994 @@ -39,10 +39,11 @@ __COPYRIGHT("@(#) Copyright (c) 1989, 1993\ #if 0 static char sccsid[] = "@(#)calendar.c 8.4 (Berkeley) 1/7/95"; #endif -__RCSID("$NetBSD: calendar.c,v 1.51 2015/07/01 06:45:51 dholland Exp $"); +__RCSID("$NetBSD: calendar.c,v 1.52 2015/07/01 06:48:25 dholland Exp $"); #endif /* not lint */ #include +#include #include #include #include @@ -120,6 +121,7 @@ static void getmmdd(struct tm *, char *); static int getmonth(char *); static bool isnow(char *); static FILE *opencal(FILE **); +static int tryopen(const char *, int); static void settime(void); static void usage(void) __dead; @@ -403,7 +405,7 @@ opencal(FILE **in) /* open up calendar file as stdin */ if (fname == NULL) { for (const char **name = defaultnames; *name != NULL; name++) { - if ((fd = open(*name, O_RDONLY)) == -1) + if ((fd = tryopen(*name, O_RDONLY)) == -1) continue; else break; @@ -413,7 +415,7 @@ opencal(FILE **in) return NULL; err(EXIT_FAILURE, "Cannot open calendar file"); } - } else if ((fd = open(fname, O_RDONLY)) == -1) { + } else if ((fd = tryopen(fname, O_RDONLY)) == -1) { if (doall) return NULL; err(EXIT_FAILURE, "Cannot open `%s'", fname); @@ -482,6 +484,74 @@ opencal(FILE **in) /*NOTREACHED*/ } +static int +tryopen(const char *pathname, int flags) +{ + int fd, serrno, zero; + struct stat st; + + /* + * XXX: cpp_restricted has inverted sense; it is false by default, + * and -x sets it to true. CPP_RESTRICTED is set in the environment + * if cpp_restricted is false... go figure. This should be fixed + * later. + */ + if (doall && cpp_restricted == false) { + /* + * We are running with the user's euid, so they can't + * cause any mayhem (e.g. opening rewinding tape + * devices) that they couldn't do easily enough on + * their own. All we really need to worry about is opens + * that hang, because that would DoS the calendar run. + */ + fd = open(pathname, flags | O_NONBLOCK); + if (fd == -1) { + return -1; + } + if (fstat(fd, &st) == -1) { + serrno = errno; + close(fd); + errno = serrno; + return -1; + } + if (S_ISCHR(st.st_mode) || + S_ISBLK(st.st_mode) || + S_ISFIFO(st.st_mode)) { + close(fd); + + /* Call shenanigans in the daily output */ + errno = EPERM; + warn("%s: %s", pw->pw_name, pathname); + + errno = EPERM; + return -1; + } + if (S_ISDIR(st.st_mode)) { + /* Don't warn about this */ + close(fd); + errno = EISDIR; + return -1; + } + if (!S_ISREG(st.st_mode)) { + /* There shouldn't be other cases to go here */ + close(fd); + errno = EINVAL; + return -1; + } + zero = 0; + if (ioctl(fd, FIONBIO, &zero) == -1) { + serrno = errno; + warn("%s: %s: FIONBIO", pw->pw_name, pathname); + close(fd); + errno = serrno; + return -1; + } + return fd; + } else { + return open(pathname, flags); + } +} + static void closecal(FILE *fp) {