Original patch, modified to apply on top of the patch to ensure that db->open isn't expanded as a macro. #! /bin/sh /usr/share/dpatch/dpatch-run ## 200-set-db-environment.dpatch by Kees Cook <kees@ubuntu.com> ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: Description: fix file content leak when using db (CVE-2010-0826). ## DP: Author: Kees Cook <kees@ubuntu.com> ## DP: Bug-Ubuntu: https://launchpad.net/bugs/531976 @DPATCH@ diff -urNad libnss-db-2.2.3pre1~/src/db-XXX.c libnss-db-2.2.3pre1/src/db-XXX.c --- libnss-db-2.2.3pre1~/src/db-XXX.c 2010-03-30 10:41:48.106484308 -0700 +++ libnss-db-2.2.3pre1/src/db-XXX.c 2010-03-30 10:41:48.286483656 -0700 @@ -56,6 +56,7 @@ /* Maintenance of the shared handle open on the database. */ +static DB_ENV *dbenv; static DB *db; static int keep_db; static int entidx; @@ -69,7 +70,7 @@ pthread_mutex_lock (&lock); - status = internal_setent (DBFILE, &db); + status = internal_setent (DBFILE, &db, &dbenv); /* Remember STAYOPEN flag. */ if (db != NULL) @@ -89,7 +90,7 @@ { pthread_mutex_lock (&lock); - internal_endent (&db); + internal_endent (&db, &dbenv); /* Reset STAYOPEN flag. */ keep_db = 0; @@ -112,7 +113,7 @@ /* Open the database. */ if (db == NULL) { - status = internal_setent (DBFILE, &db); + status = internal_setent (DBFILE, &db, &dbenv); if (status != NSS_STATUS_SUCCESS) { *errnop = errno; @@ -194,7 +195,7 @@ } if (! keep_db) - internal_endent (&db); + internal_endent (&db, &dbenv); return status; } diff -urNad libnss-db-2.2.3pre1~/src/db-alias.c libnss-db-2.2.3pre1/src/db-alias.c --- libnss-db-2.2.3pre1~/src/db-alias.c 2010-03-30 10:41:48.096484006 -0700 +++ libnss-db-2.2.3pre1/src/db-alias.c 2010-03-30 10:41:48.286483656 -0700 @@ -34,6 +34,7 @@ /* Maintenance of the shared handle open on the database. */ +static DB_ENV *dbenv; static DB *db; static int keep_db; static unsigned int entidx; /* Index for `getaliasent_r'. */ @@ -47,7 +48,7 @@ pthread_mutex_lock (&lock); - status = internal_setent (_PATH_VARDB "aliases.db", &db); + status = internal_setent (_PATH_VARDB "aliases.db", &db, &dbenv); /* Remember STAYOPEN flag. */ if (db != NULL) @@ -68,7 +69,7 @@ { pthread_mutex_lock (&lock); - internal_endent (&db); + internal_endent (&db, &dbenv); /* Reset STAYOPEN flag. */ keep_db = 0; @@ -92,7 +93,7 @@ /* Open the database. */ if (db == NULL) { - status = internal_setent (_PATH_VARDB "aliases.db", &db); + status = internal_setent (_PATH_VARDB "aliases.db", &db, &dbenv); if (status != NSS_STATUS_SUCCESS) { *errnop = errno; @@ -165,7 +166,7 @@ status = NSS_STATUS_NOTFOUND; if (! keep_db) - internal_endent (&db); + internal_endent (&db, &dbenv); return status; } diff -urNad libnss-db-2.2.3pre1~/src/db-compat.c libnss-db-2.2.3pre1/src/db-compat.c --- libnss-db-2.2.3pre1~/src/db-compat.c 2010-03-30 10:41:48.076483572 -0700 +++ libnss-db-2.2.3pre1/src/db-compat.c 2010-03-30 10:41:48.286483656 -0700 @@ -27,15 +27,14 @@ int db_open (const char *file, DBTYPE type, u_int32_t flags, int mode, - void *dbenv, void *dbinfo, DB **dbp) + DB_ENV *dbenv, void *dbinfo, DB **dbp) { DB *db; int err; - assert (dbenv == NULL); assert (dbinfo == NULL); - err = db_create (&db, NULL, 0); + err = db_create (&db, dbenv, 0); if (err) return err; diff -urNad libnss-db-2.2.3pre1~/src/db-compat.h libnss-db-2.2.3pre1/src/db-compat.h --- libnss-db-2.2.3pre1~/src/db-compat.h 2001-04-29 18:07:41.000000000 -0700 +++ libnss-db-2.2.3pre1/src/db-compat.h 2010-03-30 10:41:48.286483656 -0700 @@ -2,5 +2,5 @@ #if DB_VERSION_MAJOR > 2 extern int db_open (const char *__file, DBTYPE __type, u_int32_t __flags, - int __mode, void *__dbenv, void *__dbinfo, DB **__dbp); + int __mode, DB_ENV *dbenv, void *__dbinfo, DB **__dbp); #endif diff -urNad libnss-db-2.2.3pre1~/src/db-netgrp.c libnss-db-2.2.3pre1/src/db-netgrp.c --- libnss-db-2.2.3pre1~/src/db-netgrp.c 2010-03-30 10:41:48.096484006 -0700 +++ libnss-db-2.2.3pre1/src/db-netgrp.c 2010-03-30 10:41:48.286483656 -0700 @@ -35,6 +35,7 @@ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; /* Maintenance of the shared handle open on the database. */ +static DB_ENV *dbenv; static DB *db; static char *entry; static char *cursor; @@ -46,7 +47,7 @@ pthread_mutex_lock (&lock); - status = internal_setent (DBFILE, &db); + status = internal_setent (DBFILE, &db, &dbenv); if (status == NSS_STATUS_SUCCESS) { @@ -72,7 +73,7 @@ { pthread_mutex_lock (&lock); - internal_endent (&db); + internal_endent (&db, &dbenv); pthread_mutex_unlock (&lock); diff -urNad libnss-db-2.2.3pre1~/src/db-open.c libnss-db-2.2.3pre1/src/db-open.c --- libnss-db-2.2.3pre1~/src/db-open.c 2010-03-30 10:41:48.096484006 -0700 +++ libnss-db-2.2.3pre1/src/db-open.c 2010-03-30 10:42:24.146482862 -0700 @@ -21,6 +21,9 @@ #include <db.h> #include <errno.h> #include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <libgen.h> #include "db-compat.h" @@ -45,35 +48,46 @@ handle in *DBP and return NSS_STATUS_SUCCESS. On failure, return the appropriate lookup status. */ enum nss_status -internal_setent (const char *file, DB **dbp) +internal_setent (const char *file, DB **dbp, DB_ENV **dbenvp) { - DB *db; + char *filecopy = NULL, *home; + DB_ENV *dbenv = NULL; + DB *db = NULL; int err; int fd; if (*dbp) return NSS_STATUS_SUCCESS; - err = db_open (file, DB_BTREE, DB_RDONLY, 0, NULL, NULL, &db); + err = db_env_create(&dbenv, 0); if (err != 0) - { - if (err > 0) - errno = err; - return NSS_STATUS_UNAVAIL; - } + goto fail; + filecopy = strdup(file); + home = dirname(filecopy); + err = (dbenv->open)(dbenv, home, DB_INIT_MPOOL | DB_CREATE | DB_PRIVATE, 0); + if (err != 0) + goto fail_env; + err = db_open (file, DB_BTREE, DB_RDONLY, 0, dbenv, NULL, &db); + if (err != 0) + goto fail_env; /* We have to make sure the file is `closed on exec'. */ err = db->fd (db, &fd); if (err) - goto fail; + goto fail_db; if (set_cloexec_flag (fd) < 0) - goto fail; + goto fail_db; + *dbenvp = dbenv; *dbp = db; return NSS_STATUS_SUCCESS; - fail: + fail_db: db->close (db, 0); + fail_env: + dbenv->close (dbenv, 0); + fail: + if (filecopy) free(filecopy); if (err > 0) errno = err; return NSS_STATUS_UNAVAIL; @@ -81,8 +95,9 @@ /* Close the database *DBP. */ void -internal_endent (DB **dbp) +internal_endent (DB **dbp, DB_ENV **dbenvp) { + DB_ENV *dbenv = *dbenvp; DB *db = *dbp; if (db != NULL) @@ -90,4 +105,9 @@ db->close (db, 0); *dbp = NULL; } + if (dbenv != NULL) + { + dbenv->close (dbenv, 0); + *dbenvp = NULL; + } } diff -urNad libnss-db-2.2.3pre1~/src/nss_db.h libnss-db-2.2.3pre1/src/nss_db.h --- libnss-db-2.2.3pre1~/src/nss_db.h 2001-04-29 18:07:41.000000000 -0700 +++ libnss-db-2.2.3pre1/src/nss_db.h 2010-03-30 10:41:48.286483656 -0700 @@ -26,9 +26,9 @@ /* Open the database stored in FILE. If succesful, store the database handle in *DBP and return NSS_STATUS_SUCCESS. On failure, return the appropriate lookup status. */ -extern enum nss_status internal_setent (const char *file, DB **dbp); +extern enum nss_status internal_setent (const char *file, DB **dbp, DB_ENV **dbenvp); /* Close the database *DBP. */ -extern void internal_endent (DB **dbp); +extern void internal_endent (DB **dbp, DB_ENV **dbenvp); #endif /* nss_db.h */ -- libnss-db-2.2.3pre1.orig/debian/patches/010-db2_upgrade_code.patch ++ libnss-db-2.2.3pre1/debian/patches/010-db2_upgrade_code.patch @ -0,0 +1,29 @@ #! /bin/sh /usr/share/dpatch/dpatch-run ## 010-db2_upgrade_code.patch by Piotr Roszatycki <dexter@debian.org> ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: Make sure we upgrade, in case this is an older database; and handle the ## DP: DB4.3 API change for DB->open(). @DPATCH@ diff -urN nss_db-2.2.orig/src/db-compat.c nss_db-2.2/src/db-compat.c --- nss_db-2.2.orig/src/db-compat.c Mon Mar 26 15:34:53 2001 +++ nss_db-2.2/src/db-compat.c Mon Mar 26 15:31:36 2001 @@ -39,7 +39,15 @@ if (err) return err; - err = (db->open) (db, NULL, file, NULL, type, flags, mode); + err = (db->open) (db, NULL, file, NULL, type, flags, mode); + /* Make sure we upgrade, in case this is an older database */ + if (err == DB_OLD_VERSION) { + db->close (db, 0); + err = db->upgrade(db, file, 0); + if (err) + return err; + err = (db->open) (db, NULL, file, NULL, type, flags, mode); + } if (err) { db->close (db, 0);