Cluster
C6 — Hardening & Privilege Separation (de Raadt-led): evaluate whether the current architecture warrants a privsep worker pattern.
Recommendation
Do not adopt the privsep worker pattern at this time. Reassess if the threat surface materially expands.
Cost / benefit analysis
What the pattern would buy
A worker forking from pusb_sm_authenticate, dropping privileges to a synthetic uid before parsing XML and before opening attacker-supplied USB filesystem contents, would isolate the following code paths from the host PAM process's root context:
libxml2 XML parsing and XPath evaluation (conf.c, xpath.c).
- USB-side pad I/O and
fsync on attacker-controlled FAT/exFAT volumes (pad.c).
getrandom(2) + write-and-rename atomic update (pad.c).
A compromise of any of those subsystems would terminate the worker without lasting effect on the host PAM process.
What the pattern would cost
- Fork-from-PAM-hook is fragile: glib/UDisks2 client state (
udisks_client_new_sync) is initialized in the parent; forking after it is a documented anti-pattern (pthread_atfork warning in glib docs).
- Re-architecting
device.c / volume.c to talk to UDisks2 in the parent while delegating pad I/O to a worker requires either a second IPC channel or marshalling mount points across the boundary.
- The current binary footprint (~4,200 LOC) does not justify the operational complexity of a worker; the audit floor for medium-or-higher vulns surfaced from the named subsystems over six prior rounds is small.
- Debug cycles increase substantially —
strace -f becomes the only useful introspection tool.
Adoption blockers identified in current code
Should the pattern become warranted later, the following blockers would need to be addressed:
pusb_log_init writes to thread-local globals (src/log.c:26-28); a worker would need its own init call.
udisks_client_new_sync in device.c:123 initializes long-lived glib state; this initialization must remain on one side of the boundary, not straddle a fork.
- The PAM stack assumes synchronous return from
pam_sm_authenticate; the worker boundary must be fully drained before the hook returns.
Conclusion
The libxml2 + UDisks2 + OTP surface, audited across rounds 1-6, has produced findings that are mostly addressable in-place. A worker model would not have prevented the published findings to date. Recommend leaving the architecture as-is and revisiting if either:
- A future round surfaces a libxml2 / glib / UDisks2 vulnerability whose only mitigation is privsep, or
- The codebase grows significantly (e.g., adds support for non-PAM auth flows).
This issue does not receive a CVSS score — it is an architectural opinion, not a vulnerability report.
Cluster
C6 — Hardening & Privilege Separation (de Raadt-led): evaluate whether the current architecture warrants a privsep worker pattern.
Recommendation
Do not adopt the privsep worker pattern at this time. Reassess if the threat surface materially expands.
Cost / benefit analysis
What the pattern would buy
A worker forking from
pusb_sm_authenticate, dropping privileges to a synthetic uid before parsing XML and before opening attacker-supplied USB filesystem contents, would isolate the following code paths from the host PAM process's root context:libxml2XML parsing and XPath evaluation (conf.c,xpath.c).fsyncon attacker-controlled FAT/exFAT volumes (pad.c).getrandom(2)+ write-and-rename atomic update (pad.c).A compromise of any of those subsystems would terminate the worker without lasting effect on the host PAM process.
What the pattern would cost
udisks_client_new_sync) is initialized in the parent; forking after it is a documented anti-pattern (pthread_atforkwarning in glib docs).device.c/volume.cto talk to UDisks2 in the parent while delegating pad I/O to a worker requires either a second IPC channel or marshalling mount points across the boundary.strace -fbecomes the only useful introspection tool.Adoption blockers identified in current code
Should the pattern become warranted later, the following blockers would need to be addressed:
pusb_log_initwrites to thread-local globals (src/log.c:26-28); a worker would need its own init call.udisks_client_new_syncindevice.c:123initializes long-lived glib state; this initialization must remain on one side of the boundary, not straddle a fork.pam_sm_authenticate; the worker boundary must be fully drained before the hook returns.Conclusion
The libxml2 + UDisks2 + OTP surface, audited across rounds 1-6, has produced findings that are mostly addressable in-place. A worker model would not have prevented the published findings to date. Recommend leaving the architecture as-is and revisiting if either:
This issue does not receive a CVSS score — it is an architectural opinion, not a vulnerability report.