/****************************** Module Header ******************************\ * Module Name: heap.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * This module contains kernel-mode heap management code. * * History: * 03-16-95 JimA Created. \***************************************************************************/ #include "precomp.h" #pragma hdrstop NTSTATUS UserCommitDesktopMemory( PVOID pBase, PVOID *ppCommit, PSIZE_T pCommitSize) { PDESKTOPVIEW pdv; DWORD dwCommitOffset; PWINDOWSTATION pwinsta; PDESKTOP pdesk; int dCommit; NTSTATUS Status; PETHREAD Thread = PsGetCurrentThread(); /* * If this is a system thread, we have no view of the desktop * and must map it in. Fortunately, this does not happen often. * * We use the Thread variable because PsIsSystemThread is a macro * that multiply resolves the parameter. */ if (PsIsSystemThread(Thread)) { /* * Find the desktop that owns the section. */ for (pwinsta = grpWinStaList; pwinsta; pwinsta = pwinsta->rpwinstaNext) { for (pdesk = pwinsta->rpdeskList; pdesk; pdesk = pdesk->rpdeskNext) { if (pdesk->pDeskInfo->pvDesktopBase == pBase) goto FoundIt; } } FoundIt: if (pwinsta == NULL) { RIPMSG3(RIP_ERROR, "UserCommitDesktopMemory failed: pBase %#p, ppCommit %#p, pCommitSize %d", pBase, ppCommit, *pCommitSize); return STATUS_NO_MEMORY; } /* * Map the section into the current process and commit the * first page of the section. */ dwCommitOffset = (ULONG)((PBYTE)*ppCommit - (PBYTE)pBase); Status = CommitReadOnlyMemory(pdesk->hsectionDesktop, pCommitSize, dwCommitOffset, &dCommit); if (NT_SUCCESS(Status)) { *ppCommit = (PBYTE)*ppCommit + dCommit; } } else { /* * Find the current process' view of the desktop */ for (pdv = PpiCurrent()->pdvList; pdv != NULL; pdv = pdv->pdvNext) { if (pdv->pdesk->pDeskInfo->pvDesktopBase == pBase) break; } /* * 254954: If we didn't find a desktop view then map the desktop view * to the current process. */ if (pdv == NULL) { /* * Find the desktop that owns the section. */ for (pwinsta = grpWinStaList; pwinsta; pwinsta = pwinsta->rpwinstaNext) { for (pdesk = pwinsta->rpdeskList; pdesk; pdesk = pdesk->rpdeskNext) { if (pdesk->pDeskInfo->pvDesktopBase == pBase) goto FoundTheDesktop; } } FoundTheDesktop: if (pwinsta == NULL) { RIPMSG3(RIP_ERROR, "UserCommitDesktopMemory failed: pBase %#p, ppCommit %#p, pCommitSize %d", pBase, ppCommit, *pCommitSize); return STATUS_NO_MEMORY; } UserAssert(pdesk != NULL); /* * Map the desktop into the current process */ { WIN32_OPENMETHOD_PARAMETERS OpenParams; OpenParams.OpenReason = ObOpenHandle; OpenParams.Process = PsGetCurrentProcess(); OpenParams.Object = pdesk; OpenParams.GrantedAccess = 0; OpenParams.HandleCount = 1; if (!NT_SUCCESS (MapDesktop(&OpenParams))) { RIPMSG2(RIP_WARNING, "UserCommitDesktopMemory: Could't map pdesk %#p in ppi %#p", pdesk, PpiCurrent()); return STATUS_NO_MEMORY; } } pdv = GetDesktopView(PpiCurrent(), pdesk); if (pdv == NULL) { RIPMSG2(RIP_ERROR, "UserCommitDesktopMemory: GetDesktopView returns NULL for pdesk %#p in ppi %#p", pdesk, PpiCurrent()); return STATUS_NO_MEMORY; } } /* * Commit the memory using the session view base so it doesn't matter * if the user destroys (and replaces) his usermode view. */ Status = MmCommitSessionMappedView (*ppCommit, *pCommitSize); } return Status; } NTSTATUS UserCommitSharedMemory( PVOID pBase, PVOID *ppCommit, PSIZE_T pCommitSize) { ULONG_PTR ulClientDelta; DWORD dwCommitOffset; PBYTE pUserBase; NTSTATUS Status; PEPROCESS Process; int dCommit; PW32PROCESS pw32p; #if DBG if (pBase != Win32HeapGetHandle(gpvSharedAlloc)) { RIPMSG0(RIP_WARNING, "pBase != gpvSharedAlloc"); } #else UNREFERENCED_PARAMETER(pBase); #endif Process = PsGetCurrentProcess(); ValidateProcessSessionId(Process); pw32p = PsGetProcessWin32Process(Process); if (pw32p == NULL || (((PPROCESSINFO)pw32p)->pClientBase == NULL)) { dwCommitOffset = (ULONG)((PBYTE)*ppCommit - (PBYTE)gpvSharedBase); Status = CommitReadOnlyMemory( ghSectionShared, pCommitSize, dwCommitOffset, &dCommit); if (NT_SUCCESS(Status)) { *ppCommit = (PBYTE) *ppCommit + dCommit; } } else { /* * Commit the memory */ ulClientDelta = (ULONG_PTR)((PBYTE)gpvSharedBase - (PBYTE)(PpiCurrent()->pClientBase)); pUserBase = (PVOID)((PBYTE)*ppCommit - ulClientDelta); Status = ZwAllocateVirtualMemory( NtCurrentProcess(), &pUserBase, 0, pCommitSize, MEM_COMMIT, PAGE_EXECUTE_READ); if (NT_SUCCESS(Status)) { *ppCommit = (PVOID)((PBYTE)pUserBase + ulClientDelta); } } return Status; } PWIN32HEAP UserCreateHeap( HANDLE hSection, ULONG ulViewOffset, PVOID pvBaseAddress, DWORD dwSize, PRTL_HEAP_COMMIT_ROUTINE pfnCommit) { PVOID pUserBase; SIZE_T ulViewSize; LARGE_INTEGER liOffset; PEPROCESS Process = PsGetCurrentProcess(); RTL_HEAP_PARAMETERS HeapParams; NTSTATUS Status; ULONG HeapFlags; ULONG CommitSize; #if defined(_WIN64) CommitSize = 8192; #else CommitSize = 4096; #endif /* * Map the section into the current process and commit the * first page of the section. */ ulViewSize = 0; liOffset.LowPart = ulViewOffset; liOffset.HighPart = 0; pUserBase = NULL; Status = MmMapViewOfSection( hSection, Process, &pUserBase, 0, CommitSize, &liOffset, &ulViewSize, ViewUnmap, SEC_NO_CHANGE, PAGE_EXECUTE_READ); if (!NT_SUCCESS(Status)) return NULL; MmUnmapViewOfSection(Process, pUserBase); /* * We now have a committed page to create the heap in. */ RtlZeroMemory(&HeapParams, sizeof(HeapParams)); HeapParams.Length = sizeof(HeapParams); HeapParams.InitialCommit = CommitSize; HeapParams.InitialReserve = dwSize; HeapParams.CommitRoutine = pfnCommit; UserAssert(HeapParams.InitialCommit < dwSize); HeapFlags = HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY; #if DBG HeapFlags |= HEAP_TAIL_CHECKING_ENABLED; #endif // DBG return Win32HeapCreate("UH_HEAD", "UH_TAIL", HeapFlags, pvBaseAddress, dwSize, CommitSize, NULL, &HeapParams); }