Bug 221032

Summary: Absolute pathnames not working with libmap.conf
Product: Base System Reporter: Tatu Kilappa <tatu.kilappa>
Component: kernAssignee: Konstantin Belousov <kib>
Status: Closed FIXED    
Severity: Affects Some People CC: emaste, feld, kib
Priority: --- Keywords: feature, patch
Version: 11.0-RELEASE   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
Patch to enable absolute pathname as target in libmap.conf none

Description Tatu Kilappa 2017-07-26 18:28:51 UTC
Created attachment 184747 [details]
Patch to enable absolute pathname as target in libmap.conf

It seems it's not possible to replace entries in libmap configuration with absolute pathnames and have them work.

For example, consider installing Nvidia driver from package or ports, it will create the following libmap directive:

libGL.so	libGL-NVIDIA.so
libGL.so.1	libGL-NVIDIA.so.1

While investigating other things, I found out that replacing the target shared object with the following:

libGL.so	/usr/local/lib/libGL-NVIDIA.so.1

Creates an error:

Shared object "/usr/local/lib/libGL-NVIDIA.so.1" not found, required by "<binary>"

The problem lies in rtld.c line 1519 and onward, that checks for absolute path before going to lm_find. This means, that if libmap.conf contains a mapping with an absolute pathname, it will try to search that name from the library search paths, which will obviously not work.

I've attached a patch that fixes the issue at least for me.

If current behavior is intended, or if this should be handled elsewhere, please disregard this bug report.
Comment 1 commit-hook freebsd_committer freebsd_triage 2017-07-27 08:34:29 UTC
A commit references this bug:

Author: kib
Date: Thu Jul 27 08:33:31 UTC 2017
New revision: 321607
URL: https://svnweb.freebsd.org/changeset/base/321607

Log:
  Allow to specify targets by absolute paths in libmap.conf.

  Submitted by:	Tatu Kilappa <tatu.kilappa@iki.fi>
  PR:	221032
  MFC after:	2 weeks

Changes:
  head/libexec/rtld-elf/rtld.c
Comment 2 commit-hook freebsd_committer freebsd_triage 2017-08-10 09:02:51 UTC
A commit references this bug:

Author: kib
Date: Thu Aug 10 09:02:45 UTC 2017
New revision: 322346
URL: https://svnweb.freebsd.org/changeset/base/322346

Log:
  MFC r321607:
  Allow to specify targets by absolute paths in libmap.conf.

  PR:	221032

Changes:
_U  stable/11/
  stable/11/libexec/rtld-elf/rtld.c
Comment 3 Mark Linimon freebsd_committer freebsd_triage 2017-08-24 14:16:36 UTC
MFCed Thu Aug 10 09:02:45 UTC 2017.
Comment 4 Mark Felder freebsd_committer freebsd_triage 2018-06-29 21:45:39 UTC
I would like to re-open this PR as it seems this patch may be the one that broke relative paths in libmap.conf. They no longer work as of 11.2-RELEASE and this PR appears to be the reason. Anyone upgrading to 11.2-RELEASE with relative paths in their libmap.conf (as previously required) will have binaries that refuse to work due to "missing" libraries.
Comment 5 Konstantin Belousov freebsd_committer freebsd_triage 2018-06-30 17:04:55 UTC
(In reply to Mark Felder from comment #4)
You report does not contain a bit of the useful information.  It works for me like this:
orion% cat /usr/local/etc/libmap.d/gdb.conf
[/usr/local/opt/gdb-8.1/bin/gdb]
libgc-threaded.so.2     libgc-threaded.so.1

orion% ldd /usr/local/opt/gdb-8.1/bin/gdb
/usr/local/opt/gdb-8.1/bin/gdb:
...
        libgc-threaded.so.2 => /usr/local/lib/libgc-threaded.so.1 (0x801972000)
...
Comment 6 Mark Felder freebsd_committer freebsd_triage 2018-07-03 12:39:18 UTC
FreeBSD 11.1-RELEASE

/usr/local/etc/libmap.d/sshd.conf:

[/usr/sbin/sshd]
libkrb5.so.11	talos/libkrb5.so.11

$ ldd /usr/sbin/sshd | grep libkrb5
	libkrb5.so.11 => /usr/local/lib/talos/libkrb5.so.11 (0x801774000)


FreeBSD 11.2-RELEASE

$ ldd /usr/sbin/sshd | grep libkrb
	libkrb5.so.11 => not found (0)


Unless I change libmap config to this:

[/usr/sbin/sshd]
libkrb5.so.11	/usr/local/lib/talos/libkrb5.so.11
Comment 7 Konstantin Belousov freebsd_committer freebsd_triage 2018-07-03 13:02:23 UTC
Did you checked the output of ldconfig -r ?  In particular, is
the /usr/local/lib/talos/ directory present in the search dir line on
the problematic machine ?
Comment 8 Tatu Kilappa 2018-07-03 22:03:15 UTC
It seems my original patch from last summer was erroneous. I'm sorry for the trouble.

I did not consider the case where libmap configuration could introduce slashes to the name, but the resulting name still was not an absolute pathname. If this happens, the block:

if (strchr(name, '/') != NULL) {
  ...
}

Will of course be hit, and since the slash is not at the beginning, the name will not be accepted.

After running some tests, the following beginning to find_library accepts all combinations (no path, relative path, absolute path):

    objgiven = refobj != NULL;
    if (strchr(xname, '/') != NULL) {	/* Hard coded pathname */
	if (xname[0] != '/' && !trust) {
	    _rtld_error("Absolute pathname required for shared object \"%s\"",
	      xname);
	    return NULL;
	}
        return (origin_subst(__DECONST(Obj_Entry *, refobj),
	  __DECONST(char *, xname)));
    }

    if (libmap_disable || !objgiven ||
	(name = lm_find(refobj->path, xname)) == NULL)
	name = (char *)xname;

    if (name != xname && name[0] == '/') { /* libmap hard coded pathname */
        return (origin_subst(__DECONST(Obj_Entry *, refobj),
          __DECONST(char *, name)));
    }

So, here the beginning of the function would be exactly as before r321607, but supposing libmap returns an absolute pathname, i.e. if lm_find returned something for that differs from xname, AND that returned name begins with '/', then it can be treated like the absolute pathname earlier.

But please take this with a grain of salt now, seeing as I already made an error. In particular, I'm unsure if 'origin_subst' is really necessary at the later point.

Yet again, I'm sorry for the earlier error.
Comment 9 Konstantin Belousov freebsd_committer freebsd_triage 2018-07-04 14:10:59 UTC
(In reply to Tatu Kilappa from comment #8)
So it is really not the relative names that do not work.  It is relative _path_ which does not, for setuid binaries.

I cannot decide if this is a feature or not.  We do not allow to specify relative pathes in the DT_NEEDED for the suid binaries.  Why should we allow that if path comes from libmap.conf.  If the relative path in DT_NEEDED is a problem, then the same path after libmap translation is the problem as well.  And it is, since the motivation is that we do not really know where the path ends up resolving.

For now I tend to think that it is better not allowed.
Comment 10 Tatu Kilappa 2018-07-04 20:17:02 UTC
I think there is an inconsistency no way we think about this. Let's write all the cases down.

Before the patch from last summer:

1) Relative paths from DT_NEEDED do not work.
- Unless 'trust' is set.
2) Absolute paths from DT_NEEDED work.
3) Relative paths from libmap.conf work.
- 'trust' does not matter.
4) Absolute paths from libmap.conf do not work.

This presents us with an inconsistency, since clearly absolute paths are okay if they're in the headers, but they somehow do not work coming from libmap.conf, because the full pathname is just subjected to normal library search.

After the patch:

1) Relative paths from DT_NEEDED do not work.
- Unless 'trust' is set.
2) Absolute paths from DT_NEEDED work.
3) Relative paths from libmap.conf do not work.
- 'trust' does not matter.
4) Absolute paths from libmap.conf work.

It's still not consistent, and this was my error, as said above. If relative paths work from DT_NEEDED should 'trust' be set, they propably should work the same way from libmap.conf to be consistent.

About relative paths from libmap.conf working regardless of 'trust' I have no opinion of, since I'm not a security expert, and I'd like to not make any more of a fool of myself.
Comment 11 Konstantin Belousov freebsd_committer freebsd_triage 2018-07-04 20:39:20 UTC
(In reply to Tatu Kilappa from comment #10)
From the find_library() code, it seems that relative pathes from libmap works iff trust is set, same as DT_NEEDED, no ?
Comment 12 Tatu Kilappa 2018-07-04 21:55:13 UTC
Yeah, true, they indeed work exactly the same way.
Comment 13 Tatu Kilappa 2018-07-04 22:01:45 UTC
But if I can still ask one question...

As far as I can see, library names with relative path are never searched from library paths (if there's a '/', it never goes to the end of find_library). Doesn't it then open with relative path from current location? And if yes, why is this ok but searching is not?
Comment 14 Konstantin Belousov freebsd_committer freebsd_triage 2018-07-07 16:10:53 UTC
(In reply to Tatu Kilappa from comment #13)
I can see the at least one  purpose of allowing the relative pathes, it is the
$ORIGIN token substitution.  If you have the path like $ORIGIN/../lib/libmylib.so.1,
it is 1. relative 2. should work.

It might be that we can further tight the handling of the relative paths by requiring the absolute path after the tokens expansiton, but we might be also
friendly for the developers who link locally for debugging purposes with the
relative paths.  I do not know enough of the real world usage there to state
an opinion.