Add our own version of execve for GNO, which can quote arguments and can remove variables from the environment if needed.

Our versions of the execv* functions have been moved to their own file. They are now used for all the exec* calls in hush.
This commit is contained in:
Stephen Heumann 2014-11-22 16:53:59 -06:00
parent 8728cdf2b8
commit 3e7c0d0ace
3 changed files with 93 additions and 64 deletions

View File

@ -36,7 +36,8 @@ LIBBB_B_SRC = \
libbb/messages.c \
libbb/bb.basename.c \
libbb/mempcpy.c \
libbb/get.exec.path.c
libbb/get.exec.path.c \
libbb/exec.gno.c
LIBBB_C_SRC = \
libbb/perror.msg.c \

91
libbb/exec.gno.c Normal file
View File

@ -0,0 +1,91 @@
#include <libbb.h>
#ifdef __GNO__
/* We use our own implementations of execv* because we need to
* do some things that libc's version doesn't:
* 1) Quote arguments containing spaces or tabs
* 2) Execute shell scripts in a shell (TODO)
*/
/* Note that this expects environ to be initialized.
* Also, if envp != environ, it will update the environment of this process
* (and the one it's forked from, if any, unless there's been an environPush).
*/
int execve(const char *path, char *const *argv, char *const *envp)
{
int result;
char *args;
size_t argslen = 0;
int i;
char *nextarg;
for (i = 0; argv[i] != NULL; i++) {
/* 3 bytes extra for space (or terminating 0) and possible quotes */
argslen += strlen(argv[i]) + 3;
}
nextarg = args = malloc(argslen);
if (args == NULL) {
free(path);
errno = ENOMEM;
return -1;
}
/* Copy arguments into a single string, quoting ones that contain spaces
* or tabs. This approach won't give the right result in all cases
* (e.g. when the argument starts with " or contains both spaces and "),
* but it's about the best we can do, since we're dependent on the
* argument-parsing code in the target program.
*/
for (i = 0; argv[i] != NULL; i++) {
bool has_space = (strpbrk(argv[i], " \t") != NULL);
if (has_space)
*nextarg++ = '"';
strcpy(nextarg, argv[i]);
nextarg += strlen(argv[i]);
if (has_space)
*nextarg++ = '"';
*nextarg++ = ' ';
}
*(nextarg - 1) = 0;
/* Clear environment and then rebuild it, if necessary. */
if (envp != environ) {
while (environ[0] != NULL)
bb_unsetenv(environ[0]);
if (buildEnv(envp) != 0)
return -1;
}
result = _execve(path, args);
/* error case */
free(args);
return result;
}
int execv(const char *path, char *const *argv)
{
return execve(path, argv, environ);
}
int execvp(const char *file, char *const *argv)
{
int result;
char *path;
path = buildPath(file);
if (path == NULL) {
errno = ENOENT;
return -1;
}
result = execve(path, argv, environ);
/* error case */
free(path);
return result;
}
#endif

View File

@ -6746,69 +6746,6 @@ static void exec_builtin(char ***to_free,
}
#ifdef __GNO__
/* We use our own implementation of execvp because we need to
* do some things that libc's version doesn't:
* 1) Quote arguments containing spaces or tabs
* 2) Execute shell scripts in a shell (TODO)
*/
#define execvp execvp_gno
static int execvp_gno(const char *file, char *const argv[])
{
int result;
char *args;
char *path;
size_t argslen = 0;
int i;
char *nextarg;
path = buildPath(file);
if (path == NULL) {
errno = ENOENT;
return -1;
}
for (i = 0; argv[i] != NULL; i++) {
/* 3 bytes extra for space (or terminating 0) and possible quotes */
argslen += strlen(argv[i]) + 3;
}
nextarg = args = malloc(argslen);
if (args == NULL) {
free(path);
errno = ENOMEM;
return -1;
}
/* Copy arguments into a single string, quoting ones that contain spaces
* or tabs. This approach won't give the right result in all cases
* (e.g. when the argument starts with " or contains both spaces and "),
* but it's about the best we can do, since we're dependent on the
* argument-parsing code in the target program.
*/
for (i = 0; argv[i] != NULL; i++) {
bool has_space = (strpbrk(argv[i], " \t") != NULL);
if (has_space)
*nextarg++ = '"';
strcpy(nextarg, argv[i]);
nextarg += strlen(argv[i]);
if (has_space)
*nextarg++ = '"';
*nextarg++ = ' ';
}
*(nextarg - 1) = 0;
result = _execve(path, args);
/* error case */
free(path);
free(args);
return result;
}
#endif
static void execvp_or_die(char **argv) NORETURN;
static void execvp_or_die(char **argv)
{