]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Delay release of root privileges until after configuring controls
authorEvan Hunt <each@isc.org>
Wed, 3 Jul 2024 06:40:54 +0000 (23:40 -0700)
committerEvan Hunt <each@isc.org>
Thu, 29 Aug 2024 17:34:38 +0000 (10:34 -0700)
On systems where root access is needed to configure privileged
ports, we don't want to fully relinquish root privileges until
after the control channel (which typically runs on port 953) has
been established.

named_os_changeuser() now takes a boolean argument 'permanent'.
This allows us to switch the effective userid temporarily with
named_os_changeuser(false) and restore it with named_os_restoreuser(),
before permanently dropping privileges with named_os_changeuser(true).

bin/named/include/named/os.h
bin/named/os.c
bin/named/server.c

index 6066fc391de8ba3330171d59b48464f0104a64de..a150872f47d6ec8e895bdfef931377a19d941ac2 100644 (file)
@@ -39,10 +39,13 @@ void
 named_os_inituserinfo(const char *username);
 
 void
-named_os_changeuser(void);
+named_os_changeuser(bool permanent);
+
+void
+named_os_restoreuser(void);
 
 uid_t
-ns_os_uid(void);
+named_os_uid(void);
 
 void
 named_os_adjustnofile(void);
index 031779e4a30101651ecc0b9b2816190464a58524..6c93d387e25a8b54f82a2dd8a94d0be405a96ce8 100644 (file)
@@ -61,6 +61,9 @@ static struct passwd *runas_pw = NULL;
 static bool done_setuid = false;
 static int dfd[2] = { -1, -1 };
 
+static uid_t saved_uid = (uid_t)-1;
+static gid_t saved_gid = (gid_t)-1;
+
 #if HAVE_LIBCAP
 
 static bool non_root = false;
@@ -461,12 +464,33 @@ named_os_inituserinfo(const char *username) {
 }
 
 void
-named_os_changeuser(void) {
+named_os_restoreuser(void) {
+       if (runas_pw == NULL || done_setuid) {
+               return;
+       }
+
+       REQUIRE(saved_uid != (uid_t)-1);
+       REQUIRE(saved_gid != (gid_t)-1);
+
+       setperms(saved_uid, saved_gid);
+}
+
+void
+named_os_changeuser(bool permanent) {
        char strbuf[ISC_STRERRORSIZE];
        if (runas_pw == NULL || done_setuid) {
                return;
        }
 
+       if (!permanent) {
+               saved_uid = getuid();
+               saved_gid = getgid();
+
+               setperms(runas_pw->pw_uid, runas_pw->pw_gid);
+
+               return;
+       }
+
        done_setuid = true;
 
        if (setgid(runas_pw->pw_gid) == -1) {
@@ -495,7 +519,7 @@ named_os_changeuser(void) {
 }
 
 uid_t
-ns_os_uid(void) {
+named_os_uid(void) {
        if (runas_pw == NULL) {
                return (0);
        }
@@ -551,7 +575,7 @@ void
 named_os_minprivs(void) {
 #if HAVE_LIBCAP
        linux_keepcaps();
-       named_os_changeuser();
+       named_os_changeuser(true);
        linux_minprivs();
 #endif /* HAVE_LIBCAP */
 }
@@ -678,19 +702,16 @@ named_os_openfile(const char *filename, mode_t mode, bool switch_user) {
        free(f);
 
        if (switch_user && runas_pw != NULL) {
-               uid_t olduid = getuid();
-               gid_t oldgid = getgid();
-
                /*
-                * Set UID/GID to the one we'll be running with
+                * Temporarily set UID/GID to the one we'll be running with
                 * eventually.
                 */
-               setperms(runas_pw->pw_uid, runas_pw->pw_gid);
+               named_os_changeuser(false);
 
                fd = safe_open(filename, mode, false);
 
                /* Restore UID/GID to previous uid/gid */
-               setperms(olduid, oldgid);
+               named_os_restoreuser();
 
                if (fd == -1) {
                        fd = safe_open(filename, mode, false);
index 7c42ae808e780e65c94592c430d01feb12408365..0204c32f969ab8557166e9b26d802431096cd6dd 100644 (file)
@@ -9370,10 +9370,12 @@ load_configuration(const char *filename, named_server_t *server,
 #endif /* HAVE_LMDB */
 
        /*
-        * Relinquish root privileges.
+        * Switch to the effective UID for setting up files.
+        * Later, after configuring all the listening ports,
+        * we'll relinquish root privileges permanently.
         */
        if (first_time) {
-               named_os_changeuser();
+               named_os_changeuser(false);
        }
 
        /*
@@ -9719,6 +9721,11 @@ load_configuration(const char *filename, named_server_t *server,
        isc_loopmgr_resume(named_g_loopmgr);
        exclusive = false;
 
+       /* Take back root privileges temporarily */
+       if (first_time) {
+               named_os_restoreuser();
+       }
+
        /* Configure the statistics channel(s) */
        result = named_statschannels_configure(named_g_server, config,
                                               named_g_aclconfctx);
@@ -9744,6 +9751,13 @@ load_configuration(const char *filename, named_server_t *server,
 
        (void)ns_interfacemgr_scan(server->interfacemgr, true, true);
 
+       /*
+        * Permanently drop root privileges now.
+        */
+       if (first_time) {
+               named_os_changeuser(true);
+       }
+
        /*
         * These cleans up either the old production view list
         * or our temporary list depending on whether they
@@ -13258,7 +13272,7 @@ nzd_env_close(dns_view_t *view) {
        /*
         * Database files must be owned by the eventual user, not by root.
         */
-       ret = chown(dbpath_copy, ns_os_uid(), -1);
+       ret = chown(dbpath_copy, named_os_uid(), -1);
        UNUSED(ret);
 
        /*