diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c index 7366ef17384..538de704a4b 100644 --- a/dlls/kernel32/tests/virtual.c +++ b/dlls/kernel32/tests/virtual.c @@ -1444,7 +1444,61 @@ static void test_NtAreMappedFilesTheSame(void) static void test_CreateFileMapping(void) { - HANDLE handle, handle2; + HANDLE handle, handle2, file[3]; + char path[MAX_PATH], filename[MAX_PATH]; + unsigned int i; + NTSTATUS status; + + static const struct { DWORD file, flags, error, attrs; } sec_flag_tests[] = + { + /* anonymous mapping */ + { 0, SEC_RESERVE, 0 }, /* 0 */ + { 0, SEC_RESERVE | SEC_NOCACHE, 0 }, + { 0, SEC_RESERVE | SEC_LARGE_PAGES, ERROR_INVALID_PARAMETER }, + { 0, SEC_RESERVE | SEC_WRITECOMBINE, 0 }, + { 0, SEC_COMMIT, 0 }, + { 0, SEC_COMMIT | SEC_NOCACHE, 0 }, /* 5 */ + { 0, SEC_COMMIT | SEC_WRITECOMBINE, 0 }, + { 0, SEC_RESERVE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, + { 0, SEC_IMAGE, ERROR_BAD_EXE_FORMAT }, + { 0, SEC_IMAGE | SEC_RESERVE, ERROR_INVALID_PARAMETER }, + { 0, SEC_IMAGE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, /* 10 */ + { 0, SEC_NOCACHE, ERROR_INVALID_PARAMETER }, + { 0, SEC_LARGE_PAGES, ERROR_INVALID_PARAMETER }, + { 0, SEC_WRITECOMBINE, ERROR_INVALID_PARAMETER }, + { 0, SEC_FILE, ERROR_INVALID_PARAMETER }, + { 0, SEC_FILE | SEC_RESERVE, ERROR_INVALID_PARAMETER }, /* 15 */ + { 0, SEC_FILE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, + { 0, 0, 0, SEC_COMMIT }, + /* normal file */ + { 1, SEC_RESERVE, 0, SEC_FILE }, + { 1, SEC_RESERVE | SEC_NOCACHE, 0, SEC_FILE | SEC_NOCACHE }, + { 1, SEC_RESERVE | SEC_LARGE_PAGES, ERROR_INVALID_PARAMETER }, /* 20 */ + { 1, SEC_RESERVE | SEC_WRITECOMBINE, 0, SEC_FILE | SEC_WRITECOMBINE }, + { 1, SEC_COMMIT, 0, SEC_FILE }, + { 1, SEC_COMMIT | SEC_NOCACHE, 0, SEC_FILE | SEC_NOCACHE }, + { 1, SEC_COMMIT | SEC_LARGE_PAGES, ERROR_INVALID_PARAMETER }, + { 1, SEC_COMMIT | SEC_WRITECOMBINE, 0, SEC_FILE | SEC_WRITECOMBINE }, /* 25 */ + { 1, SEC_RESERVE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, + { 1, SEC_IMAGE, ERROR_BAD_EXE_FORMAT }, + { 1, SEC_IMAGE | SEC_RESERVE, ERROR_INVALID_PARAMETER }, + { 1, SEC_IMAGE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, + { 1, SEC_NOCACHE, ERROR_INVALID_PARAMETER }, /* 30 */ + { 1, SEC_LARGE_PAGES, ERROR_INVALID_PARAMETER }, + { 1, SEC_WRITECOMBINE, ERROR_INVALID_PARAMETER }, + { 1, SEC_FILE, ERROR_INVALID_PARAMETER }, + { 1, SEC_FILE | SEC_RESERVE, ERROR_INVALID_PARAMETER }, + { 1, SEC_FILE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, /* 35 */ + { 1, 0, 0, SEC_FILE }, + /* PE image file */ + { 2, SEC_IMAGE, 0, SEC_FILE | SEC_IMAGE }, + { 2, SEC_IMAGE | SEC_FILE, ERROR_INVALID_PARAMETER }, + { 2, SEC_IMAGE | SEC_NOCACHE, 0, SEC_FILE | SEC_IMAGE }, + { 2, SEC_IMAGE | SEC_LARGE_PAGES, ERROR_INVALID_PARAMETER }, /* 40 */ + { 2, SEC_IMAGE | SEC_WRITECOMBINE, ERROR_INVALID_PARAMETER }, + { 2, SEC_IMAGE | SEC_RESERVE, ERROR_INVALID_PARAMETER }, + { 2, SEC_IMAGE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, + }; /* test case sensitivity */ @@ -1479,6 +1533,62 @@ static void test_CreateFileMapping(void) ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError()); CloseHandle( handle ); + + /* test SEC_* flags */ + + file[0] = INVALID_HANDLE_VALUE; + GetTempPathA( MAX_PATH, path ); + GetTempFileNameA( path, "map", 0, filename ); + + file[1] = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( file[1] != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() ); + SetFilePointer( file[1], 0x2000, NULL, FILE_BEGIN ); + SetEndOfFile( file[1] ); + + GetSystemDirectoryA( path, MAX_PATH ); + strcat( path, "\\kernel32.dll" ); + file[2] = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); + ok( file[2] != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() ); + + for (i = 0; i < sizeof(sec_flag_tests) / sizeof(sec_flag_tests[0]); i++) + { + DWORD flags = sec_flag_tests[i].flags; + DWORD perm = sec_flag_tests[i].file == 2 ? PAGE_READONLY : PAGE_READWRITE; + SetLastError( 0xdeadbeef ); + handle = CreateFileMappingA( file[sec_flag_tests[i].file], NULL, + flags | perm, 0, 0x1000, "Wine Test Mapping" ); + if (sec_flag_tests[i].error) + { + ok( !handle, "%u: CreateFileMapping succeeded\n", i ); + ok( GetLastError() == sec_flag_tests[i].error, "%u: wrong error %u\n", i, GetLastError()); + } + else + { + /* SEC_WRITECOMBINE and SEC_IMAGE_NO_EXECUTE not supported on older Windows */ + BOOL new_flags = ((flags & SEC_WRITECOMBINE) || + ((flags & SEC_IMAGE_NO_EXECUTE) == SEC_IMAGE_NO_EXECUTE)); + ok( handle != NULL || broken(new_flags), + "%u: CreateFileMapping failed with error %u\n", i, GetLastError()); + ok( GetLastError() == 0 || broken(new_flags && GetLastError() == ERROR_INVALID_PARAMETER), + "%u: wrong error %u\n", i, GetLastError()); + } + + if (handle) + { + SECTION_BASIC_INFORMATION info; + DWORD expect = sec_flag_tests[i].attrs ? sec_flag_tests[i].attrs : sec_flag_tests[i].flags; + + status = pNtQuerySection( handle, SectionBasicInformation, &info, sizeof(info), NULL ); + ok( !status, "%u: NtQuerySection failed err %x\n", i, status ); + /* SEC_NOCACHE not supported on older Windows */ + ok( info.Attributes == expect || broken( info.Attributes == (expect & ~SEC_NOCACHE) ), + "%u: NtQuerySection wrong attr %08x\n", i, info.Attributes ); + CloseHandle( handle ); + } + } + CloseHandle( file[1] ); + CloseHandle( file[2] ); + DeleteFileA( filename ); } static void test_IsBadReadPtr(void) diff --git a/dlls/kernel32/virtual.c b/dlls/kernel32/virtual.c index 5733a42bbf5..6d5f8d81a6f 100644 --- a/dlls/kernel32/virtual.c +++ b/dlls/kernel32/virtual.c @@ -340,8 +340,8 @@ HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa, DWORD protect, DWORD size_high, DWORD size_low, LPCWSTR name ) { - static const int sec_flags = SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE; - + static const int sec_flags = (SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | + SEC_NOCACHE | SEC_WRITECOMBINE | SEC_LARGE_PAGES); HANDLE ret; NTSTATUS status; DWORD access, sec_type; diff --git a/server/mapping.c b/server/mapping.c index f03ea7a6f63..6563b6afd51 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -497,6 +497,28 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s return STATUS_INVALID_FILE_FOR_SECTION; } +static unsigned int get_mapping_flags( obj_handle_t handle, unsigned int flags ) +{ + switch (flags & (SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_FILE)) + { + case SEC_IMAGE: + if (flags & (SEC_WRITECOMBINE | SEC_LARGE_PAGES)) break; + if (handle) return SEC_FILE | SEC_IMAGE; + set_error( STATUS_INVALID_FILE_FOR_SECTION ); + return 0; + case SEC_COMMIT: + if (!handle) return flags; + /* fall through */ + case SEC_RESERVE: + if (flags & SEC_LARGE_PAGES) break; + if (handle) return SEC_FILE | (flags & (SEC_NOCACHE | SEC_WRITECOMBINE)); + return flags; + } + set_error( STATUS_INVALID_PARAMETER ); + return 0; +} + + static struct object *create_mapping( struct object *root, const struct unicode_str *name, unsigned int attr, mem_size_t size, unsigned int flags, int protect, obj_handle_t handle, const struct security_descriptor *sd ) @@ -516,12 +538,13 @@ static struct object *create_mapping( struct object *root, const struct unicode_ return &mapping->obj; /* Nothing else to do */ mapping->size = size; - mapping->flags = flags & (SEC_IMAGE | SEC_NOCACHE | SEC_WRITECOMBINE | SEC_LARGE_PAGES); mapping->protect = protect; mapping->fd = NULL; mapping->shared_file = NULL; mapping->committed = NULL; + if (!(mapping->flags = get_mapping_flags( handle, flags ))) goto error; + if (protect & VPROT_READ) access |= FILE_READ_DATA; if (protect & VPROT_WRITE) access |= FILE_WRITE_DATA; @@ -530,11 +553,6 @@ static struct object *create_mapping( struct object *root, const struct unicode_ const unsigned int sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; unsigned int mapping_access = FILE_MAPPING_ACCESS; - if (flags & SEC_RESERVE) - { - set_error( STATUS_INVALID_PARAMETER ); - goto error; - } if (!(file = get_file_obj( current->process, handle, access ))) goto error; fd = get_obj_fd( (struct object *)file ); @@ -542,7 +560,6 @@ static struct object *create_mapping( struct object *root, const struct unicode_ if (flags & SEC_IMAGE) mapping_access |= FILE_MAPPING_IMAGE; else if (protect & VPROT_WRITE) mapping_access |= FILE_MAPPING_WRITE; - mapping->flags |= SEC_FILE; if (!(mapping->fd = get_fd_object_for_mapping( fd, mapping_access, sharing ))) { mapping->fd = dup_fd_object( fd, mapping_access, sharing, FILE_SYNCHRONOUS_IO_NONALERT ); @@ -585,12 +602,11 @@ static struct object *create_mapping( struct object *root, const struct unicode_ } else /* Anonymous mapping (no associated file) */ { - if (!mapping->size || (flags & SEC_IMAGE)) + if (!mapping->size) { set_error( STATUS_INVALID_PARAMETER ); goto error; } - mapping->flags |= flags & (SEC_COMMIT | SEC_RESERVE); if (flags & SEC_RESERVE) { if (!(mapping->committed = mem_alloc( offsetof(struct ranges, ranges[8]) ))) goto error;