summaryrefslogtreecommitdiffstats
path: root/collectors/cgroups.plugin/cgroup-network.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--collectors/cgroups.plugin/cgroup-network.c (renamed from src/cgroup-network.c)97
1 files changed, 64 insertions, 33 deletions
diff --git a/src/cgroup-network.c b/collectors/cgroups.plugin/cgroup-network.c
index 0e2d5163a..0cf2a2633 100644
--- a/src/cgroup-network.c
+++ b/collectors/cgroups.plugin/cgroup-network.c
@@ -1,5 +1,6 @@
-#include "common.h"
-#include <libgen.h>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "libnetdata/libnetdata.h"
#ifdef HAVE_SETNS
#ifndef _GNU_SOURCE
@@ -8,8 +9,6 @@
#include <sched.h>
#endif
-char *host_prefix = "";
-
char environment_variable2[FILENAME_MAX + 50] = "";
char *environment[] = {
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin",
@@ -19,14 +18,28 @@ char *environment[] = {
// ----------------------------------------------------------------------------
-// callback required by fatal()
+// callback required by fatal()
void netdata_cleanup_and_exit(int ret) {
exit(ret);
}
-void health_reload(void) {};
-void rrdhost_save_all(void) {};
+// callbacks required by popen()
+void signals_block(void) {};
+void signals_unblock(void) {};
+void signals_reset(void) {};
+
+// callback required by eval()
+int health_variable_lookup(const char *variable, uint32_t hash, struct rrdcalc *rc, calculated_number *result) {
+ (void)variable;
+ (void)hash;
+ (void)rc;
+ (void)result;
+ return 0;
+};
+
+// required by get_system_cpus()
+char *netdata_configured_host_prefix = "";
// ----------------------------------------------------------------------------
@@ -41,8 +54,10 @@ struct iface {
};
unsigned int read_iface_iflink(const char *prefix, const char *iface) {
+ if(!prefix) prefix = "";
+
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/iflink", prefix?prefix:"", iface);
+ snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/iflink", prefix, iface);
unsigned long long iflink = 0;
int ret = read_single_number_file(filename, &iflink);
@@ -52,8 +67,10 @@ unsigned int read_iface_iflink(const char *prefix, const char *iface) {
}
unsigned int read_iface_ifindex(const char *prefix, const char *iface) {
+ if(!prefix) prefix = "";
+
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/ifindex", prefix?prefix:"", iface);
+ snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/ifindex", prefix, iface);
unsigned long long ifindex = 0;
int ret = read_single_number_file(filename, &ifindex);
@@ -63,10 +80,12 @@ unsigned int read_iface_ifindex(const char *prefix, const char *iface) {
}
struct iface *read_proc_net_dev(const char *prefix) {
+ if(!prefix) prefix = "";
+
procfile *ff = NULL;
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s%s", prefix?prefix:"", "/proc/net/dev");
+ snprintfz(filename, FILENAME_MAX, "%s%s", prefix, (*prefix)?"/proc/1/net/dev":"/proc/net/dev");
ff = procfile_open(filename, " \t,:|", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) {
error("Cannot open file '%s'", filename);
@@ -163,12 +182,14 @@ static void continue_as_child(void) {
}
int proc_pid_fd(const char *prefix, const char *ns, pid_t pid) {
+ if(!prefix) prefix = "";
+
char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/%d/%s", prefix?prefix:"", (int)pid, ns);
+ snprintfz(filename, FILENAME_MAX, "%s/proc/%d/%s", prefix, (int)pid, ns);
int fd = open(filename, O_RDONLY);
if(fd == -1)
- error("Cannot open file '%s'", filename);
+ error("Cannot open proc_pid_fd() file '%s'", filename);
return fd;
}
@@ -193,6 +214,8 @@ static struct ns {
};
int switch_namespace(const char *prefix, pid_t pid) {
+ if(!prefix) prefix = "";
+
#ifdef HAVE_SETNS
int i;
@@ -207,8 +230,8 @@ int switch_namespace(const char *prefix, pid_t pid) {
// 2 passes - found it at nsenter source code
// this is related CLONE_NEWUSER functionality
- // FIXME: this code cannot switch user namespace
- // Fortunately, we don't need it.
+ // This code cannot switch user namespace (it can all the other namespaces)
+ // Fortunately, we don't need to switch user namespaces.
int pass, errors = 0;
for(pass = 0; pass < 2 ;pass++) {
@@ -272,9 +295,15 @@ int switch_namespace(const char *prefix, pid_t pid) {
}
pid_t read_pid_from_cgroup_file(const char *filename) {
- FILE *fp = fopen(filename, "r");
+ int fd = open(filename, procfile_open_flags);
+ if(fd == -1) {
+ error("Cannot open pid_from_cgroup() file '%s'.", filename);
+ return 0;
+ }
+
+ FILE *fp = fdopen(fd, "r");
if(!fp) {
- error("Cannot read file '%s'.", filename);
+ error("Cannot upgrade fd to fp for file '%s'.", filename);
return 0;
}
@@ -387,14 +416,13 @@ int send_devices(void) {
// since it switches namespaces, so after this call, everything is different!
void detect_veth_interfaces(pid_t pid) {
- struct iface *host, *cgroup, *h, *c;
- const char *prefix = getenv("NETDATA_HOST_PREFIX");
+ struct iface *host = NULL, *cgroup = NULL, *h, *c;
- host = read_proc_net_dev(prefix);
+ host = read_proc_net_dev(netdata_configured_host_prefix);
if(!host) {
errno = 0;
error("cannot read host interface list.");
- return;
+ goto cleanup;
}
if(!eligible_ifaces(host)) {
@@ -403,7 +431,7 @@ void detect_veth_interfaces(pid_t pid) {
goto cleanup;
}
- if(switch_namespace(prefix, pid)) {
+ if(switch_namespace(netdata_configured_host_prefix, pid)) {
errno = 0;
error("cannot switch to the namespace of pid %u", (unsigned int) pid);
goto cleanup;
@@ -433,6 +461,7 @@ void detect_veth_interfaces(pid_t pid) {
}
cleanup:
+ free_host_ifaces(cgroup);
free_host_ifaces(host);
}
@@ -444,17 +473,18 @@ void call_the_helper(pid_t pid, const char *cgroup) {
if(setresuid(0, 0, 0) == -1)
error("setresuid(0, 0, 0) failed.");
- char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
+ char command[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
if(cgroup)
- snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --cgroup '%s'", cgroup);
+ snprintfz(command, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --cgroup '%s'", cgroup);
else
- snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --pid %d", pid);
+ snprintfz(command, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec " PLUGINS_DIR "/cgroup-network-helper.sh --pid %d", pid);
- info("running: %s", buffer);
+ info("running: %s", command);
pid_t cgroup_pid;
- FILE *fp = mypopene(buffer, &cgroup_pid, environment);
+ FILE *fp = mypopene(command, &cgroup_pid, environment);
if(fp) {
+ char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
char *s;
while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) {
trim(s);
@@ -475,7 +505,7 @@ void call_the_helper(pid_t pid, const char *cgroup) {
mypclose(fp, cgroup_pid);
}
else
- error("cannot execute cgroup-network helper script: %s", buffer);
+ error("cannot execute cgroup-network helper script: %s", command);
}
int is_valid_path_symbol(char c) {
@@ -588,22 +618,23 @@ int main(int argc, char **argv) {
program_version = VERSION;
error_log_syslog = 0;
+ // since cgroup-network runs as root, prevent it from opening symbolic links
+ procfile_open_flags = O_RDONLY|O_NOFOLLOW;
// ------------------------------------------------------------------------
// make sure NETDATA_HOST_PREFIX is safe
- host_prefix = getenv("NETDATA_HOST_PREFIX");
- if(!host_prefix || !*host_prefix)
- host_prefix = "";
+ netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
+ if(verify_netdata_host_prefix() == -1) exit(1);
- if(host_prefix[0] != '\0' && verify_path(host_prefix) == -1)
- fatal("invalid NETDATA_HOST_PREFIX '%s'", host_prefix);
+ if(netdata_configured_host_prefix[0] != '\0' && verify_path(netdata_configured_host_prefix) == -1)
+ fatal("invalid NETDATA_HOST_PREFIX '%s'", netdata_configured_host_prefix);
// ------------------------------------------------------------------------
// build a safe environment for our script
// the first environment variable is a fixed PATH=
- snprintfz(environment_variable2, sizeof(environment_variable2) - 1, "NETDATA_HOST_PREFIX=%s", host_prefix);
+ snprintfz(environment_variable2, sizeof(environment_variable2) - 1, "NETDATA_HOST_PREFIX=%s", netdata_configured_host_prefix);
// ------------------------------------------------------------------------