On Thu, Apr 09 2020, Jeremie Courreges-Anglas <j...@wxcvbn.org> wrote:
> find(1) uses ARG_MAX to compute the maximum space it can pass to
> execve(2).  This doesn't fly if userland and the kernel don't agree, as
> noticed by some after the recent ARG_MAX bump.
>
> --8<--
> ritchie /usr/src/usr.bin/find$ obj/find /usr/src/ -type f -exec true {} +
> find: true: Argument list too long
> find: true: Argument list too long
> find: true: Argument list too long
> ^C
> -->8--
>
> While having the kernel and userland out of sync is not a good idea,
> making find(1) more robust by using sysconf(3) is easy.  This is what
> xargs(1) already does.
>
> ok?

Committed, thanks.

> PS: a followup diff will take into account the space taken by the
> environment

Right now we don't account for the space used by the environment.
We get lucky either because of the 5000 max args limit or because
environment size usually fits in the 4096 bytes safety net.

The diff below uses the same approach as xargs(1).
While here, tweak the message in case of (unlikely) sysconf(3) failure.

ok?


Index: function.c
===================================================================
RCS file: /d/cvs/src/usr.bin/find/function.c,v
retrieving revision 1.48
diff -u -p -p -u -r1.48 function.c
--- function.c  9 Apr 2020 10:27:32 -0000       1.48
+++ function.c  9 Apr 2020 12:36:52 -0000
@@ -588,6 +588,8 @@ c_exec(char *unused, char ***argvp, int 
 
        if (new->flags & F_PLUSSET) {
                long arg_max;
+               extern char **environ;
+               char **ep;
                u_int c, bufsize;
 
                cnt = ap - *argvp - 1;                  /* units are words */
@@ -605,7 +607,11 @@ c_exec(char *unused, char ***argvp, int 
                 */
                arg_max = sysconf(_SC_ARG_MAX);
                if (arg_max == -1)
-                       err(1, "sysconf(_SC_ARG_MAX) failed");
+                       err(1, "-exec: sysconf(_SC_ARG_MAX) failed");
+               for (ep = environ; *ep != NULL; ep++) {
+                       /* 1 byte for each '\0' */
+                       arg_max -= strlen(*ep) + 1 + sizeof(*ep);
+               }
 
                /*
                 * Count up the space of the user's arguments, and
@@ -617,6 +623,8 @@ c_exec(char *unused, char ***argvp, int 
                        c += strlen(*argv) + 1;
                        new->e_argv[cnt] = *argv;
                }
+               if (arg_max < 4 * 1024 + c)
+                       errx(1, "-exec: no space left to run child command");
                bufsize = arg_max - 4 * 1024 - c;
 
                /*

-- 
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE

Reply via email to