[PATCH v2 0/3] posix: Execute file function fixes
Paul Eggert
eggert@cs.ucla.edu
Fri Feb 19 23:13:00 GMT 2016
On 02/19/2016 12:19 PM, Adhemerval Zanella wrote:
> And it is a regression only if you consider dynamic allocation an alternative,
It's a regression in that it would break some applications that
currently work. An application that is simple (no signal handling,
single-threaded, etc.) can invoke programs with many arguments now, but
the same application won't work if that patch is installed.
Come to think of it, execlp, posix_spawn, and posix_spawnp can all use
malloc, since POSIX does not require them to be async-signal-safe. So
you can go back to using malloc for their implementations, when they are
given large argument vectors. The only conformance problem here will be
execl and execle.
For these two, I suggest a machine-dependent implementation, with the
default being something along the lines of the attached (this is totally
untested, I'm just trying to give the gist).
> A better strategy would be set either hard limits on stack usage in design phase or to focus on enable GLIBC to use a better stack protection mechanism (preferable through compiler assistance).
The latter sounds like a good idea, but is a bigger project and I doubt
whether we'd want to wait for that project to be finished before fixing
the exec-family problems in question.
-------------- next part --------------
#include <unistd.h>
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
int
execl (const char *file, const char *arg, ...)
{
enum { N = 1024 };
char *argv[N];
va_list args;
int argc = 0;
argv[0] = (char *) arg;
va_start (args, arg);
while (argv[argc++] != NULL && argc < N)
argv[argc] = va_arg (args, char *);
va_end (args);
if (argv[argc - 1] == NULL)
return __execve (file, argv, __environ);
/* The argument vector does not fit into ARGV. Find out where in
the stack the caller put the arguments, store the initial
arguments there (as they are often cached in registers), and use
that part of the stack as an argument vector. If the exec fails,
restore the temporarily-trashed stack. This is not guaranteed to
work on all platforms, but it should be portable to most, and the
exceptions need to have machine-specific replacements. */
char **parg = (char **) &arg;
for (int i = N / 2; ; i++)
{
int j;
for (j = 0; parg[i + j] == argv[N / 2 + j]; j++)
if (j == N / 2)
{
char **reused_argv = parg + i - N / 2;
size_t half_size = N / 2 * sizeof *argv;
/* Save the part of the stack that will be temporarily trashed. */
memcpy (argv + N / 2, reused_argv, half_size);
/* Temporarily trash the stack. */
memcpy (reused_argv, argv, half_size);
__execve (file, reused_argv, __environ);
/* Restore the temporarily-trashed stack. */
memcpy (reused_argv, argv + N / 2, half_size);
return -1;
}
}
}
More information about the Libc-alpha
mailing list