Scott Kitterman:
> >Postfix daemons run with cwd == /var/spool/postfix which is writable
> >only by root. So that is safe.
> >
> >Set-gid Postfix non-daemon programs will eventually chdir() to
> >/var/spool/postfix, but it is possible that PAM or NSS opens a db
> >file before that time, or that postdrop or postqueue open a db file
> >while initializing some main.cf setting.
> >
> >I guess that means one could trick Berkeley DB into reading a message
> >file in the maildrop directory, if you know the maildrop file name.
> >Normally, a maildrop file will be removed quickly by the pickup
> >dameon, so I don't know how realistic an attack like this would be.
> >
> >Other Postfix non-daemon programs run with the same privileges as
> >the process that invokes the command. There is no privilege escalation.
> 
> Thanks for reviewing.

Oh, and it will of course open a DB_CONFIG file in whatever happens
to be the super-user's cwd when they invoke the postmap or postalias
command, so this is not just a matter of set-gid Postfix commands.

Although opening a DB_CONFIG file in the current directory is
undocumented, there is prior art fixing Berkeley DB callers instead
Berkeley DB, for example the fix for nss_db (CVE-2010-0826).

Having rolled a new release this Saturday, I can save people some
time by rolling out another one today, based on the nss_db fix.
No point reinventing this.

        Wietse

--- /var/tmp/postfix-3.3-20170610/src/util/dict_db.c    2014-12-06 
20:35:33.000000000 -0500
+++ src/util/dict_db.c  2017-06-11 13:29:22.581994051 -0400
@@ -122,6 +122,9 @@
 typedef struct {
     DICT    dict;                      /* generic members */
     DB     *db;                                /* open db file */
+#if DB_VERSION_MAJOR > 2
+    DB_ENV *dbenv;
+#endif
 #if DB_VERSION_MAJOR > 1
     DBC    *cursor;                    /* dict_db_sequence() */
 #endif
@@ -553,6 +556,9 @@
     if (DICT_DB_CLOSE(dict_db->db) < 0)
        msg_info("close database %s: %m (possible Berkeley DB bug)",
                 dict_db->dict.name);
+#if DB_VERSION_MAJOR > 2
+    dict_db->dbenv->close(dict_db->dbenv, 0);
+#endif
     if (dict_db->key_buf)
        vstring_free(dict_db->key_buf);
     if (dict_db->val_buf)
@@ -578,6 +584,11 @@
     int     db_flags;
 
 #endif
+#if DB_VERSION_MAJOR > 2
+    DB_ENV *dbenv;
+    VSTRING *dirname_buf;
+
+#endif
 
     /*
      * Mismatches between #include file and library are a common cause for
@@ -681,12 +692,18 @@
        db_flags |= DB_CREATE;
     if (open_flags & O_TRUNC)
        db_flags |= DB_TRUNCATE;
-    if ((errno = db_create(&db, 0, 0)) != 0)
+    /* Fix 20170611 workaround for undocumented ./DB_CONFIG read. */
+    if ((errno = db_env_create(&dbenv, 0)) != 0)
+       msg_fatal("create DB environment: %m");
+    dirname_buf = vstring_alloc(100);
+    if ((errno = dbenv->open(dbenv, sane_dirname(dirname_buf, db_path),
+                          DB_INIT_MPOOL | DB_CREATE | DB_PRIVATE, 0)) != 0)
+       msg_fatal("open DB environment: %m");
+    vstring_free(dirname_buf);
+    if ((errno = db_create(&db, dbenv, 0)) != 0)
        msg_fatal("create DB database: %m");
     if (db == 0)
        msg_panic("db_create null result");
-    if ((errno = db->set_cachesize(db, 0, dict_db_cache_size, 0)) != 0)
-       msg_fatal("set DB cache size %d: %m", dict_db_cache_size);
     if (type == DB_HASH && db->set_h_nelem(db, DICT_DB_NELM) != 0)
        msg_fatal("set DB hash element count %d: %m", DICT_DB_NELM);
 #if DB_VERSION_MAJOR == 6 || DB_VERSION_MAJOR == 5 || \
@@ -743,6 +760,7 @@
     if (dict_flags & DICT_FLAG_FOLD_FIX)
        dict_db->dict.fold_buf = vstring_alloc(10);
     dict_db->db = db;
+    dict_db->dbenv = dbenv;
 #if DB_VERSION_MAJOR > 1
     dict_db->cursor = 0;
 #endif

Reply via email to