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