From 28f0bba7b4f8d01838d41f97e00eb7c81aa3b967 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Sat, 18 Feb 2012 23:59:31 +0000 Subject: [PATCH] [NTOSKRNL]: Implement SeCheckPrivilegedObject and call it in the two cases where it's needed (when changing process priority) instead of spamming the debug log that we're not doing the check. [NTOSKRNL]: Implement ProcessUserModeIOPL info level (and implement Ke386SetIopl) instead of spamming we can't do this. [NTOSKRNL]: Implement ProcessExecuteOptions info level (and implement MmSetExecuteOptions) instead of spamming we can't do this. [NDK]: Add NoExecute Flags based on ProcessHacker. No longer spammed to death for every process all the time. svn path=/trunk/; revision=55688 --- reactos/include/ndk/mmtypes.h | 12 +++- reactos/ntoskrnl/include/internal/ke.h | 4 ++ reactos/ntoskrnl/include/internal/mm.h | 4 ++ reactos/ntoskrnl/include/internal/se.h | 9 +++ reactos/ntoskrnl/ke/i386/v86vdm.c | 28 +++++++++ reactos/ntoskrnl/mm/ARM3/pagfault.c | 69 ++++++++++++++++++++++ reactos/ntoskrnl/ps/query.c | 82 +++++++++++++++++++++++--- reactos/ntoskrnl/se/priv.c | 38 ++++++++++++ 8 files changed, 236 insertions(+), 10 deletions(-) diff --git a/reactos/include/ndk/mmtypes.h b/reactos/include/ndk/mmtypes.h index 32160b98cd6..1601a84185b 100644 --- a/reactos/include/ndk/mmtypes.h +++ b/reactos/include/ndk/mmtypes.h @@ -63,8 +63,18 @@ Author: #define MAP_PROCESS 1 #define MAP_SYSTEM 2 -#ifndef NTOS_MODE_USER +// +// Flags for ProcessExecutionOptions +// +#define MEM_EXECUTE_OPTION_DISABLE 0x1 +#define MEM_EXECUTE_OPTION_ENABLE 0x2 +#define MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION 0x4 +#define MEM_EXECUTE_OPTION_PERMANENT 0x8 +#define MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE 0x10 +#define MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE 0x20 +#define MEM_EXECUTE_OPTION_VALID_FLAGS 0x3F +#ifndef NTOS_MODE_USER // // Virtual Memory Flags // diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 8133b1c021c..27e46ff4a92 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -727,6 +727,10 @@ KeContextToTrapFrame( KPROCESSOR_MODE PreviousMode ); +VOID +NTAPI +Ke386SetIOPL(VOID); + VOID NTAPI KiCheckForKernelApcDelivery(VOID); diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h index 09918a62af6..bfbc60a4295 100644 --- a/reactos/ntoskrnl/include/internal/mm.h +++ b/reactos/ntoskrnl/include/internal/mm.h @@ -1503,6 +1503,10 @@ NTSTATUS NTAPI MmReleaseMmInfo(struct _EPROCESS *Process); +NTSTATUS +NTAPI +MmSetExecuteOptions(IN ULONG ExecuteOptions); + VOID NTAPI MmDeleteProcessPageDirectory(struct _EPROCESS *Process); diff --git a/reactos/ntoskrnl/include/internal/se.h b/reactos/ntoskrnl/include/internal/se.h index 034a55591a0..e7a8535c2ab 100644 --- a/reactos/ntoskrnl/include/internal/se.h +++ b/reactos/ntoskrnl/include/internal/se.h @@ -226,6 +226,15 @@ SepPrivilegeCheck( KPROCESSOR_MODE PreviousMode ); +BOOLEAN +NTAPI +SeCheckPrivilegedObject( + IN LUID PrivilegeValue, + IN HANDLE ObjectHandle, + IN ACCESS_MASK DesiredAccess, + IN KPROCESSOR_MODE PreviousMode +); + NTSTATUS NTAPI SepDuplicateToken( diff --git a/reactos/ntoskrnl/ke/i386/v86vdm.c b/reactos/ntoskrnl/ke/i386/v86vdm.c index 503f4138423..6c860626397 100644 --- a/reactos/ntoskrnl/ke/i386/v86vdm.c +++ b/reactos/ntoskrnl/ke/i386/v86vdm.c @@ -563,6 +563,34 @@ KiEnterV86Mode(IN PKV8086_STACK_FRAME StackFrame) /* Exit to V86 mode */ KiEoiHelper(TrapFrame); } + +VOID +NTAPI +Ke386SetIOPL(VOID) +{ + + PKTHREAD Thread = KeGetCurrentThread(); + PKPROCESS Process = Thread->ApcState.Process; + PKTRAP_FRAME TrapFrame; + CONTEXT Context; + + /* IOPL was enabled for this process/thread */ + Process->Iopl = TRUE; + Thread->Iopl = TRUE; + + /* Get the trap frame on exit */ + TrapFrame = KeGetTrapFrame(Thread); + + /* Convert to a context */ + Context.ContextFlags = CONTEXT_CONTROL; + KeTrapFrameToContext(TrapFrame, NULL, &Context); + + /* Set the IOPL flag */ + Context.EFlags |= EFLAGS_IOPL; + + /* Convert back to a trap frame */ + KeContextToTrapFrame(&Context, NULL, TrapFrame, CONTEXT_CONTROL, UserMode); +} /* PUBLIC FUNCTIONS ***********************************************************/ diff --git a/reactos/ntoskrnl/mm/ARM3/pagfault.c b/reactos/ntoskrnl/mm/ARM3/pagfault.c index fda089794fe..4d3fb903f57 100644 --- a/reactos/ntoskrnl/mm/ARM3/pagfault.c +++ b/reactos/ntoskrnl/mm/ARM3/pagfault.c @@ -1094,4 +1094,73 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction, return Status; } +NTSTATUS +NTAPI +MmSetExecuteOptions(IN ULONG ExecuteOptions) +{ + + PKPROCESS CurrentProcess = &PsGetCurrentProcess()->Pcb; + KLOCK_QUEUE_HANDLE ProcessLock; + NTSTATUS Status = STATUS_ACCESS_DENIED; + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + /* Only accept valid flags */ + if (ExecuteOptions & ~MEM_EXECUTE_OPTION_VALID_FLAGS) + { + /* Fail */ + DPRINT1("Invalid no-execute options\n"); + return STATUS_INVALID_PARAMETER; + } + + /* Change the NX state in the process lock */ + KiAcquireProcessLock(CurrentProcess, &ProcessLock); + + /* Don't change anything if the permanent flag was set */ + if (!CurrentProcess->Flags.Permanent) + { + /* Start by assuming it's not disabled */ + CurrentProcess->Flags.ExecuteDisable = FALSE; + + /* Now process each flag and turn the equivalent bit on */ + if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE) + { + CurrentProcess->Flags.ExecuteDisable = TRUE; + } + if (ExecuteOptions & MEM_EXECUTE_OPTION_ENABLE) + { + CurrentProcess->Flags.ExecuteEnable = TRUE; + } + if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION) + { + CurrentProcess->Flags.DisableThunkEmulation = TRUE; + } + if (ExecuteOptions & MEM_EXECUTE_OPTION_PERMANENT) + { + CurrentProcess->Flags.Permanent = TRUE; + } + if (ExecuteOptions & MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE) + { + CurrentProcess->Flags.ExecuteDispatchEnable = TRUE; + } + if (ExecuteOptions & MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE) + { + CurrentProcess->Flags.ImageDispatchEnable = TRUE; + } + + /* These are turned on by default if no-execution is also eanbled */ + if (CurrentProcess->Flags.ExecuteEnable) + { + CurrentProcess->Flags.ExecuteDispatchEnable = TRUE; + CurrentProcess->Flags.ImageDispatchEnable = TRUE; + } + + /* All good */ + Status = STATUS_SUCCESS; + } + + /* Release the lock and return status */ + KiReleaseProcessLock(&ProcessLock); + return Status; +} + /* EOF */ diff --git a/reactos/ntoskrnl/ps/query.c b/reactos/ntoskrnl/ps/query.c index d9d9b97fbf0..aa70080dbbe 100644 --- a/reactos/ntoskrnl/ps/query.c +++ b/reactos/ntoskrnl/ps/query.c @@ -928,6 +928,8 @@ NtSetInformationProcess(IN HANDLE ProcessHandle, KAFFINITY ValidAffinity, Affinity = 0; ULONG DefaultHardErrorMode = 0, BasePriority = 0, MemoryPriority = 0; ULONG DisableBoost = 0, DebugFlags = 0, EnableFixup = 0, Boost = 0; + ULONG NoExecute = 0; + BOOLEAN HasPrivilege; PLIST_ENTRY Next; PETHREAD Thread; PAGED_CODE(); @@ -1189,8 +1191,17 @@ NtSetInformationProcess(IN HANDLE ProcessHandle, if ((PriorityClass.PriorityClass != Process->PriorityClass) && (PriorityClass.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME)) { - /* TODO: Check privileges */ - DPRINT1("Should check privilege\n"); + /* Check the privilege */ + HasPrivilege = SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege, + ProcessHandle, + PROCESS_SET_INFORMATION, + PreviousMode); + if (!HasPrivilege) + { + ObDereferenceObject(Process); + DPRINT1("Privilege to change priority to realtime lacking\n"); + return STATUS_PRIVILEGE_NOT_HELD; + } } /* Check if we have a job */ @@ -1284,7 +1295,16 @@ NtSetInformationProcess(IN HANDLE ProcessHandle, /* Check if the new base is higher */ if (BasePriority > Process->Pcb.BasePriority) { - DPRINT1("Should check privilege\n"); + HasPrivilege = SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege, + ProcessHandle, + PROCESS_SET_INFORMATION, + PreviousMode); + if (!HasPrivilege) + { + ObDereferenceObject(Process); + DPRINT1("Privilege to change priority from %lx to %lx lacking\n", BasePriority, Process->Pcb.BasePriority); + return STATUS_PRIVILEGE_NOT_HELD; + } } /* Call Ke */ @@ -1595,12 +1615,61 @@ NtSetInformationProcess(IN HANDLE ProcessHandle, KeSetAutoAlignmentProcess(&Process->Pcb, FALSE); Status = STATUS_SUCCESS; break; + + case ProcessUserModeIOPL: + /* Only TCB can do this */ + if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) + { + /* Fail */ + DPRINT1("Need TCB to set IOPL\n"); + Status = STATUS_PRIVILEGE_NOT_HELD; + break; + } + + /* Only supported on x86 */ +#if defined (_X86_) + Ke386SetIOPL(); +#endif + /* Done */ + break; + + case ProcessExecuteFlags: + + /* Check buffer length */ + if (ProcessInformationLength != sizeof(ULONG)) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + if (ProcessHandle != NtCurrentProcess()) + { + Status = STATUS_INVALID_PARAMETER; + break; + } + + /* Enter SEH for direct buffer read */ + _SEH2_TRY + { + NoExecute = *(PULONG)ProcessInformation; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Get exception code */ + Status = _SEH2_GetExceptionCode(); + _SEH2_YIELD(break); + } + _SEH2_END; + + /* Call Mm for the update */ + Status = MmSetExecuteOptions(NoExecute); + break; + /* We currently don't implement any of these */ case ProcessLdtInformation: case ProcessLdtSize: case ProcessIoPortHandlers: - case ProcessUserModeIOPL: case ProcessWx86Information: DPRINT1("VDM/16-bit Request not implemented: %lx\n", ProcessInformationClass); Status = STATUS_NOT_IMPLEMENTED; @@ -1626,11 +1695,6 @@ NtSetInformationProcess(IN HANDLE ProcessHandle, Status = STATUS_NOT_IMPLEMENTED; break; - case ProcessExecuteFlags: - DPRINT1("No execute support not implemented\n"); - Status = STATUS_NOT_IMPLEMENTED; - break; - /* Anything else is invalid */ default: DPRINT1("Invalid Server 2003 Info Class: %lx\n", ProcessInformationClass); diff --git a/reactos/ntoskrnl/se/priv.c b/reactos/ntoskrnl/se/priv.c index c692ed305a5..6f7a0dd57fc 100644 --- a/reactos/ntoskrnl/se/priv.c +++ b/reactos/ntoskrnl/se/priv.c @@ -426,6 +426,44 @@ SeSinglePrivilegeCheck(IN LUID PrivilegeValue, return Result; } +BOOLEAN +NTAPI +SeCheckPrivilegedObject(IN LUID PrivilegeValue, + IN HANDLE ObjectHandle, + IN ACCESS_MASK DesiredAccess, + IN KPROCESSOR_MODE PreviousMode) +{ + SECURITY_SUBJECT_CONTEXT SubjectContext; + PRIVILEGE_SET Priv; + BOOLEAN Result; + + PAGED_CODE(); + + SeCaptureSubjectContext(&SubjectContext); + + Priv.PrivilegeCount = 1; + Priv.Control = PRIVILEGE_SET_ALL_NECESSARY; + Priv.Privilege[0].Luid = PrivilegeValue; + Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED; + + Result = SePrivilegeCheck(&Priv, &SubjectContext, PreviousMode); + if (PreviousMode != KernelMode) + { +#if 0 + SePrivilegeObjectAuditAlarm(ObjectHandle, + &SubjectContext, + DesiredAccess, + &PrivilegeValue, + Result, + PreviousMode); +#endif + } + + SeReleaseSubjectContext(&SubjectContext); + + return Result; +} + /* SYSTEM CALLS ***************************************************************/ NTSTATUS