Change interpretation of the DF_ORIGIN and DF_1_ORIGIN flags.

According to standard, the presence of the flags only means that the
object path must be resolved at the time object loading, instead of my
reading that the flag is required to enable token substitution at all.

The consequence is that -z origin linker flag is no longer required
for the token substitution in the run/rpath or the needed library
soname.  It is only recommended if token substition is needed at
dlopen(3) time, since namecache might drop the required entries at the
time of resolution.

Found, reviewed and tested by:	emaste
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
This commit is contained in:
Konstantin Belousov 2015-04-27 18:41:31 +00:00
parent 3f29603d1b
commit b3ff02bf85
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=282109

View File

@ -148,8 +148,10 @@ 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 char *origin_subst_one(char *, const char *, const char *, bool);
static char *origin_subst(char *, const char *);
static char *origin_subst_one(Obj_Entry *, char *, const char *,
const char *, bool);
static char *origin_subst(Obj_Entry *, char *);
static bool obj_resolve_origin(Obj_Entry *obj);
static void preinit_main(void);
static int rtld_verify_versions(const Objlist *);
static int rtld_verify_object_versions(Obj_Entry *);
@ -788,8 +790,8 @@ basename(const char *name)
static struct utsname uts;
static char *
origin_subst_one(char *real, const char *kw, const char *subst,
bool may_free)
origin_subst_one(Obj_Entry *obj, char *real, const char *kw,
const char *subst, bool may_free)
{
char *p, *p1, *res, *resp;
int subst_len, kw_len, subst_count, old_len, new_len;
@ -808,9 +810,15 @@ origin_subst_one(char *real, const char *kw, const char *subst,
/*
* If the keyword is not found, just return.
*
* Return non-substituted string if resolution failed. We
* cannot do anything more reasonable, the failure mode of the
* caller is unresolved library anyway.
*/
if (subst_count == 0)
if (subst_count == 0 || (obj != NULL && !obj_resolve_origin(obj)))
return (may_free ? real : xstrdup(real));
if (obj != NULL)
subst = obj->origin_path;
/*
* There is indeed something to substitute. Calculate the
@ -847,20 +855,22 @@ origin_subst_one(char *real, const char *kw, const char *subst,
}
static char *
origin_subst(char *real, const char *origin_path)
origin_subst(Obj_Entry *obj, char *real)
{
char *res1, *res2, *res3, *res4;
if (obj == NULL || !trust)
return (xstrdup(real));
if (uts.sysname[0] == '\0') {
if (uname(&uts) != 0) {
_rtld_error("utsname failed: %d", errno);
return (NULL);
}
}
res1 = origin_subst_one(real, "$ORIGIN", origin_path, false);
res2 = origin_subst_one(res1, "$OSNAME", uts.sysname, true);
res3 = origin_subst_one(res2, "$OSREL", uts.release, true);
res4 = origin_subst_one(res3, "$PLATFORM", uts.machine, true);
res1 = origin_subst_one(obj, real, "$ORIGIN", NULL, false);
res2 = origin_subst_one(NULL, res1, "$OSNAME", uts.sysname, true);
res3 = origin_subst_one(NULL, res2, "$OSREL", uts.release, true);
res4 = origin_subst_one(NULL, res3, "$PLATFORM", uts.machine, true);
return (res4);
}
@ -1124,7 +1134,7 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
#endif
case DT_FLAGS:
if ((dynp->d_un.d_val & DF_ORIGIN) && trust)
if (dynp->d_un.d_val & DF_ORIGIN)
obj->z_origin = true;
if (dynp->d_un.d_val & DF_SYMBOLIC)
obj->symbolic = true;
@ -1156,7 +1166,7 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
case DT_FLAGS_1:
if (dynp->d_un.d_val & DF_1_NOOPEN)
obj->z_noopen = true;
if ((dynp->d_un.d_val & DF_1_ORIGIN) && trust)
if (dynp->d_un.d_val & DF_1_ORIGIN)
obj->z_origin = true;
if (dynp->d_un.d_val & DF_1_GLOBAL)
obj->z_global = true;
@ -1207,30 +1217,33 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
}
}
static bool
obj_resolve_origin(Obj_Entry *obj)
{
if (obj->origin_path != NULL)
return (true);
obj->origin_path = xmalloc(PATH_MAX);
return (rtld_dirname_abs(obj->path, obj->origin_path) != -1);
}
static void
digest_dynamic2(Obj_Entry *obj, const Elf_Dyn *dyn_rpath,
const Elf_Dyn *dyn_soname, const Elf_Dyn *dyn_runpath)
{
if (obj->z_origin && obj->origin_path == NULL) {
obj->origin_path = xmalloc(PATH_MAX);
if (rtld_dirname_abs(obj->path, obj->origin_path) == -1)
rtld_die();
}
if (obj->z_origin && !obj_resolve_origin(obj))
rtld_die();
if (dyn_runpath != NULL) {
obj->runpath = (char *)obj->strtab + dyn_runpath->d_un.d_val;
if (obj->z_origin)
obj->runpath = origin_subst(obj->runpath, obj->origin_path);
}
else 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);
if (dyn_runpath != NULL) {
obj->runpath = (char *)obj->strtab + dyn_runpath->d_un.d_val;
obj->runpath = origin_subst(obj, obj->runpath);
} else if (dyn_rpath != NULL) {
obj->rpath = (char *)obj->strtab + dyn_rpath->d_un.d_val;
obj->rpath = origin_subst(obj, obj->rpath);
}
if (dyn_soname != NULL)
object_add_name(obj, obj->strtab + dyn_soname->d_un.d_val);
}
static void
@ -1480,12 +1493,8 @@ find_library(const char *xname, const Obj_Entry *refobj, int *fdp)
xname);
return NULL;
}
if (objgiven && refobj->z_origin) {
return (origin_subst(__DECONST(char *, xname),
refobj->origin_path));
} else {
return (xstrdup(xname));
}
return (origin_subst(__DECONST(Obj_Entry *, refobj),
__DECONST(char *, xname)));
}
if (libmap_disable || !objgiven ||