OSDN Git Service

toybox: find: Fix segfault when using -iname/-ipath with -exec
authorTom Marshall <tdm@cyngn.com>
Fri, 8 Apr 2016 19:00:28 +0000 (12:00 -0700)
committerTom Marshall <tdm@cyngn.com>
Wed, 13 Apr 2016 18:25:53 +0000 (11:25 -0700)
iname/ipath use the argdata list to store names (type char*) on the initial
argument parsing pass and then use these on subsequent passes with entries
returned from dirtree_flagread.  exec/execdir also use the argdata list to
store its arguments (type struct exec_range*).  Thus, it is imperative that
each value pushed onto the list be popped in exactly the same order.
Failure to do this results in pointers from the list being cast to an
incorrect type and segfaults ensue.

During subsequent passes when using an "or" predicate, the current code in
iname/ipath fails to pop the same values that it pushed when the LHS
evaluates to true.  This is because the "or" code sets active==0 which then
sets check==0 when evaluating the RHS, and the RHS name is not popped.
Subsequent usage of "exec" will try to pop this value as an argument list
and segfault.

This could be fixed by making usage of argdata consistent in iname/ipath.
However, it does not appear necessary to use argdata at all.  So remove
it and lowercase the pattern inplace.  This avoids the segfault and also
avoids unnecessary heap allocs.

Change-Id: Icb171b90a60bc6cf5629f87ed5966b4d26e22b28

toys/posix/find.c

index a9c35f4..b54fc68 100644 (file)
@@ -315,22 +315,21 @@ static int do_find(struct dirtree *new)
         || !strcmp(s, "path") || !strcmp(s, "ipath"))
       {
         int i = (*s == 'i');
-        char *arg = ss[1], *path = 0, *name = new ? new->name : arg;
-
-        // Handle path expansion and case flattening
-        if (new && s[i] == 'p') name = path = dirtree_path(new, 0);
-        if (i) {
-          if (check || !new) {
-            if (name) name = strlower(name);
-            if (!new) {
-              dlist_add(&TT.argdata, name);
-              free(path);
-            } else arg = ((struct double_list *)llist_pop(&argdata))->data;
-          }
-        }
 
+        if (i && !new) {
+            char *p;
+            for (p = ss[1]; *p; ++p) {
+                *p = tolower(*p);
+            }
+        }
         if (check) {
-          test = !fnmatch(arg, name, FNM_PATHNAME*(s[i] == 'p'));
+          char *path = 0, *name = new->name;
+
+          // Handle path expansion and case flattening
+          if (s[i] == 'p') name = path = dirtree_path(new, 0);
+          if (i) name = strlower(name);
+
+          test = !fnmatch(ss[1], name, FNM_PATHNAME*(s[i] == 'p'));
           free(path);
           if (i) free(name);
         }