os: make recursive directory deletion symlink-race safe - #776
Merged
Merged
Conversation
github-actions
Bot
force-pushed
the
codex/95-directory-delete-fd-walk-20260917
branch
from
September 17, 2026 18:20
0baa06a to
1955a82
Compare
davidgmbb
force-pushed
the
codex/95-directory-delete-fd-walk-20260917
branch
from
September 17, 2026 18:22
1955a82 to
3c2cce4
Compare
github-actions
Bot
force-pushed
the
codex/95-directory-delete-fd-walk-20260917
branch
from
September 17, 2026 18:31
30bc59f to
81c8d6c
Compare
Walk POSIX directory trees relative to retained descriptors, refuse links at every directory open, verify directory identities, and remove entries with unlinkat. Add a bounded adversarial directory-to-symlink swap regression and rebind the authenticated native-retirement closure exercised by the runtime change. Fixes #95.
davidgmbb
force-pushed
the
codex/95-directory-delete-fd-walk-20260917
branch
from
September 17, 2026 18:32
81c8d6c to
5928369
Compare
…identities Resolve the shared census, C producer, and Python validator hash conflicts using the materialized combined source tree. Preserve both the PR implementation and main's binary16, padded-vector, and GNU atomic support.
Preserve the descriptor-relative deletion fix alongside main's transactional resource-failure handling. Recompute the four evidence identities from the combined os.c. Fix the new rebind parser rejecting the repository's valid project-only descriptor: resources remains optional, and refresh preserves its absence. Add check/refresh/idempotence regression coverage. Validation: 55 contract, 23 materializer, and 15 rebind tests passed; both tool self-tests passed; exact combined-closure check and repeat refresh passed; GCC syntax checks for os.c and os_test.c passed.
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.
Summary
DIR *until its child has been removed, open child directories withopenat(..., O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC), enumerate withfdopendir, inspect withfstatat(..., AT_SYMLINK_NOFOLLOW), and remove withunlinkatSecurity invariant
After the root parent is opened, every descendant operation uses a single entry name relative to a retained directory descriptor. Directory opens refuse final-component links, and removals never follow links. A concurrent replacement can make deletion report failure or leave work for a retry, but it cannot redirect traversal into the symlink target.
openat2is not required for this portable single-component walk: the retained descriptor plusO_NOFOLLOW/AT_SYMLINK_NOFOLLOW/unlinkatcombination enforces the containment boundary on both Linux and Darwin.Validation
734f1d4597fb705b1643da1280b84283c1485eadis integrated atedb5cd81a1badd7087b7a14a767bda68ad3e6497checkreportscurrentand a secondrefreshleaves all binding files unchangedos.candos_test.cgit diff --checkpassedFixes #95.
Latest integration
Preserves the descriptor-relative deletion implementation together with main's transactional resource-failure handling from #787. Source and test changes merged cleanly. The four retirement-binding file conflicts were resolved using identities rebuilt from the combined source tree.
The new #804 rebinding parser rejected this repository's valid project-only descriptor because it required a
resourcessection. This integration makes that section optional, consistent with the existing materializer, without adding or changing resource records. A regression covers read-only checking, refresh, retained omission, and repeat-refresh idempotence. Existing pinned-input rejection checks remain in place.This is a history-preserving merge update. The available GitHub connection does not support the lease-protected force-push required to publish a history-rewriting rebase.