Skip to content

fix(vfs): follow intermediate symlinks in utimensat - #2313

Merged
fslongjin merged 1 commit into
DragonOS-Community:masterfrom
fslongjin:codex/fix-utimensat-intermediate-symlinks
Sep 21, 2026
Merged

fslongjin merged 1 commit into
DragonOS-Community:masterfrom
fslongjin:codex/fix-utimensat-intermediate-symlinks

Conversation

@fslongjin

Copy link
Copy Markdown
Member

Summary

  • Fix utimensat(AT_SYMLINK_NOFOLLOW) to follow intermediate directory symlinks while leaving the final symlink unfollowed.
  • Reuse the existing VFS pathname walker; leave fd-based timestamps, permissions, metadata updates and notifications unchanged.
  • Add 30 focused dunitest checks and register them in the CI whitelist and no-skip list.

Root cause

The pathname branch used lookup(), which disables all symlink traversal, instead of selecting only the final-component policy. A valid path such as /sbin/ip.dpkg-new therefore returned ENOTDIR on a usr-merged Ubuntu rootfs.

This was reproduced without nginx by unpacking Ubuntu iproute2 6.1.0-1ubuntu6.4. dpkg 1.22.6ubuntu6.6 then entered its diversion rollback path: extraction used the diverted directory names, while cleanup used the original names and removed /bin and /sbin. The next boot could not resolve /bin/busybox.

This PR fixes the kernel trigger by matching Linux 6.6 pathname semantics. It does not add path-specific unlink protection or modify dpkg, and does not claim to fix dpkg rollback under unrelated installation errors.

Validation

Check Result
New suite on Linux 30 passed
New suite on pre-fix DragonOS 6 passed, 24 failed
New suite on fixed DragonOS, tmpfs and ext4 30 passed
Same suite after sync and reboot 30 passed
Existing open_dangling_symlink suite 11 passed
Selected gVisor utimes/futimesat/utimensat cases 14 passed
make kernel Passed
make fmt Passed
FMT_CHECK=1 make fmt Passed
Normal apt installation of nginx and dependencies Completed; iproute2, nginx-common and nginx all installed
System links and reboot Preserved; shell and BusyBox work after reboot
Default nginx -t Passed before and after reboot

The gVisor selection excludes the existing blocklisted UtimeTest.ZeroAtimeandMtime; no reference tests or blocklists were changed. Independent adversarial reviews covered Linux semantics, permissions, lifecycle, performance, maintainability and test validity.

Scope and remaining issues

Default nginx service startup still reports EADDRINUSE for [::]:80; a separate IPv4 smoke test succeeds. This networking issue, the previously observed concurrency/TLS issues, and dpkg's independent diversion rollback risk are not fixed by this PR. Installation and reboot success must not be interpreted as full nginx compatibility.

AT_SYMLINK_NOFOLLOW must only suppress following the final pathname
component. do_utimensat previously used lookup(), whose zero symlink
budget also prevented intermediate directory symlinks from being
resolved. Valid usr-merged paths consequently failed with ENOTDIR.

Reuse lookup_follow_symlink2 with the normal follow budget and an
explicit final-component policy. Keep the fd path, timestamp permission
checks, metadata masks and notification behavior unchanged.

This fixes the trigger observed while Ubuntu dpkg sets timestamps on
/sbin/ip.dpkg-new during iproute2 installation. The prior error entered
dpkg's diversion cleanup path, which removed /bin and /sbin and prevented
the next boot. The kernel change does not special-case those names or
claim to fix dpkg's independent rollback behavior.

Add 30 parameterized dunitest checks covering tmp and current-directory
fixtures, intermediate relative/absolute links, dirfd paths, final and
dangling links, trailing slashes, search permissions, error cases,
UTIME_OMIT, current-time updates and futimens. Register the suite in the
CI whitelist and no-skip list.

Validation:
- Linux new suite: 30 passed; pre-fix DragonOS: 6 passed, 24 failed.
- Fixed DragonOS on tmpfs/ext4: 30 passed, including after reboot.
- Existing open_dangling_symlink suite: 11 passed.
- Selected gVisor utimes/futimesat/utimensat tests: 14 passed.
- make kernel, make fmt and FMT_CHECK=1 make fmt passed.
- Normal nginx apt installation completed with iproute2, nginx-common
  and nginx installed; system links survived sync and reboot.

The separate nginx dual-stack bind failure remains outside this fix.

Signed-off-by: longjin <longjin@dragonos.org>
@github-actions github-actions Bot added Bug fix A bug is fixed in this pull request test Unitest/User space test labels Sep 21, 2026
@fslongjin

Copy link
Copy Markdown
Member Author

@codex review

@fslongjin
fslongjin merged commit b9fb0c3 into DragonOS-Community:master Sep 21, 2026
15 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug fix A bug is fixed in this pull request test Unitest/User space test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant