BUG/MINOR: init: relax LSTCHK_NETADM checks for non root

Linux capabilities support and ability to preserve it for running process
after switching to a global.uid was added recently by the commit bd84387beb
("MEDIUM: capabilities: enable support for Linux capabilities")).
This new feature hasn't yet been taken into account by last config checks,
which are performed at initialization stage.

So, to update it, let's perform it after set_identity() call. Like this,
current EUID is already changed to a global.uid and prepare_caps_for_setuid()
would unset LSTCHK_NETADM flag, only if capabilities given in the 'setcap'
keyword in the configuration file were preserved.

Otherwise, if system doesn't support Linux capabilities or they were not set
via 'setcap', we keep the previous strict behaviour: process will terminate
with an alert, in order to insist that user: either needs to change
run UID (worst case: start and run as root), or he needs to set/recheck
capabilities listed as 'setcap' arguments.

In the case, when haproxy will start and run under a non-root user this patch
doesn't change the previous behaviour: we'll still let him try the
configuration, but we inform via warning that unexpected things may occur.

Need to be backported until v2.9, including v2.9.
This commit is contained in:
Valentine Krasnobaeva 2024-03-18 14:50:26 +01:00 committed by Willy Tarreau
parent a4f564b05e
commit e4306fb822
2 changed files with 36 additions and 17 deletions

View File

@ -3597,21 +3597,6 @@ int main(int argc, char **argv)
}
}
if ((global.last_checks & LSTCHK_NETADM) && global.uid) {
ha_alert("[%s.main()] Some configuration options require full privileges, so global.uid cannot be changed.\n"
"", argv[0]);
protocol_unbind_all();
exit(1);
}
/* If the user is not root, we'll still let them try the configuration
* but we inform them that unexpected behaviour may occur.
*/
if ((global.last_checks & LSTCHK_NETADM) && getuid())
ha_warning("[%s.main()] Some options which require full privileges"
" might not work well.\n"
"", argv[0]);
if ((global.mode & (MODE_MWORKER|MODE_DAEMON)) == 0) {
/* chroot if needed */
@ -3640,6 +3625,34 @@ int main(int argc, char **argv)
if ((global.mode & (MODE_MWORKER | MODE_DAEMON)) == 0)
set_identity(argv[0]);
/* set_identity() above might have dropped LSTCHK_NETADM if
* it changed to a new UID while preserving enough permissions
* to honnor LSTCHK_NETADM.
*/
if ((global.last_checks & LSTCHK_NETADM) && getuid()) {
/* If global.uid is present in config, it is already set as euid
* and ruid by set_identity() call just above, so it's better to
* remind the user to fix uncoherent settings.
*/
if (global.uid) {
ha_alert("[%s.main()] Some configuration options require full "
"privileges, so global.uid cannot be changed.\n", argv[0]);
#if defined(USE_LINUX_CAP)
ha_alert("[%s.main()] Alternately, if your system supports "
"Linux capabilities, you may also consider using "
"'setcap cap_net_raw' or 'setcap cap_net_admin' in the "
"'global' section.\n", argv[0]);
#endif
protocol_unbind_all();
exit(1);
}
/* If the user is not root, we'll still let them try the configuration
* but we inform them that unexpected behaviour may occur.
*/
ha_warning("[%s.main()] Some options which require full privileges"
" might not work well.\n", argv[0]);
}
/* check ulimits */
limit.rlim_cur = limit.rlim_max = 0;
getrlimit(RLIMIT_NOFILE, &limit);

View File

@ -23,6 +23,7 @@
#include <haproxy/api.h>
#include <haproxy/cfgparse.h>
#include <haproxy/errors.h>
#include <haproxy/global.h>
#include <haproxy/tools.h>
/* supported names, zero-terminated */
@ -59,9 +60,10 @@ static uint32_t caplist;
* - switch euid to non-zero
* - set the effective and permitted caps again
* - then the caller can safely call setuid()
* On success LSTCHK_NETADM is unset from global.last_checks, if CAP_NET_ADMIN
* or CAP_NET_RAW was found in the caplist from config.
* We don't do this if the current euid is not zero or if the target uid
* is zero. Returns >=0 on success, negative on failure. Alerts or warnings
* may be emitted.
* is zero. Returns 0 on success, negative on failure. Alerts may be emitted.
*/
int prepare_caps_for_setuid(int from_uid, int to_uid)
{
@ -101,6 +103,10 @@ int prepare_caps_for_setuid(int from_uid, int to_uid)
ha_alert("Failed to set the final capabilities using capset(): %s\n", strerror(errno));
return -1;
}
if (caplist & ((1 << CAP_NET_ADMIN)|(1 << CAP_NET_RAW)))
global.last_checks &= ~LSTCHK_NETADM;
/* all's good */
return 0;
}