link2symlink: accept O_TMPFILE anonymous inodes in linkat copy-path gate#349
Open
Ebola-Chan-bot wants to merge 1 commit into
Open
link2symlink: accept O_TMPFILE anonymous inodes in linkat copy-path gate#349Ebola-Chan-bot wants to merge 1 commit into
Ebola-Chan-bot wants to merge 1 commit into
Conversation
Extend handle_linkat_from_proc_fd() so that, in addition to the classic
" (deleted)" orphan-inode case (open() + unlink() followed by
linkat(/proc/self/fd/N, AT_SYMLINK_FOLLOW, newpath)), a readlink target
of the O_TMPFILE magic form "/<dir>/#<inode-number>" is also recognised
and routed through the existing user-space copy branch.
The copy body (stat + open(O_CREAT|O_EXCL) + read/write loop) is byte-
identical for both source types and needs no change; only the gate is
relaxed, by parsing for the "/<dir>/#<digits>" trailer as an OR with
the existing " (deleted)" suffix check.
Motivation: Alpine apk's atomic-publish pattern uses
fd = open(dir, O_TMPFILE | O_RDWR, mode);
write(fd, ...);
linkat(AT_FDCWD, "/proc/self/fd/<fd>", AT_FDCWD, newpath,
AT_SYMLINK_FOLLOW);
On kernels where link2symlink is already required, that flow produces a
/proc/<pid>/fd/<fd> magic symlink whose readlink resolves to
"/<dir>/#<inum>" rather than "<path> (deleted)", so the original gate
returned 0 and let the unsupported hardlink syscall reach the kernel,
causing apk to fail its triggers/scripts/installed-db writes.
Known semantic limitation (documented in a code comment): writes to the
source fd performed after the linkat call are not reflected in the
target file, because the copy snapshots the data at linkat time rather
than hijacking the fd. All surveyed consumers of O_TMPFILE+linkat
(apk, dpkg, ld-linux) follow a write-fully -> publish -> stop-writing
ordering and are unaffected; a future program relying on post-publish
writes would need an fd-hijack approach instead.
Tested on HarmonyOS NEXT / kernel 5.10.43 aarch64 inside an
aoco_untrusted_app SELinux domain that denies app_data_file:file link,
by running `apk add --no-cache` for a representative package set
(alpine-base, bash, busybox-extras, ...): pre-patch apk fails with
EPERM while writing triggers/scripts.tar.gz/installed; post-patch the
install completes and the resulting files are byte-identical to the
source O_TMPFILE content.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Extend
handle_linkat_from_proc_fd()so that, in addition to the classic " (deleted)" orphan-inode case (open() + unlink() followed bylinkat(/proc/self/fd/N, AT_SYMLINK_FOLLOW, newpath)), a readlink target of the O_TMPFILE magic form "/<dir>/#" is also recognised and routed through the existing user-space copy branch.The copy body (stat +
open(O_CREAT|O_EXCL)+ read/write loop) is byte- identical for both source types and needs no change; only the gate is relaxed, by parsing for the "/<dir>/#" trailer as an OR with the existing " (deleted)" suffix check.Motivation: Alpine apk's atomic-publish pattern uses
On kernels where link2symlink is already required, that flow produces a /proc/<pid>/fd/<fd> magic symlink whose readlink resolves to "/<dir>/#<inum>" rather than "<path> (deleted)", so the original gate returned 0 and let the unsupported hardlink syscall reach the kernel, causing apk to fail its triggers/scripts/installed-db writes.
Known semantic limitation (documented in a code comment): writes to the source fd performed after the linkat call are not reflected in the target file, because the copy snapshots the data at linkat time rather than hijacking the fd. All surveyed consumers of O_TMPFILE+linkat (apk, dpkg, ld-linux) follow a write-fully -> publish -> stop-writing ordering and are unaffected; a future program relying on post-publish writes would need an fd-hijack approach instead.