diff options
author | 2015-10-02 00:37:53 +0000 | |
---|---|---|
committer | 2015-10-02 00:37:53 +0000 | |
commit | cb6e8661a8f91540360973f77bc4d4302abecfa2 (patch) | |
tree | 0f4a8aad21e2280081bdf32416f014d24702038a | |
parent | introduce imsg_read_nofd() to allow reading imsg while discarding fd's when (diff) | |
download | wireguard-openbsd-cb6e8661a8f91540360973f77bc4d4302abecfa2.tar.xz wireguard-openbsd-cb6e8661a8f91540360973f77bc4d4302abecfa2.zip |
prevent users from playing hardlink/symlink/mkfifo games with their offline
messages and ~/.forward files. this allowed a local user to hang smtpd or
even reset chflags and read first line of any arbitrary file.
while at it, do not fatal() on unexpected cause of SIGCHLD as this allows a
specially crafted mda to cause smtpd to exit.
reporte by Qualys Security
-rw-r--r-- | usr.sbin/smtpd/smtpd.c | 46 |
1 files changed, 32 insertions, 14 deletions
diff --git a/usr.sbin/smtpd/smtpd.c b/usr.sbin/smtpd/smtpd.c index 820c6750c28..9e55df0cfcb 100644 --- a/usr.sbin/smtpd/smtpd.c +++ b/usr.sbin/smtpd/smtpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.c,v 1.239 2015/06/03 02:24:36 millert Exp $ */ +/* $OpenBSD: smtpd.c,v 1.240 2015/10/02 00:37:53 gilles Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -352,7 +352,8 @@ parent_sig_handler(int sig, short event, void *p) } else len = asprintf(&cause, "exited okay"); } else - fatalx("smtpd: unexpected cause of SIGCHLD"); + /* WIFSTOPPED or WIFCONTINUED */ + continue; if (len == -1) fatal("asprintf"); @@ -1073,19 +1074,34 @@ offline_enqueue(char *name) if (pid == 0) { char *envp[2], *p, *tmp; + int fd; FILE *fp; size_t len; arglist args; + if (closefrom(STDERR_FILENO + 1) == -1) + _exit(1); + memset(&args, 0, sizeof(args)); - if (lstat(path, &sb) == -1) { - log_warn("warn: smtpd: lstat: %s", path); + if ((fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK)) == -1) { + log_warn("warn: smtpd: open: %s", path); _exit(1); } - if (chflags(path, 0) == -1) { - log_warn("warn: smtpd: chflags: %s", path); + if (fstat(fd, &sb) == -1) { + log_warn("warn: smtpd: fstat: %s", path); + _exit(1); + } + + if (! S_ISREG(sb.st_mode)) { + log_warnx("warn: smtpd: file %s (uid %d) not regular", + path, sb.st_uid); + _exit(1); + } + + if (sb.st_nlink != 1) { + log_warnx("warn: smtpd: file %s is hard-link", path); _exit(1); } @@ -1096,19 +1112,17 @@ offline_enqueue(char *name) _exit(1); } - if (! S_ISREG(sb.st_mode)) { - log_warnx("warn: smtpd: file %s (uid %d) not regular", - path, sb.st_uid); + if (fchflags(fd, 0) == -1) { + log_warn("warn: smtpd: chflags: %s", path); _exit(1); } if (setgroups(1, &pw->pw_gid) || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || - setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) || - closefrom(STDERR_FILENO + 1) == -1) + setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) _exit(1); - if ((fp = fopen(path, "r")) == NULL) + if ((fp = fdopen(fd, "r")) == NULL) _exit(1); if (chdir(pw->pw_dir) == -1 && chdir("/") == -1) @@ -1208,7 +1222,7 @@ parent_forward_open(char *username, char *directory, uid_t uid, gid_t gid) } do { - fd = open(pathname, O_RDONLY); + fd = open(pathname, O_RDONLY|O_NOFOLLOW|O_NONBLOCK); } while (fd == -1 && errno == EINTR); if (fd == -1) { if (errno == ENOENT) @@ -1217,7 +1231,11 @@ parent_forward_open(char *username, char *directory, uid_t uid, gid_t gid) errno = EAGAIN; return -1; } - log_warn("warn: smtpd: parent_forward_open: %s", pathname); + if (errno == ELOOP) + log_warnx("warn: smtpd: parent_forward_open: %s: " + "cannot follow symbolic links", pathname); + else + log_warn("warn: smtpd: parent_forward_open: %s", pathname); return -1; } |