diff --git a/ntoskrnl/include/ntoskrnl.h b/ntoskrnl/include/ntoskrnl.h index 6f2f5379bec..e3b7d8ce781 100644 --- a/ntoskrnl/include/ntoskrnl.h +++ b/ntoskrnl/include/ntoskrnl.h @@ -135,4 +135,127 @@ C_ASSERT(MAX_WIN32_PATH == MAX_PATH); # pragma section("INITDATA", read,write,discard) #endif +#ifdef SARCH_XBOX +#define IMAGE_XBE_SIGNATURE 0x48454258 +#pragma pack(push,1) +typedef struct _IMAGE_XBE_HEADER { + DWORD dwMagic; // 0x0000 - magic number [should be "XBEH"] + BYTE pbDigitalSignature[256]; // 0x0004 - digital signature + DWORD dwBaseAddr; // 0x0104 - base address + DWORD dwSizeofHeaders; // 0x0108 - size of headers + DWORD dwSizeofImage; // 0x010C - size of image + DWORD dwSizeofImageHeader; // 0x0110 - size of image header + DWORD dwTimeDate; // 0x0114 - timedate stamp + DWORD dwCertificateAddr; // 0x0118 - certificate address + DWORD dwSections; // 0x011C - number of sections + DWORD dwSectionHeadersAddr; // 0x0120 - section headers address + + struct InitFlags // 0x0124 - initialization flags + { + DWORD bMountUtilityDrive : 1; // mount utility drive flag + DWORD bFormatUtilityDrive : 1; // format utility drive flag + DWORD bLimit64MB : 1; // limit development kit run time memory to 64mb flag + DWORD bDontSetupHarddisk : 1; // don't setup hard disk flag + DWORD Unused : 4; // unused (or unknown) + DWORD Unused_b1 : 8; // unused (or unknown) + DWORD Unused_b2 : 8; // unused (or unknown) + DWORD Unused_b3 : 8; // unused (or unknown) + } + dwInitFlags; + + DWORD dwEntryAddr; // 0x0128 - entry point address + DWORD dwTLSAddr; // 0x012C - thread local storage directory address + DWORD dwPeStackCommit; // 0x0130 - size of stack commit + DWORD dwPeHeapReserve; // 0x0134 - size of heap reserve + DWORD dwPeHeapCommit; // 0x0138 - size of heap commit + DWORD dwPeBaseAddr; // 0x013C - original base address + DWORD dwPeSizeofImage; // 0x0140 - size of original image + DWORD dwPeChecksum; // 0x0144 - original checksum + DWORD dwPeTimeDate; // 0x0148 - original timedate stamp + DWORD dwDebugPathnameAddr; // 0x014C - debug pathname address + DWORD dwDebugFilenameAddr; // 0x0150 - debug filename address + DWORD dwDebugUnicodeFilenameAddr; // 0x0154 - debug unicode filename address + DWORD dwKernelImageThunkAddr; // 0x0158 - kernel image thunk address + DWORD dwNonKernelImportDirAddr; // 0x015C - non kernel import directory address + DWORD dwLibraryVersions; // 0x0160 - number of library versions + DWORD dwLibraryVersionsAddr; // 0x0164 - library versions address + DWORD dwKernelLibraryVersionAddr; // 0x0168 - kernel library version address + DWORD dwXAPILibraryVersionAddr; // 0x016C - xapi library version address + DWORD dwLogoBitmapAddr; // 0x0170 - logo bitmap address + DWORD dwSizeofLogoBitmap; // 0x0174 - logo bitmap size +} IMAGE_XBE_HEADER,*PIMAGE_XBE_HEADER; +#pragma pack(pop) + +#pragma pack(push,1) + typedef struct _IMAGE_XBE_SECTION_HEADER + { + struct _Flags + { + DWORD bWritable : 1; // writable flag + DWORD bPreload : 1; // preload flag + DWORD bExecutable : 1; // executable flag + DWORD bInsertedFile : 1; // inserted file flag + DWORD bHeadPageRO : 1; // head page read only flag + DWORD bTailPageRO : 1; // tail page read only flag + DWORD Unused_a1 : 1; // unused (or unknown) + DWORD Unused_a2 : 1; // unused (or unknown) + DWORD Unused_b1 : 8; // unused (or unknown) + DWORD Unused_b2 : 8; // unused (or unknown) + DWORD Unused_b3 : 8; // unused (or unknown) + } + dwFlags; + + DWORD dwVirtualAddr; // virtual address + DWORD dwVirtualSize; // virtual size + DWORD dwRawAddr; // file offset to raw data + DWORD dwSizeofRaw; // size of raw data + DWORD dwSectionNameAddr; // section name addr + DWORD dwSectionRefCount; // section reference count + DWORD dwHeadSharedRefCountAddr; // head shared page reference count address + DWORD dwTailSharedRefCountAddr; // tail shared page reference count address + BYTE bzSectionDigest[20]; // section digest + } IMAGE_XBE_SECTION_HEADER,*PIMAGE_XBE_SECTION_HEADER; +#pragma pack(pop) + +#pragma pack(push,1) + typedef struct _IMAGE_XBE_CERTIFICATE_HEADER + { + DWORD dwSize; // 0x0000 - size of certificate + DWORD dwTimeDate; // 0x0004 - timedate stamp + DWORD dwTitleId; // 0x0008 - title id + wchar_t wsTitleName[40]; // 0x000C - title name (unicode) + DWORD dwAlternateTitleId[0x10]; // 0x005C - alternate title ids + DWORD dwAllowedMedia; // 0x009C - allowed media types + DWORD dwGameRegion; // 0x00A0 - game region + DWORD dwGameRatings; // 0x00A4 - game ratings + DWORD dwDiscNumber; // 0x00A8 - disc number + DWORD dwVersion; // 0x00AC - version + BYTE bzLanKey[16]; // 0x00B0 - lan key + BYTE bzSignatureKey[16]; // 0x00C0 - signature key + // NOT ALL XBEs have these fields! + BYTE bzTitleAlternateSignatureKey[16][16]; // 0x00D0 - alternate signature keys + DWORD dwOriginalCertificateSize; // 0x01D0 - Original Certificate Size? + DWORD dwOnlineService; // 0x01D4 - Online Service ID + DWORD dwSecurityFlags; // 0x01D8 - Extra Security Flags + BYTE bzCodeEncKey[16]; // 0x01DC - Code Encryption Key? + } IMAGE_XBE_CERTIFICATE_HEADER, *PIMAGE_XBE_CERTIFICATE_HEADER; +#pragma pack(pop) + +#pragma pack(push,1) + typedef struct _IMAGE_XBE_TLS_HEADER + { + DWORD dwDataStartAddr; // raw start address + DWORD dwDataEndAddr; // raw end address + DWORD dwTLSIndexAddr; // tls index address + DWORD dwTLSCallbackAddr; // tls callback address + DWORD dwSizeofZeroFill; // size of zero fill + DWORD dwCharacteristics; // characteristics + } IMAGE_XBE_TLS_HEADER, *PIMAGE_XBE_TLS_HEADER; +#pragma pack(pop) + + + +#endif + + #endif /* _NTOSKRNL_PCH */ diff --git a/ntoskrnl/mm/section.c b/ntoskrnl/mm/section.c index 49c0e0e8f4f..d328fad5820 100644 --- a/ntoskrnl/mm/section.c +++ b/ntoskrnl/mm/section.c @@ -278,6 +278,8 @@ MiWritePage(PMM_SECTION_SEGMENT Segment, } +#define DIE(ARGS_) { DPRINT1 ARGS_; goto l_Return; } + /* References: [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object @@ -324,8 +326,6 @@ NTSTATUS NTAPI PeFmtCreateSection(IN CONST VOID * FileHeader, ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0); -#define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; } - pBuffer = NULL; pidhDosHeader = FileHeader; @@ -899,6 +899,289 @@ l_Return: return nStatus; } +/* + References: +*/ + +#ifdef SARCH_XBOX +NTSTATUS NTAPI XbeFmtCreateSection(IN CONST VOID * FileHeader, + IN SIZE_T FileHeaderSize, + IN PVOID File, + OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, + OUT PULONG Flags, + IN PEXEFMT_CB_READ_FILE ReadFileCb, + IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb) +{ + NTSTATUS nStatus; + ULONG cbSectionHeadersOffset = 0; + ULONG cbSectionHeadersSize; + ULONG cbSectionHeadersOffsetSize = 0; + ULONG cbHeadersSize = 0; + ULONG_PTR ImageBase = 0; + const IMAGE_XBE_HEADER * pidhXbeHeader; + const IMAGE_XBE_SECTION_HEADER * pishSectionHeaders; + PMM_SECTION_SEGMENT pssSegments; + LARGE_INTEGER lnOffset; + PVOID pBuffer; + SIZE_T nPrevVirtualEndOfSegment = 0; + ULONG nFileSizeOfHeaders = 0; + int i; + ULONG AlignedLength; + + ASSERT(FileHeader); + ASSERT(FileHeaderSize > 0); + ASSERT(File); + ASSERT(ImageSectionObject); + ASSERT(ReadFileCb); + ASSERT(AllocateSegmentsCb); + + ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize)); + + ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_XBE_HEADER)) == 0); + + pBuffer = NULL; + pidhXbeHeader = FileHeader; + + /* DOS HEADER */ + nStatus = STATUS_ROS_EXEFMT_UNKNOWN_FORMAT; + + /* image too small to be an MZ executable */ + if(FileHeaderSize < sizeof(IMAGE_XBE_HEADER)) + DIE(("Too small to be an XBE executable, size is %lu\n", FileHeaderSize)); + + /* no XBE signature */ + if(pidhXbeHeader->dwMagic != IMAGE_XBE_SIGNATURE) + DIE(("No XBE signature found, dwMagic is %X - IMAGE_XBE_SIGNATURE is %X \n", pidhXbeHeader->dwMagic, IMAGE_XBE_SIGNATURE)); + + ImageBase = pidhXbeHeader->dwBaseAddr; + + if((ULONG_PTR)ImageBase % 0x10000) + DIE(("ImageBase is not aligned on a 64KB boundary")); + + ImageSectionObject->ImageInformation.ImageFileSize = pidhXbeHeader->dwSizeofImage; + + ImageSectionObject->ImageInformation.MaximumStackSize = pidhXbeHeader->dwPeStackCommit; + + ImageSectionObject->ImageInformation.CommittedStackSize = pidhXbeHeader->dwPeStackCommit; //Stack Size + + ImageSectionObject->ImageInformation.ImageContainsCode = TRUE; + + /* [1], section 3.4.2 */ + + ImageSectionObject->ImageInformation.Machine = IMAGE_FILE_MACHINE_NATIVE; + ImageSectionObject->ImageInformation.GpValue = 0; + ImageSectionObject->ImageInformation.ZeroBits = 0; + ImageSectionObject->BasedAddress = (PVOID)ImageBase; + + ImageSectionObject->ImageInformation.TransferAddress = (PVOID) (pidhXbeHeader->dwEntryAddr ^ 0x94859D4B); // Debug + + if(ImageSectionObject->ImageInformation.TransferAddress < (PVOID)pidhXbeHeader->dwBaseAddr || ImageSectionObject->ImageInformation.TransferAddress > (PVOID)(pidhXbeHeader->dwBaseAddr + pidhXbeHeader->dwSizeofImage)) + ImageSectionObject->ImageInformation.TransferAddress = (PVOID) (pidhXbeHeader->dwEntryAddr ^ 0xA8FC57AB); // Release + + /* SECTION HEADERS */ + nStatus = STATUS_INVALID_IMAGE_FORMAT; + + /* see [1], section 3.3 */ + if(pidhXbeHeader->dwSections > 96) + DIE(("Too many sections, NumberOfSections is %u\n", pidhXbeHeader->dwSections)); + + /* + * the additional segment is for the file's headers. They need to be present for + * the benefit of the dynamic loader (to locate exports, defaults for thread + * parameters, resources, etc.) + */ + ImageSectionObject->NrSegments = pidhXbeHeader->dwSections + 2; // the section header and certificate header + + /* file offset for the section headers */ + cbSectionHeadersOffset = pidhXbeHeader->dwSectionHeadersAddr - ImageBase; + + /* size of the section headers */ + ASSERT(Intsafe_CanMulULong32(pidhXbeHeader->dwSections, sizeof(IMAGE_XBE_SECTION_HEADER))); + cbSectionHeadersSize = pidhXbeHeader->dwSections * sizeof(IMAGE_XBE_SECTION_HEADER); + + if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize)) + DIE(("Section headers too large\n")); + + /* size of the executable's headers */ + if(cbSectionHeadersSize > pidhXbeHeader->dwSizeofHeaders) + DIE(("The section headers overflow SizeOfHeaders\n")); + + cbHeadersSize = pidhXbeHeader->dwSizeofHeaders; + + if(pBuffer) + { + ExFreePool(pBuffer); + pBuffer = NULL; + } + + if(FileHeaderSize < cbSectionHeadersOffsetSize) + pishSectionHeaders = NULL; + else + { + /* + * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize), + * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too + */ + ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbSectionHeadersOffset)); + pishSectionHeaders = (PVOID)((UINT_PTR)FileHeader + cbSectionHeadersOffset); + } + + /* + * the buffer doesn't contain the section headers, or the alignment is wrong: + * read the headers from the file + */ + if(FileHeaderSize < cbSectionHeadersOffsetSize || + (UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_XBE_SECTION_HEADER) != 0) + { + PVOID pData; + ULONG cbReadSize; + + lnOffset.QuadPart = cbSectionHeadersOffset; + + /* read the header from the file */ + nStatus = ReadFileCb(File, &lnOffset, cbSectionHeadersSize, &pData, &pBuffer, &cbReadSize); + + if(!NT_SUCCESS(nStatus)) + DIE(("ReadFile failed with status %08X\n", nStatus)); + + ASSERT(pData); + ASSERT(pBuffer); + ASSERT(cbReadSize > 0); + + nStatus = STATUS_INVALID_IMAGE_FORMAT; + + /* the buffer doesn't contain all the section headers */ + if(cbReadSize < cbSectionHeadersSize) + DIE(("The file doesn't contain all of the section headers\n")); + + pishSectionHeaders = pData; + + /* object still not aligned: copy it to the beginning of the buffer */ + if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_XBE_SECTION_HEADER) != 0) + { + ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_XBE_SECTION_HEADER) == 0); + RtlMoveMemory(pBuffer, pData, cbReadSize); + pishSectionHeaders = pBuffer; + } + } + + /* SEGMENTS */ + /* allocate the segments */ + nStatus = STATUS_INSUFFICIENT_RESOURCES; + ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments); + + if(ImageSectionObject->Segments == NULL) + DIE(("AllocateSegments failed\n")); + + /* initialize the headers segment */ + pssSegments = ImageSectionObject->Segments; + + if(!AlignUp(&nFileSizeOfHeaders, cbHeadersSize, PAGE_SIZE)) + DIE(("Cannot align the size of the section headers\n")); + + nPrevVirtualEndOfSegment = ALIGN_DOWN_BY(pidhXbeHeader->dwCertificateAddr, PAGE_SIZE); + if (nPrevVirtualEndOfSegment < cbHeadersSize) + DIE(("Cannot align the size of the section headers\n")); + + pssSegments[0].Image.FileOffset = 0; + pssSegments[0].Protection = PAGE_READONLY; + pssSegments[0].Length.QuadPart = nPrevVirtualEndOfSegment; + pssSegments[0].RawLength.QuadPart = nFileSizeOfHeaders; + pssSegments[0].Image.VirtualAddress = 0; + pssSegments[0].Image.Characteristics = 0; + pssSegments[0].WriteCopy = TRUE; + + PIMAGE_XBE_CERTIFICATE_HEADER pCertificate = (PIMAGE_XBE_CERTIFICATE_HEADER)(pidhXbeHeader->dwCertificateAddr - ImageBase + (UINT_PTR)FileHeader); + DPRINT1("SIMONE - Title name:%S\n",pCertificate->wsTitleName); + + pssSegments[1].Image.FileOffset = nFileSizeOfHeaders - pidhXbeHeader->dwCertificateAddr + nPrevVirtualEndOfSegment; + pssSegments[1].Length.QuadPart = pishSectionHeaders[0].dwVirtualAddr - nPrevVirtualEndOfSegment; + pssSegments[1].RawLength.QuadPart = sizeof(IMAGE_XBE_CERTIFICATE_HEADER) + pidhXbeHeader->dwCertificateAddr - nPrevVirtualEndOfSegment ; + pssSegments[1].Image.VirtualAddress = nPrevVirtualEndOfSegment; + pssSegments[1].Protection = PAGE_READWRITE; + pssSegments[1].Image.Characteristics |= (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_NOT_CACHED | IMAGE_SCN_MEM_SHARED); + pssSegments[1].WriteCopy = FALSE; + /* skip the headers and certificate header segment */ + pssSegments++; + pssSegments++; + + nStatus = STATUS_INVALID_IMAGE_FORMAT; + + ASSERT(ImageSectionObject->RefCount > 0); + + /* convert the executable sections into segments. See also [1], section 4 */ + for(i = pidhXbeHeader->dwSections - 1; i>=0; i--) + { + //CHAR* sectionName = (PVOID)((UINT_PTR)FileHeader+pishSectionHeaders[i].dwSectionNameAddr-ImageBase); + //DPRINT1("SIMONE - i=%d dwVirtualAddr=%X SectionName=%s bPreload=%d\n",i,pishSectionHeaders[i].dwVirtualAddr,sectionName,pishSectionHeaders[i].dwFlags.bPreload); + + pssSegments[i].WriteCopy = FALSE; + pssSegments[i].Image.Characteristics = IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_NOT_CACHED; + + if(pishSectionHeaders[i].dwFlags.bExecutable){ + pssSegments[i].Image.Characteristics |= (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE); + pssSegments[i].Protection = PAGE_EXECUTE_READWRITE; + } + else if(pishSectionHeaders[i].dwFlags.bWritable){ + pssSegments[i].Protection = PAGE_READWRITE; + pssSegments[i].Image.Characteristics |= (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ); + }else{ + pssSegments[i].Protection = PAGE_READONLY; + pssSegments[i].Image.Characteristics |= IMAGE_SCN_MEM_READ; + } + + if(!pishSectionHeaders[i].dwFlags.bPreload) + pssSegments[i].SegFlags |= MM_SEGMENT_DONT_PRELOAD; + + pssSegments[i].Image.VirtualAddress = ALIGN_DOWN_BY(pishSectionHeaders[i].dwVirtualAddr,PAGE_SIZE); + + if( i == pidhXbeHeader->dwSections - 1){ + pssSegments[i].Length.QuadPart = (pishSectionHeaders[i].dwVirtualSize == 0) ? pishSectionHeaders[i].dwSizeofRaw : pishSectionHeaders[i].dwVirtualSize; + if(pssSegments[i].Length.QuadPart == 0) + DIE(("Virtual size of section %u is null\n", i)); + + AlignedLength = ALIGN_UP_BY(pssSegments[i].Length.LowPart, PAGE_SIZE); + + if(AlignedLength < pssSegments[i].Length.LowPart) + DIE(("Cannot align the virtual size of section %u\n", i)); + pssSegments[i].Length.LowPart = AlignedLength; + }else{ + pssSegments[i].Length.QuadPart = pssSegments[i+1].Image.VirtualAddress - pssSegments[i].Image.VirtualAddress; + } + + nPrevVirtualEndOfSegment = pishSectionHeaders[i].dwVirtualAddr - pssSegments[i].Image.VirtualAddress; + /* ignore explicit BSS sections */ + if(pishSectionHeaders[i].dwRawAddr != 0 && pishSectionHeaders[i].dwSizeofRaw != 0) + { + /* validate the alignment */ + if(!Intsafe_CanAddULong32(pishSectionHeaders[i].dwRawAddr, pishSectionHeaders[i].dwSizeofRaw)) + DIE(("SizeOfRawData[%u] too large\n", i)); + + /* conversion */ + pssSegments[i].Image.FileOffset = pishSectionHeaders[i].dwRawAddr - nPrevVirtualEndOfSegment; + pssSegments[i].RawLength.QuadPart = pishSectionHeaders[i].dwSizeofRaw + nPrevVirtualEndOfSegment; + } + else + { + /* FIXME: Should reset PointerToRawData to 0 in the image mapping */ + ASSERT(pssSegments[i].Image.FileOffset == 0); + ASSERT(pssSegments[i].RawLength.QuadPart == 0); + } + + ASSERT(Intsafe_CanAddLong64(pssSegments[i].Image.FileOffset, pssSegments[i].RawLength.QuadPart)); + } + + /* Success */ + nStatus = STATUS_SUCCESS; + +l_Return: + if(pBuffer) + ExFreePool(pBuffer); + + return nStatus; +} +#endif + /* * FUNCTION: Waits in kernel mode indefinitely for a file object lock. * ARGUMENTS: PFILE_OBJECT to wait for. @@ -2554,11 +2837,25 @@ extern NTSTATUS NTAPI ElfFmtCreateSection IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb ); +extern NTSTATUS NTAPI XbeFmtCreateSection +( + IN CONST VOID * FileHeader, + IN SIZE_T FileHeaderSize, + IN PVOID File, + OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, + OUT PULONG Flags, + IN PEXEFMT_CB_READ_FILE ReadFileCb, + IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb +); + static PEXEFMT_LOADER ExeFmtpLoaders[] = { - PeFmtCreateSection, + PeFmtCreateSection #ifdef __ELF - ElfFmtCreateSection + ,ElfFmtCreateSection +#endif +#ifdef SARCH_XBOX + ,XbeFmtCreateSection #endif }; @@ -2714,6 +3011,7 @@ MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject) ASSERT((ImageSectionObject->Segments[i].Length.QuadPart % PAGE_SIZE) == 0); } } + #endif static @@ -2755,7 +3053,6 @@ MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, } } - /* * Ensures an image section's segments don't overlap in memory and don't have * gaps and don't have a null size. We let them map to overlapping file regions, @@ -2782,6 +3079,9 @@ MmspCheckSegmentBounds for ( i = 0; i < ImageSectionObject->NrSegments; ++ i ) { + if (ImageSectionObject->Segments[i].SegFlags & MM_SEGMENT_DONT_PRELOAD || + ImageSectionObject->Segments[i+1].SegFlags & MM_SEGMENT_DONT_PRELOAD) // /Preload and not preload segment could overlap + continue; if(ImageSectionObject->Segments[i].Length.QuadPart == 0) { return FALSE; @@ -4044,6 +4344,8 @@ MmMapViewOfSection(IN PVOID SectionObject, ImageSize = max(ImageSize, MaxExtent); } + NrSegments = ImageSectionObject->NrSegments; + ImageSectionObject->ImageInformation.ImageFileSize = (ULONG)ImageSize; /* Check for an illegal base address */