]> granicus.if.org Git - sysstat/commitdiff
Fix #162: sadc crashes on a mtab file with really long lines
authorSebastien GODARD <sysstat@users.noreply.github.com>
Sat, 26 Aug 2017 12:42:28 +0000 (14:42 +0200)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Sat, 26 Aug 2017 12:55:04 +0000 (14:55 +0200)
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>
count.c
rd_stats.c

diff --git a/count.c b/count.c
index 176a4d3b00269cdffbc3fc3db749a07dd2f20eec..c0a1d8fa749735670e537684e7451712738fd87d 100644 (file)
--- a/count.c
+++ b/count.c
@@ -463,7 +463,8 @@ 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)
@@ -472,11 +473,25 @@ int get_filesystem_nr(void)
 
        /* Get current filesystem */
        while (fgets(line, sizeof(line), 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);
index 542a0e1840fa18c4cfc753f4d9deddd2393f4be1..0788b5539e62176fb8a38d9670fd4d8fdb0435e8 100644 (file)
@@ -2097,7 +2097,8 @@ 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;
 
@@ -2105,7 +2106,21 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr)
                return;
 
        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);
@@ -2118,7 +2133,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);