strip environment on cgroup-network; fixes #3269
Costa Tsaousis (ktsaou) committed
Jan 11, 2018 at 21:03 UTC
555fa18cd10f079dffb726b54f590c614ef16ad7
4 files changed
+138
-17
plugins.d/cgroup-network-helper.sh
+4
-2
@@ -22,7 +22,10 @@
22
23
# -----------------------------------------------------------------------------
24
25
-export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/sbin"
25
+# the system path is cleared by cgroup-network
26
+export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
27
+[ -x /etc/profile ] && source /etc/profile
28
+
29
export LC_ALL=C
30
31
PROGRAM_NAME="$(basename "${0}")"
@@ -72,7 +75,6 @@ debug() {
75
76
[ -z "${NETDATA_PLUGINS_DIR}" ] && NETDATA_PLUGINS_DIR="$(dirname "${0}")"
77
[ -z "${NETDATA_CONFIG_DIR}" ] && NETDATA_CONFIG_DIR="$(dirname "${0}")/../../../../etc/netdata"
75
-[ -z "${NETDATA_CACHE_DIR}" ] && NETDATA_CACHE_DIR="$(dirname "${0}")/../../../../var/cache/netdata"
78
79
# -----------------------------------------------------------------------------
80
# parse the arguments
src/cgroup-network.c
+97
-15
@@ -8,6 +8,20 @@
8
#include <sched.h>
9
#endif
10
11
+char *host_prefix = "";
12
+char *pluginsdir = "";
13
+char *configdir = "";
14
+
15
+char environment_variable1[FILENAME_MAX + 1] = "";
16
+char environment_variable2[FILENAME_MAX + 1] = "";
17
+char environment_variable3[FILENAME_MAX + 1] = "";
18
+char *environment[] = {
19
+ environment_variable1,
20
+ environment_variable2,
21
+ environment_variable3,
22
+ NULL
23
+};
24
+
25
// ----------------------------------------------------------------------------
26
// callback required by fatal()
27
@@ -18,6 +32,8 @@ void health_reload(void) {};
32
void rrdhost_save_all(void) {};
33
34
35
+// ----------------------------------------------------------------------------
36
+
37
struct iface {
38
const char *device;
39
uint32_t hash;
@@ -428,15 +444,7 @@ cleanup:
444
// call the external helper
445
446
#define CGROUP_NETWORK_INTERFACE_MAX_LINE 2048
431
-void call_the_helper(const char *me, pid_t pid, const char *cgroup) {
432
- const char *pluginsdir = getenv("NETDATA_PLUGINS_DIR");
433
- char *m = NULL;
434
-
435
- if(!pluginsdir || !*pluginsdir) {
436
- m = strdupz(me);
437
- pluginsdir = dirname(m);
438
- }
439
-
447
+void call_the_helper(pid_t pid, const char *cgroup) {
448
if(setresuid(0, 0, 0) == -1)
449
error("setresuid(0, 0, 0) failed.");
450
@@ -449,7 +457,7 @@ void call_the_helper(const char *me, pid_t pid, const char *cgroup) {
457
info("running: %s", buffer);
458
459
pid_t cgroup_pid;
452
- FILE *fp = mypopen(buffer, &cgroup_pid);
460
+ FILE *fp = mypopene(buffer, &cgroup_pid, environment);
461
if(fp) {
462
char *s;
463
while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) {
@@ -472,8 +480,36 @@ void call_the_helper(const char *me, pid_t pid, const char *cgroup) {
480
}
481
else
482
error("cannot execute cgroup-network helper script: %s", buffer);
483
+}
484
476
- freez(m);
485
+int verify_path(const char *path) {
486
+ struct stat sb;
487
+
488
+ char c;
489
+ const char *s = path;
490
+ while((c = *s++)) {
491
+ if(c == '$' || c == '`') {
492
+ error("invalid character in path '%s'", path);
493
+ return -1;
494
+ }
495
+ }
496
+
497
+ if(path[0] != '/') {
498
+ error("only absolute path names are supported - invalid path '%s'", path);
499
+ return -1;
500
+ }
501
+
502
+ if (stat(path, &sb) == -1) {
503
+ error("cannot stat() path '%s'", path);
504
+ return -1;
505
+ }
506
+
507
+ if((sb.st_mode & S_IFMT) != S_IFDIR) {
508
+ error("path '%s' is not a directory", path);
509
+ return -1;
510
+ }
511
+
512
+ return 0;
513
}
514
515
@@ -492,6 +528,47 @@ int main(int argc, char **argv) {
528
program_version = VERSION;
529
error_log_syslog = 0;
530
531
+
532
+ // ------------------------------------------------------------------------
533
+ // make sure NETDATA_HOST_PREFIX is safe
534
+
535
+ host_prefix = getenv("NETDATA_HOST_PREFIX");
536
+ if(!host_prefix || !*host_prefix)
537
+ host_prefix = "";
538
+
539
+ if(host_prefix[0] != '\0' && verify_path(host_prefix) == -1)
540
+ fatal("cannot find path NETDATA_HOST_PREFIX '%s'", host_prefix);
541
+
542
+ // ------------------------------------------------------------------------
543
+ // make sure NETDATA_CONFIG_DIR is safe
544
+
545
+ configdir = getenv("NETDATA_CONFIG_DIR");
546
+ if(!configdir || !*configdir) {
547
+ configdir = "";
548
+ }
549
+ else if(verify_path(configdir) == -1)
550
+ fatal("cannot find path NETDATA_CONFIG_DIR '%s'", configdir);
551
+
552
+ // ------------------------------------------------------------------------
553
+ // make sure NETDATA_PLUGINS_DIR is safe
554
+
555
+ pluginsdir = getenv("NETDATA_PLUGINS_DIR");
556
+ if(!pluginsdir || !*pluginsdir) {
557
+ char *me = strdupz(argv[0]);
558
+ pluginsdir = dirname(me);
559
+ }
560
+ else if(verify_path(pluginsdir) == -1)
561
+ fatal("cannot find path NETDATA_PLUGINS_DIR '%s'", pluginsdir);
562
+
563
+ // ------------------------------------------------------------------------
564
+ // build a safe environment for our script
565
+
566
+ snprintfz(environment_variable1, FILENAME_MAX, "NETDATA_HOST_PREFIX=%s", host_prefix);
567
+ snprintfz(environment_variable2, FILENAME_MAX, "NETDATA_PLUGINS_DIR=%s", pluginsdir);
568
+ snprintfz(environment_variable3, FILENAME_MAX, "NETDATA_CONFIG_DIR=%s", configdir);
569
+
570
+ // ------------------------------------------------------------------------
571
+
572
if(argc == 2 && (!strcmp(argv[1], "version") || !strcmp(argv[1], "-version") || !strcmp(argv[1], "--version") || !strcmp(argv[1], "-v") || !strcmp(argv[1], "-V"))) {
573
fprintf(stderr, "cgroup-network %s\n", VERSION);
574
exit(0);
@@ -509,15 +586,20 @@ int main(int argc, char **argv) {
586
return 2;
587
}
588
512
- call_the_helper(argv[0], pid, NULL);
589
+ call_the_helper(pid, NULL);
590
}
591
else if(!strcmp(argv[1], "--cgroup")) {
515
- pid = read_pid_from_cgroup(argv[2]);
516
- call_the_helper(argv[0], pid, argv[2]);
592
+ char pathname[FILENAME_MAX + 1];
593
+ snprintfz(pathname, FILENAME_MAX, "%s%s", host_prefix, argv[2]);
594
+ if(verify_path(pathname) == -1)
595
+ fatal("cgroup '%s' does not exist.", pathname);
596
+
597
+ pid = read_pid_from_cgroup(pathname);
598
+ call_the_helper(pid, pathname);
599
600
if(pid <= 0 && !detected_devices) {
601
errno = 0;
520
- error("Cannot find a cgroup PID from cgroup '%s'", argv[2]);
602
+ error("Cannot find a cgroup PID from cgroup '%s'", pathname);
603
}
604
}
605
else
src/popen.c
+36
@@ -113,6 +113,42 @@ FILE *mypopen(const char *command, volatile pid_t *pidptr)
113
exit(1);
114
}
115
116
+FILE *mypopene(const char *command, volatile pid_t *pidptr, char **env) {
117
+ int pipefd[2];
118
+
119
+ if(pipe(pipefd) == -1)
120
+ return NULL;
121
+
122
+ int pid = fork();
123
+ if(pid == -1) {
124
+ close(pipefd[PIPE_READ]);
125
+ close(pipefd[PIPE_WRITE]);
126
+ return NULL;
127
+ }
128
+ if(pid != 0) {
129
+ // the parent
130
+ *pidptr = pid;
131
+ close(pipefd[PIPE_WRITE]);
132
+ FILE *fp = fdopen(pipefd[PIPE_READ], "r");
133
+ return(fp);
134
+ }
135
+ // the child
136
+
137
+ // close all files
138
+ int i;
139
+ for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i > 0; i--)
140
+ if(i != STDIN_FILENO && i != STDERR_FILENO && i != pipefd[PIPE_WRITE]) close(i);
141
+
142
+ // move the pipe to stdout
143
+ if(pipefd[PIPE_WRITE] != STDOUT_FILENO) {
144
+ dup2(pipefd[PIPE_WRITE], STDOUT_FILENO);
145
+ close(pipefd[PIPE_WRITE]);
146
+ }
147
+
148
+ execle("/bin/sh", "sh", "-c", command, NULL, env);
149
+ exit(1);
150
+}
151
+
152
int mypclose(FILE *fp, pid_t pid) {
153
debug(D_EXIT, "Request to mypclose() on pid %d", pid);
154
src/popen.h
+1
@@ -5,6 +5,7 @@
5
#define PIPE_WRITE 1
6
7
extern FILE *mypopen(const char *command, volatile pid_t *pidptr);
8
+extern FILE *mypopene(const char *command, volatile pid_t *pidptr, char **env);
9
extern int mypclose(FILE *fp, pid_t pid);
10
11
#endif /* NETDATA_POPEN_H */