Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <CAHmME9q0Xxcm7VyO-W+VkFLYW5x0Y_BgR8mbgENb1SUEFHnQbQ@mail.gmail.com>
Date: Mon, 5 Oct 2015 17:00:52 +0200
From: "Jason A. Donenfeld" <Jason@...c4.com>
To: oss-security <oss-security@...ts.openwall.com>, cve-assign@...re.org
Subject: CVE Request: OpenSMTPD <= 5.7.2 buffer overflow

Hello,

As reported in [1], OpenSMTPD <= 5.7.2 has a remotely exploitable
buffer overflow. This overflow requires a CVE. A PoC is attached to
[1].

OpenSMTPD 5.7.3 was released with fixes, and the release notes follow
below. There may be other vulnerabilities also fixed by this release.
A full diff follows for analysis and additional CVE assignment, in
case that is necessary.

Thanks,
Jason

[1] http://seclists.org/oss-sec/2015/q4/25


---------- Forwarded message ----------
From: Gilles Chehade <gilles@...lp.org>
Date: Mon, Oct 5, 2015 at 3:30 PM
Subject: Announce: OpenSMTPD 5.7.3 released
To: misc@...nsmtpd.org

[snipped]

Issues fixed in this release (since 5.7.2):
===========================================

- fix an mda buffer truncation bug which allows a user to create forward
  files that pass session checks but fail delivery later down the chain,
  within the user mda [0]
- fix remote buffer overflow in unprivileged pony process [1]
- reworked offline enqueue to better protect against hardlink attacks [2]


[0] reported by Holger Jahn
[1] reported by Jason A. Donenfeld
[2] reported by Qualys Security

------ DIFF -----

diff -ru opensmtpd-5.7.2p1/smtpd/enqueue.c opensmtpd-5.7.3p1/smtpd/enqueue.c
--- opensmtpd-5.7.2p1/smtpd/enqueue.c        2015-10-02 01:46:21.000000000 +0200
+++ opensmtpd-5.7.3p1/smtpd/enqueue.c        2015-10-05 13:33:41.000000000 +0200
@@ -795,12 +795,25 @@
         FILE        *fp;
         int         i, fd, ch;
         mode_t         omode;
+        uint64_t        rnd;
+        int         ret;

         if (ckdir(PATH_SPOOL PATH_OFFLINE, 01777, 0, 0, 0) == 0)
                 errx(EX_UNAVAILABLE, "error in offline directory setup");

-        if (! bsnprintf(path, sizeof(path), "%s%s/%lld.XXXXXXXXXX", PATH_SPOOL,
-                PATH_OFFLINE, (long long int) time(NULL)))
+        do {
+                rnd = generate_uid();
+                if (! bsnprintf(path, sizeof(path),
"%s%s/%016"PRIx64, PATH_SPOOL,
+                        PATH_OFFLINE, rnd))
+                        err(EX_UNAVAILABLE, "snprintf");
+                ret = mkdir(path, 0700);
+                if (ret == -1)
+                        if (errno != EEXIST)
+                                err(EX_UNAVAILABLE, "mkdir");
+        } while (ret == -1);
+
+        if (! bsnprintf(path, sizeof(path),
"%s%s/%016"PRIx64"/%lld.XXXXXXXXXX", PATH_SPOOL,
+                PATH_OFFLINE, rnd, (long long int) time(NULL)))
                 err(EX_UNAVAILABLE, "snprintf");

         omode = umask(7077);
diff -ru opensmtpd-5.7.2p1/smtpd/filter.c opensmtpd-5.7.3p1/smtpd/filter.c
--- opensmtpd-5.7.2p1/smtpd/filter.c        2015-10-02 01:46:21.000000000 +0200
+++ opensmtpd-5.7.3p1/smtpd/filter.c        2015-10-05 13:33:41.000000000 +0200
@@ -728,7 +728,6 @@
         struct filter_session        *s = io->arg;
         size_t                         len, n;
         char                        *data;
-        char                        buf[65535];

         log_trace(TRACE_FILTERS, "filter: filter_tx_io(%p, %s)", s,
io_strevent(evt));

@@ -736,10 +735,9 @@
         case IO_DATAIN:
                 data = iobuf_data(&s->ibuf);
                 len = iobuf_len(&s->ibuf);
-                memmove(buf, data, len);
-                buf[len] = 0;
-                log_trace(TRACE_FILTERS, "filter: filter_tx_io:
datain (%zu) for req %016"PRIx64": %s",
-                    len, s->id, buf);
+
+                log_trace(TRACE_FILTERS, "filter: filter_tx_io:
datain (%zu) for req %016"PRIx64"",
+                    len, s->id);

                 n = fwrite(data, 1, len, s->ofile);
                 if (n != len) {
diff -ru opensmtpd-5.7.2p1/smtpd/mda.c opensmtpd-5.7.3p1/smtpd/mda.c
--- opensmtpd-5.7.2p1/smtpd/mda.c        2015-10-02 01:46:21.000000000 +0200
+++ opensmtpd-5.7.3p1/smtpd/mda.c        2015-10-05 13:33:41.000000000 +0200
@@ -286,8 +286,17 @@
                                 deliver.userinfo = *userinfo;
                                 (void)strlcpy(deliver.user, userinfo->username,
                                     sizeof(deliver.user));
-                                (void)strlcpy(deliver.to, e->buffer,
-                                    sizeof(deliver.to));
+                                if (strlcpy(deliver.to, e->buffer,
+                                        sizeof(deliver.to))
+                                    >= sizeof(deliver.to)) {
+                                        mda_queue_tempfail(e->id,
+                                            "mda command too long",
+                                            ESC_OTHER_MAIL_SYSTEM_STATUS);
+                                        mda_log(e, "TempFail",
+                                            "mda command too long");
+                                        mda_done(s);
+                                        return;
+                                }
                                 break;

                         case A_MBOX:
diff -ru opensmtpd-5.7.2p1/smtpd/smtpd.c opensmtpd-5.7.3p1/smtpd/smtpd.c
--- opensmtpd-5.7.2p1/smtpd/smtpd.c        2015-10-02 01:46:21.000000000 +0200
+++ opensmtpd-5.7.3p1/smtpd/smtpd.c        2015-10-05 13:33:41.000000000 +0200
@@ -50,9 +50,11 @@
 #include <errno.h>
 #include <event.h>
 #include <fcntl.h>
+#include <fts.h>
 #include <grp.h> /* needed for setgroups */
 #include <imsg.h>
 #include <inttypes.h>
+#include <libgen.h>
 #ifdef HAVE_LOGIN_CAP_H
 #include <login_cap.h>
 #endif
@@ -440,8 +442,10 @@
                                             "couldn't enqueue offline "
                                             "message %s; smtpctl %s",
                                             child->path, cause);
-                                else
+                                else {
                                         unlink(child->path);
+                                        rmdir(dirname(child->path));
+                                }
                                 free(child->path);
                                 offline_done();
                                 break;
@@ -1075,28 +1079,43 @@
 static void
 offline_scan(int fd, short ev, void *arg)
 {
-        DIR                *dir = arg;
-        struct dirent        *d;
+        char                *path_argv[2];
+        FTS                *fts = arg;
+        FTSENT                *e;
         int                 n = 0;

-        if (dir == NULL) {
+        path_argv[0] = PATH_SPOOL PATH_OFFLINE;
+        path_argv[1] = NULL;
+
+        if (fts == NULL) {
                 log_debug("debug: smtpd: scanning offline queue...");
-                if ((dir = opendir(PATH_SPOOL PATH_OFFLINE)) == NULL)
-                        errx(1, "smtpd: opendir");
+                fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
+                if (fts == NULL) {
+                        log_warn("fts_open: %s", path_argv[0]);
+                        return;
+                }
         }

-        while ((d = readdir(dir)) != NULL) {
-                if (d->d_type != DT_REG)
+        while ((e = fts_read(fts)) != NULL) {
+                if (e->fts_info != FTS_F)
+                        continue;
+
+                /* offline files must be at depth 2 */
+                if (e->fts_level != 2)
+                        continue;
+
+                /* offline file owner must match parent directory owner */
+                if (e->fts_statp->st_uid != e->fts_parent->fts_statp->st_uid)
                         continue;

-                if (offline_add(d->d_name)) {
+                if (offline_add(e->fts_accpath)) {
                         log_warnx("warn: smtpd: "
-                            "could not add offline message %s", d->d_name);
+                            "could not add offline message %s", e->fts_name);
                         continue;
                 }

                 if ((n++) == OFFLINE_READMAX) {
-                        evtimer_set(&offline_ev, offline_scan, dir);
+                        evtimer_set(&offline_ev, offline_scan, fts);
                         offline_timeout.tv_sec = 0;
                         offline_timeout.tv_usec = 100000;
                         evtimer_add(&offline_ev, &offline_timeout);
@@ -1105,24 +1124,19 @@
         }

         log_debug("debug: smtpd: offline scanning done");
-        closedir(dir);
+        fts_close(fts);
 }

 static int
 offline_enqueue(char *name)
 {
-        char                 t[PATH_MAX], *path;
+        char                *path;
         struct stat         sb;
         pid_t                 pid;
         struct child        *child;
         struct passwd        *pw;

-        if (!bsnprintf(t, sizeof t, "%s/%s", PATH_SPOOL PATH_OFFLINE, name)) {
-                log_warnx("warn: smtpd: path name too long");
-                return (-1);
-        }
-
-        if ((path = strdup(t)) == NULL) {
+        if ((path = strdup(name)) == NULL) {
                 log_warn("warn: smtpd: strdup");
                 return (-1);
         }
diff -ru opensmtpd-5.7.2p1/smtpd/smtpd.h opensmtpd-5.7.3p1/smtpd/smtpd.h
--- opensmtpd-5.7.2p1/smtpd/smtpd.h        2015-10-02 01:46:21.000000000 +0200
+++ opensmtpd-5.7.3p1/smtpd/smtpd.h        2015-10-05 13:33:41.000000000 +0200
@@ -67,7 +67,7 @@
 #ifndef SMTPD_NAME
 #define        SMTPD_NAME                 "OpenSMTPD"
 #endif
-#define        SMTPD_VERSION                 "5.7.2p1"
+#define        SMTPD_VERSION                 "5.7.3p1"
 #define SMTPD_SESSION_TIMEOUT         300
 #define SMTPD_BACKLOG                 5

@@ -684,7 +684,7 @@
 };

 struct deliver {
-        char                        to[SMTPD_MAXMAILADDRSIZE];
+        char                        to[EXPAND_BUFFER];
         char                        from[SMTPD_MAXMAILADDRSIZE];
         char                        dest[SMTPD_MAXMAILADDRSIZE];
         char                        user[SMTPD_VUSERNAME_SIZE];

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.