elf: Add tst-ldconfig-bad-aux-cache test [BZ #18093]

Message ID 20190415181821.17616-1-ahajkova@redhat.com
State Superseded
Headers

Commit Message

Alexandra Hájková April 15, 2019, 6:18 p.m. UTC
  From: Alexandra Hájková <ahajkova@redhat.com>

      This test corrupts /var/cache/ldconfig/aux-cache and executes ldconfig
      to check it will not segfault using the corrupted aux_cache. The test
      uses the test-in-container framework. Verified no regressions on
      x86_64.

ChangeLog:
2019-04-15  Alexandra Hajkova  <ahajkova@redhat.com>

	* elf/Makefile (test-container): Add tst-ldconfig-bad-aux-cache.
	* elf/tst-ldconfig-bad-aux-cache.c: New file.
	* elf/tst-ldconfig_aux-cache.root: New directory.
	* elf/tst-ldconfig_aux-cache.root/var: Likewise.
	* elf/tst-ldconfig_aux-cache.root/var/cache: Likewise.
	* elf/tst-ldconfig_aux-cache.root/var/cache/.gitignore: New file.

---
 elf/Makefile                                  |   3 +
 elf/tst-ldconfig-bad-aux-cache.c              | 123 ++++++++++++++++++
 .../var/cache/.gitignore                      |   0
 3 files changed, 126 insertions(+)
 create mode 100644 elf/tst-ldconfig-bad-aux-cache.c
 create mode 100644 elf/tst-ldconfig-bad-aux-cache.root/var/cache/.gitignore

diff --git a/elf/tst-ldconfig-bad-aux-cache.root/var/cache/.gitignore b/elf/tst-ldconfig-bad-aux-cache.root/var/cache/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
  

Comments

Alexandra Hájková April 23, 2019, 10:43 a.m. UTC | #1
PING

On Mon, Apr 15, 2019 at 8:18 PM Alexandra Hájková
<alexandra.khirnova@gmail.com> wrote:
>
> From: Alexandra Hájková <ahajkova@redhat.com>
>
>       This test corrupts /var/cache/ldconfig/aux-cache and executes ldconfig
>       to check it will not segfault using the corrupted aux_cache. The test
>       uses the test-in-container framework. Verified no regressions on
>       x86_64.
>
> ChangeLog:
> 2019-04-15  Alexandra Hajkova  <ahajkova@redhat.com>
>
>         * elf/Makefile (test-container): Add tst-ldconfig-bad-aux-cache.
>         * elf/tst-ldconfig-bad-aux-cache.c: New file.
>         * elf/tst-ldconfig_aux-cache.root: New directory.
>         * elf/tst-ldconfig_aux-cache.root/var: Likewise.
>         * elf/tst-ldconfig_aux-cache.root/var/cache: Likewise.
>         * elf/tst-ldconfig_aux-cache.root/var/cache/.gitignore: New file.
>
> ---
>  elf/Makefile                                  |   3 +
>  elf/tst-ldconfig-bad-aux-cache.c              | 123 ++++++++++++++++++
>  .../var/cache/.gitignore                      |   0
>  3 files changed, 126 insertions(+)
>  create mode 100644 elf/tst-ldconfig-bad-aux-cache.c
>  create mode 100644 elf/tst-ldconfig-bad-aux-cache.root/var/cache/.gitignore
>
> diff --git a/elf/Makefile b/elf/Makefile
> index 310a37cc13..35052b2768 100644
> --- a/elf/Makefile
> +++ b/elf/Makefile
> @@ -155,6 +155,9 @@ tests-static-internal := tst-tls1-static tst-tls2-static \
>  CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o
>  tst-tls1-static-non-pie-no-pie = yes
>
> +tests-container = \
> +                         tst-ldconfig-bad-aux-cache
> +
>  tests := tst-tls9 tst-leaks1 \
>         tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \
>         tst-auxv
> diff --git a/elf/tst-ldconfig-bad-aux-cache.c b/elf/tst-ldconfig-bad-aux-cache.c
> new file mode 100644
> index 0000000000..d7e591b9ca
> --- /dev/null
> +++ b/elf/tst-ldconfig-bad-aux-cache.c
> @@ -0,0 +1,123 @@
> +/* Test ldconfig does not segfault when aux-cache is corrupted (Bug 18093).
> +   Copyright (C) 2019 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public License as
> +   published by the Free Software Foundation; either version 2.1 of the
> +   License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; see the file COPYING.LIB.  If
> +   not, see <http://www.gnu.org/licenses/>.  */
> +
> +/* This test does the following:
> +   Run ldconfig to create the caches.
> +   Corrupt the caches.
> +   Run ldconfig again.
> +   At each step we verify that ldconfig does not crash.  */
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <sys/wait.h>
> +#include <ftw.h>
> +#include <stdint.h>
> +
> +#include <support/check.h>
> +#include <support/support.h>
> +
> +static int
> +display_info (const char *fpath, const struct stat *sb,
> +              int tflag, struct FTW *ftwbuf)
> +{
> +  printf ("%-3s %2d %7jd   %-40s %d %s\n",
> +          (tflag == FTW_D) ? "d" : (tflag == FTW_DNR) ? "dnr" :
> +          (tflag == FTW_DP) ? "dp" : (tflag == FTW_F) ? "f" :
> +          (tflag == FTW_NS) ? "ns" : (tflag == FTW_SL) ? "sl" :
> +          (tflag == FTW_SLN) ? "sln" : "???",
> +          ftwbuf->level, (intmax_t) sb->st_size,
> +          fpath, ftwbuf->base, fpath + ftwbuf->base);
> +  /* To tell nftw() to continue */
> +  return 0;
> +}
> +
> +/* Run ldconfig with a corrupt aux-cache, in particular we test for size
> +   truncation that might happen if a previous ldconfig run failed or if
> +   there were storage or power issues while we were writing the file.
> +   We want ldconfig not to crash, and it should be able to do so by
> +   computing the expected size of the file (bug 18093).  */
> +static int
> +do_test (void)
> +{
> +  char *args[] = { (char *) "/sbin/ldconfig", NULL };
> +  struct stat fs;
> +  long int size, new_size, i;
> +  int status;
> +  pid_t pid = fork ();
> +
> +  /* Run ldconfig fist to generate the aux-cache.  */
> +  if (!pid)
> +    {
> +      execv (args[0], args);
> +    }
> +  else
> +    {
> +      if (pid)
> +        {
> +          waitpid (pid, &status, 0);
> +          if (!(WIFEXITED (status)))
> +            FAIL_EXIT1 ("ldconfig was aborted");
> +          if (stat ("/var/cache/ldconfig/aux-cache", &fs) < 0)
> +            {
> +              if (errno == ENOENT)
> +                FAIL_EXIT1 ("aux-cache does not exist\n");
> +              else
> +                FAIL_EXIT1 ("Failed to open aux-cache.");
> +              return -1;
> +            }
> +
> +          size = fs.st_size;
> +          /* Run 3 tests, each truncating aux-cache shorter and shorter.  */
> +          for (i = 3; i > 0; i--)
> +            {
> +              new_size = size * i / 4;
> +              truncate ("/var/cache/ldconfig/aux-cache", new_size);
> +              if (errno)
> +                FAIL_EXIT1 ("Truncation failed.");
> +              if (nftw
> +                  ("/var/cache/ldconfig/aux-cache", display_info, 1000,
> +                   0) == -1)
> +                {
> +                  FAIL_EXIT1 ("nftw failed.");
> +                  return -1;
> +                }
> +
> +              pid = fork ();
> +              /* Verify that ldconfig can run with a truncated
> +                 aux-cache and doesn't crash.  */
> +              if (!pid)
> +                {
> +                  execv (args[0], args);
> +                }
> +              else
> +                {
> +                  waitpid (pid, &status, 0);
> +                  if (!(WIFEXITED (status)))
> +                    FAIL_EXIT1 ("ldconfig exited with non-zero status");
> +                }
> +
> +            }
> +        }
> +    }
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/elf/tst-ldconfig-bad-aux-cache.root/var/cache/.gitignore b/elf/tst-ldconfig-bad-aux-cache.root/var/cache/.gitignore
> new file mode 100644
> index 0000000000..e69de29bb2
> --
> 2.17.2
>
  
Carlos O'Donell April 23, 2019, 2:22 p.m. UTC | #2
Sasha,

If you fix the nftw wrapping in the test then I think this is ready to go
upstream. There remains one question of implementing this slightly differently
with an mkdir script command, but it doesn't hold up this patch. Please feel
free to post upstream with the nftw fix and I can review.

Adding DJ for review of the *.script suggestion.

On 4/15/19 2:18 PM, Alexandra Hájková wrote:
> From: Alexandra Hájková <ahajkova@redhat.com>
> 
>        This test corrupts /var/cache/ldconfig/aux-cache and executes ldconfig
>        to check it will not segfault using the corrupted aux_cache. The test
>        uses the test-in-container framework. Verified no regressions on
>        x86_64.

If you don't create the "/var/cache/" directory, does ldconfig fail to run?

If we had a "mkdir" command in the test script syntax could we use it to
create the directories at runtime?

e.g.
elf/tst-ldconfig_aux-cache.root/tst-ldconfig_aux-cache.script

# Create the needed directories.
mkdir -p /var/cache

Then we don't need the /var/cache/.gitignore file?

> ChangeLog:
> 2019-04-15  Alexandra Hajkova  <ahajkova@redhat.com>
> 
> 	* elf/Makefile (test-container): Add tst-ldconfig-bad-aux-cache.
> 	* elf/tst-ldconfig-bad-aux-cache.c: New file.
> 	* elf/tst-ldconfig_aux-cache.root: New directory.
> 	* elf/tst-ldconfig_aux-cache.root/var: Likewise.
> 	* elf/tst-ldconfig_aux-cache.root/var/cache: Likewise.
> 	* elf/tst-ldconfig_aux-cache.root/var/cache/.gitignore: New file.

OK.

> 
> ---
>   elf/Makefile                                  |   3 +
>   elf/tst-ldconfig-bad-aux-cache.c              | 123 ++++++++++++++++++
>   .../var/cache/.gitignore                      |   0
>   3 files changed, 126 insertions(+)
>   create mode 100644 elf/tst-ldconfig-bad-aux-cache.c
>   create mode 100644 elf/tst-ldconfig-bad-aux-cache.root/var/cache/.gitignore
> 
> diff --git a/elf/Makefile b/elf/Makefile
> index 310a37cc13..35052b2768 100644
> --- a/elf/Makefile
> +++ b/elf/Makefile
> @@ -155,6 +155,9 @@ tests-static-internal := tst-tls1-static tst-tls2-static \
>   CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o
>   tst-tls1-static-non-pie-no-pie = yes
>   
> +tests-container = \
> +			  tst-ldconfig-bad-aux-cache

OK.

> +
>   tests := tst-tls9 tst-leaks1 \
>   	tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \
>   	tst-auxv
> diff --git a/elf/tst-ldconfig-bad-aux-cache.c b/elf/tst-ldconfig-bad-aux-cache.c
> new file mode 100644
> index 0000000000..d7e591b9ca
> --- /dev/null
> +++ b/elf/tst-ldconfig-bad-aux-cache.c
> @@ -0,0 +1,123 @@
> +/* Test ldconfig does not segfault when aux-cache is corrupted (Bug 18093).

OK.

> +   Copyright (C) 2019 Free Software Foundation, Inc.

OK.

> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public License as
> +   published by the Free Software Foundation; either version 2.1 of the
> +   License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; see the file COPYING.LIB.  If
> +   not, see <http://www.gnu.org/licenses/>.  */
> +
> +/* This test does the following:
> +   Run ldconfig to create the caches.
> +   Corrupt the caches.
> +   Run ldconfig again.
> +   At each step we verify that ldconfig does not crash.  */

OK.

> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <sys/wait.h>
> +#include <ftw.h>
> +#include <stdint.h>
> +
> +#include <support/check.h>
> +#include <support/support.h>
> +
> +static int
> +display_info (const char *fpath, const struct stat *sb,
> +              int tflag, struct FTW *ftwbuf)
> +{
> +  printf ("%-3s %2d %7jd   %-40s %d %s\n",
> +          (tflag == FTW_D) ? "d" : (tflag == FTW_DNR) ? "dnr" :
> +          (tflag == FTW_DP) ? "dp" : (tflag == FTW_F) ? "f" :
> +          (tflag == FTW_NS) ? "ns" : (tflag == FTW_SL) ? "sl" :
> +          (tflag == FTW_SLN) ? "sln" : "???",
> +          ftwbuf->level, (intmax_t) sb->st_size,
> +          fpath, ftwbuf->base, fpath + ftwbuf->base);
> +  /* To tell nftw() to continue */
> +  return 0;
> +}
> +
> +/* Run ldconfig with a corrupt aux-cache, in particular we test for size
> +   truncation that might happen if a previous ldconfig run failed or if
> +   there were storage or power issues while we were writing the file.
> +   We want ldconfig not to crash, and it should be able to do so by
> +   computing the expected size of the file (bug 18093).  */

OK.

> +static int
> +do_test (void)
> +{
> +  char *args[] = { (char *) "/sbin/ldconfig", NULL };
> +  struct stat fs;
> +  long int size, new_size, i;
> +  int status;
> +  pid_t pid = fork ();
> +
> +  /* Run ldconfig fist to generate the aux-cache.  */
> +  if (!pid)
> +    {
> +      execv (args[0], args);
> +    }
> +  else
> +    {
> +      if (pid)
> +        {
> +          waitpid (pid, &status, 0);
> +          if (!(WIFEXITED (status)))
> +            FAIL_EXIT1 ("ldconfig was aborted");
> +          if (stat ("/var/cache/ldconfig/aux-cache", &fs) < 0)
> +            {
> +              if (errno == ENOENT)
> +                FAIL_EXIT1 ("aux-cache does not exist\n");
> +              else
> +                FAIL_EXIT1 ("Failed to open aux-cache.");
> +              return -1;
> +            }
> +
> +          size = fs.st_size;
> +          /* Run 3 tests, each truncating aux-cache shorter and shorter.  */
> +          for (i = 3; i > 0; i--)
> +            {
> +              new_size = size * i / 4;
> +              truncate ("/var/cache/ldconfig/aux-cache", new_size);
> +              if (errno)
> +                FAIL_EXIT1 ("Truncation failed.");
> +              if (nftw
> +                  ("/var/cache/ldconfig/aux-cache", display_info, 1000,

This line is not properly wrapped.

It should be:

if (nftw ("/var/cache/ldconfig/aux-cache"
	  display_info, 1000, 0) == -1)
   {

   }

You want to keep "nftw (" together, and then split on parameters, and line
the parameters up with the first parameter on the previous line.

> +                   0) == -1)
> +                {
> +                  FAIL_EXIT1 ("nftw failed.");
> +                  return -1;
> +                }
> +
> +              pid = fork ();
> +              /* Verify that ldconfig can run with a truncated
> +                 aux-cache and doesn't crash.  */
> +              if (!pid)
> +                {
> +                  execv (args[0], args);
> +                }
> +              else
> +                {
> +                  waitpid (pid, &status, 0);
> +                  if (!(WIFEXITED (status)))
> +                    FAIL_EXIT1 ("ldconfig exited with non-zero status");
> +                }
> +
> +            }
> +        }
> +    }
> +
> +  return 0;
> +}

OK.

> +
> +#include <support/test-driver.c>
> diff --git a/elf/tst-ldconfig-bad-aux-cache.root/var/cache/.gitignore b/elf/tst-ldconfig-bad-aux-cache.root/var/cache/.gitignore
> new file mode 100644
> index 0000000000..e69de29bb2
>
  
Carlos O'Donell April 24, 2019, 7:21 p.m. UTC | #3
On 4/24/19 8:00 AM, Alexandra Hajkova wrote:
> 
> 
>     If you don't create the "/var/cache/" directory, does ldconfig fail to run?
> 
>   Yes, it does:
> 
> rm -r elf/tst-ldconfig-bad-aux-cache.root/var
> also from build dir:
> rm -r testroot.root/var/cache/
> and remove all the test results:
> rm elf/tst-ldconfig-bad-aux-cache.*
> and the results after rerunning my test:
> cat elf/tst-ldconfig-bad-aux-cache.out
> error: tst-ldconfig-bad-aux-cache.c:80: aux-cache does not exist
> 
> error: 1 test failures
> cat elf/tst-ldconfig-bad-aux-cache.test-result
> FAIL: elf/tst-ldconfig-bad-aux-cache
> original exit status 1

OK, thanks for verifying that.

Please post v2 with the fixed nftw wrapping and I'll
do a final review.
  

Patch

diff --git a/elf/Makefile b/elf/Makefile
index 310a37cc13..35052b2768 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -155,6 +155,9 @@  tests-static-internal := tst-tls1-static tst-tls2-static \
 CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o
 tst-tls1-static-non-pie-no-pie = yes
 
+tests-container = \
+			  tst-ldconfig-bad-aux-cache
+
 tests := tst-tls9 tst-leaks1 \
 	tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \
 	tst-auxv
diff --git a/elf/tst-ldconfig-bad-aux-cache.c b/elf/tst-ldconfig-bad-aux-cache.c
new file mode 100644
index 0000000000..d7e591b9ca
--- /dev/null
+++ b/elf/tst-ldconfig-bad-aux-cache.c
@@ -0,0 +1,123 @@ 
+/* Test ldconfig does not segfault when aux-cache is corrupted (Bug 18093).
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+/* This test does the following:
+   Run ldconfig to create the caches.
+   Corrupt the caches.
+   Run ldconfig again.
+   At each step we verify that ldconfig does not crash.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <ftw.h>
+#include <stdint.h>
+
+#include <support/check.h>
+#include <support/support.h>
+
+static int
+display_info (const char *fpath, const struct stat *sb,
+              int tflag, struct FTW *ftwbuf)
+{
+  printf ("%-3s %2d %7jd   %-40s %d %s\n",
+          (tflag == FTW_D) ? "d" : (tflag == FTW_DNR) ? "dnr" :
+          (tflag == FTW_DP) ? "dp" : (tflag == FTW_F) ? "f" :
+          (tflag == FTW_NS) ? "ns" : (tflag == FTW_SL) ? "sl" :
+          (tflag == FTW_SLN) ? "sln" : "???",
+          ftwbuf->level, (intmax_t) sb->st_size,
+          fpath, ftwbuf->base, fpath + ftwbuf->base);
+  /* To tell nftw() to continue */
+  return 0;
+}
+
+/* Run ldconfig with a corrupt aux-cache, in particular we test for size
+   truncation that might happen if a previous ldconfig run failed or if
+   there were storage or power issues while we were writing the file.
+   We want ldconfig not to crash, and it should be able to do so by
+   computing the expected size of the file (bug 18093).  */
+static int
+do_test (void)
+{
+  char *args[] = { (char *) "/sbin/ldconfig", NULL };
+  struct stat fs;
+  long int size, new_size, i;
+  int status;
+  pid_t pid = fork ();
+
+  /* Run ldconfig fist to generate the aux-cache.  */
+  if (!pid)
+    {
+      execv (args[0], args);
+    }
+  else
+    {
+      if (pid)
+        {
+          waitpid (pid, &status, 0);
+          if (!(WIFEXITED (status)))
+            FAIL_EXIT1 ("ldconfig was aborted");
+          if (stat ("/var/cache/ldconfig/aux-cache", &fs) < 0)
+            {
+              if (errno == ENOENT)
+                FAIL_EXIT1 ("aux-cache does not exist\n");
+              else
+                FAIL_EXIT1 ("Failed to open aux-cache.");
+              return -1;
+            }
+
+          size = fs.st_size;
+          /* Run 3 tests, each truncating aux-cache shorter and shorter.  */
+          for (i = 3; i > 0; i--)
+            {
+              new_size = size * i / 4;
+              truncate ("/var/cache/ldconfig/aux-cache", new_size);
+              if (errno)
+                FAIL_EXIT1 ("Truncation failed.");
+              if (nftw
+                  ("/var/cache/ldconfig/aux-cache", display_info, 1000,
+                   0) == -1)
+                {
+                  FAIL_EXIT1 ("nftw failed.");
+                  return -1;
+                }
+
+              pid = fork ();
+              /* Verify that ldconfig can run with a truncated
+                 aux-cache and doesn't crash.  */
+              if (!pid)
+                {
+                  execv (args[0], args);
+                }
+              else
+                {
+                  waitpid (pid, &status, 0);
+                  if (!(WIFEXITED (status)))
+                    FAIL_EXIT1 ("ldconfig exited with non-zero status");
+                }
+
+            }
+        }
+    }
+
+  return 0;
+}
+
+#include <support/test-driver.c>