Topology publishes never wait: one private-lock exchange primitive
exchange_behind_private_lock (drivers.rs) is the single write primitive for the projection directory: one nonblocking compare-exchange behind a lock only Idunn can hold. An absent lock is created O_EXCL 0600; a lock that is not a regular file, ours, mode 0600 is replaced by a fresh 0600 file renamed over it (a chmod does not revoke a descriptor another uid already holds); a private lock is opened as is. The topology driver's mutate and the incident store both go through it; the blocking compare_exchange_snapshot call, publish_projection_mode (which published the lock 0644 on a false premise that readers open it) and incident.rs secure_lock are deleted. mutate now retries only a lost race; a held lock is Err "the topology projection is locked by another holder" and a no-op, so no caller records a digest, evidence or phase for a publish that did not land. Test helpers: the lock holder is a separate flock process, and run_while_held counts opens of the lock (inotify), so ANY wait on a held lock fails, not only one past the 30 s ceiling. Tests reproduce the live default ACL and use setpriv for the other-uid half. This commit has not been built; the verify run follows. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
a909f931ea
commit
102c129891
5 changed files with 647 additions and 131 deletions
|
|
@ -520,7 +520,7 @@ started, ran, and then died on a file it could not open:
|
|||
| `runtime_root` and every directory above it | traversable by the workload: `o+x`, or group-owned by the state group with `g+x` | the workload is a `DynamicUser` and owns nothing, and `ReadOnlyPaths=` binds the bundle's leaf into the namespace without granting traversal above it. Idunn now checks the whole chain and names the closed directory |
|
||||
| `runtime_root` | setgid, group-owned by the state group (`2750 root:<state_group>`) | `harden_root_authority_file` requires the write-lease record's group to equal its parent's, and only setgid makes a newly created record inherit it. Without it the record lands `root:root` and the workload cannot read its own lease |
|
||||
| the write-lease record | `root:<state_group>`, mode `0640` | follows from the setgid parent; the workload reads it through the state group. Idunn writes it, so fixing an existing wrong-group record means deleting it, and that is safe only when no transaction is live |
|
||||
| `/var/lib/gamecult/idunn-projection` | default ACL `u::rw-,g::r--,o::r--` | Idunn runs with `UMask=027`, so each publish creates the store and its `.lock` at `0640`. The code re-opens them after every write, but that leaves a window; a default ACL sets the mode at creation and closes it |
|
||||
| `/var/lib/gamecult/idunn-projection` | default ACL `u::rw-,g::r--,o::r--` | Idunn runs with `UMask=027`, so a store is created `0640` and each publish re-opens it `0644`; the default ACL sets the mode at creation and closes that window for stores. The `.lock` is not published and no reader opens it: Idunn creates it `0600` (replacing one found wider, so a descriptor another uid already holds is orphaned), and the ACL never decides its mode |
|
||||
| `/etc/nginx/idunn-stream-routes` | `root:root`, not group-writable | "route authority parent is not canonical root-owned and nonwritable". It was `root:idunn 0775` from the generation where Idunn ran unprivileged and needed to write it as a group member |
|
||||
|
||||
Two shapes are worth stating plainly because they are easy to get backwards.
|
||||
|
|
|
|||
Loading…
Reference in a new issue