mirror of
https://github.com/sheumann/hush.git
synced 2024-12-22 14:30:31 +00:00
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:
parent
8728cdf2b8
commit
3e7c0d0ace
3
Makefile
3
Makefile
@ -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
91
libbb/exec.gno.c
Normal 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
|
63
shell/hush.c
63
shell/hush.c
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user