summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgilles <gilles@openbsd.org>2015-10-02 00:37:53 +0000
committergilles <gilles@openbsd.org>2015-10-02 00:37:53 +0000
commitcb6e8661a8f91540360973f77bc4d4302abecfa2 (patch)
tree0f4a8aad21e2280081bdf32416f014d24702038a
parentintroduce imsg_read_nofd() to allow reading imsg while discarding fd's when (diff)
downloadwireguard-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.c46
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;
}