SysStatus PageAllocatorDefault::init(uval start, uval size) { lock.init(); lock.acquire(); anchor = 0; freeList = 0; tassert((PAGE_ROUND_UP(start)==start), err_printf("page allocator does not support unaligned memory\n")); #ifdef DEBUG_MEMORY uval leakSize; leakSize = LeakProof::sizePerEntry*(size/PAGE_SIZE); if (KernelInfo::OnSim()) { leakSize = 200*LeakProof::sizePerEntry; } else { leakSize = 20000*LeakProof::sizePerEntry; } leakSize = size>(16*leakSize)?leakSize:size/16; leakSize = PAGE_ROUND_UP(leakSize); leakProof.init(start+size-leakSize,leakSize); size-=leakSize; #endif /* #ifdef DEBUG_MEMORY */ available = size; extendFreeList(start,size); anchor = freeList; freeList = freeList->low; anchor->start = start; anchor->size = size; anchor->low = anchor->high = 0; lock.release(); return 0; }
static PVOID AllocateGuarded( _In_ SIZE_T SizeRequested) { NTSTATUS Status; SIZE_T Size = PAGE_ROUND_UP(SizeRequested + PAGE_SIZE); PVOID VirtualMemory = NULL; PCHAR StartOfBuffer; Status = NtAllocateVirtualMemory(NtCurrentProcess(), &VirtualMemory, 0, &Size, MEM_RESERVE, PAGE_NOACCESS); if (!NT_SUCCESS(Status)) return NULL; Size -= PAGE_SIZE; if (Size) { Status = NtAllocateVirtualMemory(NtCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE); if (!NT_SUCCESS(Status)) { Size = 0; Status = NtFreeVirtualMemory(NtCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE); ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status); return NULL; } } StartOfBuffer = VirtualMemory; StartOfBuffer += Size - SizeRequested; return StartOfBuffer; }
/* fix the program header that represetns the text segment. * make it large enough to contain the extra bits we are going * to put in - fix both the memory and file size */ int adj_phdr(Elf32_Ehdr *eh32) { Elf32_Phdr *phdr; int phdr_num; int i; int new_text_size; int text_mem_size; phdr = (Elf32_Phdr *)(kern_file+eh32->e_phoff); phdr_num = eh32->e_phnum; if (debug_level == 2) { printf("Dumping phdr information\n"); } /* look for text segment and data segment info */ for (i=0; i<phdr_num; i++,phdr++) { if (debug_level == 2) { dump_phdr(phdr); } if (phdr->p_vaddr == TEXT_VADDR) { text_file_size = phdr->p_filesz; text_mem_size = phdr->p_memsz; text_file_offset = phdr->p_offset; } if (phdr->p_vaddr == DATA_VADDR) { old_data_file_offset = phdr->p_offset; } } if (old_data_file_offset < text_file_offset) { fprintf(stderr, "error data segment before text segment\n"); exit(-1); } /* now go through and adjust text sizes and data offset */ phdr = (Elf32_Phdr *)(kern_file+eh32->e_phoff); for (i=0; i<phdr_num; i++,phdr++) { if (phdr->p_vaddr == TEXT_VADDR) { new_text_size = PAGE_ROUND_UP((BITS_VADDR - TEXT_VADDR) + bits_info.st_size); phdr->p_filesz = new_text_size; phdr->p_memsz = new_text_size; } if (phdr->p_vaddr == DATA_VADDR) { data_file_offset = text_file_offset + new_text_size; amount_push_back = data_file_offset - old_data_file_offset; phdr->p_offset = data_file_offset; } } if (debug_level == 2) { printf("\n\n"); } return 0; }
void MPMsgMgr::init(DispatcherID dspid, MemoryMgrPrimitive *pa, MPMsgMgrRegistryRef ®istry) { SysStatus rc; sendQueue.init(); replyQueue.init(); allocMsgLock.init(); thisDspID = dspid; // allocate array of buffers tassert((sizeof(MsgHolder) == MSG_HOLDER_SIZE), err_printf("oops\n")); const uval amt = NUM_MSGS * sizeof(MsgHolder); uval space; if (pa != NULL) { pa->alloc(space, amt, MSG_CHUNK_SIZE); } else { space = uval(allocGlobalPadded(amt)); } tassert(space != 0, err_printf("couldn't allocate msg buffers\n")); msgHolder = (MsgHolder *) space; uval i; for (i = 0; i < NUM_MSGS; i++) { msgHolder[i].manager = this; msgHolder[i].busy = 0; } nextMsgIdx = 0; // Create the registry, but don't register ourselves yet because our // interrupt handlers haven't been installed. if (dspid == SysTypes::DSPID(0,0)) { if (registry!=NULL) { uval* y = (uval*)PAGE_ROUND_UP((uval)®istry); uval* x = (uval*)PAGE_ROUND_DOWN((uval)®istry); while (x < y) { if (*x) { err_printf("%p: %lx\n",x,*x); } ++x; } } passertMsg(registry == NULL,"MPMsgMgr already initialized %p\n", registry); rc = MPMsgMgrRegistry::Create(registry, pa); tassert(_SUCCESS(rc), err_printf("MPMsgMgrRegistry::Create failed\n")); } registryRef = registry; }
static PVOID AllocateReadOnly( _In_ SIZE_T SizeRequested) { NTSTATUS Status; SIZE_T Size = PAGE_ROUND_UP(SizeRequested); PVOID VirtualMemory = NULL; Status = NtAllocateVirtualMemory(NtCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READONLY); if (!NT_SUCCESS(Status)) return NULL; return VirtualMemory; }
void * allocate_memory( void ) { uint8_t *p; p = mmap( NULL, MEMORY_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0 ); if (p == MAP_FAILED) { err(1, "mmap setup 0"); } physical_memory = p; g_bf = get_aligned(physical_memory, MEMORY_SIZE, STRICTEST_ALIGNMENT, sizeof(*g_bf)); if (g_bf == NULL) { errx(1, "alignment"); } p = mmap( NULL, PAGE_ROUND_UP(sizeof(*sys_io_base)), PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0 ); if (p == MAP_FAILED) { err(1, "mmap setup 1"); } sys_io_base = (SYS_IO_MEMORY_BASE *)p; syscall_memory = &sys_io_base->syscall_memory; io_memory = &sys_io_base->io_memory; memset(syscall_memory, 0, sizeof(*syscall_memory)); memset(io_memory, 0, sizeof(*io_memory)); return (void *)g_bf; }
static VOID MakeReadOnly( PVOID Pointer, SIZE_T SizeRequested) { NTSTATUS Status; SIZE_T Size = PAGE_ROUND_UP(SizeRequested); PVOID VirtualMemory = (PVOID)PAGE_ROUND_DOWN((SIZE_T)Pointer); if (Size) { Status = NtAllocateVirtualMemory(NtCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE); if (!NT_SUCCESS(Status)) { Size = 0; Status = NtFreeVirtualMemory(NtCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE); ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status); } } }
void cleanup_memory( void ) { uint32_t status; status = munmap(sys_io_base, PAGE_ROUND_UP(sizeof(*sys_io_base))); if (status != 0) { err(1, "munmap cleanup 0"); } io_memory = NULL; status = munmap(physical_memory, MEMORY_SIZE); if (status != 0) { err(1, "munmap cleanup 1"); } physical_memory = NULL; }
/*virtual*/ SysStatus ProcessShared<ALLOC>::getMemory(__in uval size, __inout uval &vaddr) { // LOCKING: none needed, only internal access is getRef, // comes back and allocates region via region list SysStatus rc; FCMRef fcmRef; RegionRef regionRef; size = PAGE_ROUND_UP(size); // cprintf("in process default alloc region %ld\n", size); // create region on the users behalf with the size and memory type desired rc = FCMPrimitive<PageSet<AllocGlobal>,AllocGlobal>::Create(fcmRef); if (rc) return rc; rc = RegionDefault::CreateFixedLen(regionRef, getRef(), vaddr, size, 0, fcmRef, 0, AccessMode::writeUserWriteSup); return rc; }
/* unlocked version exists to allow one to atomically expand space while * trying to allocate memory, so only one thread expands the space if * all try to allocate at the same time */ SysStatus PageAllocatorDefault::locked_deallocPages(uval vaddr, uval size) { _ASSERT_HELD(lock); // must be called with lock held #ifdef marcdebug marcCheckAvail(); #endif /* #ifdef marcdebug */ size = PAGE_ROUND_UP(size); tassertMsg((vaddr & PAGE_MASK) == 0, "%lx not page aligned?\n",vaddr); #ifdef DEBUG_MEMORY leakProof.free(vaddr,size); #if 0 /*DEBUG_MEMORY too slow on simulator*/ { uval* p=(uval*)vaddr; //can't aford to clear monster allocations here for (;p<(uval*)(vaddr+PAGE_SIZE);*(p++)=(uval)0xDFDFDFDFDFDFDFDFLL); } #endif /* #if 0 */ #endif /* #ifdef DEBUG_MEMORY */ #ifdef marcdebug marcaddr=vaddr;marcsize=size; if ((vaddr == marcstop) || (vaddr & (PAGE_SIZE-1))) breakpoint(); #endif /* #ifdef marcdebug */ sanity(vaddr, size); // first check for coallesce tassert(((vaddr & (~PAGE_MASK)) == vaddr), err_printf("not aligned?\n")); available += size; freePages *cur = anchor; freePages **top= 0; freePages *cur1; freePages **top1; uval topSize = 0; // size of node top is in // look for coalesce while (cur) { if (cur->start+cur->size == vaddr) { cur->size += size; // No find smallest bigger than this if ((cur1=cur->high)) { top1 = &(cur->high); while (cur1->low) { top1 = &(cur1->low); cur1 = cur1->low; } if ((cur->start+cur->size) == cur1->start) { //coalesce this as well cur->size += cur1->size; *top1 = cur1->high; cur1->low = freeList; freeList = cur1; } } goto enlarge; } else if (vaddr+size == cur->start) { // similar searching to the left cur->start = vaddr; cur->size += size; if ((cur1 = cur->low)) { top1 = &(cur->low); while (cur1->high) { top1= &(cur1->high); cur1 = cur1->high; } if ((cur1->start+cur1->size)==cur->start) { //coalesce this as well cur->start = cur1->start; cur->size += cur1->size; *top1 = cur1->low; cur1->low = freeList; freeList = cur1; } } goto enlarge; } else { topSize = cur->size; if (vaddr<cur->start) { top = &(cur->low); cur = cur->low; } else { top = &(cur->high); cur = cur->high; } } } // no coalesce found - so make new free block cur = freeList; // freelist never empty if (!(freeList = freeList->low)) { // may modify vaddr and size if // space for freelist can't be found elsewhere extendFreeList(vaddr,size); if (size == 0) goto done; } // back to the main story - cur is the new node cur->start = vaddr; cur->size = size; anchor = add(anchor,cur); done: sanity(); #ifdef marcdebug marcCheckAvail(); #endif /* #ifdef marcdebug */ return 0; enlarge: // cur points to enlarged block, topSize size of parent, // top points to parent if (top && (cur->size > topSize)) { // cur has gotten be enough to be in wrong place // remove it from current place *top = merge(cur->low,cur->high); // reinsert it anchor = add(anchor,cur); } goto done; }
/* * * Allocate a region with an alignment or fail. * The aligment is specifed as an alignment and an offset. * The resultant vaddr will satisfy vaddr mod align = offset. * The old style power of two interface is gotten with a power of two * align value, and a zero offset value. * This routine does a brute force search and is relatively expensive. * Note the bounded stack size - this may cause the allocation to fail * when it could be done, or cause a larger than necessary block to be * fragmented. */ SysStatus PageAllocatorDefault::allocPagesAligned(uval &vaddr, uval size, uval align, uval offset, uval f, VPNum n) { (void)f; (void)n; // flags and node parms not used here size = PAGE_ROUND_UP(size); lock.acquire(); #ifdef marcdebug marcCheckAvail(); #endif /* #ifdef marcdebug */ retry: #define STACK_SIZE 64 // Made up value - should be OK freePages *stack[STACK_SIZE]; uval sp = 0; freePages* cur = anchor; freePages** top = &anchor; freePages *found = 0; freePages **foundtop = 0; //search for first (smallest address) block which satisfies aligned request if (!cur) goto bad; while (1) { /* this test sees if the aligned request is within this block * start by rounding block address up as required * vaddr will always be ge cur->start */ vaddr = ((cur->start+align-offset-1)/align)*align+offset; if ((vaddr+size) <= (cur->start+cur->size)) { found = cur; foundtop = top; } // if block is completely too small or has no successors backtrack if ((cur->size < size) || (!(cur->low) && !(cur->high))) { if (found) break; if (sp) { cur = stack[--sp]; top = &(cur->high); cur = cur->high; // every stack entry has a high subtree } else { goto bad; } } else if (cur->low) { // continue down the tree searching if (cur->high && sp<STACK_SIZE) stack[sp++] = cur; top = &(cur->low); cur = cur->low; } else { top = &(cur->high); cur = cur->high; } } // we reach here with found pointing to first feasible block, foundtop // to anchor for that block in the tree // first remove that block vaddr = ((found->start+align-offset-1)/align)*align+offset; allocFromBlock(found,foundtop,vaddr,size); available -= size; tassertMsg((vaddr & PAGE_MASK) == 0, "%lx not page aligned?\n",vaddr); sanity(vaddr, size); #ifdef marcdebug marcCheckAvail(); #endif /* #ifdef marcdebug */ #ifdef DEBUG_MEMORY { leakProof.alloc(vaddr,size); #if 0 uval* p=(uval*)vaddr; //don't kill pages for now - simulator too slow //most unitialized bugs caught by clobber in alloc.H for (;p<(uval*)(vaddr+PAGE_SIZE);*(p++)=(uval)0xBFBFBFBFBFBFBFBFLL); #endif /* #if 0 */ } #endif /* #ifdef DEBUG_MEMORY */ lock.release(); return 0; bad: // call virtual function possibly overridden by subclass to get more space if (_SUCCESS(getMoreMem(size))) goto retry; lock.release(); tassertWrn(0, "warning allocator out of space: " "size %lx align %lx offset %lx\n", size, align, offset); vaddr = 0; return _SERROR(1476, 0, ENOMEM); }
/* * *Allocate the first region of size or return null */ SysStatus PageAllocatorDefault::allocPages(uval &vaddr, uval size, uval f, VPNum n) { (void)f; (void)n; // flags and node parms not used here freePages **top; // address of pointer to subtree freePages *cur, *next; // round up to a multiple of a page size = PAGE_ROUND_UP(size); lock.acquire(); #ifdef marcdebug marcCheckAvail(); #endif /* #ifdef marcdebug */ retry: top = &anchor; cur = anchor; // top node is (one of) the largest blocks if (!cur || cur->size < size) goto nospace; // search for lowest address block which is big enough while (1) { if ((next = cur->low) && (next->size == cur->size)) { //To avoid quadradic behavior allocating a number of //blocks of the same size, we reroot the subtree at the //lower address node of the same size *top = next; cur->low = next->high; next->high = cur; } else if (next && (next->size >= size)) { top = &(cur->low); } else if ((next=cur->high) && (next->size >= size)) { top = &(cur->high); } else break; cur = next; } // cur now points to the lowest address node which can provide size // top points to the pointer to cur in the tree vaddr = cur->start; tassert(((vaddr & (~PAGE_MASK)) == vaddr), err_printf("not aligned?\n")); cur->start += size; cur->size -= size; next = merge(cur->low,cur->high); if (cur->size) { next = add(next,cur); } else { cur->low = freeList; freeList = cur; } *top = next; available -= size; sanity(vaddr,size); #ifdef DEBUG_MEMORY { leakProof.alloc(vaddr,size); #if 0 uval* p=(uval*)vaddr; //don't kill pages for now - simulator too slow //most unitialized bugs caught by clobber in alloc.H for (;p<(uval*)(vaddr+PAGE_SIZE);*(p++)=(uval)0xBFBFBFBFBFBFBFBFLL); #endif /* #if 0 */ } #endif /* #ifdef DEBUG_MEMORY */ #ifdef marcdebug marcCheckAvail(); #endif /* #ifdef marcdebug */ lock.release(); return 0; nospace: // call virtual function possibly overridden by subclass to get more space if (_SUCCESS(getMoreMem(size))) goto retry; tassertWrn(0, "warning allocator out of space: size %lx\n", size); lock.release(); return _SERROR(1474, 0, ENOMEM); }
/* This could be implemented much more intelligently by mapping instances of a CoW zero page into the affected regions. We just RtlZeroMemory for now. */ BOOLEAN NTAPI CcZeroData(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER StartOffset, IN PLARGE_INTEGER EndOffset, IN BOOLEAN Wait) { PNOCC_BCB Bcb = NULL; PLIST_ENTRY ListEntry = NULL; LARGE_INTEGER LowerBound = *StartOffset; LARGE_INTEGER UpperBound = *EndOffset; LARGE_INTEGER Target, End; PVOID PinnedBcb, PinnedBuffer; PNOCC_CACHE_MAP Map = FileObject->SectionObjectPointer->SharedCacheMap; DPRINT("S %08x%08x E %08x%08x\n", StartOffset->u.HighPart, StartOffset->u.LowPart, EndOffset->u.HighPart, EndOffset->u.LowPart); if (!Map) { NTSTATUS Status; IO_STATUS_BLOCK IOSB; PCHAR ZeroBuf = ExAllocatePool(PagedPool, PAGE_SIZE); ULONG ToWrite; if (!ZeroBuf) RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, PAGE_SIZE); RtlZeroMemory(ZeroBuf, PAGE_SIZE); Target.QuadPart = PAGE_ROUND_DOWN(LowerBound.QuadPart); End.QuadPart = PAGE_ROUND_UP(UpperBound.QuadPart); // Handle leading page if (LowerBound.QuadPart != Target.QuadPart) { ToWrite = MIN(UpperBound.QuadPart - LowerBound.QuadPart, (PAGE_SIZE - LowerBound.QuadPart) & (PAGE_SIZE - 1)); DPRINT("Zero last half %08x%08x %x\n", Target.u.HighPart, Target.u.LowPart, ToWrite); Status = MiSimpleRead(FileObject, &Target, ZeroBuf, PAGE_SIZE, TRUE, &IOSB); if (!NT_SUCCESS(Status)) { ExFreePool(ZeroBuf); RtlRaiseStatus(Status); } DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf + LowerBound.QuadPart - Target.QuadPart, ToWrite); RtlZeroMemory(ZeroBuf + LowerBound.QuadPart - Target.QuadPart, ToWrite); Status = MiSimpleWrite(FileObject, &Target, ZeroBuf, MIN(PAGE_SIZE, UpperBound.QuadPart-Target.QuadPart), &IOSB); if (!NT_SUCCESS(Status)) { ExFreePool(ZeroBuf); RtlRaiseStatus(Status); } Target.QuadPart += PAGE_SIZE; } DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, PAGE_SIZE); RtlZeroMemory(ZeroBuf, PAGE_SIZE); while (UpperBound.QuadPart - Target.QuadPart > PAGE_SIZE) { DPRINT("Zero full page %08x%08x\n", Target.u.HighPart, Target.u.LowPart); Status = MiSimpleWrite(FileObject, &Target, ZeroBuf, PAGE_SIZE, &IOSB); if (!NT_SUCCESS(Status)) { ExFreePool(ZeroBuf); RtlRaiseStatus(Status); } Target.QuadPart += PAGE_SIZE; } if (UpperBound.QuadPart > Target.QuadPart) { ToWrite = UpperBound.QuadPart - Target.QuadPart; DPRINT("Zero first half %08x%08x %x\n", Target.u.HighPart, Target.u.LowPart, ToWrite); Status = MiSimpleRead(FileObject, &Target, ZeroBuf, PAGE_SIZE, TRUE, &IOSB); if (!NT_SUCCESS(Status)) { ExFreePool(ZeroBuf); RtlRaiseStatus(Status); } DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, ToWrite); RtlZeroMemory(ZeroBuf, ToWrite); Status = MiSimpleWrite(FileObject, &Target, ZeroBuf, MIN(PAGE_SIZE, UpperBound.QuadPart-Target.QuadPart), &IOSB); if (!NT_SUCCESS(Status)) { ExFreePool(ZeroBuf); RtlRaiseStatus(Status); } Target.QuadPart += PAGE_SIZE; } ExFreePool(ZeroBuf); return TRUE; } CcpLock(); ListEntry = Map->AssociatedBcb.Flink; while (ListEntry != &Map->AssociatedBcb) { Bcb = CONTAINING_RECORD(ListEntry, NOCC_BCB, ThisFileList); CcpReferenceCache(Bcb - CcCacheSections); if (Bcb->FileOffset.QuadPart + Bcb->Length >= LowerBound.QuadPart && Bcb->FileOffset.QuadPart < UpperBound.QuadPart) { DPRINT("Bcb #%x (@%08x%08x)\n", Bcb - CcCacheSections, Bcb->FileOffset.u.HighPart, Bcb->FileOffset.u.LowPart); Target.QuadPart = MAX(Bcb->FileOffset.QuadPart, LowerBound.QuadPart); End.QuadPart = MIN(Map->FileSizes.ValidDataLength.QuadPart, UpperBound.QuadPart); End.QuadPart = MIN(End.QuadPart, Bcb->FileOffset.QuadPart + Bcb->Length); CcpUnlock(); if (!CcPreparePinWrite(FileObject, &Target, End.QuadPart - Target.QuadPart, TRUE, Wait, &PinnedBcb, &PinnedBuffer)) { return FALSE; } ASSERT(PinnedBcb == Bcb); CcpLock(); ListEntry = ListEntry->Flink; /* Return from pin state */ CcpUnpinData(PinnedBcb, TRUE); } CcpUnpinData(Bcb, TRUE); } CcpUnlock(); return TRUE; }
NTSTATUS openProcByName(PHANDLE pProcess, PUNICODE_STRING pProcName, BOOLEAN useDebugPrivilege) { SYSTEM_PROCESS_INFORMATION procInfo; OBJECT_ATTRIBUTES procAttr; OBJECT_BASIC_INFORMATION processHandleInfo; CLIENT_ID cid; BOOLEAN oldValue; HANDLE pid; NTSTATUS status = STATUS_CACHE_PAGE_LOCKED; ULONG procListSize = 0; ULONGLONG memSize = 0; ULONG obQueryLen = 0; PVOID pProcListHead = NULL; PSYSTEM_PROCESS_INFORMATION pProcEntry = NULL; do { if (!pProcName || !pProcess) { status = STATUS_INVALID_PARAMETER; break; } *pProcess = NULL; ///Since we specify a buffer size of 0 the buffer must overflow for sure even if there was running a ///single process only. If we don't receive the dedicated error, something other has gone wrong ///and we cannot rely on the return length. status = NtQuerySystemInformation(SystemProcessInformation, &procInfo, procListSize, &procListSize); if (STATUS_INFO_LENGTH_MISMATCH != status) break; memSize = PAGE_ROUND_UP(procListSize) + PAGE_SIZE; ///We better allocate one page extra ///since between our "test" call and the real call below ///additional processes might be started. (race condition) status = NtAllocateVirtualMemory(INVALID_HANDLE_VALUE, &pProcListHead, 0, &memSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (status) { pProcListHead = NULL; break; } ///By now, we have allocated a buffer large enough for the complete process list, ///even if some new processes have been started in the mean time. ///Hence, the next call is entirely expected to succeed. procListSize = (ULONG)memSize; status = NtQuerySystemInformation(SystemProcessInformation, pProcListHead, procListSize, &procListSize); if (status) break; pid = NULL; pProcEntry = pProcListHead; ///The list of all system processes is a so called singly linked list. while (pProcEntry->NextEntryOffset) { ///If NextEntryOffset member is NULL, we have reached the list end (tail). pProcEntry = (PSYSTEM_PROCESS_INFORMATION)((PUCHAR)pProcEntry + pProcEntry->NextEntryOffset); //DebugPrint2A("PID: %d, %wZ", pProcEntry->UniqueProcessId, pProcEntry->ImageName); if (0 == RtlCompareUnicodeString(pProcName, &pProcEntry->ImageName, TRUE)) { pid = pProcEntry->UniqueProcessId; break; } } if (!pid) { status = STATUS_OBJECT_NAME_NOT_FOUND; break; } if (useDebugPrivilege) { status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &oldValue); if (status){ ///Since we're for some reason supposed to use the SeDebugPrivilege, useDebugPrivilege = FALSE; break; ///we fail deliberately if we can't enable it. } } InitializeObjectAttributes(&procAttr, NULL, 0, NULL, NULL); cid.UniqueThread = (HANDLE)0; cid.UniqueProcess = pid; ///Opening a process for full access might be less suspicious than opening with our real intentions. status = NtOpenProcess(pProcess, PROCESS_ALL_ACCESS, &procAttr, &cid); if (status) { ///Most likely STATUS_ACCESS_DENIED if ///either we didn't specify the useDebugPrivilege flag when opening a cross session process ///or if we tried to open an elevated process while running non-elevated ///or if the process being opened is a so-called "Protected Process". ///In x64 windows, HIPS or AV drivers have the possibility to legally ///receive a notification if a process is about to open a handle to another process. ///In those ObCallback routines they cannot completely deny the opening. ///However, they are able to modify the access masks, so a handle supposed for VM operations still ///will be lacking the PROCESS_VM_XXX rights, for example. If we therefore query the handle rights ///we can still return an appropriate error if wasn't granted the rights we want ///And are not going to fail at first when performing our process operations. *pProcess = NULL; break; } status = NtQueryObject(*pProcess, ObjectBasicInformation, &processHandleInfo, sizeof(OBJECT_BASIC_INFORMATION), &obQueryLen); if (status) ///Not sure if this call ever will fail... break; ///Maybe, HIPS just wanted to deny PROCESS_TERMINATE/PROCESS_SUSPEND right? ///If so, we don't care. We're only interested in VM rights. if (MIN_VM_ACCESS_MASK & ~processHandleInfo.GrantedAccess) { status = STATUS_UNSUCCESSFUL; break; } } while (status); if (status && pProcess) { if (*pProcess) { NtClose(*pProcess); *pProcess = NULL; } } if (pProcListHead) { memSize = 0; NtFreeVirtualMemory(INVALID_HANDLE_VALUE, &pProcListHead, &memSize, MEM_RELEASE); ///We don't need the list anymore. } if (useDebugPrivilege) RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, oldValue, FALSE, &oldValue); ///We don't need the privilege anymore. return status; }
VOID NTAPI MiInitializeSpecialPool() { ULONG SpecialPoolPtes, i; PMMPTE PointerPte; /* Check if there is a special pool tag */ if ((MmSpecialPoolTag == 0) || (MmSpecialPoolTag == -1)) return; /* Calculate number of system PTEs for the special pool */ if ( MmNumberOfSystemPtes >= 0x3000 ) SpecialPoolPtes = MmNumberOfSystemPtes / 3; else SpecialPoolPtes = MmNumberOfSystemPtes / 6; /* Don't let the number go too high */ if (SpecialPoolPtes > 0x6000) SpecialPoolPtes = 0x6000; /* Round up to the page size */ SpecialPoolPtes = PAGE_ROUND_UP(SpecialPoolPtes); ASSERT((SpecialPoolPtes & (PTE_PER_PAGE - 1)) == 0); /* Reserve those PTEs */ do { PointerPte = MiReserveAlignedSystemPtes(SpecialPoolPtes, 0, /*0x400000*/0); // FIXME: if (PointerPte) break; /* Reserving didn't work, so try to reduce the requested size */ ASSERT(SpecialPoolPtes >= PTE_PER_PAGE); SpecialPoolPtes -= 1024; } while (SpecialPoolPtes); /* Fail if we couldn't reserve them at all */ if (!SpecialPoolPtes) return; /* Make sure we got enough */ ASSERT(SpecialPoolPtes >= PTE_PER_PAGE); /* Save first PTE and its address */ MiSpecialPoolFirstPte = PointerPte; MmSpecialPoolStart = MiPteToAddress(PointerPte); for (i = 0; i<512; i++) { /* Point it to the next entry */ PointerPte->u.List.NextEntry = &PointerPte[2] - MmSystemPteBase; /* Move to the next pair */ PointerPte += 2; } /* Save extra values */ MiSpecialPoolExtra = PointerPte; MiSpecialPoolExtraCount = SpecialPoolPtes - 1024; /* Mark the previous PTE as the last one */ MiSpecialPoolLastPte = PointerPte - 2; MiSpecialPoolLastPte->u.List.NextEntry = MM_EMPTY_PTE_LIST; /* Save end address of the special pool */ MmSpecialPoolEnd = MiPteToAddress(MiSpecialPoolLastPte + 1); /* Calculate maximum non-paged part of the special pool */ MiSpecialPagesNonPagedMaximum = MmResidentAvailablePages >> 4; /* And limit it if it turned out to be too big */ if (MmNumberOfPhysicalPages > 0x3FFF) MiSpecialPagesNonPagedMaximum = MmResidentAvailablePages >> 3; DPRINT1("Special pool start %p - end %p\n", MmSpecialPoolStart, MmSpecialPoolEnd); //MiTestSpecialPool(); }
NTSTATUS SetupCopyFile( PWCHAR SourceFileName, PWCHAR DestinationFileName) { OBJECT_ATTRIBUTES ObjectAttributes; HANDLE FileHandleSource; HANDLE FileHandleDest; static IO_STATUS_BLOCK IoStatusBlock; FILE_STANDARD_INFORMATION FileStandard; FILE_BASIC_INFORMATION FileBasic; ULONG RegionSize; UNICODE_STRING FileName; NTSTATUS Status; PVOID SourceFileMap = 0; HANDLE SourceFileSection; SIZE_T SourceSectionSize = 0; LARGE_INTEGER ByteOffset; #ifdef __REACTOS__ RtlInitUnicodeString(&FileName, SourceFileName); InitializeObjectAttributes(&ObjectAttributes, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandleSource, GENERIC_READ, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ, FILE_SEQUENTIAL_ONLY); if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenFile failed: %x, %wZ\n", Status, &FileName); goto done; } #else FileHandleSource = CreateFileW(SourceFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (FileHandleSource == INVALID_HANDLE_VALUE) { Status = STATUS_UNSUCCESSFUL; goto done; } #endif Status = NtQueryInformationFile(FileHandleSource, &IoStatusBlock, &FileStandard, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtQueryInformationFile failed: %x\n", Status); goto closesrc; } Status = NtQueryInformationFile(FileHandleSource, &IoStatusBlock,&FileBasic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtQueryInformationFile failed: %x\n", Status); goto closesrc; } Status = NtCreateSection(&SourceFileSection, SECTION_MAP_READ, NULL, NULL, PAGE_READONLY, SEC_COMMIT, FileHandleSource); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateSection failed: %x, %S\n", Status, SourceFileName); goto closesrc; } Status = NtMapViewOfSection(SourceFileSection, NtCurrentProcess(), &SourceFileMap, 0, 0, NULL, &SourceSectionSize, ViewUnmap, 0, PAGE_READONLY ); if (!NT_SUCCESS(Status)) { DPRINT1("NtMapViewOfSection failed: %x, %S\n", Status, SourceFileName); goto closesrcsec; } RtlInitUnicodeString(&FileName, DestinationFileName); InitializeObjectAttributes(&ObjectAttributes, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtCreateFile(&FileHandleDest, GENERIC_WRITE | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, FILE_NO_INTERMEDIATE_BUFFERING | FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(Status)) { /* Open may have failed because the file to overwrite * is in readonly mode */ if (Status == STATUS_ACCESS_DENIED) { FILE_BASIC_INFORMATION FileBasicInfo; /* Reattempt to open it with limited access */ Status = NtCreateFile(&FileHandleDest, FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_NO_INTERMEDIATE_BUFFERING | FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); /* Fail for real if we cannot open it that way */ if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateFile failed: %x, %wZ\n", Status, &FileName); goto unmapsrcsec; } /* Zero our basic info, just to set attributes */ RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo)); /* Reset attributes to normal, no read-only */ FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL; /* We basically don't care about whether it succeed: * if it didn't, later open will fail */ NtSetInformationFile(FileHandleDest, &IoStatusBlock, &FileBasicInfo, sizeof(FileBasicInfo), FileBasicInformation); /* Close file */ NtClose(FileHandleDest); /* And re-attempt overwrite */ Status = NtCreateFile(&FileHandleDest, GENERIC_WRITE | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, FILE_NO_INTERMEDIATE_BUFFERING | FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); } /* We failed */ if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateFile failed: %x, %wZ\n", Status, &FileName); goto unmapsrcsec; } } RegionSize = (ULONG)PAGE_ROUND_UP(FileStandard.EndOfFile.u.LowPart); IoStatusBlock.Status = 0; ByteOffset.QuadPart = 0ULL; Status = NtWriteFile(FileHandleDest, NULL, NULL, NULL, &IoStatusBlock, SourceFileMap, RegionSize, &ByteOffset, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n", Status, IoStatusBlock.Status, &IoStatusBlock, SourceFileMap, RegionSize); goto closedest; } /* Copy file date/time from source file */ Status = NtSetInformationFile(FileHandleDest, &IoStatusBlock, &FileBasic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtSetInformationFile failed: %x\n", Status); goto closedest; } /* shorten the file back to it's real size after completing the write */ Status = NtSetInformationFile(FileHandleDest, &IoStatusBlock, &FileStandard.EndOfFile, sizeof(FILE_END_OF_FILE_INFORMATION), FileEndOfFileInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtSetInformationFile failed: %x\n", Status); } closedest: NtClose(FileHandleDest); unmapsrcsec: NtUnmapViewOfSection(NtCurrentProcess(), SourceFileMap); closesrcsec: NtClose(SourceFileSection); closesrc: NtClose(FileHandleSource); done: return Status; }
NTSTATUS obtainImageFileEatEntries(PVOID pImageFileBase, PUCHAR pListBuffer, PULONGLONG pNeededBufferSize, PUCHAR pModuleName, ULONGLONG moduleNameSize){ UCHAR szError[] = "Error"; ULONGLONG nameLength = 0; ULONGLONG maxReadSize = 0; ULONGLONG minExportSize = 0; NTSTATUS status = STATUS_UNABLE_TO_UNLOAD_MEDIA; ULONGLONG exportSize = 0; PIMAGE_NT_HEADERS64 pImagePeHdr = NULL; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL; PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL; PULONG piListBuffer = NULL; PULONG pNameRvaArray = NULL; PUCHAR pCurrName = NULL; PUCHAR pListPointer = NULL; if (!pImageFileBase || !pNeededBufferSize || !pModuleName) return STATUS_INVALID_PARAMETER; if (!pListBuffer && *pNeededBufferSize) return STATUS_INVALID_PARAMETER; pImagePeHdr = (PIMAGE_NT_HEADERS64)((PUCHAR)pImageFileBase + ((PIMAGE_DOS_HEADER)pImageFileBase)->e_lfanew); pDataDirectory = pImagePeHdr->OptionalHeader.DataDirectory; ///Is it safe to read the data directory array until the desired entry? maxReadSize = sizeof(IMAGE_DATA_DIRECTORY) * (IMAGE_DIRECTORY_ENTRY_EXPORT + 1); status = validatePePointer(pImageFileBase, pDataDirectory, maxReadSize, TRUE); if (status) return status; pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pImageFileBase + pDataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); ///Is it safe to read all members of the export directory structure? maxReadSize = sizeof(IMAGE_EXPORT_DIRECTORY); status = validatePePointer(pImageFileBase, pExportDirectory, maxReadSize, FALSE); if (status) return status; ///Is the claimed export size viable? exportSize = pDataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; status = validatePePointer(pImageFileBase, pExportDirectory, exportSize, FALSE); if (status) return status; ///By doing some math one can prove that the maximum needed buffer size is guaranteed ///to not exceed the export directory size: Due to PE specifications the export size is going to be ///more than at least: all_namelengths + NumberOfNames * (sizeof(ANSI_NULL) + sizeof(ULONG)). ///This simplifies to: all_namelengths + 5 * NumberOfNames. ///Since we will be adding one more char for each name entry, our actual needed buffer size becomes at maximum: ///all_namelengths + NumberOfNames * 2 * sizeof(char), which simplifies to all_namelengths + 2 * NumberOfNames. ///As we can see, there exists still a huge safety margin, even though we completely neglected ///the sizes of both the function RVA and the ordinal tables. It is therefore fully sufficient if we ///set the needed buffer size to the export size. if (*pNeededBufferSize < PAGE_ROUND_UP(exportSize)){ *pNeededBufferSize = PAGE_ROUND_UP(exportSize); return STATUS_BUFFER_TOO_SMALL; } ///Is it safe to scan down the name RVA array? pNameRvaArray = (PULONG)((PUCHAR)pImageFileBase + pExportDirectory->AddressOfNames); maxReadSize = pExportDirectory->NumberOfNames * sizeof(ULONG); status = validatePePointer(pImageFileBase, pNameRvaArray, maxReadSize, FALSE); if (status) return status; ///Since NumberOfNames can be any value, we need to roughly estimate the exportSize ///according to the combined sizes of the three export describing arrays. ///If this yields to greater export size than the claimed export size, the image must be rejected. minExportSize = sizeof(ULONG) * pExportDirectory->NumberOfFunctions + pExportDirectory->NumberOfNames * sizeof(ULONG) + sizeof(USHORT) + sizeof(ANSI_NULL); if (exportSize <= minExportSize) return STATUS_INVALID_IMAGE_FORMAT; ///It is NOT guaranteed, that an entry in the name RVA array at position 'n' has a value ///which also orders as the n-th element in the entire name RVA range. ///It is therefore not permissible to calculate the name length by simply doing ///pNameRvaArray[n+1] - pNameRvaArray[n]. If we still want to make this assumption ///the RVAs values must be sorted until they are in an ascending order. ///By utilizing the last unused bytes of the caller-allocated buffer we avoid having ///to allocate a buffer on our own. Doing the math above (see exportsize calculation) ///one can prove that the safety margin is sufficient if we use the buffer in that way. piListBuffer = (PULONG)(pListBuffer + *pNeededBufferSize - pExportDirectory->NumberOfNames * sizeof(ULONG)); RtlCopyMemory(piListBuffer, pNameRvaArray, pExportDirectory->NumberOfNames * sizeof(ULONG)); qsort(piListBuffer, (ULONGLONG)pExportDirectory->NumberOfNames, sizeof(ULONG), mycompare); ///Is it safe to read the module name? maxReadSize = pNameRvaArray[0] - pExportDirectory->Name; status = validatePePointer(pImageFileBase, (PVOID)((PUCHAR)pImageFileBase + pExportDirectory->Name), maxReadSize, FALSE); if (status) return status; if (moduleNameSize < maxReadSize) return STATUS_STACK_OVERFLOW; RtlCopyMemory(pModuleName, (PUCHAR)pImageFileBase + pExportDirectory->Name, maxReadSize); pModuleName[maxReadSize - 1] = 0x0; pListPointer = pListBuffer; printf_s("\nmodule name: %s", pModuleName); pNameRvaArray = piListBuffer; for (ULONG i = 0; i < pExportDirectory->NumberOfNames; i++){ ///Will none of the obtained name RVAs evaluate to an invalid name pointer? if (!(exportSize + pDataDirectory->VirtualAddress > pNameRvaArray[i])) return STATUS_INVALID_IMAGE_FORMAT; pCurrName = (PUCHAR)pImageFileBase + pNameRvaArray[i]; ///At the end of RVA array there is no longer a next name entry. ///There must by PE design a terminating zero though, which we're going to exploit ///in order to still have a valid name length. if (pExportDirectory->NumberOfNames - 1 == i){ int j = 0; while (pCurrName[j]) j++; nameLength = j; } else{ nameLength = (ULONGLONG)(pNameRvaArray[i + 1] - pNameRvaArray[i]/*pNextName - pCurrName*/) - 1; } ///If for some reason the allocated buffer is about to be overran ///we print an error signature into the buffer and abort the scan. ///In regard of our thousands of sanity checks this surely denotes a major PE damage. ///Additionally, we break a little earlier to not have the failure overwrite the sorted RVAs. if ((PUCHAR)piListBuffer <= pListPointer + nameLength + sizeof(WCHAR)){ pCurrName = szError; nameLength = sizeof(szError) - 1; pListPointer = (PUCHAR)piListBuffer - (nameLength + sizeof(WCHAR)); ///Indirect break, bail out. i = pExportDirectory->NumberOfNames; } RtlCopyMemory(pListPointer, pCurrName, nameLength); *(PWCHAR)&pListPointer[nameLength] = (WCHAR)0x0A0D; pListPointer += nameLength + sizeof(WCHAR); } ///Hit two birds with one stone by replacing last 0D 0A sequence with a terminating WCHAR 0. *((PWCHAR)pListPointer - 1) = (WCHAR)0x0; *pNeededBufferSize = (ULONGLONG)(pListPointer - pListBuffer); return STATUS_SUCCESS; }
/* virtual */ SysStatus PacketRing::init(ProcessID caller, uval &vaddrTX, uval &vaddrRX, uval txSize, uval rxSize) { SysStatus rc; uval size; refCount = 0; beingDestroyed = 0; pageArrayNumTX = 0; pageArrayNumRX = 0; packetCountRX = 0; ringCurrentIdxRX = 0; ringCurrentOffsetRX = 0; ringCurrentIdxTX = pageArrayNumRX; ringCurrentOffsetTX = 0; beginIdxRX = 0; beginOffsetRX = 0; beginIdxTX = pageArrayNumRX; beginOffsetTX = 0; packetsReceived = 0; packetsTransmitted = 0; packetsDropped = 0; packetsRecvCoalesced = 0; fcmOffset = 0; // Get references for the process DREFGOBJ(TheProcessSetRef)->getRefFromPID(caller, (BaseProcessRef &)processRef); // Create new FCM rc = FCMFixed<AllocGlobal>::Create(fcmRef); if (_FAILURE(rc)) { err_printf("create fcm failed: %#lx\n", rc); return rc; } size = PAGE_ROUND_UP(rxSize) + PAGE_ROUND_UP(txSize) + PAGE_SIZE; // Create shared region rc = RegionDefault::CreateFixedLen(regionRef, processRef, baseVaddr, size, 0, fcmRef, 0, AccessMode::writeUserWriteSup); if (_FAILURE(rc)) { err_printf("create region failed: %#lx\n", rc); return rc; } // Allocate packet rings rc = allocRings(PAGE_ROUND_UP(txSize), PAGE_ROUND_UP(rxSize)); if (_FAILURE(rc)) { err_printf("allocRings failed\n"); return rc; } // Allocate ctrl region rc = allocCtrl(); if (_FAILURE(rc)) { err_printf("allocCtrl failed\n"); return rc; } vaddrRX = baseVaddr; vaddrTX = baseVaddr + PAGE_ROUND_UP(rxSize); return 0; }
SysStatus RegionReplicated::RegionReplicatedRoot::initRegion( ProcessRef pRef, uval &vaddr, uval vaddr2, uval size, uval alignreq, FRRef frRef, uval writable, uval fOff, AccessMode::mode accessreq, uval useVaddr, RegionType::Type regionType) { SysStatus rc=0; PMRef pmRef; size = PAGE_ROUND_UP(size); tassertWrn(!useVaddr || (PAGE_ROUND_DOWN(vaddr)==vaddr), "creating an unaligned region, vaddr=%lx\n", vaddr); rc = DREF(pRef)->getPM(pmRef); if (!_SUCCESS(rc)) return rc; regionState = CREATING; /* * we record the actual permission of the FR. This is so that * if a debugger asks to write a readonly mapping, we can decide * if its legal. * Of course, we also use this to prevent an initial writable * mapping of a read only FR. */ writeAllowed = writable; rc = DREF(pRef)->getHATProcess(hat); tassert(_SUCCESS(rc), err_printf("process destroyed\n")); regionVaddr = vaddr; regionSize = size; proc = pRef; access = accessreq; alignment = alignreq; fileOffset = fOff; /* can make regions without an fcm - see redzone for example * we attach first so we can ask fcm if it uses shared segments */ if (frRef) { rc = DREF(frRef)->attachRegion(fcm, (RegionRef)getRef(), pmRef, accessreq); tassertWrn(_SUCCESS(rc), "attach failed\n"); if (_FAILURE(rc)) { fcm = 0; // clear our fcm field tassert(0,err_printf("attach failed\n")); // FIXME we going to have a problem if we just call destroy // because that will attempt to create a // rep to call the method on, but we are currently holding // a lock preventing reps from being created (*((RegionRef)getRef()))->destroy(); // destroy ourselves regionState = DESTROYING; return rc; } } else { fcm = NULL; } // If ok, attach the region to the process // attach newly contructed region to process if (useVaddr) { rc = DREF(pRef)->attachFixedRegion( regionVaddr, regionSize, (RegionRef)getRef(), regionType); } else if (vaddr2 == 0) { // alignment fix up for shared segments if(size >= SEGMENT_SIZE && alignment == 0 && !useVaddr && fcm && DREF(fcm)->sharedSegments()) { alignment = SEGMENT_SIZE; } rc = DREF(pRef)->attachDynamicRegion( regionVaddr, regionSize, (RegionRef)getRef(), regionType, alignment); // return address allocated by process vaddr = regionVaddr; } else { rc = DREF(pRef)->attachWithinRangeRegion( vaddr, vaddr2, regionSize, (RegionRef)getRef(), regionType, alignment); regionVaddr = vaddr; } if (!_SUCCESS(rc)) { // failed - delete it tassert(0,err_printf("Region constructor failed\n")); if (fcm != NULL) { DREF(fcm)->detachRegion((RegionRef)getRef()); fcm = NULL; } // FIXME we are going to have a problem if we just call destroy // unchecked because that will attempt to create a // rep to call the method on, but we are currently holding // a lock preventing reps from being created (*((RegionRef)getRef()))->destroyUnchecked(); // free ref regionState = DESTROYING; return rc; } // unmap any full segments so shared mappings can be used if ((SEGMENT_ROUND_DOWN(vaddr+size)>SEGMENT_ROUND_UP(vaddr)) && fcm && DREF(fcm)->sharedSegments()) { rc = DREF(hat)->unmapRange( SEGMENT_ROUND_UP(vaddr), SEGMENT_ROUND_DOWN(vaddr+size)- SEGMENT_ROUND_UP(vaddr), ppset); tassert(_SUCCESS(rc), err_printf("oops\n")); } regionState = NORMAL; return rc; }
NTSTATUS SetupCopyFile( PWCHAR SourceFileName, PWCHAR DestinationFileName) { OBJECT_ATTRIBUTES ObjectAttributes; HANDLE FileHandleSource; HANDLE FileHandleDest; static IO_STATUS_BLOCK IoStatusBlock; FILE_STANDARD_INFORMATION FileStandard; FILE_BASIC_INFORMATION FileBasic; ULONG RegionSize; UNICODE_STRING FileName; NTSTATUS Status; PVOID SourceFileMap = 0; HANDLE SourceFileSection; SIZE_T SourceSectionSize = 0; LARGE_INTEGER ByteOffset; #ifdef __REACTOS__ RtlInitUnicodeString(&FileName, SourceFileName); InitializeObjectAttributes(&ObjectAttributes, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandleSource, GENERIC_READ, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ, FILE_SEQUENTIAL_ONLY); if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenFile failed: %x, %wZ\n", Status, &FileName); goto done; } #else FileHandleSource = CreateFileW(SourceFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (FileHandleSource == INVALID_HANDLE_VALUE) { Status = STATUS_UNSUCCESSFUL; goto done; } #endif Status = NtQueryInformationFile(FileHandleSource, &IoStatusBlock, &FileStandard, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtQueryInformationFile failed: %x\n", Status); goto closesrc; } Status = NtQueryInformationFile(FileHandleSource, &IoStatusBlock,&FileBasic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtQueryInformationFile failed: %x\n", Status); goto closesrc; } Status = NtCreateSection(&SourceFileSection, SECTION_MAP_READ, NULL, NULL, PAGE_READONLY, SEC_COMMIT, FileHandleSource); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateSection failed: %x, %S\n", Status, SourceFileName); goto closesrc; } Status = NtMapViewOfSection(SourceFileSection, NtCurrentProcess(), &SourceFileMap, 0, 0, NULL, &SourceSectionSize, ViewUnmap, 0, PAGE_READONLY ); if (!NT_SUCCESS(Status)) { DPRINT1("NtMapViewOfSection failed: %x, %S\n", Status, SourceFileName); goto closesrcsec; } RtlInitUnicodeString(&FileName, DestinationFileName); InitializeObjectAttributes(&ObjectAttributes, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtCreateFile(&FileHandleDest, GENERIC_WRITE | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, FILE_NO_INTERMEDIATE_BUFFERING | FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateFile failed: %x\n", Status); goto unmapsrcsec; } RegionSize = (ULONG)PAGE_ROUND_UP(FileStandard.EndOfFile.u.LowPart); IoStatusBlock.Status = 0; ByteOffset.QuadPart = 0; Status = NtWriteFile(FileHandleDest, NULL, NULL, NULL, &IoStatusBlock, SourceFileMap, RegionSize, &ByteOffset, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n", Status, IoStatusBlock.Status, &IoStatusBlock, SourceFileMap, RegionSize); goto closedest; } /* Copy file date/time from source file */ Status = NtSetInformationFile(FileHandleDest, &IoStatusBlock, &FileBasic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtSetInformationFile failed: %x\n", Status); goto closedest; } /* shorten the file back to it's real size after completing the write */ Status = NtSetInformationFile(FileHandleDest, &IoStatusBlock, &FileStandard.EndOfFile, sizeof(FILE_END_OF_FILE_INFORMATION), FileEndOfFileInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtSetInformationFile failed: %x\n", Status); } closedest: NtClose(FileHandleDest); unmapsrcsec: NtUnmapViewOfSection(NtCurrentProcess(), SourceFileMap); closesrcsec: NtClose(SourceFileSection); closesrc: NtClose(FileHandleSource); done: return Status; }
NTSTATUS NTAPI NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PEXTENDED_IO_STACK_LOCATION IoStack; PFILE_OBJECT FileObject; PNPFS_VCB Vcb; PNPFS_FCB Fcb; PNPFS_CCB Ccb; PNAMED_PIPE_CREATE_PARAMETERS Buffer; DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp); Vcb = (PNPFS_VCB)DeviceObject->DeviceExtension; IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp); FileObject = IoStack->FileObject; DPRINT("FileObject %p\n", FileObject); DPRINT("Pipe name %wZ\n", &FileObject->FileName); Buffer = IoStack->Parameters.CreatePipe.Parameters; Irp->IoStatus.Information = 0; if (!(IoStack->Parameters.CreatePipe.ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE)) || (IoStack->Parameters.CreatePipe.ShareAccess & ~(FILE_SHARE_READ|FILE_SHARE_WRITE))) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_PARAMETER; } KeLockMutex(&Vcb->PipeListLock); /* * First search for existing Pipe with the same name. */ Fcb = NpfsFindPipe(Vcb, &FileObject->FileName); if (Fcb != NULL) { /* * Found Pipe with the same name. Check if we are * allowed to use it. */ KeUnlockMutex(&Vcb->PipeListLock); if (Fcb->CurrentInstances >= Fcb->MaximumInstances) { DPRINT("Out of instances.\n"); NpfsDereferenceFcb(Fcb); Irp->IoStatus.Status = STATUS_INSTANCE_NOT_AVAILABLE; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INSTANCE_NOT_AVAILABLE; } if (Fcb->MaximumInstances != Buffer->MaximumInstances || Fcb->TimeOut.QuadPart != Buffer->DefaultTimeout.QuadPart || Fcb->PipeType != Buffer->NamedPipeType) { DPRINT("Asked for invalid pipe mode.\n"); NpfsDereferenceFcb(Fcb); Irp->IoStatus.Status = STATUS_ACCESS_DENIED; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_ACCESS_DENIED; } } else { Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(NPFS_FCB), TAG_NPFS_FCB); if (Fcb == NULL) { KeUnlockMutex(&Vcb->PipeListLock); Irp->IoStatus.Status = STATUS_NO_MEMORY; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NO_MEMORY; } Fcb->Type = FCB_PIPE; Fcb->Vcb = Vcb; Fcb->RefCount = 1; Fcb->PipeName.Length = FileObject->FileName.Length; Fcb->PipeName.MaximumLength = Fcb->PipeName.Length + sizeof(UNICODE_NULL); Fcb->PipeName.Buffer = ExAllocatePoolWithTag(NonPagedPool, Fcb->PipeName.MaximumLength, TAG_NPFS_NAMEBLOCK); if (Fcb->PipeName.Buffer == NULL) { KeUnlockMutex(&Vcb->PipeListLock); ExFreePoolWithTag(Fcb, TAG_NPFS_FCB); Irp->IoStatus.Status = STATUS_NO_MEMORY; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NO_MEMORY; } RtlCopyUnicodeString(&Fcb->PipeName, &FileObject->FileName); InitializeListHead(&Fcb->ServerCcbListHead); InitializeListHead(&Fcb->ClientCcbListHead); InitializeListHead(&Fcb->WaiterListHead); KeInitializeMutex(&Fcb->CcbListLock, 0); Fcb->PipeType = Buffer->NamedPipeType; Fcb->ServerReadMode = Buffer->ReadMode; /* MSDN documentation reads that clients always start off in byte mode */ Fcb->ClientReadMode = FILE_PIPE_BYTE_STREAM_MODE; Fcb->CompletionMode = Buffer->CompletionMode; switch (IoStack->Parameters.CreatePipe.ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE)) { case FILE_SHARE_READ: Fcb->PipeConfiguration = FILE_PIPE_OUTBOUND; break; case FILE_SHARE_WRITE: Fcb->PipeConfiguration = FILE_PIPE_INBOUND; break; case FILE_SHARE_READ|FILE_SHARE_WRITE: Fcb->PipeConfiguration = FILE_PIPE_FULL_DUPLEX; break; } Fcb->MaximumInstances = Buffer->MaximumInstances; Fcb->CurrentInstances = 0; Fcb->TimeOut = Buffer->DefaultTimeout; if (!(Fcb->PipeConfiguration & FILE_PIPE_OUTBOUND) || Fcb->PipeConfiguration & FILE_PIPE_FULL_DUPLEX) { if (Buffer->InboundQuota == 0) { Fcb->InboundQuota = Vcb->DefaultQuota; } else { Fcb->InboundQuota = PAGE_ROUND_UP(Buffer->InboundQuota); if (Fcb->InboundQuota < Vcb->MinQuota) { Fcb->InboundQuota = Vcb->MinQuota; } else if (Fcb->InboundQuota > Vcb->MaxQuota) { Fcb->InboundQuota = Vcb->MaxQuota; } } } else { Fcb->InboundQuota = 0; } if (Fcb->PipeConfiguration & (FILE_PIPE_FULL_DUPLEX|FILE_PIPE_OUTBOUND)) { if (Buffer->OutboundQuota == 0) { Fcb->OutboundQuota = Vcb->DefaultQuota; } else { Fcb->OutboundQuota = PAGE_ROUND_UP(Buffer->OutboundQuota); if (Fcb->OutboundQuota < Vcb->MinQuota) { Fcb->OutboundQuota = Vcb->MinQuota; } else if (Fcb->OutboundQuota > Vcb->MaxQuota) { Fcb->OutboundQuota = Vcb->MaxQuota; } } } else { Fcb->OutboundQuota = 0; } InsertTailList(&Vcb->PipeListHead, &Fcb->PipeListEntry); KeUnlockMutex(&Vcb->PipeListLock); } Ccb = NpfsAllocateCcb(CCB_PIPE, Fcb); if (Ccb == NULL) { NpfsDereferenceFcb(Fcb); Irp->IoStatus.Status = STATUS_NO_MEMORY; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NO_MEMORY; } Ccb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread; if (Fcb->InboundQuota) { Ccb->Data = ExAllocatePoolWithTag(PagedPool, Fcb->InboundQuota, TAG_NPFS_CCB_DATA); if (Ccb->Data == NULL) { NpfsDereferenceCcb(Ccb); NpfsDereferenceFcb(Fcb); Irp->IoStatus.Status = STATUS_NO_MEMORY; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NO_MEMORY; } } else { Ccb->Data = NULL; } Ccb->ReadPtr = Ccb->Data; Ccb->WritePtr = Ccb->Data; Ccb->ReadDataAvailable = 0; Ccb->WriteQuotaAvailable = Fcb->InboundQuota; Ccb->MaxDataLength = Fcb->InboundQuota; InitializeListHead(&Ccb->ReadRequestListHead); ExInitializeFastMutex(&Ccb->DataListLock); Fcb->CurrentInstances++; Ccb->Fcb = Fcb; Ccb->FileObject = FileObject; Ccb->PipeEnd = FILE_PIPE_SERVER_END; Ccb->PipeState = FILE_PIPE_LISTENING_STATE; DPRINT("CCB: %p\n", Ccb); KeInitializeEvent(&Ccb->ConnectEvent, SynchronizationEvent, FALSE); KeInitializeEvent(&Ccb->ReadEvent, NotificationEvent, FALSE); KeInitializeEvent(&Ccb->WriteEvent, NotificationEvent, FALSE); KeLockMutex(&Fcb->CcbListLock); InsertTailList(&Fcb->ServerCcbListHead, &Ccb->CcbListEntry); KeUnlockMutex(&Fcb->CcbListLock); FileObject->FsContext = Fcb; FileObject->FsContext2 = Ccb; FileObject->Flags |= FO_NAMED_PIPE; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); DPRINT("Success!\n"); return STATUS_SUCCESS; }