From 09aebf9c9a092021c315d9e18a95e9c5b897b8f3 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 26 May 2013 11:14:23 -0500 Subject: [PATCH 07/23] bsd-user: find target executable in path when absolute path not given To: Cc: If the target executable's path is not absolute then this code will search the PATH to find it. Save the fullpath to put on to the stack for the runtime linker. Signed-off-by: Stacey Son --- bsd-user/bsdload.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++-- bsd-user/qemu.h | 3 +- 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c index cc4f534..c768855 100644 --- a/bsd-user/bsdload.c +++ b/bsd-user/bsdload.c @@ -169,19 +169,95 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, return sp; } +static int is_there(const char *candidate) +{ + struct stat fin; + + /* XXX work around access(2) false positives for superuser */ + if (access(candidate, X_OK) == 0 && stat(candidate, &fin) == 0 && + S_ISREG(fin.st_mode) && (getuid() != 0 || + (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) { + return 1; + } + + return 0; +} + +static int find_in_path(char *path, const char *filename, char *retpath, + size_t rpsize) +{ + const char *d; + int found; + + if (strchr(filename, '/') != NULL) { + if (is_there(filename)) { + if (!realpath(filename, retpath)) { + return -1; + } + return 0; + } else { + return -1; + } + } + + found = 0; + while ((d = strsep(&path, ":")) != NULL) { + if (*d == '\0') { + d = "."; + } + if (snprintf(retpath, rpsize, "%s/%s", d, filename) >= (int)rpsize) { + continue; + } + if (is_there((const char *)retpath)) { + found = 1; + break; + } + } + return found; +} + int loader_exec(const char * filename, char ** argv, char ** envp, struct target_pt_regs *regs, struct image_info *infop, struct bsd_binprm *bprm) { - int retval; - int i; + char *p, *path = NULL, fullpath[PATH_MAX]; + const char *execname = NULL; + int retval, i; - bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); + bprm->p = TARGET_PAGE_SIZE * MAX_ARG_PAGES; /* -sizeof(unsigned int); */ for (i=0 ; ipage[i] = NULL; - retval = open(filename, O_RDONLY); + + /* Find target executable in path, if not already an absolute path. */ + p = getenv("PATH"); + if (p != NULL) { + path = g_strdup(p); + if (path == NULL) { + fprintf(stderr, "Out of memory\n"); + return -1; + } + execname = realpath(filename, NULL); + if (execname == NULL) { + execname = filename; + } + if (!find_in_path(path, execname, fullpath, sizeof(fullpath))) { + retval = open(fullpath, O_RDONLY); + bprm->fullpath = g_strdup(fullpath); + } else { + retval = open(execname, O_RDONLY); + bprm->fullpath = NULL; + } + if (execname) { + free((void *)execname); + } + free(path); + } else { + retval = open(filename, O_RDONLY); + bprm->fullpath = NULL; + } if (retval < 0) return retval; + bprm->fd = retval; bprm->filename = (char *)filename; bprm->argc = count(argv); diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index a36e9d2..1e2abd5 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -128,7 +128,8 @@ struct bsd_binprm { int argc, envc; char **argv; char **envp; - char *filename; /* Name of binary */ + char *filename; /* (Given) Name of binary */ + char *fullpath; /* Full path of binary */ int (*core_dump)(int, const CPUArchState *); }; -- 1.7.8