Allow buffer mapping to happen concurrently
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
88bde5b28e
commit
d82a68f830
56
wintun.c
56
wintun.c
@ -112,9 +112,11 @@ typedef struct _TUN_CTX
|
||||
|
||||
typedef struct _TUN_MAPPED_UBUFFER
|
||||
{
|
||||
VOID *UserAddress, *KernelAddress;
|
||||
VOID *volatile UserAddress;
|
||||
VOID *KernelAddress;
|
||||
MDL *Mdl;
|
||||
ULONG Size;
|
||||
FAST_MUTEX InitializationComplete;
|
||||
// TODO: ThreadID for checking
|
||||
} TUN_MAPPED_UBUFFER;
|
||||
|
||||
@ -295,38 +297,56 @@ _Must_inspect_result_
|
||||
static NTSTATUS
|
||||
TunMapUbuffer(_Inout_ TUN_MAPPED_UBUFFER *MappedBuffer, _In_ VOID *UserAddress, _In_ ULONG Size)
|
||||
{
|
||||
if (MappedBuffer->UserAddress)
|
||||
VOID *current_uaddr = InterlockedGetPointer(&MappedBuffer->UserAddress);
|
||||
if (current_uaddr)
|
||||
{
|
||||
if (UserAddress == MappedBuffer->UserAddress) // TODO: Check ThreadID
|
||||
if (UserAddress == current_uaddr) // TODO: Check ThreadID
|
||||
return STATUS_SUCCESS;
|
||||
return STATUS_ALREADY_INITIALIZED;
|
||||
}
|
||||
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
ExAcquireFastMutex(&MappedBuffer->InitializationComplete);
|
||||
|
||||
// Recheck the same thing as above, but locked this time.
|
||||
current_uaddr = InterlockedGetPointer(&MappedBuffer->UserAddress);
|
||||
if (current_uaddr)
|
||||
{
|
||||
if (UserAddress != current_uaddr) // TODO: Check ThreadID
|
||||
status = STATUS_ALREADY_INITIALIZED;
|
||||
goto err_releasemutex;
|
||||
}
|
||||
|
||||
MappedBuffer->Mdl = IoAllocateMdl(UserAddress, Size, FALSE, FALSE, NULL);
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
if (!MappedBuffer->Mdl)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto err_releasemutex;
|
||||
|
||||
status = STATUS_INVALID_USER_BUFFER;
|
||||
try
|
||||
{
|
||||
MmProbeAndLockPages(MappedBuffer->Mdl, UserMode, IoWriteAccess);
|
||||
}
|
||||
except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
IoFreeMdl(MappedBuffer->Mdl);
|
||||
MappedBuffer->Mdl = NULL;
|
||||
return STATUS_INVALID_USER_BUFFER;
|
||||
}
|
||||
except(EXCEPTION_EXECUTE_HANDLER) { goto err_freemdl; }
|
||||
|
||||
MappedBuffer->KernelAddress =
|
||||
MmGetSystemAddressForMdlSafe(MappedBuffer->Mdl, NormalPagePriority | MdlMappingNoExecute);
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
if (!MappedBuffer->KernelAddress)
|
||||
{
|
||||
MmUnlockPages(MappedBuffer->Mdl);
|
||||
IoFreeMdl(MappedBuffer->Mdl);
|
||||
MappedBuffer->Mdl = NULL;
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
MappedBuffer->UserAddress = UserAddress;
|
||||
goto err_unlockmdl;
|
||||
MappedBuffer->Size = Size;
|
||||
InterlockedExchangePointer(&MappedBuffer->UserAddress, UserAddress);
|
||||
ExReleaseFastMutex(&MappedBuffer->InitializationComplete);
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
err_unlockmdl:
|
||||
MmUnlockPages(MappedBuffer->Mdl);
|
||||
err_freemdl:
|
||||
IoFreeMdl(MappedBuffer->Mdl);
|
||||
MappedBuffer->Mdl = NULL;
|
||||
err_releasemutex:
|
||||
ExReleaseFastMutex(&MappedBuffer->InitializationComplete);
|
||||
return status;
|
||||
}
|
||||
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
@ -974,6 +994,8 @@ TunDispatchCreate(_Inout_ TUN_CTX *Ctx, _Inout_ IRP *Irp)
|
||||
if (!file_ctx)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
RtlZeroMemory(file_ctx, sizeof(*file_ctx));
|
||||
ExInitializeFastMutex(&file_ctx->ReadBuffer.InitializationComplete);
|
||||
ExInitializeFastMutex(&file_ctx->WriteBuffer.InitializationComplete);
|
||||
|
||||
KIRQL irql = ExAcquireSpinLockShared(&Ctx->TransitionLock);
|
||||
LONG flags = InterlockedGet(&Ctx->Flags);
|
||||
|
Loading…
Reference in New Issue
Block a user