Author: kib
Date: Wed Mar 18 13:40:37 2009
New Revision: 189959
URL: http://svn.freebsd.org/changeset/base/189959

Log:
  Implement the dynamic string token substitution in the rpath and
  soneeded pathes. The $ORIGIN, $OSNAME, $OSREL and $PLATFORM tokens
  are supported. Enabling the substitution requires DF_ORIGIN flag in
  DT_FLAGS or DF_1_ORIGIN if DF_FLAGS_1, that may be set with -z origin
  gnu ld flag. Translation is unconditionally disabled for setuid/setgid
  processes.
  
  The $ORIGIN translation relies on the AT_EXECPATH auxinfo supplied
  by kernel.
  
  Requested by: maho
  Tested by:    maho, pho
  Reviewed by:  kan

Modified:
  head/libexec/rtld-elf/map_object.c
  head/libexec/rtld-elf/rtld.c
  head/libexec/rtld-elf/rtld.h

Modified: head/libexec/rtld-elf/map_object.c
==============================================================================
--- head/libexec/rtld-elf/map_object.c  Wed Mar 18 13:19:46 2009        
(r189958)
+++ head/libexec/rtld-elf/map_object.c  Wed Mar 18 13:40:37 2009        
(r189959)
@@ -348,6 +348,8 @@ obj_free(Obj_Entry *obj)
        free(obj->vertab);
     if (obj->origin_path)
        free(obj->origin_path);
+    if (obj->z_origin)
+       free(obj->rpath);
     if (obj->priv)
        free(obj->priv);
     if (obj->path)

Modified: head/libexec/rtld-elf/rtld.c
==============================================================================
--- head/libexec/rtld-elf/rtld.c        Wed Mar 18 13:19:46 2009        
(r189958)
+++ head/libexec/rtld-elf/rtld.c        Wed Mar 18 13:40:37 2009        
(r189959)
@@ -41,6 +41,7 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/uio.h>
+#include <sys/utsname.h>
 #include <sys/ktrace.h>
 
 #include <dlfcn.h>
@@ -118,6 +119,7 @@ static void objlist_remove_unref(Objlist
 static void *path_enumerate(const char *, path_enum_proc, void *);
 static int relocate_objects(Obj_Entry *, bool, Obj_Entry *);
 static int rtld_dirname(const char *, char *);
+static int rtld_dirname_abs(const char *, char *);
 static void rtld_exit(void);
 static char *search_library_path(const char *, const char *);
 static const void **get_program_var_addr(const char *);
@@ -134,6 +136,9 @@ static void unlink_object(Obj_Entry *);
 static void unload_object(Obj_Entry *);
 static void unref_dag(Obj_Entry *);
 static void ref_dag(Obj_Entry *);
+static int origin_subst_one(char **res, const char *real, const char *kw,
+  const char *subst, char *may_free);
+static char *origin_subst(const char *real, const char *origin_path);
 static int  rtld_verify_versions(const Objlist *);
 static int  rtld_verify_object_versions(Obj_Entry *);
 static void object_add_name(Obj_Entry *, const char *);
@@ -412,7 +417,25 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
            die();
     }
 
-    obj_main->path = xstrdup(argv0);
+    if (aux_info[AT_EXECPATH] != 0) {
+           char *kexecpath;
+           char buf[MAXPATHLEN];
+
+           kexecpath = aux_info[AT_EXECPATH]->a_un.a_ptr;
+           dbg("AT_EXECPATH %p %s", kexecpath, kexecpath);
+           if (kexecpath[0] == '/')
+                   obj_main->path = kexecpath;
+           else if (getcwd(buf, sizeof(buf)) == NULL ||
+                    strlcat(buf, "/", sizeof(buf)) >= sizeof(buf) ||
+                    strlcat(buf, kexecpath, sizeof(buf)) >= sizeof(buf))
+                   obj_main->path = xstrdup(argv0);
+           else
+                   obj_main->path = xstrdup(buf);
+    } else {
+           dbg("No AT_EXECPATH");
+           obj_main->path = xstrdup(argv0);
+    }
+    dbg("obj_main path %s", obj_main->path);
     obj_main->mainprog = true;
 
     /*
@@ -614,6 +637,83 @@ basename(const char *name)
     return p != NULL ? p + 1 : name;
 }
 
+static struct utsname uts;
+
+static int
+origin_subst_one(char **res, const char *real, const char *kw, const char 
*subst,
+    char *may_free)
+{
+    const char *p, *p1;
+    char *res1;
+    int subst_len;
+    int kw_len;
+
+    res1 = *res = NULL;
+    p = real;
+    subst_len = kw_len = 0;
+    for (;;) {
+        p1 = strstr(p, kw);
+        if (p1 != NULL) {
+            if (subst_len == 0) {
+                subst_len = strlen(subst);
+                kw_len = strlen(kw);
+            }
+            if (*res == NULL) {
+                *res = xmalloc(PATH_MAX);
+                res1 = *res;
+            }
+            if ((res1 - *res) + subst_len + (p1 - p) >= PATH_MAX) {
+                _rtld_error("Substitution of %s in %s cannot be performed",
+                    kw, real);
+                if (may_free != NULL)
+                    free(may_free);
+                free(res);
+                return (false);
+            }
+            memcpy(res1, p, p1 - p);
+            res1 += p1 - p;
+            memcpy(res1, subst, subst_len);
+            res1 += subst_len;
+            p = p1 + kw_len;
+        } else {
+           if (*res == NULL) {
+               if (may_free != NULL)
+                   *res = may_free;
+               else
+                   *res = xstrdup(real);
+               return (true);
+           }
+           *res1 = '\0';
+           if (may_free != NULL)
+               free(may_free);
+           if (strlcat(res1, p, PATH_MAX - (res1 - *res)) >= PATH_MAX) {
+               free(res);
+               return (false);
+           }
+           return (true);
+        }
+    }
+}
+
+static char *
+origin_subst(const char *real, const char *origin_path)
+{
+    char *res1, *res2, *res3, *res4;
+
+    if (uts.sysname[0] == '\0') {
+       if (uname(&uts) != 0) {
+           _rtld_error("utsname failed: %d", errno);
+           return (NULL);
+       }
+    }
+    if (!origin_subst_one(&res1, real, "$ORIGIN", origin_path, NULL) ||
+       !origin_subst_one(&res2, res1, "$OSNAME", uts.sysname, res1) ||
+       !origin_subst_one(&res3, res2, "$OSREL", uts.release, res2) ||
+       !origin_subst_one(&res4, res3, "$PLATFORM", uts.machine, res3))
+           return (NULL);
+    return (res4);
+}
+
 static void
 die(void)
 {
@@ -790,11 +890,8 @@ digest_dynamic(Obj_Entry *obj, int early
 #endif
 
        case DT_FLAGS:
-               if (dynp->d_un.d_val & DF_ORIGIN) {
-                   obj->origin_path = xmalloc(PATH_MAX);
-                   if (rtld_dirname(obj->path, obj->origin_path) == -1)
-                       die();
-               }
+               if ((dynp->d_un.d_val & DF_1_ORIGIN) && trust)
+                   obj->z_origin = true;
                if (dynp->d_un.d_val & DF_SYMBOLIC)
                    obj->symbolic = true;
                if (dynp->d_un.d_val & DF_TEXTREL)
@@ -826,6 +923,15 @@ digest_dynamic(Obj_Entry *obj, int early
                break;
 #endif
 
+       case DT_FLAGS_1:
+               if ((dynp->d_un.d_val & DF_1_ORIGIN) && trust)
+                   obj->z_origin = true;
+               if (dynp->d_un.d_val & DF_1_GLOBAL)
+                       /* XXX */;
+               if (dynp->d_un.d_val & DF_1_BIND_NOW)
+                   obj->bind_now = true;
+           break;
+
        default:
            if (!early) {
                dbg("Ignoring d_tag %ld = %#lx", (long)dynp->d_tag,
@@ -844,8 +950,17 @@ digest_dynamic(Obj_Entry *obj, int early
        obj->pltrelsize = 0;
     }
 
-    if (dyn_rpath != NULL)
-       obj->rpath = obj->strtab + dyn_rpath->d_un.d_val;
+    if (obj->z_origin && obj->origin_path == NULL) {
+       obj->origin_path = xmalloc(PATH_MAX);
+       if (rtld_dirname_abs(obj->path, obj->origin_path) == -1)
+           die();
+    }
+
+    if (dyn_rpath != NULL) {
+       obj->rpath = (char *)obj->strtab + dyn_rpath->d_un.d_val;
+       if (obj->z_origin)
+           obj->rpath = origin_subst(obj->rpath, obj->origin_path);
+    }
 
     if (dyn_soname != NULL)
        object_add_name(obj, obj->strtab + dyn_soname->d_un.d_val);
@@ -1003,7 +1118,10 @@ find_library(const char *xname, const Ob
              xname);
            return NULL;
        }
-       return xstrdup(xname);
+       if (refobj->z_origin)
+           return origin_subst(xname, refobj->origin_path);
+       else
+           return xstrdup(xname);
     }
 
     if (libmap_disable || (refobj == NULL) ||
@@ -2309,6 +2427,23 @@ rtld_dirname(const char *path, char *bna
     return (0);
 }
 
+static int
+rtld_dirname_abs(const char *path, char *base)
+{
+       char base_rel[PATH_MAX];
+
+       if (rtld_dirname(path, base) == -1)
+               return (-1);
+       if (base[0] == '/')
+               return (0);
+       if (getcwd(base_rel, sizeof(base_rel)) == NULL ||
+           strlcat(base_rel, "/", sizeof(base_rel)) >= sizeof(base_rel) ||
+           strlcat(base_rel, base, sizeof(base_rel)) >= sizeof(base_rel))
+               return (-1);
+       strcpy(base, base_rel);
+       return (0);
+}
+
 static void
 linkmap_add(Obj_Entry *obj)
 {

Modified: head/libexec/rtld-elf/rtld.h
==============================================================================
--- head/libexec/rtld-elf/rtld.h        Wed Mar 18 13:19:46 2009        
(r189958)
+++ head/libexec/rtld-elf/rtld.h        Wed Mar 18 13:40:37 2009        
(r189959)
@@ -195,7 +195,7 @@ typedef struct Struct_Obj_Entry {
     const Elf_Hashelt *chains; /* Hash table chain array */
     unsigned long nchains;     /* Number of chains */
 
-    const char *rpath;         /* Search path specified in object */
+    char *rpath;               /* Search path specified in object */
     Needed_Entry *needed;      /* Shared objects needed by this one (%) */
 
     STAILQ_HEAD(, Struct_Name_Entry) names; /* List of names for this object we
@@ -216,6 +216,7 @@ typedef struct Struct_Obj_Entry {
     bool init_done : 1;                /* Already have added object to init 
list */
     bool tls_done : 1;         /* Already allocated offset for static TLS */
     bool phdr_alloc : 1;       /* Phdr is allocated and needs to be freed. */
+    bool z_origin : 1;         /* Process rpath and soname tokens */
 
     struct link_map linkmap;   /* for GDB and dlinfo() */
     Objlist dldags;            /* Object belongs to these dlopened DAGs (%) */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to