more security fixes by Synacktiv
Costa Tsaousis (ktsaou) committed
Apr 18, 2018 at 23:10 UTC
d17f6869ee8542c54d4c2280203676fb7b229001
7 files changed
+85
-28
src/apps_plugin.c
+9
-17
@@ -856,7 +856,7 @@ static inline int read_proc_pid_cmdline(struct pid_stat *p) {
856
p->cmdline_filename = strdupz(filename);
857
}
858
859
- int fd = open(p->cmdline_filename, O_RDONLY, 0666);
859
+ int fd = open(p->cmdline_filename, procfile_open_flags, 0666);
860
if(unlikely(fd == -1)) goto cleanup;
861
862
ssize_t i, bytes = read(fd, cmdline, MAX_CMDLINE);
@@ -3314,7 +3314,6 @@ cleanup:
3314
static void parse_args(int argc, char **argv)
3315
{
3316
int i, freq = 0;
3317
- char *name = NULL;
3317
3318
for(i = 1; i < argc; i++) {
3319
if(!freq) {
@@ -3428,20 +3427,14 @@ static void parse_args(int argc, char **argv)
3427
exit(1);
3428
}
3429
3431
- if(!name) {
3432
- name = argv[i];
3433
- continue;
3434
- }
3435
-
3430
error("Cannot understand option %s", argv[i]);
3431
exit(1);
3432
}
3433
3434
if(freq > 0) update_every = freq;
3441
- if(!name || !*name) name = "groups";
3435
3443
- if(read_apps_groups_conf(name)) {
3444
- error("Cannot read process groups '%s/apps_%s.conf'. There are no internal defaults. Failing.", config_dir, name);
3436
+ if(read_apps_groups_conf("groups")) {
3437
+ error("Cannot read process groups '%s/apps_groups.conf'. There are no internal defaults. Failing.", config_dir);
3438
exit(1);
3439
}
3440
}
@@ -3523,12 +3516,11 @@ int main(int argc, char **argv) {
3516
error_log_errors_per_period = 100;
3517
error_log_throttle_period = 3600;
3518
3519
+ // since apps.plugin runs as root, prevent it from opening symbolic links
3520
+ procfile_open_flags = O_RDONLY|O_NOFOLLOW;
3521
+
3522
netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
3527
- if(netdata_configured_host_prefix == NULL) {
3528
- // info("NETDATA_HOST_PREFIX is not passed from netdata");
3529
- netdata_configured_host_prefix = "";
3530
- }
3531
- // else info("Found NETDATA_HOST_PREFIX='%s'", netdata_configured_host_prefix);
3523
+ if(verify_netdata_host_prefix() == -1) exit(1);
3524
3525
config_dir = getenv("NETDATA_CONFIG_DIR");
3526
if(config_dir == NULL) {
@@ -3563,14 +3555,14 @@ int main(int argc, char **argv) {
3555
error("apps.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
3556
"Without these, apps.plugin cannot report disk I/O utilization of other processes. "
3557
"To enable capabilities run: sudo setcap cap_dac_read_search,cap_sys_ptrace+ep %s; "
3566
- "To enable setuid to root run: sudo chown root %s; sudo chmod 4755 %s; "
3558
+ "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; "
3559
, uid, euid, argv[0], argv[0], argv[0]
3560
);
3561
#else
3562
error("apps.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
3563
"Without these, apps.plugin cannot report disk I/O utilization of other processes. "
3564
"Your system does not support capabilities. "
3573
- "To enable setuid to root run: sudo chown root %s; sudo chmod 4755 %s; "
3565
+ "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; "
3566
, uid, euid, argv[0], argv[0]
3567
);
3568
#endif
src/cgroup-network.c
+5
-8
@@ -8,8 +8,6 @@
8
#include <sched.h>
9
#endif
10
11
-char *host_prefix = "";
12
-
11
char environment_variable2[FILENAME_MAX + 50] = "";
12
char *environment[] = {
13
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin",
@@ -592,18 +590,17 @@ int main(int argc, char **argv) {
590
// ------------------------------------------------------------------------
591
// make sure NETDATA_HOST_PREFIX is safe
592
595
- host_prefix = getenv("NETDATA_HOST_PREFIX");
596
- if(!host_prefix || !*host_prefix)
597
- host_prefix = "";
593
+ netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
594
+ if(verify_netdata_host_prefix() == -1) exit(1);
595
599
- if(host_prefix[0] != '\0' && verify_path(host_prefix) == -1)
600
- fatal("invalid NETDATA_HOST_PREFIX '%s'", host_prefix);
596
+ if(netdata_configured_host_prefix[0] != '\0' && verify_path(netdata_configured_host_prefix) == -1)
597
+ fatal("invalid NETDATA_HOST_PREFIX '%s'", netdata_configured_host_prefix);
598
599
// ------------------------------------------------------------------------
600
// build a safe environment for our script
601
602
// the first environment variable is a fixed PATH=
606
- snprintfz(environment_variable2, sizeof(environment_variable2) - 1, "NETDATA_HOST_PREFIX=%s", host_prefix);
603
+ snprintfz(environment_variable2, sizeof(environment_variable2) - 1, "NETDATA_HOST_PREFIX=%s", netdata_configured_host_prefix);
604
605
// ------------------------------------------------------------------------
606
src/common.c
+61
@@ -1359,3 +1359,64 @@ int recursively_delete_dir(const char *path, const char *reason) {
1359
1360
return ret;
1361
}
1362
+
1363
+static int is_virtual_filesystem(const char *path, char **reason) {
1364
+ struct statfs stat;
1365
+ // stat.f_fsid.__val[0] is a file system id
1366
+ // stat.f_fsid.__val[1] is the inode
1367
+ // so their combination uniquely identifies the file/dir
1368
+
1369
+ if (statfs(path, &stat) == -1) {
1370
+ if(reason) *reason = "failed to statfs()";
1371
+ return -1;
1372
+ }
1373
+
1374
+ if(stat.f_fsid.__val[0] != 0 || stat.f_fsid.__val[1] != 0) {
1375
+ errno = EINVAL;
1376
+ if(reason) *reason = "is not a virtual file system";
1377
+ return -1;
1378
+ }
1379
+
1380
+ return 0;
1381
+}
1382
+
1383
+int verify_netdata_host_prefix() {
1384
+ if(!netdata_configured_host_prefix)
1385
+ netdata_configured_host_prefix = "";
1386
+
1387
+ if(!*netdata_configured_host_prefix)
1388
+ return 0;
1389
+
1390
+ char buffer[FILENAME_MAX + 1];
1391
+ char *path = netdata_configured_host_prefix;
1392
+ char *reason = "unknown reason";
1393
+ errno = 0;
1394
+
1395
+ struct stat sb;
1396
+ if (stat(path, &sb) == -1) {
1397
+ reason = "failed to stat()";
1398
+ goto failed;
1399
+ }
1400
+
1401
+ if((sb.st_mode & S_IFMT) != S_IFDIR) {
1402
+ errno = EINVAL;
1403
+ reason = "is not a directory";
1404
+ goto failed;
1405
+ }
1406
+
1407
+ path = buffer;
1408
+ snprintfz(path, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix);
1409
+ if(is_virtual_filesystem(path, &reason) == -1)
1410
+ goto failed;
1411
+
1412
+ snprintfz(path, FILENAME_MAX, "%s/sys", netdata_configured_host_prefix);
1413
+ if(is_virtual_filesystem(path, &reason) == -1)
1414
+ goto failed;
1415
+
1416
+ return 0;
1417
+
1418
+failed:
1419
+ error("Ignoring host prefix '%s': path '%s' %s", netdata_configured_host_prefix, path, reason);
1420
+ netdata_configured_host_prefix = "";
1421
+ return -1;
1422
+}
src/common.h
+2
-1
@@ -5,7 +5,6 @@
5
#include <config.h>
6
#endif
7
8
-
8
// ----------------------------------------------------------------------------
9
// system include files for all netdata C programs
10
@@ -76,6 +75,7 @@
75
#include <sys/resource.h>
76
#include <sys/socket.h>
77
#include <sys/stat.h>
78
+#include <sys/vfs.h>
79
#include <sys/statvfs.h>
80
#include <sys/syscall.h>
81
#include <sys/time.h>
@@ -333,6 +333,7 @@ extern char *fgets_trim_len(char *buf, size_t buf_size, FILE *fp, size_t *len);
333
334
extern int processors;
335
extern long get_system_cpus(void);
336
+extern int verify_netdata_host_prefix();
337
338
extern pid_t pid_max;
339
extern pid_t get_system_pid_max(void);
src/main.c
+1
@@ -480,6 +480,7 @@ static void get_netdata_configured_variables() {
480
// ------------------------------------------------------------------------
481
482
netdata_configured_host_prefix = config_get(CONFIG_SECTION_GLOBAL, "host access prefix", "");
483
+ verify_netdata_host_prefix();
484
485
// --------------------------------------------------------------------
486
// get KSM settings
src/procfile.c
+4
-2
@@ -7,6 +7,8 @@
7
#define PFLINES_INCREASE_STEP 10
8
#define PROCFILE_INCREMENT_BUFFER 512
9
10
+int procfile_open_flags = O_RDONLY;
11
+
12
int procfile_adaptive_initial_allocation = 0;
13
14
// if adaptive allocation is set, these store the
@@ -391,7 +393,7 @@ void procfile_set_open_close(procfile *ff, const char *open, const char *close)
393
procfile *procfile_open(const char *filename, const char *separators, uint32_t flags) {
394
debug(D_PROCFILE, PF_PREFIX ": Opening file '%s'", filename);
395
394
- int fd = open(filename, O_RDONLY, 0666);
396
+ int fd = open(filename, procfile_open_flags, 0666);
397
if(unlikely(fd == -1)) {
398
if(unlikely(!(flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot open file '%s'", filename);
399
return NULL;
@@ -427,7 +429,7 @@ procfile *procfile_reopen(procfile *ff, const char *filename, const char *separa
429
close(ff->fd);
430
}
431
430
- ff->fd = open(filename, O_RDONLY, 0666);
432
+ ff->fd = open(filename, procfile_open_flags, 0666);
433
if(unlikely(ff->fd == -1)) {
434
procfile_close(ff);
435
return NULL;
src/procfile.h
+3
@@ -103,6 +103,9 @@ extern char *procfile_filename(procfile *ff);
103
104
// ----------------------------------------------------------------------------
105
106
+// set to the O_XXXX flags, to have procfile_open and procfile_reopen use them when opening proc files
107
+extern int procfile_open_flags;
108
+
109
// set this to 1, to have procfile adapt its initial buffer allocation to the max allocation used so far
110
extern int procfile_adaptive_initial_allocation;
111