Blob Blame History Raw
From 01efeb144322c61e53cc4e21783ce0a69ec28922 Mon Sep 17 00:00:00 2001
From: Sebastien GODARD <sysstat@users.noreply.github.com>
Date: Sat, 26 Aug 2017 14:42:28 +0200
Subject: [PATCH] Fix #162: sadc crashes on a mtab file with really long lines

A segmentation fault may happen with "sadc -S DISK..." or
"sadc -S XDISK..." when lines longer than 512 bytes are read from
/etc/mtab.

Such lines are possible for instance when overlay2 filesystem
with docker is used. In such a case a single mtab entry can look
like this (note that new line characters were added for readability,
the original entry contained only one '\n' at the end):

overlay /var/lib/docker/overlay2/f23d2377a67b9ab1b49555ecd09b2ccdc03
7e0ee5d9e54f87e59f07f4398e71f/merged overlay rw,relatime,lowerdir=/v
ar/lib/docker/overlay2/l/L6VKIYXWBQSJ5R7V35SS43R6Y6:/var/lib/docker/
overlay2/l/UCCHKGXUJPWCMLHR36IZJNNIQP:/var/lib/docker/overlay2/l/RKV
YEXD2FH65FTMK76RDWPLESX:/var/lib/docker/overlay2/l/DX4JZRKTFP2GOO4V6
OWQ6CPJFY:/var/lib/docker/overlay2/l/6CYNWDKADUPPDZJ5IHOH2R7Y5S:/var
/lib/docker/overlay2/l/JTPINUZIATXADL6XWFHG2OYGSF:/var/lib/docker/ov
erlay2/l/OTSTIV5TTRHF4IUD7BODQ2FUON:/var/lib/docker/overlay2/l/QFNH3
EFS5EZGRTC4DPHU3PJ4TU:/var/lib/docker/overlay2/l/ZOOUKT2E5U4CSLP57Z7
MXYX5CD:/var/lib/docker/overlay2/l/3LUU6IDR2HWPTVBARC5K6XSMRC:/var/l
ib/docker/overlay2/l/XOHYBP4RWXQKQZ43I7JKG24KE4:/var/lib/docker/over
lay2/l/MN5M5B7AY5LPXQQC6V2MBJWWBF:/var/lib/docker/overlay2/l/3DRMKQ3
4AIZD2AROU3TVK3OCUT:/var/lib/docker/overlay2/l/73ZXDHBV6C53Q3SPXA57E
OLGHU:/var/lib/docker/overlay2/l/C2IZBQ55EUTGEAAORSLE73ZPNM:/var/lib
/docker/overlay2/l/ITHARNV7RPWN5S3BCZ2QDMZIMJ:/var/lib/docker/overla
y2/l/TQKUV4LEG4AFUUCMFHHRLDBHAH:/var/lib/docker/overlay2/l/N75JZWPPD
EKJ4DTN4GMEGTDIZL:/var/lib/docker/overlay2/l/QGUUYAETPMK643DG3AKWJAI
IZA,upperdir=/var/lib/docker/overlay2/f23d2377a67b9ab1b49555ecd09b2c
cdc037e0ee5d9e54f87e59f07f4398e71f/diff,workdir=/var/lib/docker/over
lay2/f23d2377a67b9ab1b49555ecd09b2ccdc037e0ee5d9e54f87e59f07f4398e71
f/work 0 0

The crash occurs in the get_filesystem_nr() and read_filesystem()
functions which call strchr(line, ' ') but fail to check if the result
is not NULL.

This patch adds this check, and when a single mtab entry requires more
that one call to fgets() (i.e. the entry is longer than 512 bytes), it
ignores outcome of the second and following calls.

Bugs-Debian: https://bugs.debian.org/872926
Signed-off-by: Robert Luberda <robert@debian.org>
Signed-off-by: Sebastien GODARD <sysstat@users.noreply.github.com>
(cherry picked from commit d40c8ecc530303d7e802617f21a9ac85dbcd68bd)
---
 rd_stats.c | 41 ++++++++++++++++++++++++++++++++++++-----
 1 file changed, 36 insertions(+), 5 deletions(-)

diff --git a/rd_stats.c b/rd_stats.c
index 01276b6..c054b58 100644
--- a/rd_stats.c
+++ b/rd_stats.c
@@ -1916,15 +1916,30 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr)
 {
 	FILE *fp;
 	char line[512], fs_name[128], mountp[256];
-	int fs = 0;
+	int fs = 0, skip = 0, skip_next = 0;
+	char *pos = 0;
 	struct stats_filesystem *st_filesystem_i;
 	struct statvfs buf;
 
 	if ((fp = fopen(MTAB, "r")) == NULL)
 		return;
 
-	while ((fgets(line, 256, fp) != NULL) && (fs < nbr)) {
+	while ((fgets(line, sizeof(line), fp) != NULL) && (fs < nbr)) {
+		/*
+		 * Ignore line if the preceding line did not contain '\n'.
+		 * (Some very long lines may be found for instance when
+		 * overlay2 filesystem with docker is used).
+		 */
+		skip = skip_next;
+		skip_next = (strchr(line, '\n') == NULL);
+		if (skip)
+			continue;
+
 		if (line[0] == '/') {
+			/* Find field separator position */
+			pos = strchr(line, ' ');
+			if (pos == NULL)
+				continue;
 
 			/* Read current filesystem name */
 			sscanf(line, "%127s", fs_name);
@@ -1937,7 +1952,7 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr)
 			 * from the fs name. This will result in a bogus name
 			 * and following statvfs() function will always fail.
 			 */
-			sscanf(strchr(line, ' ') + 1, "%255s", mountp);
+			sscanf(pos + 1, "%255s", mountp);
 
 			/* Replace octal codes */
 			oct2chr(mountp);
@@ -2397,7 +2412,9 @@ int get_filesystem_nr(void)
 {
 	FILE *fp;
 	char line[512], fs_name[MAX_FS_LEN], mountp[256];
-	int fs = 0;
+        int fs = 0, skip = 0, skip_next = 0;
+        char *pos = 0;
+
 	struct statvfs buf;
 
 	if ((fp = fopen(MTAB, "r")) == NULL)
@@ -2406,11 +2423,25 @@ int get_filesystem_nr(void)
 
 	/* Get current filesystem */
 	while (fgets(line, 256, fp) != NULL) {
+                /*
+		 * Ignore line if the preceding line did not contain '\n'.
+		 * (Some very long lines may be found for instance when
+		 * overlay2 filesystem with docker is used).
+		 */
+		skip = skip_next;
+		skip_next = (strchr(line, '\n') == NULL);
+		if (skip)
+			continue;
+
 		if (line[0] == '/') {
+			/* Find field separator position */
+			pos = strchr(line, ' ');
+			if (pos == NULL)
+				continue;
 			
 			/* Read filesystem name and mount point */
                        sscanf(line, "%127s", fs_name);
-                       sscanf(strchr(line, ' ') + 1, "%255s", mountp);
+                       sscanf(pos + 1, "%255s", mountp);
 
                         /* Replace octal codes */
 			oct2chr(mountp);
-- 
2.14.3