From 748e21b42e4ca8276e085e447e8dbe43352908bb Mon Sep 17 00:00:00 2001 From: Stanislav Levin Date: Fri, 29 May 2020 15:31:08 +0300 Subject: [PATCH] ALT: Make it possible to retain Linux capabilities of named Current behaviour of named is differ from upstream version. This leads to the failures under the certain conditions. One of the incompatibilities is the different employment of Linux capabilities(7). This is how the process of caps setup/dropping looks for now: ___________________________________________________ conditions: HAVE_LINUX_CAPABILITY_H && HAVE_LIBCAP && HAVE_LINUXTHREADS caps initial set: CAP_NET_BIND_SERVICE CAP_SYS_CHROOT CAP_SETUID CAP_SETGID CAP_DAC_READ_SEARCH CAP_SYS_RESOURCE CAP_CHOWN caps working set: CAP_NET_BIND_SERVICE CAP_SYS_RESOURCE ___________________________________________________ upstream version: ns_os_init: linux_initialprivs : apply caps initial set ns_os_minprivs : linux_keepcaps : keep caps after setuid ns_os_changeuser : setgid; setuid; linux_minprivs : apply caps working set ___________________________________________________ ALT specific: ns_os_init: linux_initialprivs : apply caps initial set ns_os_minprivs : linux_keepcaps : keep caps after setuid ns_os_changeuser : setgid; setresuid (named, named, -1) linux_minprivs : apply caps working set linux_losecaps : don't keep caps after setuid => configuration was loaded, threads run ns_os_dropprivs : setresuid all uids to non-zero (also clears all caps for all threads) ___________________________________________________ Simply put, we drop all the capabilities, while upstream retains CAP_NET_BIND_SERVICE and CAP_SYS_RESOURCE. Proposal is the implementation of another mode of operation on capabilities: ns_os_init linux_cap_drop_bounding_set : clear cap bounding set linux_initialprivs : sets initial caps ns_os_minprivs : linux_keepcaps : keep caps after setuid ns_os_changeuser : setgid; setuid linux_minprivs : apply caps working set linux_losecaps : don't keep caps after setuid In this mode named retains CAP_NET_BIND_SERVICE and CAP_SYS_RESOURCE, but drops caps bounding set as well as SECBIT_KEEP_CAPS. Fixes: https://bugzilla.altlinux.org/show_bug.cgi?id=33300 --- bind/bin/named/include/named/globals.h | 1 + bind/bin/named/include/named/main.h | 2 +- bind/bin/named/main.c | 5 +++- bind/bin/named/server.c | 4 ++- bind/bin/named/unix/os.c | 36 +++++++++++++++++++++++--- 5 files changed, 42 insertions(+), 6 deletions(-) diff --git a/bind/bin/named/include/named/globals.h b/bind/bin/named/include/named/globals.h index 82b632ef043..4436ef8eb61 100644 --- a/bind/bin/named/include/named/globals.h +++ b/bind/bin/named/include/named/globals.h @@ -111,6 +111,7 @@ EXTERN isc_resourcevalue_t named_g_initopenfiles INIT(0); /* * Misc. */ +EXTERN bool named_g_retain_caps INIT(false); EXTERN bool named_g_coreok INIT(true); EXTERN const char *named_g_chrootdir INIT(NULL); EXTERN bool named_g_foreground INIT(false); diff --git a/bind/bin/named/include/named/main.h b/bind/bin/named/include/named/main.h index ee790b96ca3..ee4a451b3dd 100644 --- a/bind/bin/named/include/named/main.h +++ b/bind/bin/named/include/named/main.h @@ -23,7 +23,7 @@ /* * Commandline arguments for named; also referenced in win32/ntservice.c */ -#define NAMED_MAIN_ARGS "46A:c:Cd:D:E:fFgL:M:m:n:N:p:sS:t:T:U:u:vVx:X:" +#define NAMED_MAIN_ARGS "46A:c:Cd:D:E:fFgL:M:m:n:N:p:rsS:t:T:U:u:vVx:X:" ISC_PLATFORM_NORETURN_PRE void named_main_earlyfatal(const char *format, ...) diff --git a/bind/bin/named/main.c b/bind/bin/named/main.c index 97cd36f6925..25c3313fc35 100644 --- a/bind/bin/named/main.c +++ b/bind/bin/named/main.c @@ -345,7 +345,7 @@ usage(void) { fprintf(stderr, "usage: named [-4|-6] [-c conffile] [-d debuglevel] " "[-D comment] [-E engine]\n" " [-f|-g] [-L logfile] [-n number_of_cpus] " - "[-p port] [-s]\n" + "[-p port] [-r] [-s]\n" " [-S sockets] [-t chrootdir] [-u " "username] [-U listeners]\n" " [-X lockfile] [-m " @@ -954,6 +954,9 @@ parse_command_line(int argc, char *argv[]) { } named_g_port = port; break; + case 'r': + named_g_retain_caps = true; + break; case 's': /* XXXRTH temporary syntax */ want_stats = true; diff --git a/bind/bin/named/server.c b/bind/bin/named/server.c index 0c0fdc409bd..3a5e2e15cd7 100644 --- a/bind/bin/named/server.c +++ b/bind/bin/named/server.c @@ -9194,7 +9194,9 @@ load_configuration(const char *filename, named_server_t *server, */ if (first_time) { named_os_changeuser(); - named_os_dropprivs(); + if (!named_g_retain_caps) { + named_os_dropprivs(); + } } /* diff --git a/bind/bin/named/unix/os.c b/bind/bin/named/unix/os.c index 44faacde85e..090b1654fd3 100644 --- a/bind/bin/named/unix/os.c +++ b/bind/bin/named/unix/os.c @@ -197,6 +197,28 @@ linux_initialprivs(void) { FREE_CAP; } +static void +linux_cap_drop_bounding_set(void) { + /* + * actually, cap_drop_bound (PR_CAPBSET_DROP) requires CAP_SETPCAP + * capability, but to simplify the logic drop bounding set only + * for root assuming that a regular user is not granted with caps. + */ + if (getuid() != 0) { + return; + } + cap_value_t capval = 0; + char strbuf[ISC_STRERRORSIZE]; + while (CAP_IS_SUPPORTED(capval)) { + if (cap_drop_bound(capval) != 0) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("cap_drop_bound failed: %s", + strbuf); + } + capval++; + } +} + static void linux_minprivs(void) { cap_t caps; @@ -278,6 +300,7 @@ void named_os_init(const char *progname) { setup_syslog(progname); #ifdef HAVE_SYS_CAPABILITY_H + linux_cap_drop_bounding_set(); linux_initialprivs(); #endif /* ifdef HAVE_SYS_CAPABILITY_H */ #ifdef SIGXFSZ @@ -467,9 +490,16 @@ named_os_changeuser(void) { named_main_earlyfatal("setgid(): %s", strbuf); } - if (setresuid(runas_pw->pw_uid, runas_pw->pw_uid, -1) < 0) { - strerror_r(errno, strbuf, sizeof(strbuf)); - named_main_earlyfatal("setuid(): %s", strbuf); + if (!named_g_retain_caps) { + if (setresuid(runas_pw->pw_uid, runas_pw->pw_uid, -1) < 0) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("setresuid(): %s", strbuf); + } + } else { + if (setuid(runas_pw->pw_uid) < 0) { + strerror_r(errno, strbuf, sizeof(strbuf)); + named_main_earlyfatal("setuid(): %s", strbuf); + } } #if defined(HAVE_SYS_CAPABILITY_H) -- 2.33.4