Re: [PATCH] execve.2: execve also returns E2BIG if a string is too long
From: Rik van Riel
Date: Wed Oct 11 2023 - 09:21:39 EST
On Wed, 2023-10-11 at 12:41 +0200, Alejandro Colomar wrote:
> Hi Rik,
>
> On Tue, Oct 10, 2023 at 11:41:53PM -0400, Rik van Riel wrote:
> > Document that if a command line or environment string is too long
> > (> MAX_ARG_STRLEN), execve will also return E2BIG.
>
> That's already implied by the current text:
>
> E2BIG The total number of bytes in the environment (envp) and
> argument
> list (argv) is too large.
>
> That means that
>
> size_t bytes;
>
> bytes = 0;
> for (char *e = envp; e != NULL; e++)
> bytes += strlen(e) + 1; // I have doubts about the +1
> for (char *a = argv; a != NULL; a++)
> bytes += strlen(a) + 1; // Same doubts
>
> if (bytes > MAX_ARG_STRLEN) // Maybe >= ?
> return -E2BIG;
The code in fs/exec.c enforces MAX_ARG_STRLEN against
each individual string, not against the total.
If any string, either argument or environment, is larger
than 32 * PAGE_SIZE, the kernel will return -E2BIG.
do_execveat_common() has this code, which uses copy_strings
to copy both the strings from the environment, and from
the command line arguments:
retval = copy_strings(bprm->envc, envp, bprm);
if (retval < 0)
goto out_free;
retval = copy_strings(bprm->argc, argv, bprm);
if (retval < 0)
goto out_free;
Inside copy_strings() we have this code:
while (argc-- > 0) {
...
len = strnlen_user(str, MAX_ARG_STRLEN);
if (!len)
goto out;
ret = -E2BIG;
if (!valid_arg_len(bprm, len))
goto out;
The valid_arg_len() function does not need explanation:
static bool valid_arg_len(struct linux_binprm *bprm, long len)
{
return len <= MAX_ARG_STRLEN;
}
The current man page wording is very clear about the total
length being enforced, but IMHO not as clear about the limit
that gets enforced on each individual string.
The total length limit of environment & commandline arguments
is enforced by bprm_stack_limits(), and is checked against
either 1/4 of the maximum stack size, or 3/4 of _STK_LIM, whichever
is smaller. The MAX_ARG_STRLEN value does not come into play when
enforcing the total.
--
All Rights Reversed.