mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-05 08:23:53 +08:00
fix(install): trust the local machine's built-in Administrator; name untrusted owners (#1705, #2023, #1686)
Windows install/daemon runtime directories created by an elevated process are owned by the built-in Administrator ACCOUNT (RID 500 under the local machine account-domain SID), even when that account is renamed or disabled. cbm's directory-owner/ACL trust refused it, breaking install/activation on such machines. #1705: resolve THIS machine's built-in Administrator SID via LSA (LsaOpenPolicy(POLICY_VIEW_LOCAL_INFORMATION) + LsaQueryInformationPolicy(PolicyAccountDomainInformation) -> CreateWellKnownSid(WinAccountAdministratorSid, accountDomainSid)), cached once per process, and accept it as a trusted owner/grantee in the daemon (win_sid_trusted) and the CLI activation transaction. Resolution is deliberately NOT IsWellKnownSid(WinAccountAdministratorSid) and NOT a trailing-RID-500 match: both accept a FOREIGN S-1-5-21-*-500 (a domain administrator, or another machine's built-in Administrator), which would be a cross-machine trust escalation. Any LSA or synthesis failure caches "none" and grants no tolerance (fail closed). owner-not-current-user (the exact-owner target rule) is unchanged. #2023/#1686: an owner-trust refusal now names the offending owner SID (the path was already carried), so a terse "status -3, os 0" becomes actionable. Scope notes: on a domain controller -- which has no separate local SAM, so its account domain IS the AD domain -- this trusts the domain Administrator, by design (on a DC that account is the machine-equivalent top admin). An un-sysprepped cloned Windows image shares the machine account-domain SID, so a sibling clone's built-in Administrator would be non-foreign; this is inherent to machine-SID identity. Verified on a native Windows (arm64) VM: compiles under the sanitized build; the daemon_ipc SID-trust test passes (local RID-500 trusted, a fabricated foreign S-1-5-21-*-500 rejected, BUILTIN\Administrators trusted) at 35 passed / 0 failed with the fix, and 34 passed / 1 failed (ASSERT(local_ok)) with the trust clause reverted -- the test binds precisely to the fix. #1856 (stock ancestor ACEs): the Windows ancestor-ACL guards already pass; no defect reproduced, no code change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
cdff08f313
commit
df579830f3
@@ -18,6 +18,7 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <aclapi.h>
|
||||
#include <ntsecapi.h>
|
||||
#include <sddl.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
@@ -424,6 +425,101 @@ static void activation_windows_security_destroy(activation_windows_security_t *s
|
||||
memset(security, 0, sizeof(*security));
|
||||
}
|
||||
|
||||
/* #1705: THIS machine's built-in Administrator ACCOUNT (RID 500 under the local
|
||||
* machine account-domain SID, S-1-5-21-<machine>-500) is a trusted owner/grantee,
|
||||
* mirroring the daemon's win_sid_trusted (src/daemon/ipc.c). It is resolved via
|
||||
* LSA (the local machine account-domain SID) plus CreateWellKnownSid and compared
|
||||
* with EqualSid. It is deliberately NOT IsWellKnownSid(WinAccountAdministratorSid)
|
||||
* and NOT a trailing-RID-500 test: both accept a FOREIGN S-1-5-21-*-500 (a domain
|
||||
* admin, or another machine's built-in Administrator), opening a cross-machine
|
||||
* bypass. Resolved once and cached for the process; any LSA or synthesis failure
|
||||
* caches "none" and grants NO tolerance (fail closed). advapi32 is already loaded
|
||||
* (this file calls GetSecurityInfo etc.), so the functions are resolved from its
|
||||
* module handle with no new import. CLI activation is single-threaded by
|
||||
* contract, so the cache needs no lock. */
|
||||
typedef NTSTATUS(NTAPI *activation_lsa_open_policy_fn)(PLSA_UNICODE_STRING, PLSA_OBJECT_ATTRIBUTES,
|
||||
ACCESS_MASK, PLSA_HANDLE);
|
||||
typedef NTSTATUS(NTAPI *activation_lsa_query_information_policy_fn)(LSA_HANDLE,
|
||||
POLICY_INFORMATION_CLASS,
|
||||
PVOID *);
|
||||
typedef NTSTATUS(NTAPI *activation_lsa_free_memory_fn)(PVOID);
|
||||
typedef NTSTATUS(NTAPI *activation_lsa_close_fn)(LSA_HANDLE);
|
||||
typedef BOOL(WINAPI *activation_create_well_known_sid_fn)(WELL_KNOWN_SID_TYPE, PSID, PSID, DWORD *);
|
||||
|
||||
static PSID activation_windows_local_admin_sid(void) {
|
||||
static bool resolved = false;
|
||||
static PSID cached = NULL;
|
||||
if (resolved) {
|
||||
return cached;
|
||||
}
|
||||
resolved = true;
|
||||
HMODULE advapi = GetModuleHandleW(L"advapi32.dll");
|
||||
if (!advapi) {
|
||||
return NULL;
|
||||
}
|
||||
activation_lsa_open_policy_fn lsa_open =
|
||||
(activation_lsa_open_policy_fn)(void (*)(void))GetProcAddress(advapi, "LsaOpenPolicy");
|
||||
activation_lsa_query_information_policy_fn lsa_query =
|
||||
(activation_lsa_query_information_policy_fn)(void (*)(void))GetProcAddress(
|
||||
advapi, "LsaQueryInformationPolicy");
|
||||
activation_lsa_free_memory_fn lsa_free =
|
||||
(activation_lsa_free_memory_fn)(void (*)(void))GetProcAddress(advapi, "LsaFreeMemory");
|
||||
activation_lsa_close_fn lsa_close =
|
||||
(activation_lsa_close_fn)(void (*)(void))GetProcAddress(advapi, "LsaClose");
|
||||
activation_create_well_known_sid_fn create_sid =
|
||||
(activation_create_well_known_sid_fn)(void (*)(void))GetProcAddress(advapi,
|
||||
"CreateWellKnownSid");
|
||||
if (!lsa_open || !lsa_query || !lsa_free || !lsa_close || !create_sid) {
|
||||
return NULL;
|
||||
}
|
||||
LSA_OBJECT_ATTRIBUTES attributes;
|
||||
memset(&attributes, 0, sizeof(attributes));
|
||||
LSA_HANDLE policy = NULL;
|
||||
/* STATUS_SUCCESS is 0; any other status is treated as failure (fail closed). */
|
||||
if (lsa_open(NULL, &attributes, POLICY_VIEW_LOCAL_INFORMATION, &policy) != 0 || !policy) {
|
||||
return NULL;
|
||||
}
|
||||
POLICY_ACCOUNT_DOMAIN_INFO *domain = NULL;
|
||||
if (lsa_query(policy, PolicyAccountDomainInformation, (PVOID *)&domain) == 0 && domain &&
|
||||
domain->DomainSid && IsValidSid(domain->DomainSid)) {
|
||||
DWORD needed = 0;
|
||||
(void)create_sid(WinAccountAdministratorSid, domain->DomainSid, NULL, &needed);
|
||||
if (needed > 0U) {
|
||||
PSID admin = malloc(needed);
|
||||
if (admin && create_sid(WinAccountAdministratorSid, domain->DomainSid, admin, &needed) &&
|
||||
IsValidSid(admin)) {
|
||||
cached = admin;
|
||||
} else {
|
||||
free(admin);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (domain) {
|
||||
(void)lsa_free(domain);
|
||||
}
|
||||
(void)lsa_close(policy);
|
||||
return cached;
|
||||
}
|
||||
|
||||
/* #2023/#1686: an owner refusal must name WHICH owner, not just "status -3, os 0".
|
||||
* The path is already carried by g_activation_refusal_object; this appends the
|
||||
* offending owner's SID string, mirroring the daemon's ACL/owner diagnostics, so
|
||||
* the operator sees the exact identity to remove or the directory to move. */
|
||||
static void activation_windows_note_untrusted_owner(const char *predicate, PSID owner,
|
||||
DWORD os_error) {
|
||||
char label[192];
|
||||
LPSTR owner_text = NULL;
|
||||
(void)snprintf(
|
||||
label, sizeof(label), "%s; owner=%s", predicate,
|
||||
(owner && IsValidSid(owner) && ConvertSidToStringSidA(owner, &owner_text) && owner_text)
|
||||
? owner_text
|
||||
: "unresolved-sid");
|
||||
if (owner_text) {
|
||||
(void)LocalFree(owner_text);
|
||||
}
|
||||
activation_note_refusal(label, os_error);
|
||||
}
|
||||
|
||||
/* Trusted-owner acceptance for SOURCE-side objects: a downloaded release
|
||||
* bundle is owned by whatever the machine's default-owner policy dictates
|
||||
* (Administrators on GitHub-runner-class images). Its integrity is enforced
|
||||
@@ -440,11 +536,13 @@ static bool activation_windows_owner_is_trusted(HANDLE handle) {
|
||||
PSECURITY_DESCRIPTOR descriptor = NULL;
|
||||
DWORD result = GetSecurityInfo(handle, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, &owner, NULL,
|
||||
NULL, NULL, &descriptor);
|
||||
PSID local_admin = activation_windows_local_admin_sid();
|
||||
bool trusted = result == ERROR_SUCCESS && owner && IsValidSid(owner) &&
|
||||
(EqualSid(owner, user_sid) || IsWellKnownSid(owner, WinLocalSystemSid) ||
|
||||
IsWellKnownSid(owner, WinBuiltinAdministratorsSid));
|
||||
IsWellKnownSid(owner, WinBuiltinAdministratorsSid) ||
|
||||
(local_admin && EqualSid(owner, local_admin)));
|
||||
if (!trusted) {
|
||||
activation_note_refusal("owner-not-trusted", result);
|
||||
activation_windows_note_untrusted_owner("owner-not-trusted", owner, result);
|
||||
}
|
||||
if (descriptor) {
|
||||
(void)LocalFree(descriptor);
|
||||
@@ -522,7 +620,7 @@ static bool activation_windows_owner_is_current(HANDLE handle) {
|
||||
}
|
||||
}
|
||||
if (!same) {
|
||||
activation_note_refusal("owner-not-current-user", result);
|
||||
activation_windows_note_untrusted_owner("owner-not-current-user", owner, result);
|
||||
}
|
||||
if (descriptor) {
|
||||
(void)LocalFree(descriptor);
|
||||
@@ -596,10 +694,15 @@ static bool activation_windows_acl_check(HANDLE handle, DWORD tolerated_untruste
|
||||
PSID sid = (PSID)&ace->SidStart;
|
||||
size_t sid_capacity = (size_t)header->AceSize - sid_offset;
|
||||
DWORD sid_length = GetSidLengthRequired(((SID *)sid)->SubAuthorityCount);
|
||||
PSID local_admin = activation_windows_local_admin_sid();
|
||||
bool trusted = sid_length <= sid_capacity && IsValidSid(sid) &&
|
||||
GetLengthSid(sid) == sid_length &&
|
||||
(EqualSid(sid, user_sid) || IsWellKnownSid(sid, WinLocalSystemSid) ||
|
||||
IsWellKnownSid(sid, WinBuiltinAdministratorsSid) ||
|
||||
/* #1705: THIS machine's built-in Administrator (RID-500),
|
||||
* resolved via LSA — never a foreign S-1-5-21-*-500; same
|
||||
* tolerance as the daemon's win_sid_trusted. */
|
||||
(local_admin && EqualSid(sid, local_admin)) ||
|
||||
/* OWNER RIGHTS modulates whoever owns the object; the
|
||||
* owner is separately validated in every chain that
|
||||
* reaches here (same tolerance as the daemon IPC and
|
||||
|
||||
@@ -3377,6 +3377,7 @@ bool cbm_daemon_ipc_local_transition_release(cbm_daemon_ipc_local_transition_t *
|
||||
#include <windows.h>
|
||||
#include <aclapi.h>
|
||||
#include <sddl.h>
|
||||
#include <ntsecapi.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <shlobj.h>
|
||||
@@ -4034,17 +4035,121 @@ static bool win_sid_is_trusted_installer(const uint8_t *sid, size_t sid_length)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* #1705: the built-in Administrator ACCOUNT of THIS machine — RID 500 under the
|
||||
* local machine's own account-domain SID (S-1-5-21-<machine>-500) — is a
|
||||
* legitimate owner/grantee of directories an elevated install created, even when
|
||||
* that account has been renamed or is disabled. It is resolved by asking LSA for
|
||||
* the local machine account-domain SID and synthesizing its RID-500 SID with
|
||||
* CreateWellKnownSid, then compared with EqualSid.
|
||||
*
|
||||
* It is deliberately NOT tested with IsWellKnownSid(sid, WinAccountAdministratorSid)
|
||||
* and NOT by matching a trailing RID of 500: BOTH of those accept ANY domain's
|
||||
* -500 — a domain administrator, or another machine's built-in Administrator —
|
||||
* which is exactly the cross-machine trust escalation this must never open. Only
|
||||
* THIS machine's -500 is trusted.
|
||||
*
|
||||
* Resolved once per process and cached; any LSA or synthesis failure leaves the
|
||||
* cache NULL and therefore grants NO tolerance at all (fail closed). advapi32 is
|
||||
* reached through the already-loaded module handle in win_security_t and the
|
||||
* function pointers are resolved dynamically, matching this file's SID-API style
|
||||
* and adding no static import. */
|
||||
typedef NTSTATUS(NTAPI *lsa_open_policy_fn)(PLSA_UNICODE_STRING, PLSA_OBJECT_ATTRIBUTES, ACCESS_MASK,
|
||||
PLSA_HANDLE);
|
||||
typedef NTSTATUS(NTAPI *lsa_query_information_policy_fn)(LSA_HANDLE, POLICY_INFORMATION_CLASS,
|
||||
PVOID *);
|
||||
typedef NTSTATUS(NTAPI *lsa_free_memory_fn)(PVOID);
|
||||
typedef NTSTATUS(NTAPI *lsa_close_fn)(LSA_HANDLE);
|
||||
typedef BOOL(WINAPI *create_well_known_sid_fn)(WELL_KNOWN_SID_TYPE, PSID, PSID, DWORD *);
|
||||
|
||||
static INIT_ONCE g_local_admin_sid_once = INIT_ONCE_STATIC_INIT;
|
||||
static PSID g_local_admin_sid = NULL; /* process-lifetime cache; NULL => no tolerance */
|
||||
|
||||
static BOOL CALLBACK win_resolve_local_admin_sid(PINIT_ONCE once, PVOID parameter, PVOID *context) {
|
||||
(void)once;
|
||||
(void)context;
|
||||
win_security_t *security = (win_security_t *)parameter;
|
||||
if (!security || !security->advapi) {
|
||||
return TRUE; /* ran once; cache stays NULL (fail closed) */
|
||||
}
|
||||
HMODULE advapi = security->advapi;
|
||||
lsa_open_policy_fn lsa_open =
|
||||
(lsa_open_policy_fn)(void (*)(void))GetProcAddress(advapi, "LsaOpenPolicy");
|
||||
lsa_query_information_policy_fn lsa_query =
|
||||
(lsa_query_information_policy_fn)(void (*)(void))GetProcAddress(advapi,
|
||||
"LsaQueryInformationPolicy");
|
||||
lsa_free_memory_fn lsa_free =
|
||||
(lsa_free_memory_fn)(void (*)(void))GetProcAddress(advapi, "LsaFreeMemory");
|
||||
lsa_close_fn lsa_close = (lsa_close_fn)(void (*)(void))GetProcAddress(advapi, "LsaClose");
|
||||
create_well_known_sid_fn create_sid =
|
||||
(create_well_known_sid_fn)(void (*)(void))GetProcAddress(advapi, "CreateWellKnownSid");
|
||||
if (!lsa_open || !lsa_query || !lsa_free || !lsa_close || !create_sid) {
|
||||
return TRUE;
|
||||
}
|
||||
LSA_OBJECT_ATTRIBUTES attributes;
|
||||
memset(&attributes, 0, sizeof(attributes));
|
||||
LSA_HANDLE policy = NULL;
|
||||
/* STATUS_SUCCESS is 0; any other status (including informational positives) is
|
||||
* treated as failure, keeping the outcome fail-closed. */
|
||||
if (lsa_open(NULL, &attributes, POLICY_VIEW_LOCAL_INFORMATION, &policy) != 0 || !policy) {
|
||||
return TRUE;
|
||||
}
|
||||
POLICY_ACCOUNT_DOMAIN_INFO *domain = NULL;
|
||||
if (lsa_query(policy, PolicyAccountDomainInformation, (PVOID *)&domain) == 0 && domain &&
|
||||
domain->DomainSid && security->is_valid_sid(domain->DomainSid)) {
|
||||
DWORD needed = 0;
|
||||
(void)create_sid(WinAccountAdministratorSid, domain->DomainSid, NULL, &needed);
|
||||
if (needed > 0U) {
|
||||
PSID resolved = malloc(needed);
|
||||
if (resolved &&
|
||||
create_sid(WinAccountAdministratorSid, domain->DomainSid, resolved, &needed) &&
|
||||
security->is_valid_sid(resolved)) {
|
||||
g_local_admin_sid = resolved;
|
||||
} else {
|
||||
free(resolved);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (domain) {
|
||||
(void)lsa_free(domain);
|
||||
}
|
||||
(void)lsa_close(policy);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static PSID win_local_admin_sid(win_security_t *security) {
|
||||
if (!security || !security->advapi) {
|
||||
return NULL;
|
||||
}
|
||||
(void)InitOnceExecuteOnce(&g_local_admin_sid_once, win_resolve_local_admin_sid, (PVOID)security,
|
||||
NULL);
|
||||
return g_local_admin_sid;
|
||||
}
|
||||
|
||||
static bool win_sid_trusted(win_security_t *security, PSID sid) {
|
||||
if (!security || !sid || !security->is_valid_sid(sid)) {
|
||||
return false;
|
||||
}
|
||||
DWORD sid_length = security->get_length_sid(sid);
|
||||
PSID local_admin = win_local_admin_sid(security);
|
||||
return (sid_length > 0U && security->equal_sid(sid, security->user_sid)) ||
|
||||
security->is_well_known_sid(sid, WinLocalSystemSid) ||
|
||||
security->is_well_known_sid(sid, WinBuiltinAdministratorsSid) ||
|
||||
(local_admin && security->equal_sid(sid, local_admin)) ||
|
||||
win_sid_is_trusted_installer((const uint8_t *)sid, (size_t)sid_length);
|
||||
}
|
||||
|
||||
#ifdef CBM_ENABLE_TEST_SEAMS
|
||||
bool cbm_daemon_ipc_win_sid_trusted_for_testing(void *sid) {
|
||||
win_security_t security;
|
||||
if (!win_security_init(&security)) {
|
||||
return false;
|
||||
}
|
||||
bool trusted = win_sid_trusted(&security, (PSID)sid);
|
||||
win_security_destroy(&security);
|
||||
return trusted;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* AppContainer identities: package SIDs (S-1-15-2-*) and capability SIDs
|
||||
* (S-1-15-3-*), under the APP_PACKAGE identifier authority (15).
|
||||
*
|
||||
|
||||
@@ -94,6 +94,13 @@ const char *cbm_daemon_ipc_validation_detail(void);
|
||||
#ifdef CBM_ENABLE_TEST_SEAMS
|
||||
/* #1537: seed the detail so a test can prove the CLI refusal surfaces it. */
|
||||
void cbm_daemon_ipc_set_validation_detail_for_testing(const char *detail);
|
||||
#ifdef _WIN32
|
||||
/* #1705: run the daemon's directory-owner/ACE trust predicate against an
|
||||
* arbitrary SID, so a test can assert THIS machine's built-in Administrator
|
||||
* (RID-500) is trusted while a foreign S-1-5-21-*-500 is not. Returns false on
|
||||
* any setup failure. Windows only. */
|
||||
bool cbm_daemon_ipc_win_sid_trusted_for_testing(void *sid);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Create/validate an owner-only directory and securely open one regular
|
||||
|
||||
@@ -920,6 +920,120 @@ TEST(daemon_ipc_windows_private_directory_allows_add_subdirectory_only_ancestor)
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* Derive THIS machine's account-domain SID (S-1-5-21-a-b-c) from the current
|
||||
* process token (S-1-5-21-a-b-c-<rid>), independently of production's LSA-based
|
||||
* resolution. Caller frees with FreeSid. */
|
||||
static PSID ipc_test_local_account_domain_sid(void) {
|
||||
HANDLE token = NULL;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
|
||||
return NULL;
|
||||
}
|
||||
DWORD needed = 0;
|
||||
(void)GetTokenInformation(token, TokenUser, NULL, 0, &needed);
|
||||
PSID domain = NULL;
|
||||
if (needed > 0) {
|
||||
void *buffer = calloc(1, needed);
|
||||
if (buffer && GetTokenInformation(token, TokenUser, buffer, needed, &needed)) {
|
||||
PSID user = ((TOKEN_USER *)buffer)->User.Sid;
|
||||
if (user && IsValidSid(user)) {
|
||||
UCHAR count = *GetSidSubAuthorityCount(user);
|
||||
SID_IDENTIFIER_AUTHORITY *authority = GetSidIdentifierAuthority(user);
|
||||
/* Machine/domain account SID: NT authority (Value[5]==5), first
|
||||
* sub-authority 21, at least the three domain sub-authorities plus
|
||||
* the account RID. Drop the RID to recover the domain SID. */
|
||||
if (count >= 4 && authority->Value[5] == 5 && *GetSidSubAuthority(user, 0) == 21U) {
|
||||
SID_IDENTIFIER_AUTHORITY nt = {SECURITY_NT_AUTHORITY};
|
||||
(void)AllocateAndInitializeSid(
|
||||
&nt, 4, *GetSidSubAuthority(user, 0), *GetSidSubAuthority(user, 1),
|
||||
*GetSidSubAuthority(user, 2), *GetSidSubAuthority(user, 3), 0, 0, 0, 0,
|
||||
&domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
(void)CloseHandle(token);
|
||||
return domain;
|
||||
}
|
||||
|
||||
/* Synthesize the RID-500 built-in Administrator SID for a given account-domain
|
||||
* SID, exactly as production does. Caller frees with free(). */
|
||||
static PSID ipc_test_admin_sid_for_domain(PSID domain_sid) {
|
||||
if (!domain_sid) {
|
||||
return NULL;
|
||||
}
|
||||
DWORD needed = 0;
|
||||
(void)CreateWellKnownSid(WinAccountAdministratorSid, domain_sid, NULL, &needed);
|
||||
if (needed == 0) {
|
||||
return NULL;
|
||||
}
|
||||
PSID admin = malloc(needed);
|
||||
if (admin && CreateWellKnownSid(WinAccountAdministratorSid, domain_sid, admin, &needed) &&
|
||||
IsValidSid(admin)) {
|
||||
return admin;
|
||||
}
|
||||
free(admin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* #1705: THIS machine's built-in Administrator ACCOUNT (RID-500 under the local
|
||||
* account-domain SID) is a trusted directory owner/grantee, while a FOREIGN
|
||||
* S-1-5-21-*-500 (a domain administrator, or another machine's built-in
|
||||
* Administrator) must never be.
|
||||
*
|
||||
* RED without the fix: win_sid_trusted rejects the local RID-500 — on the VM this
|
||||
* process runs as `test`, whose RID is not 500, so the -500 SID matches neither
|
||||
* the current user nor SYSTEM, the Administrators GROUP, or TrustedInstaller — so
|
||||
* local_ok is false. GREEN with the fix. foreign_ok is false either way, which is
|
||||
* the exact cross-machine bypass this must never open. */
|
||||
TEST(daemon_ipc_windows_sid_trust_accepts_local_admin_rejects_foreign_500) {
|
||||
PSID local_domain = ipc_test_local_account_domain_sid();
|
||||
PSID local_admin = ipc_test_admin_sid_for_domain(local_domain);
|
||||
|
||||
SID_IDENTIFIER_AUTHORITY nt = {SECURITY_NT_AUTHORITY};
|
||||
PSID foreign_domain = NULL;
|
||||
(void)AllocateAndInitializeSid(&nt, 4, 21U, 111U, 222U, 333U, 0, 0, 0, 0, &foreign_domain);
|
||||
PSID foreign_admin = ipc_test_admin_sid_for_domain(foreign_domain);
|
||||
|
||||
PSID builtin_admins = NULL;
|
||||
DWORD builtin_needed = 0;
|
||||
(void)CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, NULL, &builtin_needed);
|
||||
if (builtin_needed > 0) {
|
||||
builtin_admins = malloc(builtin_needed);
|
||||
if (builtin_admins &&
|
||||
!CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, builtin_admins, &builtin_needed)) {
|
||||
free(builtin_admins);
|
||||
builtin_admins = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool local_built = local_admin != NULL;
|
||||
bool foreign_built = foreign_admin != NULL;
|
||||
bool builtin_built = builtin_admins != NULL;
|
||||
|
||||
bool local_ok = local_built && cbm_daemon_ipc_win_sid_trusted_for_testing(local_admin);
|
||||
bool foreign_ok = foreign_built && cbm_daemon_ipc_win_sid_trusted_for_testing(foreign_admin);
|
||||
bool builtin_ok = builtin_built && cbm_daemon_ipc_win_sid_trusted_for_testing(builtin_admins);
|
||||
|
||||
free(local_admin);
|
||||
free(foreign_admin);
|
||||
free(builtin_admins);
|
||||
if (local_domain) {
|
||||
FreeSid(local_domain);
|
||||
}
|
||||
if (foreign_domain) {
|
||||
FreeSid(foreign_domain);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(local_built);
|
||||
ASSERT_TRUE(foreign_built);
|
||||
ASSERT_TRUE(builtin_built);
|
||||
ASSERT_TRUE(builtin_ok); /* the seam works: an already-trusted SID passes */
|
||||
ASSERT_TRUE(local_ok); /* #1705 fix: THIS machine's RID-500 is trusted */
|
||||
ASSERT_FALSE(foreign_ok); /* safety: a foreign -500 is NEVER trusted */
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(daemon_ipc_windows_legacy_bridge_covers_handoff_and_lifetime) {
|
||||
static const char key[] = "91a2b3c4d5e6f708";
|
||||
char parent[TEST_PATH_CAP] = {0};
|
||||
@@ -4964,6 +5078,7 @@ SUITE(daemon_ipc) {
|
||||
RUN_TEST(daemon_ipc_windows_private_directory_rejects_untrusted_ancestor_acl);
|
||||
RUN_TEST(daemon_ipc_windows_private_directory_ace_is_inheritable);
|
||||
RUN_TEST(daemon_ipc_windows_private_directory_allows_add_subdirectory_only_ancestor);
|
||||
RUN_TEST(daemon_ipc_windows_sid_trust_accepts_local_admin_rejects_foreign_500);
|
||||
RUN_TEST(daemon_ipc_windows_legacy_bridge_covers_handoff_and_lifetime);
|
||||
RUN_TEST(daemon_ipc_windows_local_transition_atomically_reserves_legacy_pipe);
|
||||
RUN_TEST(daemon_ipc_windows_startup_retries_transient_rendezvous_reader);
|
||||
|
||||
Reference in New Issue
Block a user