]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
For b/18473397 and CVE-2014-7817, properly handle the WRDE_NOCMD flag when processing...
authorSterling Augustine <saugustine@google.com>
Tue, 25 Nov 2014 21:49:28 +0000 (13:49 -0800)
committerSterling Augustine <saugustine@google.com>
Tue, 25 Nov 2014 21:49:28 +0000 (13:49 -0800)
README.google
posix/wordexp-test.c
posix/wordexp.c

index 9bf2fbfbc8a5b95340224b64ac74e5e4a8ebcb82..a68793375b608ecbe3f97f8658ccf059b9c93363 100644 (file)
@@ -401,3 +401,10 @@ elf/dl-load.c
   To fix AARCH64 build, make code added to dl-load.c in previous CL
   conditional on SHARED. Disable dlopen_with_offet in fully-static links.
   (ppluzhnikov, google-local)
+
+wordexp.c
+posix/wordexp-test.c
+  For b/18473397 and CVE-2014-7817, properly handle the WRDE_NOCMD
+  flag when processing certain arithmetic inputs.
+  (backport)
+  https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=a39208bd7fb76c1b01c127b4c61f9bfd915bfe7c
index 4957006da74b27e6cc4a146e1269f0d989288dcc..bdd65e439fe51ac43887caf089c0e60c9a00b2d6 100644 (file)
 
 #define IFS " \n\t"
 
+extern void *__dso_handle __attribute__ ((__weak__, __visibility__ ("hidden")));
+extern int __register_atfork (void (*) (void), void (*) (void), void (*) (void), void *);
+
+static int __app_register_atfork (void (*prepare) (void), void (*parent) (void), void (*child) (void))
+{
+  return __register_atfork (prepare, parent, child,
+                           &__dso_handle == NULL ? NULL : __dso_handle);
+}
+
+/* Number of forks seen.  */
+static int registered_forks;
+
+/* For each fork increment the fork count.  */
+static void
+register_fork (void)
+{
+  registered_forks++;
+}
+
 struct test_case_struct
 {
   int retval;
@@ -206,6 +225,12 @@ struct test_case_struct
     { WRDE_SYNTAX, NULL, "$((2+))", 0, 0, { NULL, }, IFS },
     { WRDE_SYNTAX, NULL, "`", 0, 0, { NULL, }, IFS },
     { WRDE_SYNTAX, NULL, "$((010+4+))", 0, 0, { NULL }, IFS },
+    /* Test for CVE-2014-7817. We test 3 combinations of command
+       substitution inside an arithmetic expression to make sure that
+       no commands are executed and error is returned.  */
+    { WRDE_CMDSUB, NULL, "$((`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS },
+    { WRDE_CMDSUB, NULL, "$((1+`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS },
+    { WRDE_CMDSUB, NULL, "$((1+$((`echo 1`))))", WRDE_NOCMD, 0, { NULL, }, IFS },
 
     { -1, NULL, NULL, 0, 0, { NULL, }, IFS },
   };
@@ -258,6 +283,15 @@ main (int argc, char *argv[])
          return -1;
     }
 
+  /* If we are not allowed to do command substitution, we install
+     fork handlers to verify that no forks happened.  No forks should
+     happen at all if command substitution is disabled.  */
+  if (__app_register_atfork (register_fork, NULL, NULL) != 0)
+    {
+      printf ("Failed to register fork handler.\n");
+      return -1;
+    }
+
   for (test = 0; test_case[test].retval != -1; test++)
     if (testit (&test_case[test]))
       ++fail;
@@ -367,6 +401,9 @@ testit (struct test_case_struct *tc)
 
   printf ("Test %d (%s): ", ++tests, tc->words);
 
+  if (tc->flags & WRDE_NOCMD)
+    registered_forks = 0;
+
   if (tc->flags & WRDE_APPEND)
     {
       /* initial wordexp() call, to be appended to */
@@ -378,6 +415,13 @@ testit (struct test_case_struct *tc)
     }
   retval = wordexp (tc->words, &we, tc->flags);
 
+  if ((tc->flags & WRDE_NOCMD)
+      && (registered_forks > 0))
+    {
+         printf ("FAILED fork called for WRDE_NOCMD\n");
+         return 1;
+    }
+
   if (tc->flags & WRDE_DOOFFS)
       start_offs = sav_we.we_offs;
 
index 366ec18aebf69d23aac617432a5c2a43d80e2248..36a13678a4272a3bd43f65d8694131326bdd43ad 100644 (file)
@@ -893,6 +893,10 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
   pid_t pid;
   int noexec = 0;
 
+  /* Do nothing if command substitution should not succeed.  */
+  if (flags & WRDE_NOCMD)
+    return WRDE_CMDSUB;
+
   /* Don't fork() unless necessary */
   if (!comm || !*comm)
     return 0;
@@ -2082,9 +2086,6 @@ parse_dollars (char **word, size_t *word_length, size_t *max_length,
            }
        }
 
-      if (flags & WRDE_NOCMD)
-       return WRDE_CMDSUB;
-
       (*offset) += 2;
       return parse_comm (word, word_length, max_length, words, offset, flags,
                         quoted? NULL : pwordexp, ifs, ifs_white);
@@ -2196,9 +2197,6 @@ parse_dquote (char **word, size_t *word_length, size_t *max_length,
          break;
 
        case '`':
-         if (flags & WRDE_NOCMD)
-           return WRDE_CMDSUB;
-
          ++(*offset);
          error = parse_backtick (word, word_length, max_length, words,
                                  offset, flags, NULL, NULL, NULL);
@@ -2357,12 +2355,6 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
        break;
 
       case '`':
-       if (flags & WRDE_NOCMD)
-         {
-           error = WRDE_CMDSUB;
-           goto do_error;
-         }
-
        ++words_offset;
        error = parse_backtick (&word, &word_length, &max_length, words,
                                &words_offset, flags, pwordexp, ifs,