From 9fed1205cae7cdb7abacfd3c86523cb22db16ef8 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 21 Dec 2006 12:34:44 +0100 Subject: [PATCH] ntdll: File positions should be aligned to sector boundaries in PE loader. --- dlls/kernel32/tests/loader.c | 4 ---- dlls/ntdll/virtual.c | 24 +++++++++++---------- server/mapping.c | 42 ++++++++++++++++++------------------ 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 88113348cfe..4f00e4dea83 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -404,9 +404,7 @@ START_TEST(loader) ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type); if (nt_header.OptionalHeader.SectionAlignment >= si.dwPageSize) -todo_wine { ok(!memcmp((const char *)hlib + section.VirtualAddress + section.PointerToRawData, &nt_header, section.SizeOfRawData), "wrong section data\n"); -} else ok(!memcmp((const char *)hlib + section.PointerToRawData, section_data, section.SizeOfRawData), "wrong section data\n"); @@ -418,9 +416,7 @@ todo_wine { start = (const char *)hlib + section.VirtualAddress + section.PointerToRawData + section.SizeOfRawData; size = ALIGN_SIZE((ULONG_PTR)start, si.dwPageSize) - (ULONG_PTR)start; -todo_wine { ok(memcmp(start, filler, size), "%d: alignment should not be not cleared\n", i); -} } } diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 152af7baea8..fe3356621e2 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -1051,18 +1051,18 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) { - SIZE_T map_size, file_size, end; + static const SIZE_T sector_align = 0x1ff; + SIZE_T map_size, file_start, file_size, end; if (!sec->Misc.VirtualSize) - { - file_size = sec->SizeOfRawData; - map_size = ROUND_SIZE( 0, file_size ); - } + map_size = ROUND_SIZE( 0, sec->SizeOfRawData ); else - { map_size = ROUND_SIZE( 0, sec->Misc.VirtualSize ); - file_size = min( sec->SizeOfRawData, map_size ); - } + + /* file positions are rounded to sector boundaries regardless of OptionalHeader.FileAlignment */ + file_start = sec->PointerToRawData & ~sector_align; + file_size = (sec->SizeOfRawData + (sec->PointerToRawData & sector_align) + sector_align) & ~sector_align; + if (file_size > map_size) file_size = map_size; /* a few sanity checks */ end = sec->VirtualAddress + ROUND_SIZE( sec->VirtualAddress, map_size ); @@ -1115,9 +1115,11 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz /* Note: if the section is not aligned properly map_file_into_view will magically * fall back to read(), so we don't need to check anything here. */ - end = sec->PointerToRawData + file_size; - if (sec->PointerToRawData >= st.st_size || end > st.st_size || end < sec->PointerToRawData || - map_file_into_view( view, fd, sec->VirtualAddress, file_size, sec->PointerToRawData, + end = file_start + file_size; + if (sec->PointerToRawData >= st.st_size || + end > ((st.st_size + sector_align) & ~sector_align) || + end < file_start || + map_file_into_view( view, fd, sec->VirtualAddress, file_size, file_start, VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY, removable ) != STATUS_SUCCESS) { diff --git a/server/mapping.c b/server/mapping.c index 052ea4153b8..c7eb07557ad 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -119,25 +119,26 @@ static struct file *get_shared_file( struct mapping *mapping ) return NULL; } -/* return the size of the memory mapping of a given section */ -static inline unsigned int get_section_map_size( const IMAGE_SECTION_HEADER *sec ) +/* return the size of the memory mapping and file range of a given section */ +static inline void get_section_sizes( const IMAGE_SECTION_HEADER *sec, size_t *map_size, + off_t *file_start, size_t *file_size ) { - if (!sec->Misc.VirtualSize) return ROUND_SIZE( sec->SizeOfRawData ); - else return ROUND_SIZE( sec->Misc.VirtualSize ); -} + static const unsigned int sector_align = 0x1ff; -/* return the size of the file mapping of a given section */ -static inline unsigned int get_section_filemap_size( const IMAGE_SECTION_HEADER *sec ) -{ - if (!sec->Misc.VirtualSize) return sec->SizeOfRawData; - else return min( sec->SizeOfRawData, ROUND_SIZE( sec->Misc.VirtualSize ) ); + if (!sec->Misc.VirtualSize) *map_size = ROUND_SIZE( sec->SizeOfRawData ); + else *map_size = ROUND_SIZE( sec->Misc.VirtualSize ); + + *file_start = sec->PointerToRawData & ~sector_align; + *file_size = (sec->SizeOfRawData + (sec->PointerToRawData & sector_align) + sector_align) & ~sector_align; + if (*file_size > *map_size) *file_size = *map_size; } /* allocate and fill the temp file for a shared PE image mapping */ static int build_shared_mapping( struct mapping *mapping, int fd, IMAGE_SECTION_HEADER *sec, unsigned int nb_sec ) { - unsigned int i, size, max_size, total_size; + unsigned int i; + size_t file_size, map_size, max_size, total_size; off_t shared_pos, read_pos, write_pos; char *buffer = NULL; int shared_fd; @@ -151,9 +152,9 @@ static int build_shared_mapping( struct mapping *mapping, int fd, if ((sec[i].Characteristics & IMAGE_SCN_MEM_SHARED) && (sec[i].Characteristics & IMAGE_SCN_MEM_WRITE)) { - size = get_section_filemap_size( &sec[i] ); - if (size > max_size) max_size = size; - total_size += get_section_map_size( &sec[i] ); + get_section_sizes( &sec[i], &map_size, &read_pos, &file_size ); + if (file_size > max_size) max_size = file_size; + total_size += map_size; } } if (!(mapping->shared_size = total_size)) return 1; /* nothing to do */ @@ -175,20 +176,19 @@ static int build_shared_mapping( struct mapping *mapping, int fd, { if (!(sec[i].Characteristics & IMAGE_SCN_MEM_SHARED)) continue; if (!(sec[i].Characteristics & IMAGE_SCN_MEM_WRITE)) continue; + get_section_sizes( &sec[i], &map_size, &read_pos, &file_size ); write_pos = shared_pos; - shared_pos += get_section_map_size( &sec[i] ); - read_pos = sec[i].PointerToRawData; - size = get_section_filemap_size( &sec[i] ); - if (!read_pos || !size) continue; - toread = size; + shared_pos += map_size; + if (!sec[i].PointerToRawData || !file_size) continue; + toread = file_size; while (toread) { - long res = pread( fd, buffer + sec[i].SizeOfRawData - toread, toread, read_pos ); + long res = pread( fd, buffer + file_size - toread, toread, read_pos ); if (res <= 0) goto error; toread -= res; read_pos += res; } - if (pwrite( shared_fd, buffer, size, write_pos ) != size) goto error; + if (pwrite( shared_fd, buffer, file_size, write_pos ) != file_size) goto error; } free( buffer ); return 1;