Andreas Longwitz
2018-Sep-11 20:47 UTC
Constraints in libmap(32).conf do not work as expected, possible bug in rtld-elf
Thanks very much for answer ! Now I use the following libmap32.conf: ## php52 [/usr/local/php52/lib/php/20060613/mysql.so] /usr/local/lib/mysql /usr/local/lib32/mysql [/usr/local/php52/] /usr/local/lib /usr/local/lib32> I am having problem understanding what do you mean by step1/step2. The > refobj reference that you cache in the patch, comes into load_object() > as the pointer to the object which initiate the load_object() call. It > is NULL for preloaded objects, otherwise it is not. > So, could you, please, explain where does it get passed as NULL in your > case ?Ok, I try to explain better: step1 means: call of lm_find() in rtld.c (line 1500) and first argument is refobj->path, which is used in libmap.c to find the correct entry in the lmp_list. step2 means: call of lm_findn() in rtld.c (line 2834) when called from search_library_path(). In this case the first argument is NULL and in libmap.c this means "$DEFAULT" entry in the lmp_list. Please notice that after reading libmap32.conf in lm_init() the entry $DEFAULT in the lmp_list does not exist, when all mappings are defined with constraints.> Also, your patch makes the ref_object stuck for all future invocations > of the load_object(), so it cannot be correct for this reason alone.I do not think so. The patch only caches refobj->path from step1 to use the same path in step2. I have updated my patch a little bit to clarify, that the patch only wants to change the call of lm_findn() in the case of search_library_path(): --- rtld.c.orig 2018-03-20 16:56:48.000000000 +0100 +++ rtld.c 2018-09-11 21:44:03.333739000 +0200 @@ -186,6 +186,7 @@ static Obj_Entry obj_rtld; /* The dynamic linker shared object */ static unsigned int obj_count; /* Number of objects in obj_list */ static unsigned int obj_loads; /* Number of loads of objects (gen count) */ +static char *lm_refobj_path = NULL; static Objlist list_global = /* Objects dlopened with RTLD_GLOBAL */ STAILQ_HEAD_INITIALIZER(list_global); @@ -1496,6 +1497,8 @@ __DECONST(char *, xname))); } + if (objgiven) + lm_refobj_path = refobj->path; if (libmap_disable || !objgiven || (name = lm_find(refobj->path, xname)) == NULL) name = (char *)xname; @@ -1513,8 +1516,10 @@ (refobj != NULL && (pathname = search_library_path(name, refobj->rpath)) != NULL) || (pathname = search_library_path(name, gethints(false))) !NULL || - (pathname = search_library_path(name, STANDARD_LIBRARY_PATH)) != NULL) + (pathname = search_library_path(name, STANDARD_LIBRARY_PATH)) != NULL) { + lm_refobj_path = NULL; return (pathname); + } } else { nodeflib = objgiven ? refobj->z_nodeflib : false; if ((objgiven && @@ -1526,10 +1531,13 @@ (pathname = search_library_path(name, refobj->runpath)) !NULL) || (pathname = search_library_path(name, gethints(nodeflib))) !NULL || (objgiven && !nodeflib && - (pathname = search_library_path(name, STANDARD_LIBRARY_PATH)) != NULL)) + (pathname = search_library_path(name, STANDARD_LIBRARY_PATH)) != NULL)) { + lm_refobj_path = NULL; return (pathname); + } } + lm_refobj_path = NULL; if (objgiven && refobj->path != NULL) { _rtld_error("Shared object \"%s\" not found, required by \"%s\"", name, basename(refobj->path)); @@ -2831,7 +2839,7 @@ char *res; len = strcspn(path, ":;"); - trans = lm_findn(NULL, path, len); + trans = lm_findn(lm_refobj_path, path, len); if (trans) res = callback(trans, strlen(trans), arg); else> Another note is that libmap.conf use that you put it for, is quite the > strengthen of the original purpose. You should just add the pathes > with your libraries to LD_32_LIBRARY_PATH or configure them into > /var/run/ld-elf32.so.hints using 'ldconfig -32'.I have tried this without success. With the original ld-elf32.so.1 and my constraints in libmap32.conf I got the following: -> /usr/local/php52/bin/php -v Shared object "libxml2.so.5" not found, required by "php" The error changed after setting LD_32_LIBRARY_PATH or (with same result) the file /var/run/ld-elf32.so.hints using 'ldconfig -32. -> export LD_32_LIBRARY_PATH="/usr/local/lib32:/usr/local/lib32/mysql" -> /usr/local/php52/bin/php -v /usr/local/lib/libiconv.so.3: unsupported file layout This error disappears when I move this 64-bit library libiconv.so away, but thats not a solution. For your information I append the beginning of the dynamic section from readelf output of /usr/local/php52/bin/php: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libcrypt.so.5] 0x00000001 (NEEDED) Shared library: [librt.so.1] 0x00000001 (NEEDED) Shared library: [libm.so.5] 0x00000001 (NEEDED) Shared library: [libxml2.so.5] 0x00000001 (NEEDED) Shared library: [libz.so.5] 0x00000001 (NEEDED) Shared library: [libiconv.so.3] 0x00000001 (NEEDED) Shared library: [libc.so.7] 0x0000000f (RPATH) Library rpath: [/usr/local/lib] Andreas Longwitz
Konstantin Belousov
2018-Sep-21 13:48 UTC
Constraints in libmap(32).conf do not work as expected, possible bug in rtld-elf
On Tue, Sep 11, 2018 at 10:47:58PM +0200, Andreas Longwitz wrote:> Thanks very much for answer ! > > Now I use the following libmap32.conf: > > ## php52 > [/usr/local/php52/lib/php/20060613/mysql.so] > /usr/local/lib/mysql /usr/local/lib32/mysql > [/usr/local/php52/] > /usr/local/lib /usr/local/lib32 > > > I am having problem understanding what do you mean by step1/step2. The > > refobj reference that you cache in the patch, comes into load_object() > > as the pointer to the object which initiate the load_object() call. It > > is NULL for preloaded objects, otherwise it is not. > > So, could you, please, explain where does it get passed as NULL in your > > case ? > > Ok, I try to explain better: > > step1 means: call of lm_find() in rtld.c (line 1500) and first argument > is refobj->path, which is used in libmap.c to find the correct entry in > the lmp_list. > > step2 means: call of lm_findn() in rtld.c (line 2834) when called from > search_library_path(). In this case the first argument is NULL and in > libmap.c this means "$DEFAULT" entry in the lmp_list. Please notice that > after reading libmap32.conf in lm_init() the entry $DEFAULT in the > lmp_list does not exist, when all mappings are defined with constraints.Can you try this instead ? diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index dfd0388478f..83d5e28e287 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -125,7 +125,7 @@ static void objlist_remove(Objlist *, Obj_Entry *); static int open_binary_fd(const char *argv0, bool search_in_path); static int parse_args(char* argv[], int argc, bool *use_pathp, int *fdp); static int parse_integer(const char *); -static void *path_enumerate(const char *, path_enum_proc, void *); +static void *path_enumerate(const char *, path_enum_proc, const char *, void *); static void print_usage(const char *argv0); static void release_object(Obj_Entry *); static int relocate_object_dag(Obj_Entry *root, bool bind_now, @@ -140,7 +140,8 @@ static int rtld_dirname(const char *, char *); static int rtld_dirname_abs(const char *, char *); static void *rtld_dlopen(const char *name, int fd, int mode); static void rtld_exit(void); -static char *search_library_path(const char *, const char *, int *); +static char *search_library_path(const char *, const char *, const char *, + int *); static char *search_library_pathfds(const char *, const char *, int *); static const void **get_program_var_addr(const char *, RtldLockState *); static void set_program_var(const char *, const void *); @@ -1576,8 +1577,7 @@ gnu_hash(const char *s) static char * find_library(const char *xname, const Obj_Entry *refobj, int *fdp) { - char *pathname; - char *name; + char *name, *pathname, *refobj_path; bool nodeflib, objgiven; objgiven = refobj != NULL; @@ -1597,6 +1597,7 @@ find_library(const char *xname, const Obj_Entry *refobj, int *fdp) } dbg(" Searching for \"%s\"", name); + refobj_path = objgiven ? refobj->path : NULL; /* * If refobj->rpath != NULL, then refobj->runpath is NULL. Fall @@ -1605,52 +1606,61 @@ find_library(const char *xname, const Obj_Entry *refobj, int *fdp) * nodeflib. */ if (objgiven && refobj->rpath != NULL && ld_library_path_rpath) { - pathname = search_library_path(name, ld_library_path, fdp); + pathname = search_library_path(name, ld_library_path, + refobj_path, fdp); if (pathname != NULL) return (pathname); if (refobj != NULL) { - pathname = search_library_path(name, refobj->rpath, fdp); + pathname = search_library_path(name, refobj->rpath, + refobj_path, fdp); if (pathname != NULL) return (pathname); } pathname = search_library_pathfds(name, ld_library_dirs, fdp); if (pathname != NULL) return (pathname); - pathname = search_library_path(name, gethints(false), fdp); + pathname = search_library_path(name, gethints(false), + refobj_path, fdp); if (pathname != NULL) return (pathname); - pathname = search_library_path(name, ld_standard_library_path, fdp); + pathname = search_library_path(name, ld_standard_library_path, + refobj_path, fdp); if (pathname != NULL) return (pathname); } else { nodeflib = objgiven ? refobj->z_nodeflib : false; if (objgiven) { - pathname = search_library_path(name, refobj->rpath, fdp); + pathname = search_library_path(name, refobj->rpath, + refobj->path, fdp); if (pathname != NULL) return (pathname); } if (objgiven && refobj->runpath == NULL && refobj != obj_main) { - pathname = search_library_path(name, obj_main->rpath, fdp); + pathname = search_library_path(name, obj_main->rpath, + refobj_path, fdp); if (pathname != NULL) return (pathname); } - pathname = search_library_path(name, ld_library_path, fdp); + pathname = search_library_path(name, ld_library_path, + refobj_path, fdp); if (pathname != NULL) return (pathname); if (objgiven) { - pathname = search_library_path(name, refobj->runpath, fdp); + pathname = search_library_path(name, refobj->runpath, + refobj_path, fdp); if (pathname != NULL) return (pathname); } pathname = search_library_pathfds(name, ld_library_dirs, fdp); if (pathname != NULL) return (pathname); - pathname = search_library_path(name, gethints(nodeflib), fdp); + pathname = search_library_path(name, gethints(nodeflib), + refobj_path, fdp); if (pathname != NULL) return (pathname); if (objgiven && !nodeflib) { pathname = search_library_path(name, - ld_standard_library_path, fdp); + ld_standard_library_path, refobj_path, fdp); if (pathname != NULL) return (pathname); } @@ -1845,8 +1855,9 @@ gethints(bool nostdlib) hargs.request = RTLD_DI_SERINFOSIZE; hargs.serinfo = &hmeta; - path_enumerate(ld_standard_library_path, fill_search_info, &sargs); - path_enumerate(hints, fill_search_info, &hargs); + path_enumerate(ld_standard_library_path, fill_search_info, NULL, + &sargs); + path_enumerate(hints, fill_search_info, NULL, &hargs); SLPinfo = xmalloc(smeta.dls_size); hintinfo = xmalloc(hmeta.dls_size); @@ -1864,8 +1875,9 @@ gethints(bool nostdlib) hargs.serpath = &hintinfo->dls_serpath[0]; hargs.strspace = (char *)&hintinfo->dls_serpath[hmeta.dls_cnt]; - path_enumerate(ld_standard_library_path, fill_search_info, &sargs); - path_enumerate(hints, fill_search_info, &hargs); + path_enumerate(ld_standard_library_path, fill_search_info, NULL, + &sargs); + path_enumerate(hints, fill_search_info, NULL, &hargs); /* * Now calculate the difference between two sets, by excluding @@ -2974,7 +2986,8 @@ rtld_exit(void) * callback on the result. */ static void * -path_enumerate(const char *path, path_enum_proc callback, void *arg) +path_enumerate(const char *path, path_enum_proc callback, + const char *refobj_path, void *arg) { const char *trans; if (path == NULL) @@ -2986,7 +2999,7 @@ path_enumerate(const char *path, path_enum_proc callback, void *arg) char *res; len = strcspn(path, ":;"); - trans = lm_findn(NULL, path, len); + trans = lm_findn(refobj_path, path, len); if (trans) res = callback(trans, strlen(trans), arg); else @@ -3045,7 +3058,8 @@ try_library_path(const char *dir, size_t dirlen, void *param) } static char * -search_library_path(const char *name, const char *path, int *fdp) +search_library_path(const char *name, const char *path, + const char *refobj_path, int *fdp) { char *p; struct try_library_args arg; @@ -3059,7 +3073,7 @@ search_library_path(const char *name, const char *path, int *fdp) arg.buflen = PATH_MAX; arg.fd = -1; - p = path_enumerate(path, try_library_path, &arg); + p = path_enumerate(path, try_library_path, refobj_path, &arg); *fdp = arg.fd; free(arg.buffer); @@ -3776,12 +3790,12 @@ do_search_info(const Obj_Entry *obj, int request, struct dl_serinfo *info) _info.dls_size = __offsetof(struct dl_serinfo, dls_serpath); _info.dls_cnt = 0; - path_enumerate(obj->rpath, fill_search_info, &args); - path_enumerate(ld_library_path, fill_search_info, &args); - path_enumerate(obj->runpath, fill_search_info, &args); - path_enumerate(gethints(obj->z_nodeflib), fill_search_info, &args); + path_enumerate(obj->rpath, fill_search_info, NULL, &args); + path_enumerate(ld_library_path, fill_search_info, NULL, &args); + path_enumerate(obj->runpath, fill_search_info, NULL, &args); + path_enumerate(gethints(obj->z_nodeflib), fill_search_info, NULL, &args); if (!obj->z_nodeflib) - path_enumerate(ld_standard_library_path, fill_search_info, &args); + path_enumerate(ld_standard_library_path, fill_search_info, NULL, &args); if (request == RTLD_DI_SERINFOSIZE) { @@ -3801,25 +3815,25 @@ do_search_info(const Obj_Entry *obj, int request, struct dl_serinfo *info) args.strspace = (char *)&info->dls_serpath[_info.dls_cnt]; args.flags = LA_SER_RUNPATH; - if (path_enumerate(obj->rpath, fill_search_info, &args) != NULL) + if (path_enumerate(obj->rpath, fill_search_info, NULL, &args) != NULL) return (-1); args.flags = LA_SER_LIBPATH; - if (path_enumerate(ld_library_path, fill_search_info, &args) != NULL) + if (path_enumerate(ld_library_path, fill_search_info, NULL, &args) != NULL) return (-1); args.flags = LA_SER_RUNPATH; - if (path_enumerate(obj->runpath, fill_search_info, &args) != NULL) + if (path_enumerate(obj->runpath, fill_search_info, NULL, &args) != NULL) return (-1); args.flags = LA_SER_CONFIG; - if (path_enumerate(gethints(obj->z_nodeflib), fill_search_info, &args) + if (path_enumerate(gethints(obj->z_nodeflib), fill_search_info, NULL, &args) != NULL) return (-1); args.flags = LA_SER_DEFAULT; - if (!obj->z_nodeflib && - path_enumerate(ld_standard_library_path, fill_search_info, &args) != NULL) + if (!obj->z_nodeflib && path_enumerate(ld_standard_library_path, + fill_search_info, NULL, &args) != NULL) return (-1); return (0); }