One bug found by Specula:
Resolver::open(..., O_CREAT, ...) can retain an InMem directory handle after walking the parent, while a concurrent rmdir unlinks that parent from the namespace. InMem::create_file_at then inserts the new file into the detached directory and returns Ok(fd), so the caller receives a live file descriptor for a file with no reachable pathname.
Two operations race:
- Thread A resolves
/victim and retains its Arc.
- Thread B removes
/victim while it is empty.
- Thread A creates
child through the retained Arc.
Both calls succeed, but /victim/child has no pathname because /victim is already detached.
Expected Behavior
Linux requires one of two outcomes:
-
Creation wins:
open(O_CREAT) succeeds.
/victim/child exists.
rmdir("/victim") fails with ENOTEMPTY.
-
Removal wins:
rmdir("/victim") succeeds.
open(O_CREAT) fails with ENOENT.
They must not both succeed.
See the full report for more details.
One bug found by Specula:
Resolver::open(..., O_CREAT, ...) can retain an InMem directory handle after walking the parent, while a concurrent rmdir unlinks that parent from the namespace. InMem::create_file_at then inserts the new file into the detached directory and returns Ok(fd), so the caller receives a live file descriptor for a file with no reachable pathname.
Two operations race:
/victimand retains itsArc./victimwhile it is empty.childthrough the retainedArc.Both calls succeed, but
/victim/childhas no pathname because/victimis already detached.Expected Behavior
Linux requires one of two outcomes:
Creation wins:
open(O_CREAT)succeeds./victim/childexists.rmdir("/victim")fails withENOTEMPTY.Removal wins:
rmdir("/victim")succeeds.open(O_CREAT)fails withENOENT.They must not both succeed.
See the full report for more details.