From 63d30566bb8be8a49dd5320c3be6bc037ec9d399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 29 Apr 2026 17:49:46 +0200 Subject: [PATCH] Stop nzd_env_close from chowning through symlinks 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 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bin/named/nzd.c b/bin/named/nzd.c index fe8e4d24c5..af1820d86a 100644 --- a/bin/named/nzd.c +++ b/bin/named/nzd.c @@ -12,6 +12,8 @@ */ #include +#include +#include #include @@ -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