Subject: bug#20210: closed (Re: bug#20210: tests/df/skip-duplicates fails on Debian-kFreeBSD due to calling 'strstr(NULL, )')

From: [email-masked] (GNU bug Tracking System)
Date: Fri, 27 Mar 2015 09:27:03 +0000

Your bug report

#20210: tests/df/skip-duplicates fails on Debian-kFreeBSD due to calling 'strstr(NULL,)'

which was filed against the coreutils package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
20210: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=20210
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#20210: tests/df/skip-duplicates fails on Debian-kFreeBSD due to calling 'strstr(NULL, )'
From: Pádraig Brady <[email-masked]>
To: Assaf Gordon <[email-masked]>, [email-masked]
Date: Fri, 27 Mar 2015 09:26:00 +0000
List-Id: <debbugs-submit.debbugs.gnu.org>

On 27/03/15 00:28, Assaf Gordon wrote:
> Hello,
> 
> A somewhat exotic test failure:
> 
> On Debian/kFreeBSD 'tests/df/skip-duplicates' fails with 'df' segfaulting like so:
> 
>       ...
>       ./tests/df/skip-duplicates.sh: line 113:  7741 Segmentation fault      LD_PRELOAD=./k.so df
>       ...

> I'm not sure what is the correct,clean fix, attached are two options (one fixes the test, one avoids the call in lib/mountlist.c).

Nice one. I'll apply the test fix to coreutils.

thanks!
Pádraig.

Subject: tests/df/skip-duplicates fails on Debian-kFreeBSD due to calling 'strstr(NULL,)'
From: Assaf Gordon <[email-masked]>
To: [email-masked]
Date: Thu, 26 Mar 2015 20:28:40 -0400
List-Id: <debbugs-submit.debbugs.gnu.org>

Hello,

A somewhat exotic test failure:

On Debian/kFreeBSD 'tests/df/skip-duplicates' fails with 'df' segfaulting like so:

      ...
      ./tests/df/skip-duplicates.sh: line 113:  7741 Segmentation fault      LD_PRELOAD=./k.so df
      ...

The flow is:
1. the "k.so" file (inlined C code in 'tests/df/skip-duplicates.sh') returns 'struct mntent' in which '.mnt_opts' is NULL (not just empty string)
2. read_file_system_list() calls dev_from_mount_options(mnt->mnt_opts) .
3. in dev_from_mount_options()  "__linux__" is not defined (using FreeBSD kernel v9).
4. strstr() is called with 'mount_options==NULL'.
5. libc segfaults.

The direct culprit is 'dev_from_mount_options' in gnulib's mountlist.c, which has:

      static dev_t
      dev_from_mount_options (char const *mount_options)
      {
        /* GNU/Linux allows file system implementations to define their own
           meaning for "dev=" mount options, so don't trust the meaning
           here.  */
      # ifndef __linux__
        static char const dev_pattern[] = ",dev=";
        char const *devopt = strstr (mount_options, dev_pattern);
      ...

Using gdb, the stack-trace is:
      $ gdb ../src/df
      (gdb) set environment LD_PRELOAD=./k.so
      (gdb) start
      Program received signal SIGSEGV, Segmentation fault.
      0x0000000800abcc04 in strstr () from /lib/x86_64-kfreebsd-gnu/libc.so.0.1
      (gdb) bt
      #0  0x0000000800abcc04 in strstr () from /lib/x86_64-kfreebsd-gnu/libc.so.0.1
      #1  0x000000000040f7ed in dev_from_mount_options (mount_options=0x0) at lib/mountlist.c:363
      #2  0x000000000040fb6c in read_file_system_list (need_fs_type=false) at lib/mountlist.c:449
      #3  0x0000000000405751 in main (argc=1, argv=0x7fffffffd648) at src/df.c:1647

I'm not sure what is the correct,clean fix, attached are two options (one fixes the test, one avoids the call in lib/mountlist.c).

Regards,
   - assaf

P.S.
On FReeBSD-10.1 the test is skipped:
    skip-duplicates.sh: skipped test: $CC -shared ... failed to build a shared lib
    SKIP: tests/df/skip-duplicates.sh

--- tests/df/skip-duplicates.sh.bad	2014-07-13 18:09:52.000000000 -0400
+++ tests/df/skip-duplicates.sh	2015-03-26 20:24:22.000000000 -0400
@@ -56,13 +56,13 @@ struct mntent *getmntent (FILE *fp)
     }
 
   static struct mntent mntents[] = {
-    {.mnt_fsname="/short",  .mnt_dir="/invalid/mount/dir"},
-    {.mnt_fsname="fsname",  .mnt_dir="/",},
-    {.mnt_fsname="/fsname", .mnt_dir="/."},
-    {.mnt_fsname="/fsname", .mnt_dir="/"},
-    {.mnt_fsname="virtfs",  .mnt_dir="/NONROOT", .mnt_type="fstype1"},
-    {.mnt_fsname="virtfs2", .mnt_dir="/NONROOT", .mnt_type="fstype2"},
-    {.mnt_fsname="netns",   .mnt_dir="net:[1234567]"},
+    {.mnt_fsname="/short",  .mnt_dir="/invalid/mount/dir",            .mnt_opts=""},
+    {.mnt_fsname="fsname",  .mnt_dir="/",                             .mnt_opts=""},
+    {.mnt_fsname="/fsname", .mnt_dir="/.",                            .mnt_opts=""},
+    {.mnt_fsname="/fsname", .mnt_dir="/",                             .mnt_opts=""},
+    {.mnt_fsname="virtfs",  .mnt_dir="/NONROOT", .mnt_type="fstype1", .mnt_opts=""},
+    {.mnt_fsname="virtfs2", .mnt_dir="/NONROOT", .mnt_type="fstype2", .mnt_opts=""},
+    {.mnt_fsname="netns",   .mnt_dir="net:[1234567]",                 .mnt_opts=""},
   };
 
   if (done == 1)

--- lib/mountlist.c.bad	2015-03-26 20:30:05.000000000 -0400
+++ lib/mountlist.c	2015-03-26 20:36:54.000000000 -0400
@@ -360,7 +360,9 @@ dev_from_mount_options (char const *moun
 # ifndef __linux__
 
   static char const dev_pattern[] = ",dev=";
-  char const *devopt = strstr (mount_options, dev_pattern);
+  char const *devopt = (mount_options)?
+                       strstr (mount_options, dev_pattern):
+                       NULL;
 
   if (devopt)
     {