fix(daemon): make private directory DACL inheritable - #1531
Conversation
|
Thanks for opening this — it has been seen, and it is queued. This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence. Current review status: working through a backlog. What that means for this PR, concretely:
Things that will genuinely speed it up whenever review does happen:
If this fixes a bug, a reproduction we can run is worth more than a description of the symptom. Thanks for contributing, and sorry in advance for the wait. |
293b1f9 to
5ac55ad
Compare
win_security_init built its owner-only ACL with AddAccessAllowedAce, which has no AceFlags parameter and can only emit an ACE with flags set to zero. Applied to a directory together with PROTECTED_DACL_SECURITY_INFORMATION that yields D:PAI(A;;FA;;;<user>): the protection severs the inherited ACEs while the new ACE propagates nothing, so every child created afterwards is born with an empty DACL and is unreadable even by its owner. win_runtime_directory_secure is also a repair path. It continues on ERROR_ALREADY_EXISTS and re-stamps the existing directory, so a tree restored by hand with icacls is destroyed again on the next daemon or client start. Add a second ACL for containers, built with AddAccessAllowedAceEx and CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, and use it at the three directory sites. Files and kernel objects are leaves and keep the flagless ACL. The container ACE carries FILE_ALL_ACCESS rather than GENERIC_ALL. Windows splits an inheritable generic-rights ACE into an effective mapped ACE plus an INHERIT_ONLY one holding the generic bits, and the owner-only DACL validators require exactly one ACE, so the generic form fails every lock directory with "secure CLI coordination could not be created (project-locks)". Fixes DeusData#1351 Signed-off-by: PETRO YAKOVYSHYN <petroyakovyshyn@gmail.com>
5ac55ad to
3e540aa
Compare
|
On the The failing client's last line was Local runs, MinGW gcc on Windows 11 26200:
All four runs were green across all seven sections. The control and the patched binary differ only in this change. One thing may be worth fixing in the harness regardless. My guess is startup-transition contention among six racing cold clients on a shared runner, which a 28-core machine resolves and a 2-core one may not. That is a guess. I can rebuild under |
|
Merged — thank you @Kiborgik. This is precise Windows work and the diagnosis is the valuable part: a flagless ACE combined with The Worth noting this does not relax the security posture: children now inherit the same owner-only ACE the parent already enforced. Shipping in v0.10.3. |
Fixes #1351
Problem
win_security_initbuilds the owner-only ACL withAddAccessAllowedAce(src/daemon/ipc.c:3664). That API has noAceFlagsparameter, so the ACE it produces always has flags set to zero. Applied to a directory together withPROTECTED_DACL_SECURITY_INFORMATION, the result is:The protection severs the inherited ACEs and the new ACE propagates nothing, so every child created afterwards is born with an empty DACL and is unreadable even by its owner. That is the
RuleCount=0state on_config.db,logs, and project databases reported in #1351.win_runtime_directory_secureis also a repair path: line 4051 continues onERROR_ALREADY_EXISTSand line 4093 re-stamps the existing directory, so a tree repaired by hand withicaclsis destroyed again on the next daemon or client start.The three other owner-only ACL builders in the tree avoid this by using
SetEntriesInAclWwith an explicitgrfInheritance(compat.c:88,compat_fs.c:454, andactivation_transaction.c:368, the last correctly usingNO_INHERITANCEbecause it is applied only to aCREATE_NEWfile).Change
Build a second ACL for containers using
AddAccessAllowedAceExwithCONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, and use it at the three directory sites (ipc.c:4050,4097,4184). Files and kernel objects are leaves and keep the existing flagless ACL (3819,3823,4236,4260).The container ACE carries
FILE_ALL_ACCESSrather thanGENERIC_ALL. Windows splits an inheritable generic-rights ACE into an effective mapped ACE plus anINHERIT_ONLYone holding the generic bits, andprivate_win_owner_only_daclrequires exactly one ACE (private_file_lock.c:910). Using generic rights here fails every lock directory withsecure CLI coordination could not be created (project-locks). I hit that while developing this patch, which is why the test asserts the ACE count.Verification
Built from this branch and compared against the stock 0.10.0 release binary on the same cache path (Windows 11 26200, MinGW gcc, non-elevated standard token):
<user>:(F)<user>:(OI)(CI)(F)(F)(OI)(CI)(F)cli list_projectsTest
daemon_ipc_windows_private_directory_ace_is_inheritableasserts that the secured directory has exactly one ACE, that it carries both inherit flags, that a child created inside it has a non-empty DACL, and thatcbm_private_lock_directory_adopt_windowsstill accepts the directory. The inherit-flag and child-DACL assertions fail on currentmain.What I could not verify locally
MinGW ships no
libsanitizer, soscripts/test.shcould not run in its ASan and UBSan configuration; my run was unsanitized. Several pre-existing-Werrordiagnostics intests/test_daemon_ipc.candtests/test_daemon_application.c(stringop-overflow,free-nonheap-object) also had to be downgraded before the runner would build under this gcc. None are in code this patch touches, but CI is the authority on sanitizer and warning cleanliness here.Separately,
scripts/run-tests-parallel.shstamps the build directory using a bare username, which misresolves on a machine whose hostname equals the username and locks the harness out of its own log directory. That is unrelated to this change and I will open it separately.