Bug 248184 - readlink("/proc/curproc/file") returns arbitrary correct name for programs with more than one link (name)
Summary: readlink("/proc/curproc/file") returns arbitrary correct name for programs wi...
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 12.1-RELEASE
Hardware: Any Any
: --- Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-07-22 16:53 UTC by Jörg Schilling
Modified: 2021-11-06 02:26 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jörg Schilling 2020-07-22 16:53:25 UTC
The expected returned string is the first argument to the exec*() call, but it returns a random hardlink to that file instead.

This prevents it from being used to detect how a program has been called and to select the dedicated behavior from a fat binary, that e.g. implements both POSIX and non-POSIX behavior.

I came over that problem when calling the parallel version of SunPro Make as:

/opt/schily/bin/dmake

and readlink(/porc/curproc/file) returned /opt/schily/xpg4/bin/make
Comment 1 Conrad Meyer freebsd_committer 2020-07-22 18:11:43 UTC
The canonical way to do this in FreeBSD is making use of elf_aux_info(3) with AT_EXECPATH.  The information is copied to userspace in the program image during activation, but is not tracked by the kernel afterwards.
Comment 2 Jörg Schilling 2020-07-22 19:03:55 UTC
Solaris introduced getexecname() 23 years ago and I need/use it since 15 years.

At that time, there was nothing similar in FreeBSD and procfs was the only way to go for porting.

elf_aux_info() seems to be *really* new...I discovered after making the report.

BTW: Solaris returns the expected result from procfs.
Comment 3 Ed Maste freebsd_committer 2020-07-23 14:57:04 UTC
From the man page:

    #include <stdlib.h>
    const char *getexecname(void);

    ...

    If successful, getexecname() returns a pointer to the executables pathname; otherwise, it returns 0.

    ...

    The getexecname() function obtains the executable pathname from the AT_SUN_EXECNAME aux vector. These vectors are made available to dynamically linked processes only.

It seems like we could also add getexecname as a slightly more convenient interface than elf_aux_info.
Comment 4 Jörg Schilling 2020-07-24 08:45:17 UTC
Implementing getexecname() would be an improvement as it does not need to use a private buffer and in many cases  requires strdup() even though the string is on the stack anyway.
Comment 5 commit-hook freebsd_committer 2020-07-24 15:51:03 UTC
A commit references this bug:

Author: tobik
Date: Fri Jul 24 15:50:57 UTC 2020
New revision: 543251
URL: https://svnweb.freebsd.org/changeset/ports/543251

Log:
  lang/rust-nightly: Attempt to fix intermittent "can't find crate for `std`" build failures

  The location of rustc (found via env::current_exe()) is used to
  find the right libstd.  However it might have been "copied" by
  creating a hard link to the new location instead.  Like /proc/curproc/file,
  KERN_PROC_PATHNAME (used internally by current_exe()) can return
  any of the file's multiple paths.  Most of the time it returns the
  right rustc path and the build will succeed but occasionally it
  will return the "wrong" path and the build fails with:

      error[E0463]: can't find crate for `std`

  If this is right a viable workaround should be to never create hard
  links during the build, so let's try that.

  Also drop the related llvm-config-wrapper workaround.

  PR:		248184

Changes:
  head/lang/rust-nightly/files/patch-src_bootstrap_lib.rs
  head/lang/rust-nightly/files/patch-src_bootstrap_native.rs
Comment 6 Tobias Kortkamp freebsd_committer 2021-10-19 13:11:48 UTC
(In reply to Conrad Meyer from comment #1)
The problem is also present with AT_EXECPATH.

AT_EXECPATH doesn't really make a difference if the wrong name
is copied to userspace in the first place.

$ freebsd-version
13.0-RELEASE-p4
$ cat execpath.c
#include <sys/auxv.h>
#include <limits.h>
#include <stdio.h>

int
main(int argc, char *argv[])
{
        char pathname[PATH_MAX];
        elf_aux_info(AT_EXECPATH, pathname, PATH_MAX);
        puts(pathname);
        return 0;
}
$ make execpath
$ ln -f execpath tmp/execpath
$ ./execpath
/home/tobias/execpath
$ ./tmp/execpath
/home/tobias/tmp/execpath
$ ./execpath # I'd expect this to return /home/tobias/execpath again but:
/home/tobias/tmp/execpath

Now I'm coming back to this because lang/rust uses hardlinks in the build
by default. We have disabled this since it caused intermittent build failures
because env::current_exe (uses kern.proc.pathname.-1 sysctl internally) might
returns the wrong pathname (one of the hardlinks) sometimes and rustc fails
to find the right std crate.  This is my working theory anyway. It's difficult
to trigger the problem on my package builder.

I was going to experiment with switching it over to AT_EXECPATH but I guess
that will make no difference because of the current behavior of it.

If getexecname() would be just a wrapper for elf_aux_info(AT_EXECPATH) then
it wouldn't solve the problem either.

Any suggestions what we should use instead of kern.proc.pathname, AT_EXECPATH,
or /proc/curproc/file?
Comment 7 Konstantin Belousov freebsd_committer 2021-10-23 01:07:47 UTC
https://reviews.freebsd.org/D32611
Comment 8 commit-hook freebsd_committer 2021-10-28 17:51:50 UTC
A commit in branch main references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=0c10648fbb758bb76fd29330b7fe1bc519252325

commit 0c10648fbb758bb76fd29330b7fe1bc519252325
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-10-23 00:24:08 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-10-28 17:49:31 +0000

    exec: provide right hardlink name in AT_EXECPATH

    For this, use vn_fullpath_hardlink() to resolve executable name for
    execve(2).

    This should provide the right hardlink name, used for execution, instead
    of random hardlink pointing to this binary.  Also this should make the
    AT_EXECNAME reliable for execve(2), since kernel only needs to resolve
    parent directory path, which should always succeed (except pathological
    cases like unlinking a directory).

    PR:     248184
    Reviewed by:    markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D32611

 sys/kern/kern_exec.c | 38 ++++++++++++++++++++++++++++----------
 1 file changed, 28 insertions(+), 10 deletions(-)
Comment 9 commit-hook freebsd_committer 2021-10-28 17:51:51 UTC
A commit in branch main references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=ee92c8a842d61ffda8d111e1b0e398085c5bfb3a

commit ee92c8a842d61ffda8d111e1b0e398085c5bfb3a
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-10-23 19:01:37 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-10-28 17:50:02 +0000

    sysctl kern.proc.procname: report right hardlink name

    PR:     248184
    Reviewed by:    markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D32611

 sys/kern/kern_proc.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 49 insertions(+), 5 deletions(-)
Comment 10 commit-hook freebsd_committer 2021-10-31 01:05:31 UTC
A commit in branch main references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=e5248548f95ff1c89667847e0d945dea38adeca7

commit e5248548f95ff1c89667847e0d945dea38adeca7
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-10-29 01:43:32 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-10-31 01:05:14 +0000

    procfs: return right hardlink from /proc/curproc/file

    Use proc_get_binpath() to get the hardlink right.

    PR:     248184
    Reviewed by:    emaste, markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D32738

 sys/fs/procfs/procfs.c | 17 ++++++-----------
 1 file changed, 6 insertions(+), 11 deletions(-)
Comment 11 commit-hook freebsd_committer 2021-10-31 18:36:33 UTC
A commit in branch main references this bug:

URL: https://cgit.FreeBSD.org/ports/commit/?id=d5f09dc31fcfdb77b69c86b9093bf67ec67653d9

commit d5f09dc31fcfdb77b69c86b9093bf67ec67653d9
Author:     Tobias Kortkamp <tobik@FreeBSD.org>
AuthorDate: 2021-10-19 10:27:40 +0000
Commit:     Tobias Kortkamp <tobik@FreeBSD.org>
CommitDate: 2021-10-31 18:20:54 +0000

    lang/rust-nightly: Update to 1.58.0.20211030

    Make the no-hardlinks-patches conditional and move them to
    files/no-hardlinks.

    Newer kernels should return sane kern.proc.pathname values for
    hardlinks which will hopefully help avoid the intermittent "can't
    find crate for `std`" build failures we had on the package
    builders.

    Thanks to kib@ for fixing kernel behavior. Now let's see if it
    makes a difference for lang/rust-nightly.

    Changes:        https://github.com/rust-lang/rust/compare/25ec8273855fde2d72ae877b397e054de5300e10...e249ce6b2345587d6e11052779c86adbad626dff
    PR:             248184

 lang/rust-nightly/Makefile                            |  6 +++---
 lang/rust-nightly/distinfo                            | 18 +++++++++---------
 .../{ => no-hardlinks}/patch-src_bootstrap_lib.rs     |  0
 .../{ => no-hardlinks}/patch-src_bootstrap_native.rs  |  0
 ...r_rustc__target_src_spec_i686__unknown__freebsd.rs |  8 ++++----
 lang/rust/Makefile                                    | 19 +++++++++++++++++++
 6 files changed, 35 insertions(+), 16 deletions(-)
Comment 12 commit-hook freebsd_committer 2021-11-06 02:26:09 UTC
A commit in branch stable/13 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=f61af036ab291b558e8632bc58290b3321c2bafc

commit f61af036ab291b558e8632bc58290b3321c2bafc
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-10-29 01:43:32 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-11-06 02:12:32 +0000

    procfs: return right hardlink from /proc/curproc/file

    PR:     248184

    (cherry picked from commit e5248548f95ff1c89667847e0d945dea38adeca7)

 sys/fs/procfs/procfs.c | 17 ++++++-----------
 1 file changed, 6 insertions(+), 11 deletions(-)
Comment 13 commit-hook freebsd_committer 2021-11-06 02:26:11 UTC
A commit in branch stable/13 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=ea4e8e191c0ecb12da16c34c2d14f04bc7f955c7

commit ea4e8e191c0ecb12da16c34c2d14f04bc7f955c7
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-10-23 19:01:37 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-11-06 02:12:32 +0000

    sysctl kern.proc.procname: report right hardlink name

    PR:     248184

    (cherry picked from commit ee92c8a842d61ffda8d111e1b0e398085c5bfb3a)

 sys/kern/kern_proc.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 49 insertions(+), 5 deletions(-)
Comment 14 commit-hook freebsd_committer 2021-11-06 02:26:12 UTC
A commit in branch stable/13 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=a69fb7452ef97b5690f1811d4fb3b7b9f8ad78f8

commit a69fb7452ef97b5690f1811d4fb3b7b9f8ad78f8
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-10-23 00:24:08 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-11-06 02:12:31 +0000

    exec: provide right hardlink name in AT_EXECPATH

    PR:     248184

    (cherry picked from commit 0c10648fbb758bb76fd29330b7fe1bc519252325)

 sys/kern/kern_exec.c | 38 ++++++++++++++++++++++++++++----------
 1 file changed, 28 insertions(+), 10 deletions(-)