@cryptotaxi247 / netdata-1 / commits / 39e629e24

Consistently start the agent as root and rely on it to drop privileges properly. (#14890)

* Consolidate preparation of required directories. The only differences between cases where the prep is done is how we derive the UID and GID that get passed to some of the functions. By just encapsulating the preparation in a function like this, we make this differentiation obvious while also making it easier to modify what directories need to be created or prepared. * Create the log directory if it does not already exist. We treat the log directory not existing as a fatal error, but we can (in most cases) just create it on startup, so just do so. * Trust netdata to handle dropping privileges itself. This allows more correct behavior with respect to handling of required directories, and also ensures that our system service scripts properly support running the agent as arbitrary users instead of requiring it to run as the user configured at build time. * Fix build issues. * Move directory creation to be done alongside directory existence checks. * Fix syntax errors and address review feedback.

Austin S. Hemmelgarn committed Jun 15, 2023 at 07:33 UTC 39e629e24cf176963d112ec54fd1db1a24afc5b5
6 files changed +34 -39
daemon/analytics.c
+16 -5
@@ -632,6 +632,17 @@ static const char *verify_required_directory(const char *dir)
632 return dir;
633 }
634
635 +static const char *verify_or_create_required_directory(const char *dir) {
636 + int result;
637 +
638 + result = mkdir(dir, 0755);
639 +
640 + if (result != 0 && errno != EEXIST)
641 + fatal("Cannot create required directory '%s'", dir);
642 +
643 + return verify_required_directory(dir);
644 +}
645 +
646 /*
647 * This is called after the rrdinit
648 * These values will be sent on the START event
@@ -827,11 +838,11 @@ void set_global_environment()
838 setenv("NETDATA_STOCK_CONFIG_DIR", verify_required_directory(netdata_configured_stock_config_dir), 1);
839 setenv("NETDATA_PLUGINS_DIR", verify_required_directory(netdata_configured_primary_plugins_dir), 1);
840 setenv("NETDATA_WEB_DIR", verify_required_directory(netdata_configured_web_dir), 1);
830 - setenv("NETDATA_CACHE_DIR", verify_required_directory(netdata_configured_cache_dir), 1);
831 - setenv("NETDATA_LIB_DIR", verify_required_directory(netdata_configured_varlib_dir), 1);
832 - setenv("NETDATA_LOCK_DIR", netdata_configured_lock_dir, 1);
833 - setenv("NETDATA_LOG_DIR", verify_required_directory(netdata_configured_log_dir), 1);
834 - setenv("HOME", verify_required_directory(netdata_configured_home_dir), 1);
841 + setenv("NETDATA_CACHE_DIR", verify_or_create_required_directory(netdata_configured_cache_dir), 1);
842 + setenv("NETDATA_LIB_DIR", verify_or_create_required_directory(netdata_configured_varlib_dir), 1);
843 + setenv("NETDATA_LOCK_DIR", verify_or_create_required_directory(netdata_configured_lock_dir), 1);
844 + setenv("NETDATA_LOG_DIR", verify_or_create_required_directory(netdata_configured_log_dir), 1);
845 + setenv("HOME", verify_or_create_required_directory(netdata_configured_home_dir), 1);
846 setenv("NETDATA_HOST_PREFIX", netdata_configured_host_prefix, 1);
847
848 {
daemon/daemon.c
+15 -24
@@ -43,19 +43,10 @@ static void chown_open_file(int fd, uid_t uid, gid_t gid) {
43 }
44 }
45
46 -void create_needed_dir(const char *dir, uid_t uid, gid_t gid)
46 +void change_dir_ownership(const char *dir, uid_t uid, gid_t gid)
47 {
48 - // attempt to create the directory
49 - if(mkdir(dir, 0755) == 0) {
50 - // we created it
51 -
52 - // chown it to match the required user
53 - if(chown(dir, uid, gid) == -1)
54 - error("Cannot chown directory '%s' to %u:%u", dir, (unsigned int)uid, (unsigned int)gid);
55 - }
56 - else if(errno != EEXIST)
57 - // log an error only if the directory does not exist
58 - error("Cannot create directory '%s'", dir);
48 + if (chown(dir, uid, gid) == -1)
49 + error("Cannot chown directory '%s' to %u:%u", dir, (unsigned int)uid, (unsigned int)gid);
50 }
51
52 void clean_directory(char *dirname)
@@ -74,6 +65,16 @@ void clean_directory(char *dirname)
65 closedir(dir);
66 }
67
68 +void prepare_required_directories(uid_t uid, gid_t gid) {
69 + change_dir_ownership(netdata_configured_cache_dir, uid, gid);
70 + change_dir_ownership(netdata_configured_varlib_dir, uid, gid);
71 + change_dir_ownership(netdata_configured_lock_dir, uid, gid);
72 + change_dir_ownership(netdata_configured_log_dir, uid, gid);
73 + change_dir_ownership(claimingdirectory, uid, gid);
74 +
75 + clean_directory(netdata_configured_lock_dir);
76 +}
77 +
78 int become_user(const char *username, int pid_fd) {
79 int am_i_root = (getuid() == 0)?1:0;
80
@@ -86,12 +87,7 @@ int become_user(const char *username, int pid_fd) {
87 uid_t uid = pw->pw_uid;
88 gid_t gid = pw->pw_gid;
89
89 - create_needed_dir(netdata_configured_cache_dir, uid, gid);
90 - create_needed_dir(netdata_configured_varlib_dir, uid, gid);
91 - create_needed_dir(netdata_configured_lock_dir, uid, gid);
92 - create_needed_dir(claimingdirectory, uid, gid);
93 -
94 - clean_directory(netdata_configured_lock_dir);
90 + prepare_required_directories(uid, gid);
91
92 if(pidfile[0]) {
93 if(chown(pidfile, uid, gid) == -1)
@@ -487,12 +483,7 @@ int become_daemon(int dont_fork, const char *user)
483 else debug(D_SYSTEM, "Successfully became user '%s'.", user);
484 }
485 else {
490 - create_needed_dir(netdata_configured_cache_dir, getuid(), getgid());
491 - create_needed_dir(netdata_configured_varlib_dir, getuid(), getgid());
492 - create_needed_dir(netdata_configured_lock_dir, getuid(), getgid());
493 - create_needed_dir(claimingdirectory, getuid(), getgid());
494 -
495 - clean_directory(netdata_configured_lock_dir);
486 + prepare_required_directories(getuid(), getgid());
487 }
488
489 if(pidfd != -1)
system/openrc/init.d/netdata.in
+1 -2
@@ -15,7 +15,6 @@ command_prefix="@sbindir_POST@"
15 command="${command_prefix}/netdata"
16 command_args="-P ${NETDATA_PIDFILE} ${NETDATA_EXTRA_ARGS}"
17 command_args_foreground="-D"
18 -start_stop_daemon_args="-u ${NETDATA_OWNER}"
18
19 depend() {
20 use logger
@@ -24,7 +23,7 @@ depend() {
23 }
24
25 start_pre() {
27 - checkpath -o ${NETDATA_OWNER} -d @localstatedir_POST@/cache/netdata @localstatedir_POST@/run/netdata
26 + checkpath -o ${NETDATA_OWNER} -d @localstatedir_POST@/run/netdata
27
28 if [ -z "${supervisor}" ]; then
29 pidfile="${NETDATA_PIDFILE}"
system/runit/run.in
-4
@@ -3,14 +3,10 @@
3 piddir="@localstatedir_POST@/run/netdata/netdata.pid"
4 pidfile="${piddir}/netdata.pid"
5
6 -cachedir="@localstatedir_POST@/cache/netdata"
7 -
6 command="@sbindir_POST@/netdata"
7 command_args="-P ${pidfile} -D"
8
9 [ ! -d "${piddir}" ] && mkdir -p "${piddir}"
12 -[ ! -d "${cachedir}" ] && mkdir -p "${cachedir}"
10 chown -R @netdata_user_POST@ "${piddir}"
14 -chown -R @netdata_user_POST@ "${cachedir}"
11
12 exec ${command} ${command_args}
system/systemd/netdata.service.in
+1 -2
@@ -7,8 +7,7 @@ After=network.target httpd.service squid.service nfs-server.service mysqld.servi
7
8 [Service]
9 Type=simple
10 -User=@netdata_user_POST@
11 -Group=netdata
10 +User=root
11 RuntimeDirectory=netdata
12 RuntimeDirectoryMode=0775
13 PIDFile=/run/netdata/netdata.pid
system/systemd/netdata.service.v235.in
+1 -2
@@ -7,8 +7,7 @@ After=network.target httpd.service squid.service nfs-server.service mysqld.servi
7
8 [Service]
9 Type=simple
10 -User=@netdata_user_POST@
11 -Group=netdata
10 +User=root
11 RuntimeDirectory=netdata
12 CacheDirectory=netdata
13 StateDirectory=netdata