diff --git a/postfix/HISTORY b/postfix/HISTORY index 1c0c5eac3..0f55b7bd1 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -23021,15 +23021,12 @@ Apologies for any names omitted. 20170611 - Security: Berkeley DB 2 and later have an undocumented - feature that tries to read instructions from a file DB_CONFIG - in the current directory. This may expose Postfix set-gid - programs (postdrop, postqueue) to attacks before they chdir - to the Postfix queue directory, and the postmap and postalias - commands depending on whether the user's current directory - is writable by other users. This fix does not change Postfix - behavior for Berkeley DB < 3. It makes the berkeley_db_buffer_size - and berkeley_db_create_buffer_size parameters obsolete for - Berkeley DB 3 and later, because they appear to have no API - to find out the maximal cache size they would accept. Postmap - create operations will be about 3x slower. File: util/dict_db.c. + Security: Berkeley DB 2 and later try to read settings from + a file DB_CONFIG in the current directory. This undocumented + feature may introduce undisclosed vulnerabilities resulting in + privilege escalation with Postfix set-gid programs (postdrop, + postqueue) before they chdir to the Postfix queue directory, + and with the postmap and postalias commands depending on whether + the user's current directory is writable by other users. This + fix does not change Postfix behavior for Berkeley DB < 3. + File: util/dict_db.c. diff --git a/postfix/src/global/mail_params.c b/postfix/src/global/mail_params.c index ece9ec071..adee25848 100644 --- a/postfix/src/global/mail_params.c +++ b/postfix/src/global/mail_params.c @@ -881,6 +881,7 @@ void mail_params_init() check_sgid_group(); check_overlap(); dict_db_cache_size = var_db_read_buf; + dict_db_home = mystrdup(var_config_dir); dict_lmdb_map_size = var_lmdb_map_size; inet_windowsize = var_inet_windowsize; diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 9a5bc87e7..bd7b1b29b 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20170611" +#define MAIL_RELEASE_DATE "20170612" #define MAIL_VERSION_NUMBER "3.3" #ifdef SNAPSHOT diff --git a/postfix/src/util/dict_db.c b/postfix/src/util/dict_db.c index 7671bbeed..5dc91738e 100644 --- a/postfix/src/util/dict_db.c +++ b/postfix/src/util/dict_db.c @@ -7,6 +7,7 @@ /* #include /* /* extern int dict_db_cache_size; +/* extern char *dict_db_home; /* /* DEFINE_DICT_DB_CACHE_SIZE; /* @@ -33,6 +34,9 @@ /* must therefore be defined in the calling program by invoking /* the DEFINE_DICT_DB_CACHE_SIZE macro at the global level. /* +/* dict_db_home specifies the default location of the DB_CONFIG +/* file with configuration overrides. +/* /* Arguments: /* .IP path /* The database pathname, not including the ".db" suffix. @@ -586,7 +590,9 @@ static DICT *dict_db_open(const char *class, const char *path, int open_flags, #endif #if DB_VERSION_MAJOR > 2 DB_ENV *dbenv; - VSTRING *dirname_buf; + u_int32_t cache_size_gbytes; + u_int32_t cache_size_bytes; + int ncache; #endif @@ -692,14 +698,28 @@ static DICT *dict_db_open(const char *class, const char *path, int open_flags, db_flags |= DB_CREATE; if (open_flags & O_TRUNC) db_flags |= DB_TRUNCATE; - /* Fix 20170611 workaround for undocumented ./DB_CONFIG read. */ + /* Begin 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), +#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 7) + /* Begin fix 20170612 workaround for invisible cache size limit. */ + if ((errno = dbenv->get_cachesize(dbenv, &cache_size_gbytes, + &cache_size_bytes, &ncache)) != 0) + msg_fatal("get DB cache size: %m"); + if (cache_size_gbytes == 0 && cache_size_bytes < dict_db_cache_size) { + if ((errno = dbenv->set_cache_max(dbenv, cache_size_gbytes, + dict_db_cache_size)) != 0) + msg_fatal("set DB max cache size %d: %m", dict_db_cache_size); + if ((errno = dbenv->set_cachesize(dbenv, cache_size_gbytes, + dict_db_cache_size, ncache)) != 0) + msg_fatal("set DB cache size %d: %m", dict_db_cache_size); + } + /* End fix 20170612 workaround for invisible cache size limit. */ +#endif + if ((errno = dbenv->open(dbenv, dict_db_home, DB_INIT_MPOOL | DB_CREATE | DB_PRIVATE, 0)) != 0) msg_fatal("open DB environment: %m"); - vstring_free(dirname_buf); + /* End fix 20170611 workaround for undocumented ./DB_CONFIG read. */ if ((errno = db_create(&db, dbenv, 0)) != 0) msg_fatal("create DB database: %m"); if (db == 0) diff --git a/postfix/src/util/dict_db.h b/postfix/src/util/dict_db.h index 9b5f6cada..862685332 100644 --- a/postfix/src/util/dict_db.h +++ b/postfix/src/util/dict_db.h @@ -33,8 +33,10 @@ extern DICT *dict_btree_open(const char *, int, int); * set a larger memory pool for database (re)builds. */ extern int dict_db_cache_size; +extern char *dict_db_home; #define DEFINE_DICT_DB_CACHE_SIZE int dict_db_cache_size = (128 * 1024) +#define DEFINE_DICT_DB_HOME char *dict_db_home = "/" /* LICENSE /* .ad diff --git a/postfix/src/util/dict_open.c b/postfix/src/util/dict_open.c index bc33174ea..8328296a5 100644 --- a/postfix/src/util/dict_open.c +++ b/postfix/src/util/dict_open.c @@ -395,6 +395,7 @@ static DICT_MAPNAMES_EXTEND_FN dict_mapnames_extend_hook; */ DEFINE_DICT_LMDB_MAP_SIZE; DEFINE_DICT_DB_CACHE_SIZE; +DEFINE_DICT_DB_HOME; /* dict_open_init - one-off initialization */