Patchwork [07/23] bsd-user: find target executable in path when absolute path not given

login
register
mail settings
Submitter Stacey Son
Date June 24, 2013, 2:03 a.m.
Message ID <1372039435-41921-8-git-send-email-sson@FreeBSD.org>
Download mbox | patch
Permalink /patch/253943/
State New
Headers show

Comments

Stacey Son - June 24, 2013, 2:03 a.m.
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 <sson@FreeBSD.org>
---
 bsd-user/bsdload.c |   84 +++++++++++++++++++++++++++++++++++++++++++++++++--
 bsd-user/qemu.h    |    3 +-
 2 files changed, 82 insertions(+), 5 deletions(-)

Patch

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 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
             bprm->page[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 *);
 };