2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-02 15:45:25 +00:00

[master] prevent reload failure due to LMDB database perms

4638.	[bug]		Reloading or reconfiguring named could fail on
			some platforms when LMDB was in use. [RT #45203]
This commit is contained in:
Evan Hunt
2017-06-13 10:15:34 -07:00
parent 0471530aae
commit bf05e66bb3
9 changed files with 176 additions and 35 deletions

View File

@@ -1,3 +1,6 @@
4638. [bug] Reloading or reconfiguring named could fail on
some platforms when LMDB was in use. [RT #45203]
4637. [func] "nsec3hash -r" option ("rdata order") takes arguments 4637. [func] "nsec3hash -r" option ("rdata order") takes arguments
in the same order as they appear in NSEC3 or in the same order as they appear in NSEC3 or
NSEC3PARAM records, so that NSEC3 parameters can NSEC3PARAM records, so that NSEC3 parameters can

View File

@@ -484,6 +484,12 @@ nzd_writable(dns_view_t *view);
static isc_result_t static isc_result_t
nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi); nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
static isc_result_t
nzd_env_reopen(dns_view_t *view);
static void
nzd_env_close(dns_view_t *view);
static isc_result_t static isc_result_t
nzd_close(MDB_txn **txnp, isc_boolean_t commit); nzd_close(MDB_txn **txnp, isc_boolean_t commit);
@@ -6727,12 +6733,21 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
return (ISC_R_NOMEMORY); return (ISC_R_NOMEMORY);
} }
/*
* We attach the parser that was used for config as well
* as the one that will be used for added zones, to avoid
* a shutdown race later.
*/
memset(nzcfg, 0, sizeof(*nzcfg)); memset(nzcfg, 0, sizeof(*nzcfg));
cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
cfg_parser_attach(ns_g_addparser, &nzcfg->add_parser);
isc_mem_attach(view->mctx, &nzcfg->mctx);
cfg_aclconfctx_attach(actx, &nzcfg->actx);
result = dns_view_setnewzones(view, ISC_TRUE, nzcfg, result = dns_view_setnewzones(view, ISC_TRUE, nzcfg,
newzone_cfgctx_destroy, mapsize); newzone_cfgctx_destroy, mapsize);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
isc_mem_put(view->mctx, nzcfg, sizeof(*nzcfg)); dns_view_setnewzones(view, ISC_FALSE, NULL, NULL, 0ULL);
return (result); return (result);
} }
@@ -6740,16 +6755,6 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
if (vconfig != NULL) if (vconfig != NULL)
cfg_obj_attach(vconfig, &nzcfg->vconfig); cfg_obj_attach(vconfig, &nzcfg->vconfig);
/*
* We attach the parser that was used for config as well
* as the one that will be used for added zones, to avoid
* a shutdown race later.
*/
cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
cfg_parser_attach(ns_g_addparser, &nzcfg->add_parser);
isc_mem_attach(view->mctx, &nzcfg->mctx);
cfg_aclconfctx_attach(actx, &nzcfg->actx);
result = count_newzones(view, nzcfg, num_zones); result = count_newzones(view, nzcfg, num_zones);
return (result); return (result);
} }
@@ -7936,6 +7941,21 @@ load_configuration(const char *filename, ns_server_t *server,
} }
} }
/*
* If we're using LMDB, we may have created newzones databases
* as root, making it impossible to reopen them later after
* switching to a new userid. We close them now, and reopen
* after relinquishing privileges them.
*/
if (first_time) {
for (view = ISC_LIST_HEAD(server->viewlist);
view != NULL;
view = ISC_LIST_NEXT(view, link))
{
nzd_env_close(view);
}
}
/* /*
* Relinquish root privileges. * Relinquish root privileges.
*/ */
@@ -7951,6 +7971,20 @@ load_configuration(const char *filename, ns_server_t *server,
"the working directory is not writable"); "the working directory is not writable");
} }
#ifdef HAVE_LMDB
/*
* Reopen NZD databases.
*/
if (first_time) {
for (view = ISC_LIST_HEAD(server->viewlist);
view != NULL;
view = ISC_LIST_NEXT(view, link))
{
nzd_env_reopen(view);
}
}
#endif /* HAVE_LMDB */
/* /*
* Configure the logging system. * Configure the logging system.
* *
@@ -11317,6 +11351,93 @@ nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
} }
/*
* nzd_env_close() and nzd_env_reopen are a kluge to address the
* problem of an NZD file possibly being created before we drop
* root privileges.
*/
static void
nzd_env_close(dns_view_t *view) {
if (view->new_zone_dbenv != NULL) {
const char *dbpath = NULL;
char lockpath[PATH_MAX];
int ret;
if (mdb_env_get_path(view->new_zone_dbenv, &dbpath) == 0) {
snprintf(lockpath, sizeof(lockpath), "%s-lock",
dbpath);
}
mdb_env_close((MDB_env *) view->new_zone_dbenv);
view->new_zone_dbenv = NULL;
/*
* Database files must be owned by the eventual user, not
* by root.
*/
ret = chown(dbpath, ns_os_uid(), -1);
UNUSED(ret);
/*
* Some platforms need the lockfile not to exist when we
* reopen the environment.
*/
(void) isc_file_remove(lockpath);
}
}
static isc_result_t
nzd_env_reopen(dns_view_t *view) {
isc_result_t result;
MDB_env *env = NULL;
int status;
if (view->new_zone_db == NULL) {
return (ISC_R_SUCCESS);
}
nzd_env_close(view);
status = mdb_env_create(&env);
if (status != 0) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
"mdb_env_create failed: %s",
mdb_strerror(status));
CHECK(ISC_R_FAILURE);
}
if (view->new_zone_mapsize != 0ULL) {
status = mdb_env_set_mapsize(env, view->new_zone_mapsize);
if (status != 0) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
"mdb_env_set_mapsize failed: %s",
mdb_strerror(status));
CHECK(ISC_R_FAILURE);
}
}
status = mdb_env_open(env, view->new_zone_db,
MDB_NOSUBDIR|MDB_CREATE, 0600);
if (status != 0) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
"mdb_env_open of '%s' failed: %s",
view->new_zone_db, mdb_strerror(status));
CHECK(ISC_R_FAILURE);
}
view->new_zone_dbenv = env;
env = NULL;
cleanup:
if (env != NULL) {
mdb_env_close(env);
}
return (result);
}
static isc_result_t static isc_result_t
nzd_close(MDB_txn **txnp, isc_boolean_t commit) { nzd_close(MDB_txn **txnp, isc_boolean_t commit) {
isc_result_t result = ISC_R_SUCCESS; isc_result_t result = ISC_R_SUCCESS;
@@ -12659,7 +12780,6 @@ ns_server_showzone(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
static void static void
newzone_cfgctx_destroy(void **cfgp) { newzone_cfgctx_destroy(void **cfgp) {
ns_cfgctx_t *cfg; ns_cfgctx_t *cfg;
isc_mem_t *mctx;
REQUIRE(cfgp != NULL && *cfgp != NULL); REQUIRE(cfgp != NULL && *cfgp != NULL);
@@ -12681,8 +12801,7 @@ newzone_cfgctx_destroy(void **cfgp) {
if (cfg->actx != NULL) if (cfg->actx != NULL)
cfg_aclconfctx_detach(&cfg->actx); cfg_aclconfctx_detach(&cfg->actx);
mctx = cfg->mctx; isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
isc_mem_putanddetach(&mctx, cfg, sizeof(*cfg));
*cfgp = NULL; *cfgp = NULL;
} }

View File

@@ -11,6 +11,8 @@
/*! \file */ /*! \file */
#include <pwd.h>
#include <isc/types.h> #include <isc/types.h>
void void
@@ -34,6 +36,9 @@ ns_os_inituserinfo(const char *username);
void void
ns_os_changeuser(void); ns_os_changeuser(void);
uid_t
ns_os_uid(void);
void void
ns_os_adjustnofile(void); ns_os_adjustnofile(void);

View File

@@ -601,6 +601,13 @@ ns_os_changeuser(void) {
#endif #endif
} }
uid_t
ns_os_uid(void) {
if (runas_pw == NULL)
return (0);
return (runas_pw->pw_uid);
}
void void
ns_os_adjustnofile(void) { ns_os_adjustnofile(void) {
#ifdef HAVE_LINUXTHREADS #ifdef HAVE_LINUXTHREADS

View File

@@ -32,6 +32,9 @@ ns_os_inituserinfo(const char *username);
void void
ns_os_changeuser(void); ns_os_changeuser(void);
unsigned int
ns_os_uid(void);
void void
ns_os_adjustnofile(void); ns_os_adjustnofile(void);

View File

@@ -163,6 +163,11 @@ void
ns_os_changeuser(void) { ns_os_changeuser(void) {
} }
unsigned int
ns_os_uid(void) {
return (0);
}
void void
ns_os_adjustnofile(void) { ns_os_adjustnofile(void) {
} }

View File

@@ -412,6 +412,12 @@
<section xml:id="relnotes_bugs"><info><title>Bug Fixes</title></info> <section xml:id="relnotes_bugs"><info><title>Bug Fixes</title></info>
<itemizedlist> <itemizedlist>
<listitem>
<para>
Reloading or reconfiguring <command>named</command> could
fail on some platforms when LMDB was in use. [RT #45203]
</para>
</listitem>
<listitem> <listitem>
<para> <para>
Due to some incorrectly deleted code, when BIND was Due to some incorrectly deleted code, when BIND was
@@ -422,7 +428,6 @@
server restart. This has been corrected. [RT #45185] server restart. This has been corrected. [RT #45185]
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
Semicolons are no longer escaped when printing CAA and Semicolons are no longer escaped when printing CAA and

View File

@@ -212,6 +212,7 @@ struct dns_view {
char * new_zone_file; char * new_zone_file;
char * new_zone_db; char * new_zone_db;
void * new_zone_dbenv; void * new_zone_dbenv;
isc_uint64_t new_zone_mapsize;
void * new_zone_config; void * new_zone_config;
void (*cfg_destroy)(void **); void (*cfg_destroy)(void **);
isc_mutex_t new_zone_lock; isc_mutex_t new_zone_lock;

View File

@@ -236,6 +236,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view->new_zone_file = NULL; view->new_zone_file = NULL;
view->new_zone_db = NULL; view->new_zone_db = NULL;
view->new_zone_dbenv = NULL; view->new_zone_dbenv = NULL;
view->new_zone_mapsize = 0ULL;
view->new_zone_config = NULL; view->new_zone_config = NULL;
view->cfg_destroy = NULL; view->cfg_destroy = NULL;
view->fail_ttl = 0; view->fail_ttl = 0;
@@ -2038,7 +2039,7 @@ isc_result_t
dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx, dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
void (*cfg_destroy)(void **), isc_uint64_t mapsize) void (*cfg_destroy)(void **), isc_uint64_t mapsize)
{ {
isc_result_t result; isc_result_t result = ISC_R_SUCCESS;
char buffer[1024]; char buffer[1024];
#ifdef HAVE_LMDB #ifdef HAVE_LMDB
MDB_env *env = NULL; MDB_env *env = NULL;
@@ -2078,27 +2079,21 @@ dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
} }
result = nz_legacy(view->new_zone_dir, view->name, "nzf", CHECK(nz_legacy(view->new_zone_dir, view->name, "nzf",
buffer, sizeof(buffer)); buffer, sizeof(buffer)));
if (result != ISC_R_SUCCESS)
goto out;
view->new_zone_file = isc_mem_strdup(view->mctx, buffer); view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
if (view->new_zone_file == NULL) { if (view->new_zone_file == NULL) {
result = ISC_R_NOMEMORY; CHECK(ISC_R_NOMEMORY);
goto out;
} }
#ifdef HAVE_LMDB #ifdef HAVE_LMDB
result = nz_legacy(view->new_zone_dir, view->name, "nzd", CHECK(nz_legacy(view->new_zone_dir, view->name, "nzd",
buffer, sizeof(buffer)); buffer, sizeof(buffer)));
if (result != ISC_R_SUCCESS)
goto out;
view->new_zone_db = isc_mem_strdup(view->mctx, buffer); view->new_zone_db = isc_mem_strdup(view->mctx, buffer);
if (view->new_zone_db == NULL) { if (view->new_zone_db == NULL) {
result = ISC_R_NOMEMORY; CHECK(ISC_R_NOMEMORY);
goto out;
} }
status = mdb_env_create(&env); status = mdb_env_create(&env);
@@ -2107,19 +2102,18 @@ dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
ISC_LOGMODULE_OTHER, ISC_LOG_ERROR, ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
"mdb_env_create failed: %s", "mdb_env_create failed: %s",
mdb_strerror(status)); mdb_strerror(status));
result = ISC_R_FAILURE; CHECK(ISC_R_FAILURE);
goto out;
} }
if (mapsize != 0ULL) { if (mapsize != 0ULL) {
status = mdb_env_set_mapsize(env, mapsize); status = mdb_env_set_mapsize(env, mapsize);
view->new_zone_mapsize = mapsize;
if (status != 0) { if (status != 0) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_OTHER, ISC_LOG_ERROR, ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
"mdb_env_set_mapsize failed: %s", "mdb_env_set_mapsize failed: %s",
mdb_strerror(status)); mdb_strerror(status));
result = ISC_R_FAILURE; CHECK(ISC_R_FAILURE);
goto out;
} }
} }
@@ -2130,8 +2124,7 @@ dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
ISC_LOGMODULE_OTHER, ISC_LOG_ERROR, ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
"mdb_env_open of '%s' failed: %s", "mdb_env_open of '%s' failed: %s",
view->new_zone_db, mdb_strerror(status)); view->new_zone_db, mdb_strerror(status));
result = ISC_R_FAILURE; CHECK(ISC_R_FAILURE);
goto out;
} }
view->new_zone_dbenv = env; view->new_zone_dbenv = env;
@@ -2141,7 +2134,7 @@ dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
view->new_zone_config = cfgctx; view->new_zone_config = cfgctx;
view->cfg_destroy = cfg_destroy; view->cfg_destroy = cfg_destroy;
out: cleanup:
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
if (view->new_zone_file != NULL) { if (view->new_zone_file != NULL) {
isc_mem_free(view->mctx, view->new_zone_file); isc_mem_free(view->mctx, view->new_zone_file);