implement realpath directly instead of using procfs readlink
authorRich Felker <dalias@aerifal.cx>
Mon, 30 Nov 2020 17:14:47 +0000 (12:14 -0500)
committerRich Felker <dalias@aerifal.cx>
Mon, 30 Nov 2020 18:46:52 +0000 (13:46 -0500)
commit29ff7599a448232f2527841c2362643d246cee36
tree668d86c24719f2acd784767b662810a7e443e294
parent5d464f524ba5447e2a8fc77560b98c1ad9a83570
implement realpath directly instead of using procfs readlink

inability to use realpath in chroot/container without procfs access
and at early boot prior to mount of /proc has been an ongoing issue,
and it turns out realpath was one of the last remaining interfaces
that needed procfs for its core functionality. during investigation
while reimplementing, it was determined that there were also serious
problems with the procfs-based implementation. most seriously it was
unsafe on pre-O_PATH kernels, and unlike other places where O_PATH was
used, the unsafety was hard or impossible to fix because O_NOFOLLOW
can't be used (since the whole purpose was to follow symlinks).

the new implementation is a direct one, performing readlink on each
path component to resolve it. an explicit stack, as opposed to
recursion, is used to represent the remaining components to be
processed. the stack starts out holding just the input string, and
reading a link pushes the link contents onto the stack.

unlike many other implementations, this one does not call getcwd
initially for relative pathnames. instead it accumulates initial ..
components to be applied to the working directory if the result is
still a relative path. this avoids calling getcwd (which may fail) at
all when symlink traversal will eventually yield an absolute path. it
also doesn't use any form of stat operation; instead it arranges for
readlink to tell it when a non-directory is used in a context where a
directory is needed. this minimizes the number of syscalls needed,
avoids accessing inodes when the directory table suffices, and reduces
the amount of code pulled in for static linking.
src/misc/realpath.c