// Kernel security contexts. Contexts are immutable authority sets carried by processes and delegated only by attenuation. #include #include #include #include #include static KE_ID_ALLOCATOR gSecurityIds = KE_ID_ALLOCATOR_INIT(1u); static SECURITY_CONTEXT* gRootSecurityContext; // Destroys one non-root security context after its last object reference disappears. static void KiSecurityContextDestroy(OBJECT* object) { (void)object; } // Allocates and initializes one immutable security context object. static KSTATUS KiCreateSecurityContext(SYS_PRIVILEGES effectivePrivileges, SYS_PRIVILEGES delegablePrivileges, SECURITY_CONTEXT** contextOut) { if (!contextOut) return NTLSTATUS_INVALID_PARAMETER; *contextOut = (SECURITY_CONTEXT*)0; if ((effectivePrivileges & ~SYS_PRIV_ALL) != 0 || (delegablePrivileges & ~SYS_PRIV_ALL) != 0) return NTLSTATUS_INVALID_PARAMETER; if ((delegablePrivileges & ~effectivePrivileges) != 0) return NTLSTATUS_ACCESS_DENIED; SECURITY_CONTEXT* context = (SECURITY_CONTEXT*)ObAllocateObject(ObjectTypeSecurityContext, sizeof(SECURITY_CONTEXT)); if (!context) return NTLSTATUS_NO_MEMORY; context->Header.Destroy = KiSecurityContextDestroy; KSTATUS status = KeAllocateId32(&gSecurityIds, &context->SecurityId); if (!KSUCCESS(status)) { ObDereferenceObject(&context->Header); return status; } context->EffectivePrivileges = effectivePrivileges; context->DelegablePrivileges = delegablePrivileges; context->Flags = SYS_SECURITY_CONTEXT_FLAG_NONE; *contextOut = context; return NTLSTATUS_SUCCESS; } // Initializes the root context exactly once before any process is created. KSTATUS SeInitializeSecurity(void) { if (gRootSecurityContext) return NTLSTATUS_SUCCESS; SECURITY_CONTEXT* context = (SECURITY_CONTEXT*)0; KSTATUS status = KiCreateSecurityContext(SYS_PRIV_ALL, SYS_PRIV_ALL, &context); if (!KSUCCESS(status)) return status; gRootSecurityContext = context; return NTLSTATUS_SUCCESS; } // Returns the permanently referenced bootstrap root context. SECURITY_CONTEXT* SeGetRootSecurityContext(void) { return gRootSecurityContext; } // Derives one child context whose effective and delegable authority are subsets of the source delegable sets. KSTATUS SeDeriveSecurityContext(SECURITY_CONTEXT* source, SYS_PRIVILEGES effectivePrivileges, SYS_PRIVILEGES delegablePrivileges, SECURITY_CONTEXT** contextOut) { if (!source || !contextOut) return NTLSTATUS_INVALID_PARAMETER; if ((effectivePrivileges & ~source->DelegablePrivileges) != 0 || (delegablePrivileges & ~source->DelegablePrivileges) != 0) return NTLSTATUS_ACCESS_DENIED; return KiCreateSecurityContext(effectivePrivileges, delegablePrivileges, contextOut); } // Tests one process's immutable effective privilege mask. bool SeProcessHasPrivilege(const struct PROCESS* process, SYS_PRIVILEGES privileges) { if (!process || !process->SecurityContext) return false; return (process->SecurityContext->EffectivePrivileges & privileges) == privileges; } // Exports immutable context metadata to one public structure. void SeQuerySecurityContext(const SECURITY_CONTEXT* context, SYS_SECURITY_CONTEXT_INFO* infoOut) { if (!context || !infoOut) return; memset(infoOut, 0, sizeof(*infoOut)); infoOut->Size = sizeof(*infoOut); infoOut->SecurityId = context->SecurityId; infoOut->EffectivePrivileges = context->EffectivePrivileges; infoOut->DelegablePrivileges = context->DelegablePrivileges; infoOut->Flags = context->Flags; }