Files
nt-lite/code/kernel/se_security.c
T

131 lines
5.4 KiB
C

// Kernel security contexts. Contexts are immutable authority sets carried by processes and delegated only by attenuation.
#include <string.h>
#include <kernel/se_security.h>
#include <kernel/ke_id.h>
#include <kernel/ke_process.h>
#include <kernel/ob_object.h>
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,
SYS_SERVICE_CLAIMS serviceClaims,
SYS_SERVICE_CLAIMS delegableServiceClaims,
SECURITY_CONTEXT** contextOut) {
if (!contextOut)
return NTLSTATUS_INVALID_PARAMETER;
*contextOut = (SECURITY_CONTEXT*)0;
if ((effectivePrivileges & ~SYS_PRIV_ALL) != 0 ||
(delegablePrivileges & ~SYS_PRIV_ALL) != 0 ||
(serviceClaims & ~SYS_SERVICE_CLAIM_ALL) != 0 ||
(delegableServiceClaims & ~SYS_SERVICE_CLAIM_ALL) != 0)
return NTLSTATUS_INVALID_PARAMETER;
if ((delegablePrivileges & ~effectivePrivileges) != 0 ||
(delegableServiceClaims & ~serviceClaims) != 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->ServiceClaims = serviceClaims;
context->DelegableServiceClaims = delegableServiceClaims;
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,
SYS_SERVICE_CLAIM_ALL,
SYS_SERVICE_CLAIM_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,
SYS_SERVICE_CLAIMS serviceClaims,
SYS_SERVICE_CLAIMS delegableServiceClaims,
SECURITY_CONTEXT** contextOut) {
if (!source || !contextOut)
return NTLSTATUS_INVALID_PARAMETER;
if ((effectivePrivileges & ~source->DelegablePrivileges) != 0 ||
(delegablePrivileges & ~source->DelegablePrivileges) != 0 ||
(serviceClaims & ~source->DelegableServiceClaims) != 0 ||
(delegableServiceClaims & ~source->DelegableServiceClaims) != 0)
return NTLSTATUS_ACCESS_DENIED;
return KiCreateSecurityContext(effectivePrivileges,
delegablePrivileges,
serviceClaims,
delegableServiceClaims,
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;
}
// Tests one security context's effective service-claim mask.
bool SeContextHasServiceClaims(const SECURITY_CONTEXT* context, SYS_SERVICE_CLAIMS claims) {
if (!context)
return false;
return (context->ServiceClaims & claims) == claims;
}
// 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->ServiceClaims = context->ServiceClaims;
infoOut->DelegableServiceClaims = context->DelegableServiceClaims;
infoOut->Flags = context->Flags;
}