Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

328 lines
9.2 KiB

/*
Copyright (c) 2001 Microsoft Corporation
File name:
hotpatch.c
Author:
Adrian Marinescu (adrmarin) Nov 20 2001
Environment:
Kernel mode only.
Revision History:
*/
#include "exp.h"
#pragma hdrstop
NTSTATUS
ExpSyncRenameFiles(
IN HANDLE FileHandle1,
OUT PIO_STATUS_BLOCK IoStatusBlock1,
IN PFILE_RENAME_INFORMATION RenameInformation1,
IN ULONG RenameInformationLength1,
IN HANDLE FileHandle2,
OUT PIO_STATUS_BLOCK IoStatusBlock2,
IN PFILE_RENAME_INFORMATION RenameInformation2,
IN ULONG RenameInformationLength2
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,ExApplyCodePatch)
#pragma alloc_text(PAGE,ExpSyncRenameFiles)
#endif
#define EXP_MAX_HOTPATCH_INFO_SIZE PAGE_SIZE
//
// Privileged flags define the operations where we require privilege check
//
#define FLG_HOTPATCH_PRIVILEGED_FLAGS (FLG_HOTPATCH_KERNEL | FLG_HOTPATCH_RELOAD_NTDLL | FLG_HOTPATCH_RENAME_INFO | FLG_HOTPATCH_MAP_ATOMIC_SWAP)
//
// Exclusive flags define the flags that cannot be used in combinations with other flags
//
#define FLG_HOTPATCH_EXCLUSIVE_FLAGS (FLG_HOTPATCH_RELOAD_NTDLL | FLG_HOTPATCH_RENAME_INFO | FLG_HOTPATCH_MAP_ATOMIC_SWAP)
volatile LONG ExHotpSyncRenameSequence = 0;
NTSTATUS
ExpSyncRenameFiles(
IN HANDLE FileHandle1,
OUT PIO_STATUS_BLOCK IoStatusBlock1,
IN PFILE_RENAME_INFORMATION RenameInformation1,
IN ULONG RenameInformationLength1,
IN HANDLE FileHandle2,
OUT PIO_STATUS_BLOCK IoStatusBlock2,
IN PFILE_RENAME_INFORMATION RenameInformation2,
IN ULONG RenameInformationLength2
)
/*++
Routine Description:
This service changes the provided information about a specified file. The
information that is changed is determined by the FileInformationClass that
is specified. The new information is taken from the FileInformation buffer.
Arguments:
FileHandle1 - Supplies a first handle to the file to be renamed.
IoStatusBlock1 - Address of the caller's I/O status block.
FileInformation1 - Supplies the new name for the first file.
RenameInformationLength1 - Supplies the lengtd of the rename information buffer
FileHandle2 - Supplies a second handle to the file to be renamed.
IoStatusBlock2 - Address of the second caller's I/O status block.
FileInformation2 - Supplies the new name for the second file.
RenameInformationLength2 - Supplies the lengtd of the rename information buffer
Return Value:
The status returned is the final completion status of the operation.
--*/
{
NTSTATUS Status;
LONG CapturedSeqNumber;
PAGED_CODE();
CapturedSeqNumber = ExHotpSyncRenameSequence;
if ((CapturedSeqNumber & 1)
||
InterlockedCompareExchange(&ExHotpSyncRenameSequence, CapturedSeqNumber + 1, CapturedSeqNumber) != CapturedSeqNumber) {
return STATUS_UNSUCCESSFUL;
}
Status = NtSetInformationFile( FileHandle1,
IoStatusBlock1,
RenameInformation1,
RenameInformationLength1,
FileRenameInformation);
if ( NT_SUCCESS(Status) ) {
Status = NtSetInformationFile( FileHandle2,
IoStatusBlock2,
RenameInformation2,
RenameInformationLength2,
FileRenameInformation);
}
InterlockedIncrement(&ExHotpSyncRenameSequence);
return Status;
}
NTSTATUS
ExApplyCodePatch (
IN PVOID PatchInfoPtr,
IN SIZE_T PatchSize
)
/*++
Routine Description:
This routine is handling the common tasks to both user-mode
and kernel-mode patching
Arguments:
PatchInfoPtr - Pointer to PSYSTEM_HOTPATCH_CODE_INFORMATION structure
describing the patch. The pointer is user-mode.
PatchSize - the size of the PatchInfoPtr buffer passed in
Return Value:
NTSTATUS.
--*/
{
PSYSTEM_HOTPATCH_CODE_INFORMATION PatchInfo;
NTSTATUS Status = STATUS_SUCCESS;
KPROCESSOR_MODE PreviousMode;
//
// Allocate a temporary non-paged buffer to capture the used information
// Restrict the size of the data to be patched to EXP_MAX_HOTPATCH_INFO_SIZE
// The buffer must be non-paged because the information is accessed at DPC of higher level
//
if ( (PatchSize > (sizeof(SYSTEM_HOTPATCH_CODE_INFORMATION) + EXP_MAX_HOTPATCH_INFO_SIZE))
||
(PatchSize < sizeof(SYSTEM_HOTPATCH_CODE_INFORMATION)) ) {
return STATUS_INVALID_PARAMETER;
}
PatchInfo = ExAllocatePoolWithQuotaTag (NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
PatchSize,
'PtoH');
if (PatchInfo == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
PreviousMode = KeGetPreviousMode ();
try {
//
// Get previous processor mode and probe output argument if necessary.
//
if (PreviousMode != KernelMode) {
ProbeForRead (PatchInfoPtr, PatchSize, sizeof(ULONG_PTR));
}
RtlCopyMemory (PatchInfo, PatchInfoPtr, PatchSize);
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode ();
}
if (!NT_SUCCESS(Status)) {
ExFreePool (PatchInfo);
return Status;
}
if (PatchInfo->Flags & FLG_HOTPATCH_PRIVILEGED_FLAGS) {
if (!SeSinglePrivilegeCheck (SeDebugPrivilege, PreviousMode)
||
!SeSinglePrivilegeCheck (SeLoadDriverPrivilege, PreviousMode)) {
ExFreePool (PatchInfo);
return STATUS_ACCESS_DENIED;
}
}
if (PatchInfo->Flags & FLG_HOTPATCH_EXCLUSIVE_FLAGS) {
//
// Special hotpatch operation
//
if (PatchInfo->Flags & FLG_HOTPATCH_RELOAD_NTDLL) {
Status = PsLocateSystemDll( TRUE );
} else if (PatchInfo->Flags & FLG_HOTPATCH_RENAME_INFO) {
//
// The io routine is expected to perform the parameter check
//
Status = ExpSyncRenameFiles( PatchInfo->RenameInfo.FileHandle1,
PatchInfo->RenameInfo.IoStatusBlock1,
PatchInfo->RenameInfo.RenameInformation1,
PatchInfo->RenameInfo.RenameInformationLength1,
PatchInfo->RenameInfo.FileHandle2,
PatchInfo->RenameInfo.IoStatusBlock2,
PatchInfo->RenameInfo.RenameInformation2,
PatchInfo->RenameInfo.RenameInformationLength2);
} else if (PatchInfo->Flags & FLG_HOTPATCH_MAP_ATOMIC_SWAP) {
Status = ObSwapObjectNames( PatchInfo->AtomicSwap.ParentDirectory,
PatchInfo->AtomicSwap.ObjectHandle1,
PatchInfo->AtomicSwap.ObjectHandle2,
0);
}
} else {
//
// Regular patch operation which can be in either kernel mode or user mode
//
if (PatchInfo->Flags & FLG_HOTPATCH_KERNEL) {
//
// Kernel-mode patch
//
if ( (PatchInfo->InfoSize != PatchSize)
||
!(PatchInfo->Flags & FLG_HOTPATCH_NAME_INFO)
||
(PatchInfo->KernelInfo.NameOffset >= PatchSize)
||
(PatchInfo->KernelInfo.NameLength >= PatchSize)
||
((ULONG)(PatchInfo->KernelInfo.NameOffset + PatchInfo->KernelInfo.NameLength) > PatchSize)) {
Status = STATUS_INVALID_PARAMETER;
} else {
Status = MmHotPatchRoutine (PatchInfo);
}
} else {
//
// User-mode patch
//
// No privilege check is required for the user mode patching
// as it can only be done to the current process
//
//
// Lock the user buffer. This function also performs the
// validation of the patch address to be USER
//
if ((PatchSize < sizeof(SYSTEM_HOTPATCH_CODE_INFORMATION))
||
(PatchInfo->InfoSize != PatchSize)
||
((PatchInfo->CodeInfo.DescriptorsCount - 1) >
(PatchSize - sizeof(SYSTEM_HOTPATCH_CODE_INFORMATION))/sizeof(HOTPATCH_HOOK_DESCRIPTOR))) {
ExFreePool (PatchInfo);
return STATUS_INVALID_PARAMETER;
}
Status = MmLockAndCopyMemory(PatchInfo, PreviousMode);
}
}
ExFreePool (PatchInfo);
return Status;
}