mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
ntdll: Add tests for buffer overflows in NtQueryDirectoryFile.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
b0ce049cbb
commit
a4dcfd1195
2 changed files with 157 additions and 23 deletions
|
@ -2225,6 +2225,7 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event,
|
|||
BOOLEAN restart_scan )
|
||||
{
|
||||
int cwd, fd, needs_close;
|
||||
NTSTATUS status;
|
||||
|
||||
TRACE("(%p %p %p %p %p %p 0x%08x 0x%08x 0x%08x %s 0x%08x\n",
|
||||
handle, event, apc_routine, apc_context, io, buffer,
|
||||
|
@ -2234,7 +2235,7 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event,
|
|||
if (event || apc_routine)
|
||||
{
|
||||
FIXME( "Unsupported yet option\n" );
|
||||
return io->u.Status = STATUS_NOT_IMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
switch (info_class)
|
||||
{
|
||||
|
@ -2243,16 +2244,16 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event,
|
|||
case FileFullDirectoryInformation:
|
||||
case FileIdBothDirectoryInformation:
|
||||
case FileIdFullDirectoryInformation:
|
||||
if (length < dir_info_size( info_class, 1 )) return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
if (!buffer) return io->u.Status = STATUS_ACCESS_VIOLATION;
|
||||
if (length < dir_info_size( info_class, 1 )) return STATUS_INFO_LENGTH_MISMATCH;
|
||||
if (!buffer) return STATUS_ACCESS_VIOLATION;
|
||||
break;
|
||||
default:
|
||||
FIXME( "Unsupported file info class %d\n", info_class );
|
||||
return io->u.Status = STATUS_NOT_IMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
if ((io->u.Status = server_get_unix_fd( handle, FILE_LIST_DIRECTORY, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS)
|
||||
return io->u.Status;
|
||||
if ((status = server_get_unix_fd( handle, FILE_LIST_DIRECTORY, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
io->Information = 0;
|
||||
|
||||
|
@ -2290,16 +2291,17 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event,
|
|||
read_directory_readdir( fd, io, buffer, length, single_entry, mask, restart_scan, info_class );
|
||||
|
||||
done:
|
||||
status = io->u.Status;
|
||||
if (cwd == -1 || fchdir( cwd ) == -1) chdir( "/" );
|
||||
}
|
||||
else io->u.Status = FILE_GetNtStatus();
|
||||
else status = FILE_GetNtStatus();
|
||||
|
||||
RtlLeaveCriticalSection( &dir_section );
|
||||
|
||||
if (needs_close) close( fd );
|
||||
if (cwd != -1) close( cwd );
|
||||
TRACE( "=> %x (%ld)\n", io->u.Status, io->Information );
|
||||
return io->u.Status;
|
||||
TRACE( "=> %x (%ld)\n", status, io->Information );
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char
|
|||
UINT data_len; /* length of dir data */
|
||||
BYTE data[8192]; /* directory data */
|
||||
FILE_BOTH_DIRECTORY_INFORMATION *dir_info;
|
||||
DWORD status;
|
||||
NTSTATUS status;
|
||||
int numfiles;
|
||||
int i;
|
||||
|
||||
|
@ -185,8 +185,10 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char
|
|||
return;
|
||||
}
|
||||
|
||||
pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, single_entry, mask, restart_flag );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, single_entry, mask, restart_flag );
|
||||
ok (status == STATUS_SUCCESS, "failed to query directory; status %x\n", status);
|
||||
ok (U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status);
|
||||
data_len = io.Information;
|
||||
ok (data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "not enough data in directory\n");
|
||||
|
@ -199,11 +201,12 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char
|
|||
tally_test_file(dir_info);
|
||||
|
||||
if (dir_info->NextEntryOffset == 0) {
|
||||
pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, single_entry, mask, FALSE );
|
||||
if (U(io).Status == STATUS_NO_MORE_FILES)
|
||||
break;
|
||||
ok (U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status);
|
||||
U(io).Status = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, single_entry, mask, FALSE );
|
||||
ok (U(io).Status == status, "wrong status %x / %x\n", status, U(io).Status);
|
||||
if (status == STATUS_NO_MORE_FILES) break;
|
||||
ok (status == STATUS_SUCCESS, "failed to query directory; status %x\n", status);
|
||||
data_len = io.Information;
|
||||
if (data_len < sizeof(FILE_BOTH_DIRECTORY_INFORMATION))
|
||||
break;
|
||||
|
@ -239,8 +242,9 @@ static void test_NtQueryDirectoryFile(void)
|
|||
WCHAR short_name[12];
|
||||
UINT data_size;
|
||||
BYTE data[8192];
|
||||
FILE_BOTH_DIRECTORY_INFORMATION *fbdi = (FILE_BOTH_DIRECTORY_INFORMATION*)data;
|
||||
DWORD status;
|
||||
FILE_BOTH_DIRECTORY_INFORMATION *next, *fbdi = (FILE_BOTH_DIRECTORY_INFORMATION*)data;
|
||||
const WCHAR *filename = fbdi->FileName;
|
||||
NTSTATUS status;
|
||||
HANDLE dirh;
|
||||
|
||||
/* Clean up from prior aborted run, if any, then set up test files */
|
||||
|
@ -284,24 +288,152 @@ static void test_NtQueryDirectoryFile(void)
|
|||
mask.Buffer = testfiles[0].nameW;
|
||||
mask.Length = mask.MaximumLength = lstrlenW(testfiles[0].nameW) * sizeof(WCHAR);
|
||||
data_size = offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[256]);
|
||||
pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, &mask, FALSE);
|
||||
U(io).Status = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, &mask, FALSE);
|
||||
ok(status == STATUS_SUCCESS, "failed to query directory; status %x\n", status);
|
||||
ok(U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status);
|
||||
ok(fbdi->ShortName[0], "ShortName is empty\n");
|
||||
|
||||
mask.Length = mask.MaximumLength = fbdi->ShortNameLength;
|
||||
memcpy(short_name, fbdi->ShortName, mask.Length);
|
||||
mask.Buffer = short_name;
|
||||
pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, &mask, TRUE);
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, &mask, TRUE);
|
||||
ok(status == STATUS_SUCCESS, "failed to query directory status %x\n", status);
|
||||
ok(U(io).Status == STATUS_SUCCESS, "failed to query directory status %x\n", U(io).Status);
|
||||
todo_wine
|
||||
ok(U(io).Information == offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[strlen(testfiles[0].name)]),
|
||||
"wrong info %lx\n", U(io).Information);
|
||||
ok(fbdi->FileNameLength == strlen(testfiles[0].name)*sizeof(WCHAR) &&
|
||||
!memcmp(fbdi->FileName, testfiles[0].nameW, fbdi->FileNameLength),
|
||||
"incorrect long file name: %s\n", wine_dbgstr_wn(fbdi->FileName,
|
||||
fbdi->FileNameLength/sizeof(WCHAR)));
|
||||
|
||||
/* tests with short buffer */
|
||||
memset( data, 0x55, data_size );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
data_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] );
|
||||
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, &mask, TRUE);
|
||||
ok( status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", status );
|
||||
ok( U(io).Status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", U(io).Status );
|
||||
ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ),
|
||||
"wrong info %lx\n", U(io).Information );
|
||||
ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset );
|
||||
ok( fbdi->FileNameLength == strlen(testfiles[0].name) * sizeof(WCHAR),
|
||||
"wrong length %x\n", fbdi->FileNameLength );
|
||||
ok( filename[0] == testfiles[0].nameW[0], "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||
todo_wine
|
||||
ok( filename[1] == 0x5555, "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||
|
||||
memset( data, 0x55, data_size );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
data_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[0] );
|
||||
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, FALSE, &mask, TRUE);
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH, "weong status %x\n", status );
|
||||
ok( U(io).Status == 0xdeadbeef, "wrong status %x\n", U(io).Status );
|
||||
ok( U(io).Information == 0xdeadbeef, "wrong info %lx\n", U(io).Information );
|
||||
ok( fbdi->NextEntryOffset == 0x55555555, "wrong offset %x\n", fbdi->NextEntryOffset );
|
||||
|
||||
pNtClose(dirh);
|
||||
|
||||
status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE);
|
||||
ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n", testdirA);
|
||||
|
||||
memset( data, 0x55, data_size );
|
||||
data_size = sizeof(data);
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, FALSE, NULL, TRUE);
|
||||
ok(status == STATUS_SUCCESS, "wrong status %x\n", status);
|
||||
ok(U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status);
|
||||
ok(U(io).Information > 0 && U(io).Information < data_size, "wrong info %lx\n", U(io).Information);
|
||||
ok( fbdi->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||
"wrong offset %x\n", fbdi->NextEntryOffset );
|
||||
ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength );
|
||||
ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||
next = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + fbdi->NextEntryOffset);
|
||||
ok( next->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] ) + 7) & ~7),
|
||||
"wrong offset %x\n", next->NextEntryOffset );
|
||||
ok( next->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n", next->FileNameLength );
|
||||
filename = next->FileName;
|
||||
ok( filename[0] == '.' && filename[1] == '.', "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(next->FileName, next->FileNameLength/sizeof(WCHAR)));
|
||||
|
||||
data_size = fbdi->NextEntryOffset + offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ),
|
||||
memset( data, 0x55, data_size );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, FALSE, NULL, TRUE );
|
||||
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||
ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
|
||||
ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ),
|
||||
"wrong info %lx\n", U(io).Information );
|
||||
ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset );
|
||||
ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength );
|
||||
ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||
next = (FILE_BOTH_DIRECTORY_INFORMATION *)&fbdi->FileName[1];
|
||||
ok( next->NextEntryOffset == 0x55555555, "wrong offset %x\n", next->NextEntryOffset );
|
||||
|
||||
data_size = fbdi->NextEntryOffset + offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] ),
|
||||
memset( data, 0x55, data_size );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, FALSE, NULL, TRUE );
|
||||
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||
ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
|
||||
ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ),
|
||||
"wrong info %lx\n", U(io).Information );
|
||||
ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset );
|
||||
|
||||
data_size = ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7) +
|
||||
offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] );
|
||||
memset( data, 0x55, data_size );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, FALSE, NULL, TRUE );
|
||||
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||
ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
|
||||
todo_wine
|
||||
ok( U(io).Information == data_size, "wrong info %lx / %x\n", U(io).Information, data_size );
|
||||
todo_wine
|
||||
ok( fbdi->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||
"wrong offset %x\n", fbdi->NextEntryOffset );
|
||||
ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength );
|
||||
ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||
next = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + fbdi->NextEntryOffset);
|
||||
ok( next->NextEntryOffset == 0, "wrong offset %x\n", next->NextEntryOffset );
|
||||
todo_wine
|
||||
ok( next->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n", next->FileNameLength );
|
||||
filename = next->FileName;
|
||||
todo_wine
|
||||
ok( filename[0] == '.' && filename[1] == '.', "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(next->FileName, next->FileNameLength/sizeof(WCHAR)));
|
||||
|
||||
pNtClose(dirh);
|
||||
|
||||
U(io).Status = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( (HANDLE)0xbeef, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, NULL, TRUE );
|
||||
ok(status == STATUS_INVALID_HANDLE, "wrong status %x\n", status);
|
||||
ok(U(io).Status == 0xdeadbeef, "wrong status %x\n", U(io).Status);
|
||||
|
||||
done:
|
||||
tear_down_attribute_test(testdirA);
|
||||
pRtlFreeUnicodeString(&ntdirname);
|
||||
|
|
Loading…
Reference in a new issue