mcexec/execve: fix shebangs handling
There were mainly two problems with shebangs: - Suffix arguments handling e.g. '#!/bin/sh -x' - Recursive handling e.g. script1 fetchs '#!/path/to/script2' and script2 itself has a shebang - (did I say two?) running shebang would replace argv[optind] instead of appending e.g. script with '#!/bin/sh' and running './script -c' would run '/bin/sh -c' instead of '/bin/sh ./script -c' There also are two places where this needs parsing: - starting a fresh program from mcexec - starting a new program from execve in mcexec The first was easy to fix as we already had argv around, but the later required a new way to transfer the 'new argv elements from the script' to mckernel to append before its argv -- it used to be 'desc->shell_path' but that was no longer used at some point and just one keyword is not enough to handle this properly. This commit does: - Refactors the lookup_path + load_elf_desc that was only done at most twice in its own function that loops indefinitely and use that in both situations described above - Transmits the argv addition in the transfer to mckernel after the desc; mckernel allocates 4 pages (hardcoded) for the descs and we will hopefully have room for the script arguments on top of that... (there is no guard!!!) - Change flatten_strings to allow prepending a flattened string instead of a single string. Note that the flatten_string change also brought in a difference in the format, to have the full length embedded within the string, the latest slot that used to be zeroes now contains the position of the end of the buffer (where the last+1 string would be if there had been one) This required a trivial change in mckernel prepare args function that used this property for no real reason. Hopefully things work™, this probably warrants adding a couple of new ostests... - create a couple of scripts with recursive invocation/arguments and check their own argv. - execute "mcexec script args" and "mcexec sh -c 'script args'" Change-Id: I2cf9cde5c07c9293f730de89c9731bd93dbfa789 Refs: #1115
This commit is contained in:
@ -146,7 +146,6 @@ struct program_load_desc {
|
||||
int uti_use_last_cpu; /* Work-around not to share CPU with OpenMP thread */
|
||||
int nr_processes;
|
||||
int process_rank;
|
||||
char shell_path[SHELL_PATH_MAX_LEN];
|
||||
__cpu_set_unit cpu_set[PLD_CPU_SET_SIZE];
|
||||
int profile;
|
||||
struct program_image_section sections[0];
|
||||
|
||||
@ -300,7 +300,6 @@ struct program_load_desc *load_elf(FILE *fp, char **interp_pathp)
|
||||
+ sizeof(struct program_image_section) * nhdrs);
|
||||
memset(desc, '\0', sizeof(struct program_load_desc)
|
||||
+ sizeof(struct program_image_section) * nhdrs);
|
||||
desc->shell_path[0] = '\0';
|
||||
fseek(fp, hdr.e_phoff, SEEK_SET);
|
||||
j = 0;
|
||||
desc->num_sections = nhdrs;
|
||||
@ -603,8 +602,10 @@ retry:
|
||||
|
||||
/* Check whether the resolved path is a symlink */
|
||||
if (lstat(path, &sb) == -1) {
|
||||
__eprintf("lookup_exec_path(): error stat\n");
|
||||
return errno;
|
||||
error = errno;
|
||||
__dprintf("lookup_exec_path(): error stat for %s: %d\n",
|
||||
path, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
if ((sb.st_mode & S_IFMT) == S_IFLNK) {
|
||||
@ -651,13 +652,13 @@ retry:
|
||||
}
|
||||
|
||||
int load_elf_desc(char *filename, struct program_load_desc **desc_p,
|
||||
char **shell_p)
|
||||
char **shebang_p)
|
||||
{
|
||||
FILE *fp;
|
||||
FILE *interp = NULL;
|
||||
char *interp_path;
|
||||
char *shell = NULL;
|
||||
size_t shell_len = 0;
|
||||
char *shebang = NULL;
|
||||
size_t shebang_len = 0;
|
||||
struct program_load_desc *desc;
|
||||
int ret = 0;
|
||||
struct stat sb;
|
||||
@ -692,16 +693,21 @@ int load_elf_desc(char *filename, struct program_load_desc **desc_p,
|
||||
}
|
||||
|
||||
if (!strncmp(header, "#!", 2)) {
|
||||
|
||||
if (getline(&shell, &shell_len, fp) == -1) {
|
||||
fprintf(stderr, "Error: reading shell path %s\n", filename);
|
||||
if (getline(&shebang, &shebang_len, fp) == -1) {
|
||||
fprintf(stderr, "Error: reading shebang path %s\n",
|
||||
filename);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
/* Delete new line character */
|
||||
shell[strlen(shell) - 1] = 0;
|
||||
*shell_p = shell;
|
||||
/* Delete new line character and any trailing spaces */
|
||||
shebang_len = strlen(shebang) - 1;
|
||||
shebang[shebang_len] = '\0';
|
||||
while (strpbrk(shebang + shebang_len - 1, " \t")) {
|
||||
shebang_len--;
|
||||
shebang[shebang_len] = '\0';
|
||||
}
|
||||
*shebang_p = shebang;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -787,6 +793,77 @@ int load_elf_desc(char *filename, struct program_load_desc **desc_p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* recursively resolve shebangs
|
||||
*
|
||||
* Note: shebang_argv_p must point to reallocable memory or be NULL
|
||||
*/
|
||||
int load_elf_desc_shebang(char *shebang_argv0,
|
||||
struct program_load_desc **desc_p,
|
||||
char ***shebang_argv_p)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char *shebang = NULL;
|
||||
int ret;
|
||||
|
||||
if ((ret = lookup_exec_path(shebang_argv0, path, sizeof(path), 1))
|
||||
!= 0) {
|
||||
__dprintf("error: finding file: %s\n", shebang_argv0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = load_elf_desc(path, desc_p, &shebang)) != 0) {
|
||||
__eprintf("error: loading file: %s\n", shebang_argv0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (shebang) {
|
||||
char *shebang_params;
|
||||
size_t shebang_param_count = 1;
|
||||
size_t shebang_argv_count = 0;
|
||||
char **shebang_argv;
|
||||
|
||||
if (!shebang_argv_p)
|
||||
return load_elf_desc_shebang(shebang, desc_p, NULL);
|
||||
|
||||
shebang_argv = *shebang_argv_p;
|
||||
|
||||
/* if there is a space, add whatever follows as extra arg */
|
||||
shebang_params = strchr(shebang, ' ');
|
||||
if (shebang_params) {
|
||||
shebang_params[0] = '\0';
|
||||
shebang_params++;
|
||||
shebang_param_count++;
|
||||
}
|
||||
|
||||
if (shebang_argv == NULL) {
|
||||
shebang_argv_count = shebang_param_count + 1;
|
||||
shebang_argv = malloc(shebang_argv_count *
|
||||
sizeof(void *));
|
||||
shebang_argv[shebang_param_count] = 0;
|
||||
} else {
|
||||
while (shebang_argv[shebang_argv_count++])
|
||||
;
|
||||
|
||||
shebang_argv_count += shebang_param_count + 1;
|
||||
shebang_argv = realloc(shebang_argv,
|
||||
shebang_argv_count * sizeof(void *));
|
||||
memmove(shebang_argv + shebang_param_count,
|
||||
shebang_argv,
|
||||
(shebang_argv_count - shebang_param_count)
|
||||
* sizeof(void *));
|
||||
}
|
||||
shebang_argv[0] = shebang;
|
||||
if (shebang_params)
|
||||
shebang_argv[1] = shebang_params;
|
||||
|
||||
*shebang_argv_p = shebang_argv;
|
||||
|
||||
return load_elf_desc_shebang(shebang, desc_p, shebang_argv_p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int transfer_image(int fd, struct program_load_desc *desc)
|
||||
{
|
||||
struct remote_transfer pt;
|
||||
@ -936,55 +1013,66 @@ unsigned long dma_buf_pa;
|
||||
|
||||
void print_flat(char *flat)
|
||||
{
|
||||
char **string;
|
||||
|
||||
__dprintf("counter: %d\n", *((int *)flat));
|
||||
long i, count;
|
||||
long *_flat = (long *)flat;
|
||||
|
||||
string = (char **)(flat + sizeof(int));
|
||||
while (*string) {
|
||||
|
||||
__dprintf("%s\n", (flat + (unsigned long)(*string)));
|
||||
count = _flat[0];
|
||||
__dprintf("counter: %ld\n", count);
|
||||
|
||||
++string;
|
||||
for (i = 0; i < count; i++) {
|
||||
__dprintf("%s\n", (flat + _flat[i + 1]));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Flatten out a (char **) string array into the following format:
|
||||
* [nr_strings][char *offset of string_0]...[char *offset of string_n-1][NULL][string0]...[stringn_1]
|
||||
* [nr_strings][char *offset of string_0]...[char *offset of string_n-1][char *offset of end of string][string0]...[stringn_1]
|
||||
* if nr_strings == -1, we assume the last item is NULL
|
||||
*
|
||||
* sizes all are longs.
|
||||
*
|
||||
* NOTE: copy this string somewhere, add the address of the string to each offset
|
||||
* and we get back a valid argv or envp array.
|
||||
*
|
||||
* pre_strings is already flattened, so we just need to manage counts and copy
|
||||
* the string part appropriately.
|
||||
*
|
||||
* returns the total length of the flat string and updates flat to
|
||||
* point to the beginning.
|
||||
*/
|
||||
int flatten_strings(int nr_strings, char *first, char **strings, char **flat)
|
||||
int flatten_strings(char *pre_strings, char **strings, char **flat)
|
||||
{
|
||||
int full_len, string_i;
|
||||
unsigned long flat_offset;
|
||||
char *_flat;
|
||||
int full_len, i;
|
||||
int nr_strings;
|
||||
int pre_strings_count = 0;
|
||||
int pre_strings_len = 0;
|
||||
long *_flat;
|
||||
long *pre_strings_flat;
|
||||
char *p;
|
||||
|
||||
/* How many strings do we have? */
|
||||
if (nr_strings == -1) {
|
||||
for (nr_strings = 0; strings[nr_strings]; ++nr_strings);
|
||||
}
|
||||
for (nr_strings = 0; strings[nr_strings]; ++nr_strings)
|
||||
;
|
||||
|
||||
/* Count full length */
|
||||
full_len = sizeof(long) + sizeof(char *); // Counter and terminating NULL
|
||||
if (first) {
|
||||
full_len += sizeof(char *) + strlen(first) + 1;
|
||||
if (pre_strings) {
|
||||
pre_strings_flat = (long *)pre_strings;
|
||||
pre_strings_count = pre_strings_flat[0];
|
||||
|
||||
pre_strings_len = pre_strings_flat[pre_strings_count + 1];
|
||||
pre_strings_len -= sizeof(long) * (pre_strings_count + 2);
|
||||
|
||||
full_len += pre_strings_count * sizeof(long) + pre_strings_len;
|
||||
}
|
||||
|
||||
for (string_i = 0; string_i < nr_strings; ++string_i) {
|
||||
for (i = 0; strings[i]; ++i) {
|
||||
// Pointer + actual value
|
||||
full_len += sizeof(char *) + strlen(strings[string_i]) + 1;
|
||||
full_len += sizeof(char *) + strlen(strings[i]) + 1;
|
||||
}
|
||||
|
||||
full_len = (full_len + sizeof(long) - 1) & ~(sizeof(long) - 1);
|
||||
|
||||
_flat = (char *)malloc(full_len);
|
||||
_flat = malloc(full_len);
|
||||
if (!_flat) {
|
||||
return 0;
|
||||
}
|
||||
@ -992,28 +1080,32 @@ int flatten_strings(int nr_strings, char *first, char **strings, char **flat)
|
||||
memset(_flat, 0, full_len);
|
||||
|
||||
/* Number of strings */
|
||||
*((long *)_flat) = nr_strings + (first ? 1 : 0);
|
||||
_flat[0] = nr_strings + pre_strings_count;
|
||||
|
||||
// Actual offset
|
||||
flat_offset = sizeof(long) + sizeof(char *) * (nr_strings + 1 +
|
||||
(first ? 1 : 0));
|
||||
p = (char *)(_flat + nr_strings + pre_strings_count + 2);
|
||||
|
||||
if (first) {
|
||||
*((char **)(_flat + sizeof(long))) = (void *)flat_offset;
|
||||
memcpy(_flat + flat_offset, first, strlen(first) + 1);
|
||||
flat_offset += strlen(first) + 1;
|
||||
if (pre_strings) {
|
||||
for (i = 0; i < pre_strings_count; i++) {
|
||||
_flat[i + 1] = pre_strings_flat[i + 1] +
|
||||
nr_strings * sizeof(long);
|
||||
}
|
||||
memcpy(p, pre_strings + pre_strings_flat[1],
|
||||
pre_strings_len);
|
||||
p += pre_strings_len;
|
||||
}
|
||||
|
||||
for (string_i = 0; string_i < nr_strings; ++string_i) {
|
||||
|
||||
/* Fabricate the string */
|
||||
*((char **)(_flat + sizeof(long) + (string_i + (first ? 1 : 0))
|
||||
* sizeof(char *))) = (void *)flat_offset;
|
||||
memcpy(_flat + flat_offset, strings[string_i], strlen(strings[string_i]) + 1);
|
||||
flat_offset += strlen(strings[string_i]) + 1;
|
||||
}
|
||||
for (i = 0; i < nr_strings; ++i) {
|
||||
int len = strlen(strings[i]) + 1;
|
||||
|
||||
*flat = _flat;
|
||||
_flat[i + pre_strings_count + 1] = p - (char *)_flat;
|
||||
|
||||
memcpy(p, strings[i], len);
|
||||
p += len;
|
||||
}
|
||||
_flat[nr_strings + pre_strings_count + 1] = p - (char *)_flat;
|
||||
|
||||
*flat = (char *)_flat;
|
||||
return full_len;
|
||||
}
|
||||
|
||||
@ -1325,7 +1417,7 @@ static int reduce_stack(struct rlimit *orig_rlim, char *argv[])
|
||||
{
|
||||
int n;
|
||||
char newval[40];
|
||||
char path[1024];
|
||||
char path[PATH_MAX];
|
||||
int error;
|
||||
struct rlimit new_rlim;
|
||||
|
||||
@ -1477,8 +1569,7 @@ static int find_mount_prefix(char *prefix)
|
||||
}
|
||||
}
|
||||
|
||||
if (line)
|
||||
free(line);
|
||||
free(line);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2013,7 +2104,6 @@ int main(int argc, char **argv)
|
||||
struct program_load_desc *desc;
|
||||
int envs_len;
|
||||
char *envs;
|
||||
char *args;
|
||||
char *p;
|
||||
int i;
|
||||
int error;
|
||||
@ -2021,9 +2111,8 @@ int main(int argc, char **argv)
|
||||
unsigned long lmax;
|
||||
int target_core = 0;
|
||||
int opt;
|
||||
char path[1024];
|
||||
char *shell = NULL;
|
||||
char shell_path[1024];
|
||||
char **shebang_argv = NULL;
|
||||
char *shebang_argv_flat = NULL;
|
||||
int num = 0;
|
||||
int persona;
|
||||
#ifdef ADD_ENVS_OPTION
|
||||
@ -2056,6 +2145,8 @@ int main(int argc, char **argv)
|
||||
/* Disable address space layout randomization */
|
||||
__dprintf("persona=%08x\n", persona);
|
||||
if ((persona & (PER_LINUX | ADDR_NO_RANDOMIZE)) == 0) {
|
||||
char path[PATH_MAX];
|
||||
|
||||
CHKANDJUMP(getenv("MCEXEC_ADDR_NO_RANDOMIZE"), 1, "personality() and then execv() failed\n");
|
||||
|
||||
persona = personality(persona | PER_LINUX | ADDR_NO_RANDOMIZE);
|
||||
@ -2209,7 +2300,7 @@ int main(int argc, char **argv)
|
||||
#ifdef ADD_ENVS_OPTION
|
||||
#else /* ADD_ENVS_OPTION */
|
||||
/* Collect environment variables */
|
||||
envs_len = flatten_strings(-1, NULL, environ, &envs);
|
||||
envs_len = flatten_strings(NULL, environ, &envs);
|
||||
#endif /* ADD_ENVS_OPTION */
|
||||
|
||||
#ifdef ENABLE_MCOVERLAYFS
|
||||
@ -2329,32 +2420,8 @@ int main(int argc, char **argv)
|
||||
__dprintf("mcoverlay disable\n");
|
||||
#endif // ENABLE_MCOVERLAYFS
|
||||
|
||||
if (lookup_exec_path(argv[optind], path, sizeof(path), 1) != 0) {
|
||||
fprintf(stderr, "error: finding file: %s\n", argv[optind]);
|
||||
if (load_elf_desc_shebang(argv[optind], &desc, &shebang_argv))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (load_elf_desc(path, &desc, &shell) != 0) {
|
||||
fprintf(stderr, "error: loading file: %s\n", argv[optind]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check whether shell script */
|
||||
if (shell) {
|
||||
if (lookup_exec_path(shell, shell_path, sizeof(shell_path), 0) != 0) {
|
||||
fprintf(stderr, "error: finding file: %s\n", shell);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (load_elf_desc(shell_path, &desc, &shell) != 0) {
|
||||
fprintf(stderr, "error: loading file: %s\n", shell);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (shell) {
|
||||
argv[optind] = path;
|
||||
}
|
||||
|
||||
#ifdef ADD_ENVS_OPTION
|
||||
/* Collect environment variables */
|
||||
@ -2362,7 +2429,7 @@ int main(int argc, char **argv)
|
||||
add_env_list(&extra_env, environ[i]);
|
||||
}
|
||||
local_env = create_local_environ(extra_env);
|
||||
envs_len = flatten_strings(-1, NULL, local_env, &envs);
|
||||
envs_len = flatten_strings(NULL, local_env, &envs);
|
||||
destroy_local_environ(local_env);
|
||||
local_env = NULL;
|
||||
destroy_env_list(extra_env);
|
||||
@ -2375,9 +2442,14 @@ int main(int argc, char **argv)
|
||||
desc->envs = envs;
|
||||
//print_flat(envs);
|
||||
|
||||
desc->args_len = flatten_strings(-1, shell, argv + optind, &args);
|
||||
desc->args = args;
|
||||
//print_flat(args);
|
||||
if (shebang_argv)
|
||||
flatten_strings(NULL, shebang_argv, &shebang_argv_flat);
|
||||
|
||||
desc->args_len = flatten_strings(shebang_argv_flat, argv + optind,
|
||||
&desc->args);
|
||||
//print_flat(desc->args);
|
||||
free(shebang_argv);
|
||||
free(shebang_argv_flat);
|
||||
|
||||
desc->cpu = target_core;
|
||||
desc->enable_vdso = enable_vdso;
|
||||
@ -3641,85 +3713,80 @@ fork_err:
|
||||
switch (w.sr.args[0]) {
|
||||
struct program_load_desc *desc;
|
||||
struct remote_transfer trans;
|
||||
char path[1024];
|
||||
char *filename;
|
||||
char **shebang_argv;
|
||||
char *shebang_argv_flat;
|
||||
char *buffer;
|
||||
size_t size;
|
||||
int ret;
|
||||
char *shell;
|
||||
char shell_path[1024];
|
||||
|
||||
/* Load descriptor phase */
|
||||
case 1:
|
||||
|
||||
shell = NULL;
|
||||
shebang_argv = NULL;
|
||||
buffer = NULL;
|
||||
filename = (char *)w.sr.args[1];
|
||||
|
||||
if ((ret = lookup_exec_path(filename, path, sizeof(path), 0))
|
||||
!= 0) {
|
||||
if ((ret = load_elf_desc_shebang(filename, &desc,
|
||||
&shebang_argv)) != 0) {
|
||||
goto return_execve1;
|
||||
}
|
||||
|
||||
if ((ret = load_elf_desc(path, &desc, &shell)) != 0) {
|
||||
fprintf(stderr,
|
||||
"execve(): error loading ELF for file %s\n", path);
|
||||
goto return_execve1;
|
||||
}
|
||||
|
||||
/* Check whether shell script */
|
||||
if (shell) {
|
||||
if ((ret = lookup_exec_path(shell, shell_path,
|
||||
sizeof(shell_path), 0)) != 0) {
|
||||
fprintf(stderr, "execve(): error: finding file: %s\n", shell);
|
||||
goto return_execve1;
|
||||
}
|
||||
|
||||
if ((ret = load_elf_desc(shell_path, &desc, &shell))
|
||||
!= 0) {
|
||||
fprintf(stderr, "execve(): error: loading file: %s\n", shell);
|
||||
goto return_execve1;
|
||||
}
|
||||
|
||||
if (strlen(shell) >= SHELL_PATH_MAX_LEN) {
|
||||
fprintf(stderr, "execve(): error: shell path too long: %s\n", shell_path);
|
||||
ret = ENAMETOOLONG;
|
||||
goto return_execve1;
|
||||
}
|
||||
|
||||
/* Let the LWK know the shell interpreter */
|
||||
strcpy(desc->shell_path, shell);
|
||||
}
|
||||
|
||||
desc->enable_vdso = enable_vdso;
|
||||
__dprintf("execve(): load_elf_desc() for %s OK, num sections: %d\n",
|
||||
path, desc->num_sections);
|
||||
filename, desc->num_sections);
|
||||
|
||||
desc->rlimit[MCK_RLIMIT_STACK].rlim_cur = rlim_stack.rlim_cur;
|
||||
desc->rlimit[MCK_RLIMIT_STACK].rlim_max = rlim_stack.rlim_max;
|
||||
desc->stack_premap = stack_premap;
|
||||
|
||||
buffer = (char *)desc;
|
||||
size = sizeof(struct program_load_desc) +
|
||||
sizeof(struct program_image_section) *
|
||||
desc->num_sections;
|
||||
if (shebang_argv) {
|
||||
desc->args_len = flatten_strings(NULL, shebang_argv,
|
||||
&shebang_argv_flat);
|
||||
buffer = malloc(size + desc->args_len);
|
||||
if (!buffer) {
|
||||
fprintf(stderr,
|
||||
"execve(): could not alloc transfer buffer for file %s\n",
|
||||
filename);
|
||||
free(shebang_argv_flat);
|
||||
ret = ENOMEM;
|
||||
goto return_execve1;
|
||||
}
|
||||
memcpy(buffer, desc, size);
|
||||
memcpy(buffer + size, shebang_argv_flat,
|
||||
desc->args_len);
|
||||
free(shebang_argv_flat);
|
||||
size += desc->args_len;
|
||||
}
|
||||
|
||||
/* Copy descriptor to co-kernel side */
|
||||
trans.userp = (void*)desc;
|
||||
trans.userp = buffer;
|
||||
trans.rphys = w.sr.args[2];
|
||||
trans.size = sizeof(struct program_load_desc) +
|
||||
sizeof(struct program_image_section) *
|
||||
desc->num_sections;
|
||||
trans.size = size;
|
||||
trans.direction = MCEXEC_UP_TRANSFER_TO_REMOTE;
|
||||
|
||||
if (ioctl(fd, MCEXEC_UP_TRANSFER, &trans) != 0) {
|
||||
fprintf(stderr,
|
||||
"execve(): error transfering ELF for file %s\n",
|
||||
(char *)w.sr.args[1]);
|
||||
filename);
|
||||
ret = -errno;
|
||||
goto return_execve1;
|
||||
}
|
||||
|
||||
__dprintf("execve(): load_elf_desc() for %s OK\n",
|
||||
path);
|
||||
filename);
|
||||
|
||||
/* We can't be sure next phase will succeed */
|
||||
/* TODO: what shall we do with fp in desc?? */
|
||||
free(desc);
|
||||
|
||||
ret = 0;
|
||||
return_execve1:
|
||||
/* We can't be sure next phase will succeed */
|
||||
/* TODO: what shall we do with fp in desc?? */
|
||||
if (buffer != (char *)desc)
|
||||
free(buffer);
|
||||
free(desc);
|
||||
|
||||
do_syscall_return(fd, cpu, ret, 0, 0, 0, 0);
|
||||
break;
|
||||
|
||||
|
||||
@ -78,7 +78,6 @@ int prepare_process_ranges_args_envs(struct thread *thread,
|
||||
unsigned long args_envs_p, args_envs_rp;
|
||||
unsigned long s, e, up;
|
||||
char **argv;
|
||||
char **a;
|
||||
int i, n, argc, envc, args_envs_npages;
|
||||
char **env;
|
||||
int range_npages;
|
||||
@ -370,21 +369,18 @@ int prepare_process_ranges_args_envs(struct thread *thread,
|
||||
__FUNCTION__,
|
||||
proc->saved_cmdline);
|
||||
|
||||
for (a = argv; *a; a++) {
|
||||
*a = (char *)addr + (unsigned long)*a; // Process' address space!
|
||||
for (i = 0; i < argc; i++) {
|
||||
// Process' address space!
|
||||
argv[i] = (char *)addr + (unsigned long)argv[i];
|
||||
}
|
||||
|
||||
envc = *((long *)(args_envs + p->args_len));
|
||||
dkprintf("envc: %d\n", envc);
|
||||
|
||||
env = (char **)(args_envs + p->args_len + sizeof(long));
|
||||
while (*env) {
|
||||
char **_env = env;
|
||||
//dkprintf("%s\n", args_envs + p->args_len + (unsigned long)*env);
|
||||
*env = (char *)addr + p->args_len + (unsigned long)*env;
|
||||
env = ++_env;
|
||||
for (i = 0; i < envc; i++) {
|
||||
env[i] = addr + p->args_len + env[i];
|
||||
}
|
||||
env = (char **)(args_envs + p->args_len + sizeof(long));
|
||||
|
||||
dkprintf("env OK\n");
|
||||
|
||||
|
||||
@ -204,7 +204,6 @@ struct program_load_desc {
|
||||
int uti_use_last_cpu; /* Work-around not to share CPU with OpenMP thread */
|
||||
int nr_processes;
|
||||
int process_rank;
|
||||
char shell_path[SHELL_PATH_MAX_LEN];
|
||||
__cpu_set_unit cpu_set[PLD_CPU_SET_SIZE];
|
||||
int profile;
|
||||
struct program_image_section sections[0];
|
||||
|
||||
@ -2496,13 +2496,16 @@ SYSCALL_DECLARE(execve)
|
||||
dkprintf("execve(): ELF desc received, num sections: %d\n",
|
||||
desc->num_sections);
|
||||
|
||||
if (desc->shell_path[0]) {
|
||||
dkprintf("execve(): shell interpreter: %s\n", desc->shell_path);
|
||||
/* for shebang script we get extra argvs from mcexec */
|
||||
if (desc->args_len) {
|
||||
desc->args = ((char *)desc) + sizeof(struct program_load_desc) +
|
||||
sizeof(struct program_image_section) *
|
||||
desc->num_sections;
|
||||
}
|
||||
|
||||
/* Flatten argv and envp into kernel-space buffers */
|
||||
argv_flat_len = flatten_strings_from_user(-1, (desc->shell_path[0] ?
|
||||
desc->shell_path : NULL), argv, &argv_flat);
|
||||
argv_flat_len = flatten_strings_from_user(desc->args, argv,
|
||||
&argv_flat);
|
||||
if (argv_flat_len < 0) {
|
||||
char *kfilename;
|
||||
int len = strlen_user(filename);
|
||||
@ -2516,8 +2519,10 @@ SYSCALL_DECLARE(execve)
|
||||
ret = argv_flat_len;
|
||||
goto end;
|
||||
}
|
||||
desc->args = NULL;
|
||||
desc->args_len = 0;
|
||||
|
||||
envp_flat_len = flatten_strings_from_user(-1, NULL, envp, &envp_flat);
|
||||
envp_flat_len = flatten_strings_from_user(NULL, envp, &envp_flat);
|
||||
if (envp_flat_len < 0) {
|
||||
char *kfilename;
|
||||
int len = strlen_user(filename);
|
||||
|
||||
@ -47,7 +47,6 @@ extern int sscanf(const char * buf, const char * fmt, ...);
|
||||
extern int scnprintf(char * buf, size_t size, const char *fmt, ...);
|
||||
|
||||
unsigned long strtol(const char *cp, char **endp, unsigned int base);
|
||||
int flatten_strings(int nr_strings, char *first, char **strings, char **flat);
|
||||
int flatten_strings_from_user(int nr_strings, char *first, char **strings, char **flat);
|
||||
int flatten_strings_from_user(char *pre_strings, char **strings, char **flat);
|
||||
|
||||
#endif
|
||||
|
||||
138
lib/string.c
138
lib/string.c
@ -219,79 +219,30 @@ int memcmp(const void *s1, const void *s2, size_t n)
|
||||
|
||||
/*
|
||||
* Flatten out a (char **) string array into the following format:
|
||||
* [nr_strings][char *offset of string_0]...[char *offset of string_n-1][NULL][string0]...[stringn_1]
|
||||
* if nr_strings == -1, we assume the last item is NULL
|
||||
* [nr_strings][char *offset of string_0]...[char *offset of string_n-1][char *offset of end of string][string0]...[stringn_1]
|
||||
*
|
||||
* sizes all are longs.
|
||||
*
|
||||
* NOTE: copy this string somewhere, add the address of the string to each offset
|
||||
* and we get back a valid argv or envp array.
|
||||
*
|
||||
* pre_strings is already flattened, so we just need to manage counts and copy
|
||||
* the string parts appropriately.
|
||||
*
|
||||
* returns the total length of the flat string and updates flat to
|
||||
* point to the beginning.
|
||||
*/
|
||||
int flatten_strings(int nr_strings, char *first, char **strings, char **flat)
|
||||
int flatten_strings_from_user(char *pre_strings, char **strings, char **flat)
|
||||
{
|
||||
int full_len, string_i;
|
||||
unsigned long flat_offset;
|
||||
char *_flat;
|
||||
|
||||
/* How many strings do we have? */
|
||||
if (nr_strings == -1) {
|
||||
for (nr_strings = 0; strings[nr_strings]; ++nr_strings);
|
||||
}
|
||||
|
||||
/* Count full length */
|
||||
full_len = sizeof(long) + sizeof(char *); // Counter and terminating NULL
|
||||
if (first) {
|
||||
full_len += sizeof(char *) + strlen(first) + 1;
|
||||
}
|
||||
|
||||
for (string_i = 0; string_i < nr_strings; ++string_i) {
|
||||
// Pointer + actual value
|
||||
full_len += sizeof(char *) + strlen(strings[string_i]) + 1;
|
||||
}
|
||||
|
||||
full_len = (full_len + sizeof(long) - 1) & ~(sizeof(long) - 1);
|
||||
|
||||
_flat = (char *)kmalloc(full_len, IHK_MC_AP_NOWAIT);
|
||||
if (!_flat) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(_flat, 0, full_len);
|
||||
|
||||
/* Number of strings */
|
||||
*((long *)_flat) = nr_strings + (first ? 1 : 0);
|
||||
|
||||
// Actual offset
|
||||
flat_offset = sizeof(long) + sizeof(char *) * (nr_strings + 1 +
|
||||
(first ? 1 : 0));
|
||||
|
||||
if (first) {
|
||||
*((char **)(_flat + sizeof(long))) = (void *)flat_offset;
|
||||
memcpy(_flat + flat_offset, first, strlen(first) + 1);
|
||||
flat_offset += strlen(first) + 1;
|
||||
}
|
||||
|
||||
for (string_i = 0; string_i < nr_strings; ++string_i) {
|
||||
|
||||
/* Fabricate the string */
|
||||
*((char **)(_flat + sizeof(long) + (string_i + (first ? 1 : 0))
|
||||
* sizeof(char *))) = (void *)flat_offset;
|
||||
memcpy(_flat + flat_offset, strings[string_i], strlen(strings[string_i]) + 1);
|
||||
flat_offset += strlen(strings[string_i]) + 1;
|
||||
}
|
||||
|
||||
*flat = _flat;
|
||||
return full_len;
|
||||
}
|
||||
|
||||
int flatten_strings_from_user(int nr_strings, char *first, char **strings, char **flat)
|
||||
{
|
||||
int full_len, string_i;
|
||||
int full_len, i;
|
||||
int nr_strings = 0;
|
||||
int pre_strings_count = 0;
|
||||
int pre_strings_len = 0;
|
||||
long *_flat;
|
||||
long *pre_strings_flat;
|
||||
char *p;
|
||||
long r;
|
||||
int n, ret;
|
||||
int ret;
|
||||
|
||||
/* When strings is NULL, make array one NULL */
|
||||
if (!strings) {
|
||||
@ -306,35 +257,34 @@ int flatten_strings_from_user(int nr_strings, char *first, char **strings, char
|
||||
}
|
||||
|
||||
/* How many strings do we have? */
|
||||
if (nr_strings == -1) {
|
||||
nr_strings = 0;
|
||||
for (;;) {
|
||||
ret = getlong_user(&r, (void *)(strings + nr_strings));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
for (;;) {
|
||||
ret = getlong_user(&r, (void *)(strings + nr_strings));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (r == 0)
|
||||
break;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
++nr_strings;
|
||||
}
|
||||
++nr_strings;
|
||||
}
|
||||
|
||||
/* Count full length */
|
||||
full_len = sizeof(long) + sizeof(char *); // Counter and terminating NULL
|
||||
if (first) {
|
||||
int len = strlen(first);
|
||||
if (pre_strings) {
|
||||
pre_strings_flat = (long *)pre_strings;
|
||||
pre_strings_count = pre_strings_flat[0];
|
||||
|
||||
if(len < 0)
|
||||
return len;
|
||||
full_len += sizeof(char *) + len + 1;
|
||||
pre_strings_len = pre_strings_flat[pre_strings_count + 1];
|
||||
pre_strings_len -= sizeof(long) * (pre_strings_count + 2);
|
||||
|
||||
full_len += pre_strings_count * sizeof(long) + pre_strings_len;
|
||||
}
|
||||
|
||||
for (string_i = 0; string_i < nr_strings; ++string_i) {
|
||||
for (i = 0; i < nr_strings; ++i) {
|
||||
char *userp;
|
||||
int len;
|
||||
|
||||
ret = getlong_user((long *)&userp, (void *)(strings + string_i));
|
||||
ret = getlong_user((long *)&userp, (void *)(strings + i));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -354,31 +304,33 @@ int flatten_strings_from_user(int nr_strings, char *first, char **strings, char
|
||||
}
|
||||
|
||||
/* Number of strings */
|
||||
n = first? 1: 0;
|
||||
_flat[0] = nr_strings + n;
|
||||
|
||||
// Actual offset
|
||||
p = (char *)(_flat + nr_strings + 2 + n);
|
||||
_flat[0] = nr_strings + pre_strings_count;
|
||||
|
||||
n = 1;
|
||||
if (first) {
|
||||
_flat[n++] = p - (char *)_flat;
|
||||
strcpy(p, first);
|
||||
p = strchr(p, '\0') + 1;
|
||||
// Actual offset
|
||||
p = (char *)(_flat + nr_strings + pre_strings_count + 2);
|
||||
|
||||
if (pre_strings) {
|
||||
for (i = 0; i < pre_strings_count; i++) {
|
||||
_flat[i + 1] = pre_strings_flat[i + 1] +
|
||||
nr_strings * sizeof(long);
|
||||
}
|
||||
memcpy(p, pre_strings + pre_strings_flat[1],
|
||||
pre_strings_len);
|
||||
p += pre_strings_len;
|
||||
}
|
||||
|
||||
for (string_i = 0; string_i < nr_strings; ++string_i) {
|
||||
for (i = 0; i < nr_strings; ++i) {
|
||||
char *userp;
|
||||
_flat[n++] = p - (char *)_flat;
|
||||
_flat[i + pre_strings_count + 1] = p - (char *)_flat;
|
||||
|
||||
ret = getlong_user((long *)&userp, (void *)(strings + string_i));
|
||||
ret = getlong_user((long *)&userp, (void *)(strings + i));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
strcpy_from_user(p, userp);
|
||||
p = strchr(p, '\0') + 1;
|
||||
}
|
||||
_flat[n] = 0;
|
||||
_flat[nr_strings + pre_strings_count + 1] = p - (char *)_flat;
|
||||
|
||||
*flat = (char *)_flat;
|
||||
return full_len;
|
||||
|
||||
Reference in New Issue
Block a user