Index: libexec/rtld-elf/map_object.c =================================================================== --- libexec/rtld-elf/map_object.c (revision 199998) +++ libexec/rtld-elf/map_object.c (working copy) @@ -348,6 +348,8 @@ 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) Index: libexec/rtld-elf/rtld.c =================================================================== --- libexec/rtld-elf/rtld.c (revision 199998) +++ libexec/rtld-elf/rtld.c (working copy) @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -118,6 +119,7 @@ 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 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 *); @@ -419,7 +424,25 @@ 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; /* @@ -621,6 +644,83 @@ 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 @@ break; 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_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) @@ -805,6 +902,15 @@ ; break; + 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, @@ -823,9 +929,18 @@ 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); } @@ -982,7 +1097,10 @@ xname); return NULL; } - return xstrdup(xname); + if (refobj != NULL && refobj->z_origin) + return origin_subst(xname, refobj->origin_path); + else + return xstrdup(xname); } if (libmap_disable || (refobj == NULL) || @@ -2295,6 +2413,23 @@ 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) { Index: libexec/rtld-elf/rtld.h =================================================================== --- libexec/rtld-elf/rtld.h (revision 199998) +++ libexec/rtld-elf/rtld.h (working copy) @@ -190,7 +190,7 @@ 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 @@ -211,6 +211,7 @@ 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 (%) */ Index: sys/arm/include/elf.h =================================================================== --- sys/arm/include/elf.h (revision 199998) +++ sys/arm/include/elf.h (working copy) @@ -70,17 +70,14 @@ #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -#define AT_BRK 10 /* Starting point for sbrk and brk. */ -#define AT_DEBUG 11 /* Debugging level. */ - #define AT_NOTELF 10 /* Program is not ELF ?? */ #define AT_UID 11 /* Real uid. */ #define AT_EUID 12 /* Effective uid. */ #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ +#define AT_EXECPATH 15 /* Path to the executable. */ -#define AT_COUNT 15 /* Count of defined aux entry types. */ +#define AT_COUNT 16 /* Count of defined aux entry types. */ #define R_ARM_COUNT 33 /* Count of defined relocation types. */ Index: sys/powerpc/include/elf.h =================================================================== --- sys/powerpc/include/elf.h (revision 199998) +++ sys/powerpc/include/elf.h (working copy) @@ -77,12 +77,10 @@ #define AT_DCACHEBSIZE 10 /* Data cache block size for the processor. */ #define AT_ICACHEBSIZE 11 /* Instruction cache block size for the uP. */ #define AT_UCACHEBSIZE 12 /* Cache block size, or `0' if cache not unified. */ +#define AT_EXECPATH 13 /* Path to the executable. */ -#define AT_COUNT 13 /* Count of defined aux entry types. */ +#define AT_COUNT 14 /* Count of defined aux entry types. */ -/* Used in John Polstra's testbed stuff. */ -#define AT_DEBUG 14 /* Debugging level. */ - /* * Relocation types. */ Index: sys/sparc64/include/elf.h =================================================================== --- sys/sparc64/include/elf.h (revision 199998) +++ sys/sparc64/include/elf.h (working copy) @@ -78,28 +78,14 @@ #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -/* - * The following non-standard values are used for passing information - * from John Polstra's testbed program to the dynamic linker. These - * are expected to go away soon. - * - * Unfortunately, these overlap the Linux non-standard values, so they - * must not be used in the same context. - */ -#define T_BRK 10 /* Starting point for sbrk and brk. */ -#define AT_DEBUG 11 /* Debugging level. */ - -/* - * The following non-standard values are used in Linux ELF binaries. - */ #define AT_NOTELF 10 /* Program is not ELF ?? */ #define AT_UID 11 /* Real uid. */ #define AT_EUID 12 /* Effective uid. */ #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ +#define AT_EXECPATH 15 /* Path to the executable. */ -#define AT_COUNT 15 /* Count of defined aux entry types. */ +#define AT_COUNT 16 /* Count of defined aux entry types. */ /* Define "machine" characteristics */ #if __ELF_WORD_SIZE == 32 Index: sys/kern/imgact_elf.c =================================================================== --- sys/kern/imgact_elf.c (revision 199998) +++ sys/kern/imgact_elf.c (working copy) @@ -943,9 +943,6 @@ base = (Elf_Addr *)*stack_base; pos = base + (imgp->args->argc + imgp->args->envc + 2); - if (args->trace) { - AUXARGS_ENTRY(pos, AT_DEBUG, 1); - } if (args->execfd != -1) { AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); } @@ -956,6 +953,8 @@ AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); AUXARGS_ENTRY(pos, AT_BASE, args->base); + if (imgp->execpathp != 0) + AUXARGS_ENTRY(pos, AT_EXECPATH, imgp->execpathp); AUXARGS_ENTRY(pos, AT_NULL, 0); free(imgp->auxargs, M_TEMP); Index: sys/kern/kern_exec.c =================================================================== --- sys/kern/kern_exec.c (revision 199998) +++ sys/kern/kern_exec.c (working copy) @@ -360,6 +360,8 @@ imgp->ps_strings = 0; imgp->auxarg_size = 0; imgp->args = args; + imgp->execpath = imgp->freepath = NULL; + imgp->execpathp = 0; #ifdef MAC error = mac_execve_enter(imgp, mac_p); @@ -486,6 +488,10 @@ * of the sv_copyout_strings/sv_fixup operations require the vnode. */ VOP_UNLOCK(imgp->vp, 0, td); + + if (imgp->auxargs != NULL) + vn_fullpath(td, imgp->vp, &imgp->execpath, &imgp->freepath); + /* * Copy out strings (args and env) and initialize stack base */ @@ -814,6 +820,8 @@ if (imgp->object != NULL) vm_object_deallocate(imgp->object); + free(imgp->freepath, M_TEMP); + if (error == 0) { /* * Stop the process here if its stop event mask has @@ -1125,18 +1133,24 @@ register_t *stack_base; struct ps_strings *arginfo; struct proc *p; + size_t execpath_len; int szsigcode; /* * Calculate string base and vector table pointers. * Also deal with signal trampoline code for this exec type. */ + if (imgp->execpath != NULL && imgp->auxargs != NULL) + execpath_len = strlen(imgp->execpath) + 1; + else + execpath_len = 0; p = imgp->proc; szsigcode = 0; arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings; if (p->p_sysent->sv_szsigcode != NULL) szsigcode = *(p->p_sysent->sv_szsigcode); destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE - + roundup(execpath_len, sizeof(char *)) - roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); /* @@ -1147,6 +1161,15 @@ szsigcode), szsigcode); /* + * Copy the image path for the rtld. + */ + if (execpath_len != 0) { + imgp->execpathp = (uintptr_t)arginfo - szsigcode - execpath_len; + copyout(imgp->execpath, (void *)imgp->execpathp, + execpath_len); + } + + /* * If we have a valid auxargs ptr, prepare some room * on the stack. */ @@ -1163,9 +1186,8 @@ * for argument of Runtime loader. */ vectp = (char **)(destp - (imgp->args->argc + - imgp->args->envc + 2 + imgp->auxarg_size) * + imgp->args->envc + 2 + imgp->auxarg_size + execpath_len) * sizeof(char *)); - } else { /* * The '+ 2' is for the null pointers at the end of each of Index: sys/ia64/include/elf.h =================================================================== --- sys/ia64/include/elf.h (revision 199998) +++ sys/ia64/include/elf.h (working copy) @@ -82,28 +82,14 @@ #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused for i386). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -/* - * The following non-standard values are used for passing information - * from John Polstra's testbed program to the dynamic linker. These - * are expected to go away soon. - * - * Unfortunately, these overlap the Linux non-standard values, so they - * must not be used in the same context. - */ -#define AT_BRK 10 /* Starting point for sbrk and brk. */ -#define AT_DEBUG 11 /* Debugging level. */ - -/* - * The following non-standard values are used in Linux ELF binaries. - */ #define AT_NOTELF 10 /* Program is not ELF ?? */ #define AT_UID 11 /* Real uid. */ #define AT_EUID 12 /* Effective uid. */ #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ +#define AT_EXECPATH 15 /* Path to the executable. */ -#define AT_COUNT 15 /* Count of defined aux entry types. */ +#define AT_COUNT 16 /* Count of defined aux entry types. */ /* * Values for e_flags. Index: sys/sun4v/include/elf.h =================================================================== --- sys/sun4v/include/elf.h (revision 199998) +++ sys/sun4v/include/elf.h (working copy) @@ -78,28 +78,14 @@ #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -/* - * The following non-standard values are used for passing information - * from John Polstra's testbed program to the dynamic linker. These - * are expected to go away soon. - * - * Unfortunately, these overlap the Linux non-standard values, so they - * must not be used in the same context. - */ -#define T_BRK 10 /* Starting point for sbrk and brk. */ -#define AT_DEBUG 11 /* Debugging level. */ - -/* - * The following non-standard values are used in Linux ELF binaries. - */ #define AT_NOTELF 10 /* Program is not ELF ?? */ #define AT_UID 11 /* Real uid. */ #define AT_EUID 12 /* Effective uid. */ #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ +#define AT_EXECPATH 15 /* Path to the executable. */ -#define AT_COUNT 15 /* Count of defined aux entry types. */ +#define AT_COUNT 16 /* Count of defined aux entry types. */ /* Define "machine" characteristics */ #if __ELF_WORD_SIZE == 32 Index: sys/compat/ia32/ia32_sysvec.c =================================================================== --- sys/compat/ia32/ia32_sysvec.c (revision 199998) +++ sys/compat/ia32/ia32_sysvec.c (working copy) @@ -203,15 +203,21 @@ char *stringp, *destp; u_int32_t *stack_base; struct freebsd32_ps_strings *arginfo; + size_t execpath_len; int szsigcode; /* * Calculate string base and vector table pointers. * Also deal with signal trampoline code for this exec type. */ + if (imgp->execpath != NULL && imgp->auxargs != NULL) + execpath_len = strlen(imgp->execpath) + 1; + else + execpath_len = 0; arginfo = (struct freebsd32_ps_strings *)FREEBSD32_PS_STRINGS; szsigcode = *(imgp->proc->p_sysent->sv_szsigcode); destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE - + roundup(execpath_len, sizeof(char *)) - roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); /* @@ -222,6 +228,15 @@ ((caddr_t)arginfo - szsigcode), szsigcode); /* + * Copy the image path for the rtld. + */ + if (execpath_len != 0) { + imgp->execpathp = (uintptr_t)arginfo - szsigcode - execpath_len; + copyout(imgp->execpath, (void *)imgp->execpathp, + execpath_len); + } + + /* * If we have a valid auxargs ptr, prepare some room * on the stack. */ @@ -237,9 +252,9 @@ * the arg and env vector sets,and imgp->auxarg_size is room * for argument of Runtime loader. */ - vectp = (u_int32_t *) (destp - (imgp->args->argc + imgp->args->envc + 2 + - imgp->auxarg_size) * sizeof(u_int32_t)); - + vectp = (u_int32_t *) (destp - (imgp->args->argc + + imgp->args->envc + 2 + imgp->auxarg_size + execpath_len) * + sizeof(u_int32_t)); } else /* * The '+ 2' is for the null pointers at the end of each of Index: sys/compat/svr4/svr4_sysvec.c =================================================================== --- sys/compat/svr4/svr4_sysvec.c (revision 199998) +++ sys/compat/svr4/svr4_sysvec.c (working copy) @@ -222,8 +222,6 @@ args = (Elf32_Auxargs *)imgp->auxargs; pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2); - if (args->trace) - AUXARGS_ENTRY(pos, AT_DEBUG, 1); if (args->execfd != -1) AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); Index: sys/i386/include/elf.h =================================================================== --- sys/i386/include/elf.h (revision 199998) +++ sys/i386/include/elf.h (working copy) @@ -84,28 +84,14 @@ #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused for i386). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -/* - * The following non-standard values are used for passing information - * from John Polstra's testbed program to the dynamic linker. These - * are expected to go away soon. - * - * Unfortunately, these overlap the Linux non-standard values, so they - * must not be used in the same context. - */ -#define AT_BRK 10 /* Starting point for sbrk and brk. */ -#define AT_DEBUG 11 /* Debugging level. */ - -/* - * The following non-standard values are used in Linux ELF binaries. - */ #define AT_NOTELF 10 /* Program is not ELF ?? */ #define AT_UID 11 /* Real uid. */ #define AT_EUID 12 /* Effective uid. */ #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ +#define AT_EXECPATH 15 /* Path to the executable. */ -#define AT_COUNT 15 /* Count of defined aux entry types. */ +#define AT_COUNT 16 /* Count of defined aux entry types. */ /* * Relocation types. Index: sys/amd64/include/elf.h =================================================================== --- sys/amd64/include/elf.h (revision 199998) +++ sys/amd64/include/elf.h (working copy) @@ -81,28 +81,14 @@ #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused for i386). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -/* - * The following non-standard values are used for passing information - * from John Polstra's testbed program to the dynamic linker. These - * are expected to go away soon. - * - * Unfortunately, these overlap the Linux non-standard values, so they - * must not be used in the same context. - */ -#define AT_BRK 10 /* Starting point for sbrk and brk. */ -#define AT_DEBUG 11 /* Debugging level. */ - -/* - * The following non-standard values are used in Linux ELF binaries. - */ #define AT_NOTELF 10 /* Program is not ELF ?? */ #define AT_UID 11 /* Real uid. */ #define AT_EUID 12 /* Effective uid. */ #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ +#define AT_EXECPATH 15 /* Path to the executable. */ -#define AT_COUNT 15 /* Count of defined aux entry types. */ +#define AT_COUNT 16 /* Count of defined aux entry types. */ /* * Relocation types. Index: sys/sys/imgact.h =================================================================== --- sys/sys/imgact.h (revision 199998) +++ sys/sys/imgact.h (working copy) @@ -65,6 +65,9 @@ size_t auxarg_size; struct image_args *args; /* system call arguments */ struct sysentvec *sysent; /* system entry vector */ + char *execpath; + unsigned long execpathp; + char *freepath; }; #ifdef _KERNEL Index: sys/sys/elf_common.h =================================================================== --- sys/sys/elf_common.h (revision 199998) +++ sys/sys/elf_common.h (working copy) @@ -398,6 +398,11 @@ executable contains code using a static thread-local storage scheme. */ +/* Values for DT_FLAGS_1 */ +#define DF_1_BIND_NOW 0x00000001 /* Same as DF_BIND_NOW */ +#define DF_1_GLOBAL 0x00000002 /* Set the RTLD_GLOBAL for object */ +#define DF_1_ORIGIN 0x00000080 /* Process $ORIGIN */ + /* Values for n_type. Used in core files. */ #define NT_PRSTATUS 1 /* Process status. */ #define NT_FPREGSET 2 /* Floating point registers. */