]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Stop nzd_env_close from chowning through symlinks
authorOndřej Surý <ondrej@isc.org>
Wed, 29 Apr 2026 15:49:46 +0000 (17:49 +0200)
committerOndřej Surý <ondrej@isc.org>
Wed, 29 Apr 2026 17:18:47 +0000 (19:18 +0200)
When named is running as root, nzd_env_close() chowns the per-view
NZD database file to the unprivileged user that named will drop to.
The call used chown(), which follows symlinks, so a symlink at the
NZD path would silently transfer ownership of whatever the link
pointed at instead of the database file itself.

Switch to lstat() + S_ISREG() + lchown() so the chown only fires when
the path is a regular file and never traverses a symlink even if one
is planted between the lstat and the lchown.

Assisted-by: Claude:claude-opus-4-7
bin/named/nzd.c

index fe8e4d24c5850cb17534df0e1317c9d9a95f40df..af1820d86adbcf2e6756d6c01c0648f99b3348a7 100644 (file)
@@ -12,6 +12,8 @@
  */
 
 #include <lmdb.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 #include <isc/file.h>
 
@@ -235,6 +237,7 @@ nzd_env_close(dns_view_t *view) {
        const char *dbpath = NULL;
        char dbpath_copy[PATH_MAX];
        char lockpath[PATH_MAX];
+       struct stat sb;
        int status, ret;
 
        if (view->newzone.dbenv == NULL) {
@@ -249,9 +252,13 @@ nzd_env_close(dns_view_t *view) {
 
        /*
         * Database files must be owned by the eventual user, not by root.
+        * Use lstat()/S_ISREG/lchown() so a symlink at the path cannot
+        * redirect the chown to an unrelated file.
         */
-       ret = chown(dbpath_copy, named_os_uid(), -1);
-       UNUSED(ret);
+       if (lstat(dbpath_copy, &sb) == 0 && S_ISREG(sb.st_mode)) {
+               ret = lchown(dbpath_copy, named_os_uid(), -1);
+               UNUSED(ret);
+       }
 
        /*
         * Some platforms need the lockfile not to exist when we reopen the