From 55aeceb1bf7e08f8f3f513772b45a3706bb8f4cf Mon Sep 17 00:00:00 2001 From: "bgerofi@riken.jp" Date: Thu, 18 Sep 2014 21:19:24 +0900 Subject: [PATCH] execve()/creat(): handle NULL env correctly and support for holding executable file so that write access returns ETXTBSY --- executer/include/uprotocol.h | 3 +- executer/kernel/control.c | 76 ++++++++++++++++++++++++++++++++++-- executer/kernel/driver.c | 3 +- executer/user/mcexec.c | 26 +++++++++++- kernel/syscall.c | 4 +- 5 files changed, 103 insertions(+), 9 deletions(-) diff --git a/executer/include/uprotocol.h b/executer/include/uprotocol.h index ebfd8984..8a9b998b 100644 --- a/executer/include/uprotocol.h +++ b/executer/include/uprotocol.h @@ -42,7 +42,8 @@ #define MCEXEC_UP_PREPARE_DMA 0x30a02910 #define MCEXEC_UP_FREE_DMA 0x30a02911 -#define MCEXEC_UP_TEST_OPEN_EXEC 0x30a02912 +#define MCEXEC_UP_OPEN_EXEC 0x30a02912 +#define MCEXEC_UP_CLOSE_EXEC 0x30a02913 #define MCEXEC_UP_TRANSFER_TO_REMOTE 0 #define MCEXEC_UP_TRANSFER_FROM_REMOTE 1 diff --git a/executer/kernel/control.c b/executer/kernel/control.c index 8aa94a38..9e8ed75e 100644 --- a/executer/kernel/control.c +++ b/executer/kernel/control.c @@ -692,9 +692,22 @@ long mcexec_ret_syscall(ihk_os_t os, struct syscall_ret_desc *__user arg) return 0; } -int mcexec_test_open_exec(ihk_os_t os, char * __user filename) +LIST_HEAD(mckernel_exec_files); +spinlock_t mckernel_exec_file_lock = SPIN_LOCK_UNLOCKED; + + +struct mckernel_exec_file { + ihk_os_t os; + pid_t pid; + struct file *fp; + struct list_head list; +}; + +int mcexec_open_exec(ihk_os_t os, char * __user filename) { struct file *file; + struct mckernel_exec_file *mcef; + struct mckernel_exec_file *mcef_iter; int retval; file = open_exec(filename); @@ -703,13 +716,65 @@ int mcexec_test_open_exec(ihk_os_t os, char * __user filename) goto out_return; } - retval = 0; + mcef = kmalloc(sizeof(*mcef), GFP_KERNEL); + if (!mcef) { + retval = ENOMEM; + goto out_put_file; + } + + spin_lock_irq(&mckernel_exec_file_lock); + /* Find previous file (if exists) and drop it */ + list_for_each_entry(mcef_iter, &mckernel_exec_files, list) { + if (mcef_iter->os == os && mcef_iter->pid == current->tgid) { + allow_write_access(mcef_iter->fp); + fput(mcef_iter->fp); + list_del(&mcef_iter->list); + kfree(mcef_iter); + dprintk("%d open_exec dropped previous executable \n", (int)current->tgid); + break; + } + } + + /* Add new exec file to the list */ + mcef->os = os; + mcef->pid = current->tgid; + mcef->fp = file; + list_add_tail(&mcef->list, &mckernel_exec_files); + spin_unlock(&mckernel_exec_file_lock); + + dprintk("%d open_exec and holding file: %s\n", (int)current->tgid, filename); + return 0; + +out_put_file: fput(file); out_return: return -retval; } + +int mcexec_close_exec(ihk_os_t os) +{ + struct mckernel_exec_file *mcef = NULL; + int found = 0; + + spin_lock_irq(&mckernel_exec_file_lock); + list_for_each_entry(mcef, &mckernel_exec_files, list) { + if (mcef->os == os && mcef->pid == current->tgid) { + allow_write_access(mcef->fp); + fput(mcef->fp); + list_del(&mcef->list); + kfree(mcef); + found = 1; + dprintk("%d close_exec dropped executable \n", (int)current->tgid); + break; + } + } + spin_unlock(&mckernel_exec_file_lock); + + return (found ? 0 : EINVAL); +} + long mcexec_strncpy_from_user(ihk_os_t os, struct strncpy_from_user_desc * __user arg) { struct strncpy_from_user_desc desc; @@ -793,8 +858,11 @@ long __mcctrl_control(ihk_os_t os, unsigned int req, unsigned long arg) return mcexec_strncpy_from_user(os, (struct strncpy_from_user_desc *)arg); - case MCEXEC_UP_TEST_OPEN_EXEC: - return mcexec_test_open_exec(os, (char *)arg); + case MCEXEC_UP_OPEN_EXEC: + return mcexec_open_exec(os, (char *)arg); + + case MCEXEC_UP_CLOSE_EXEC: + return mcexec_close_exec(os); case MCEXEC_UP_PREPARE_DMA: return mcexec_pin_region(os, (unsigned long *)arg); diff --git a/executer/kernel/driver.c b/executer/kernel/driver.c index 6707d340..fc0f6af1 100644 --- a/executer/kernel/driver.c +++ b/executer/kernel/driver.c @@ -57,7 +57,8 @@ static struct ihk_os_user_call_handler mcctrl_uchs[] = { { .request = MCEXEC_UP_STRNCPY_FROM_USER, .func = mcctrl_ioctl }, { .request = MCEXEC_UP_PREPARE_DMA, .func = mcctrl_ioctl }, { .request = MCEXEC_UP_FREE_DMA, .func = mcctrl_ioctl }, - { .request = MCEXEC_UP_TEST_OPEN_EXEC, .func = mcctrl_ioctl }, + { .request = MCEXEC_UP_OPEN_EXEC, .func = mcctrl_ioctl }, + { .request = MCEXEC_UP_CLOSE_EXEC, .func = mcctrl_ioctl }, }; static struct ihk_os_user_call mcctrl_uc_proto = { diff --git a/executer/user/mcexec.c b/executer/user/mcexec.c index d8b21299..1822674a 100644 --- a/executer/user/mcexec.c +++ b/executer/user/mcexec.c @@ -352,7 +352,7 @@ retry: if (strncmp(filename, "/", 1)) { /* Is filename a single component without path? */ - if (strncmp(filename, ".", 1) && !strchr(filename, '/')) { + while (strncmp(filename, ".", 1) && !strchr(filename, '/')) { char *token, *string, *tofree; char *PATH = getenv("COKERNEL_PATH"); @@ -363,6 +363,21 @@ retry: if (strlen(filename) >= 255) { return ENAMETOOLONG; } + + /* See first whether file is available in current working dir */ + error = access(filename, X_OK); + if (error == 0) { + __dprintf("lookup_exec_path(): found %s in cwd\n", filename); + error = snprintf(path, max_len, "%s", filename); + + if (error < 0 || error >= max_len) { + fprintf(stderr, "lookup_exec_path(): array too small?\n"); + return ENOMEM; + } + + found = 1; + break; + } __dprintf("PATH: %s\n", PATH); @@ -390,6 +405,7 @@ retry: } free(tofree); + break; } /* Not in path, file to be open from the working directory */ @@ -520,7 +536,7 @@ int load_elf_desc(char *filename, struct program_load_desc **desc_p, rewind(fp); - if ((ret = ioctl(fd, MCEXEC_UP_TEST_OPEN_EXEC, filename)) != 0) { + if ((ret = ioctl(fd, MCEXEC_UP_OPEN_EXEC, filename)) != 0) { fprintf(stderr, "Error: open_exec() fails for %s: %d (fd: %d)\n", filename, ret, fd); return ret; @@ -1392,6 +1408,12 @@ int main_loop(int fd, int cpu, pthread_mutex_t *lock, int mcosid) case __NR_exit_group: sig = 0; term = 0; + + /* Drop executable file */ + if ((ret = ioctl(fd, MCEXEC_UP_CLOSE_EXEC)) != 0) { + fprintf(stderr, "WARNING: close_exec() couldn't find exec file?\n"); + } + do_syscall_return(fd, cpu, 0, 0, 0, 0, 0); __dprintf("__NR_exit/__NR_exit_group: %ld (cpu_id: %d)\n", diff --git a/kernel/syscall.c b/kernel/syscall.c index c8f4f588..87d7132e 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -1244,9 +1244,11 @@ SYSCALL_DECLARE(arch_prctl) SYSCALL_DECLARE(execve) { long ret; + char *empty_envp[1] = {NULL}; const char *filename = (const char *)ihk_mc_syscall_arg0(ctx); char **argv = (char **)ihk_mc_syscall_arg1(ctx); - char **envp = (char **)ihk_mc_syscall_arg2(ctx); + char **envp = (char **)ihk_mc_syscall_arg2(ctx) ? + (char **)ihk_mc_syscall_arg2(ctx) : empty_envp; char *argv_flat = NULL; int argv_flat_len = 0;