From: Alexandre Julliard Date: Tue, 19 Jan 2016 06:52:35 +0000 (+0900) Subject: server: Fix constraints on the length of NT object names. X-Git-Url: http://git.etersoft.ru/projects/?a=commitdiff_plain;h=cd6e9c38e441edd4a16f77c8e85a7b3bde1bb327;p=wine%2Feterwine.git server: Fix constraints on the length of NT object names. Signed-off-by: Alexandre Julliard --- diff --git a/dlls/ntdll/reg.c b/dlls/ntdll/reg.c index c0e213ab92..9223cb4cc9 100644 --- a/dlls/ntdll/reg.c +++ b/dlls/ntdll/reg.c @@ -42,8 +42,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(reg); -/* maximum length of a key name in bytes (without terminating null) */ -#define MAX_NAME_LENGTH (255 * sizeof(WCHAR)) /* maximum length of a value name in bytes (without terminating null) */ #define MAX_VALUE_LENGTH (16383 * sizeof(WCHAR)) @@ -61,7 +59,6 @@ NTSTATUS WINAPI NtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_AT if (!retkey || !attr) return STATUS_ACCESS_VIOLATION; if (attr->Length > sizeof(OBJECT_ATTRIBUTES)) return STATUS_INVALID_PARAMETER; - if (attr->ObjectName->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW; TRACE( "(%p,%s,%s,%x,%x,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName), debugstr_us(class), options, access, retkey ); @@ -130,24 +127,20 @@ NTSTATUS WINAPI RtlpNtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJEC NTSTATUS WINAPI NtOpenKeyEx( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, ULONG options ) { NTSTATUS ret; - DWORD len; if (!retkey || !attr) return STATUS_ACCESS_VIOLATION; if (attr->Length > sizeof(OBJECT_ATTRIBUTES)) return STATUS_INVALID_PARAMETER; - len = attr->ObjectName->Length; TRACE( "(%p,%s,%x,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName), access, retkey ); if (options) FIXME("options %x not implemented\n", options); - if (len > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW; - SERVER_START_REQ( open_key ) { req->parent = wine_server_obj_handle( attr->RootDirectory ); req->access = access; req->attributes = attr->Attributes; - wine_server_add_data( req, attr->ObjectName->Buffer, len ); + wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length ); ret = wine_server_call( req ); *retkey = wine_server_ptr_handle( reply->hkey ); } diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index a6de6a17ec..47b27d3c29 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -107,8 +107,8 @@ NTSTATUS alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_a if (attr->ObjectName) { - if (attr->ObjectName->Length >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG; - len += attr->ObjectName->Length & ~(sizeof(WCHAR) - 1); + if (attr->ObjectName->Length & (sizeof(WCHAR) - 1)) return STATUS_OBJECT_NAME_INVALID; + len += attr->ObjectName->Length; } *ret = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, len ); @@ -142,7 +142,7 @@ NTSTATUS alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_a if (attr->ObjectName) { unsigned char *ptr = (unsigned char *)(*ret + 1) + (*ret)->sd_len; - (*ret)->name_len = attr->ObjectName->Length & ~(sizeof(WCHAR) - 1); + (*ret)->name_len = attr->ObjectName->Length; memcpy( ptr, attr->ObjectName->Buffer, (*ret)->name_len ); } diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index 0f9008ac81..a736c1edc3 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -33,6 +33,12 @@ static NTSTATUS (WINAPI *pNtCreateEvent) ( PHANDLE, ACCESS_MASK, const POBJECT_A static NTSTATUS (WINAPI *pNtOpenEvent) ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES); static NTSTATUS (WINAPI *pNtPulseEvent) ( HANDLE, PULONG ); static NTSTATUS (WINAPI *pNtQueryEvent) ( HANDLE, EVENT_INFORMATION_CLASS, PVOID, ULONG, PULONG ); +static NTSTATUS (WINAPI *pNtCreateJobObject)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES ); +static NTSTATUS (WINAPI *pNtCreateKey)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG, + const UNICODE_STRING *, ULONG, PULONG ); +static NTSTATUS (WINAPI *pNtDeleteKey)( HANDLE ); +static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, + ULONG, ULONG, ULONG, PLARGE_INTEGER ); static NTSTATUS (WINAPI *pNtCreateMutant)( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES, BOOLEAN ); static NTSTATUS (WINAPI *pNtOpenMutant) ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES ); static NTSTATUS (WINAPI *pNtCreateSemaphore)( PHANDLE, ACCESS_MASK,const POBJECT_ATTRIBUTES,LONG,LONG ); @@ -356,6 +362,198 @@ static void test_name_collisions(void) pNtClose(dir); } +static void test_name_limits(void) +{ + static const WCHAR pipeW[] = {'\\','D','e','v','i','c','e','\\','N','a','m','e','d','P','i','p','e','\\'}; + static const WCHAR mailslotW[] = {'\\','D','e','v','i','c','e','\\','M','a','i','l','S','l','o','t','\\'}; + static const WCHAR registryW[] = {'\\','R','E','G','I','S','T','R','Y','\\','M','a','c','h','i','n','e','\\','S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\'}; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK iosb; + LARGE_INTEGER size, timeout; + UNICODE_STRING str, target; + NTSTATUS status; + HANDLE ret; + DWORD i; + + InitializeObjectAttributes( &attr, &str, 0, 0, NULL ); + str.Buffer = HeapAlloc( GetProcessHeap(), 0, 65536 + sizeof(registryW)); + str.MaximumLength = 65534; + for (i = 0; i < 65536 / sizeof(WCHAR); i++) str.Buffer[i] = 'a'; + + if (!(attr.RootDirectory = get_base_dir())) + { + win_skip( "couldn't find the BaseNamedObjects dir\n" ); + return; + } + + str.Length = 67; + status = pNtCreateMutant( &ret, GENERIC_ALL, &attr, FALSE ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateMutant failed %x\n", str.Length, status ); + status = pNtCreateSemaphore( &ret, GENERIC_ALL, &attr, 1, 2 ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateSemaphore failed %x\n", str.Length, status ); + status = pNtCreateEvent( &ret, GENERIC_ALL, &attr, 1, 0 ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateEvent failed %x\n", str.Length, status ); + status = pNtCreateKeyedEvent( &ret, GENERIC_ALL, &attr, 0 ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateKeyedEvent failed %x\n", str.Length, status ); + status = pNtCreateTimer( &ret, GENERIC_ALL, &attr, NotificationTimer ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateTimer failed %x\n", str.Length, status ); + status = pNtCreateIoCompletion( &ret, GENERIC_ALL, &attr, 0 ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateCompletion failed %x\n", str.Length, status ); + status = pNtCreateJobObject( &ret, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateJobObject failed %x\n", str.Length, status ); + status = pNtCreateDirectoryObject( &ret, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateDirectoryObject failed %x\n", str.Length, status ); + pRtlCreateUnicodeStringFromAsciiz( &target, "\\DosDevices" ); + status = pNtCreateSymbolicLinkObject( &ret, GENERIC_ALL, &attr, &target ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateSymbolicLinkObject failed %x\n", str.Length, status ); + size.QuadPart = 4096; + status = pNtCreateSection( &ret, SECTION_MAP_WRITE, &attr, &size, PAGE_READWRITE, SEC_COMMIT, 0 ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateSection failed %x\n", str.Length, status ); + + str.Length = 65532; + status = pNtCreateMutant( &ret, GENERIC_ALL, &attr, FALSE ); + ok( status == STATUS_SUCCESS, "%u: NtCreateMutant failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateSemaphore( &ret, GENERIC_ALL, &attr, 1, 2 ); + ok( status == STATUS_SUCCESS, "%u: NtCreateSemaphore failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateEvent( &ret, GENERIC_ALL, &attr, 1, 0 ); + ok( status == STATUS_SUCCESS, "%u: NtCreateEvent failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateKeyedEvent( &ret, GENERIC_ALL, &attr, 0 ); + ok( status == STATUS_SUCCESS, "%u: NtCreateKeyedEvent failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateTimer( &ret, GENERIC_ALL, &attr, NotificationTimer ); + ok( status == STATUS_SUCCESS, "%u: NtCreateTimer failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateIoCompletion( &ret, GENERIC_ALL, &attr, 0 ); + ok( status == STATUS_SUCCESS, "%u: NtCreateCompletion failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateJobObject( &ret, GENERIC_ALL, &attr ); + ok( status == STATUS_SUCCESS, "%u: NtCreateJobObject failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateDirectoryObject( &ret, GENERIC_ALL, &attr ); + ok( status == STATUS_SUCCESS, "%u: NtCreateDirectoryObject failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateSymbolicLinkObject( &ret, GENERIC_ALL, &attr, &target ); + ok( status == STATUS_SUCCESS, "%u: NtCreateSymbolicLinkObject failed %x\n", str.Length, status ); + pNtClose( ret ); + size.QuadPart = 4096; + status = pNtCreateSection( &ret, SECTION_MAP_WRITE, &attr, &size, PAGE_READWRITE, SEC_COMMIT, 0 ); + ok( status == STATUS_SUCCESS, "%u: NtCreateSection failed %x\n", str.Length, status ); + pNtClose( ret ); + + str.Length = 65534; + status = pNtCreateMutant( &ret, GENERIC_ALL, &attr, FALSE ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateMutant failed %x\n", str.Length, status ); + status = pNtCreateSemaphore( &ret, GENERIC_ALL, &attr, 1, 2 ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateSemaphore failed %x\n", str.Length, status ); + status = pNtCreateEvent( &ret, GENERIC_ALL, &attr, 1, 0 ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateEvent failed %x\n", str.Length, status ); + status = pNtCreateKeyedEvent( &ret, GENERIC_ALL, &attr, 0 ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateKeyedEvent failed %x\n", str.Length, status ); + status = pNtCreateTimer( &ret, GENERIC_ALL, &attr, NotificationTimer ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateTimer failed %x\n", str.Length, status ); + status = pNtCreateIoCompletion( &ret, GENERIC_ALL, &attr, 0 ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateCompletion failed %x\n", str.Length, status ); + status = pNtCreateJobObject( &ret, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateJobObject failed %x\n", str.Length, status ); + status = pNtCreateDirectoryObject( &ret, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateDirectoryObject failed %x\n", str.Length, status ); + status = pNtCreateSymbolicLinkObject( &ret, GENERIC_ALL, &attr, &target ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateSymbolicLinkObject failed %x\n", str.Length, status ); + size.QuadPart = 4096; + status = pNtCreateSection( &ret, SECTION_MAP_WRITE, &attr, &size, PAGE_READWRITE, SEC_COMMIT, 0 ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateSection failed %x\n", str.Length, status ); + + /* named pipes */ + memcpy( str.Buffer, pipeW, sizeof(pipeW) ); + for (i = 0; i < 65536 / sizeof(WCHAR); i++) str.Buffer[i + sizeof(pipeW)/sizeof(WCHAR)] = 'a'; + str.Length = 67; + attr.RootDirectory = 0; + attr.Attributes = OBJ_CASE_INSENSITIVE; + timeout.QuadPart = -10000; + status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateNamedPipeFile failed %x\n", str.Length, status ); + str.Length = 65532; + status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout ); + ok( status == STATUS_SUCCESS, "%u: NtCreateNamedPipeFile failed %x\n", str.Length, status ); + pNtClose( ret ); + str.Length = 65534; + status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateNamedPipeFile failed %x\n", str.Length, status ); + + /* mailslots */ + memcpy( str.Buffer, mailslotW, sizeof(mailslotW) ); + for (i = 0; i < 65536 / sizeof(WCHAR); i++) str.Buffer[i + sizeof(mailslotW)/sizeof(WCHAR)] = 'a'; + str.Length = 67; + status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr, &iosb, 0, 0, 0, NULL ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateMailslotFile failed %x\n", str.Length, status ); + str.Length = 65532; + status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr, &iosb, 0, 0, 0, NULL ); + ok( status == STATUS_SUCCESS, "%u: NtCreateMailslotFile failed %x\n", str.Length, status ); + pNtClose( ret ); + str.Length = 65534; + status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr, &iosb, 0, 0, 0, NULL ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateMailslotFile failed %x\n", str.Length, status ); + + /* registry keys */ + memcpy( str.Buffer, registryW, sizeof(registryW) ); + for (i = 0; i < 65536 / sizeof(WCHAR); i++) str.Buffer[i + sizeof(registryW)/sizeof(WCHAR)] = 'a'; + str.Length = sizeof(registryW) + 250 * sizeof(WCHAR) + 1; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_OBJECT_NAME_INVALID || + status == STATUS_INVALID_PARAMETER || + broken( status == STATUS_SUCCESS ), /* wow64 */ + "%u: NtCreateKey failed %x\n", str.Length, status ); + if (!status) + { + pNtDeleteKey( ret ); + pNtClose( ret ); + } + str.Length = sizeof(registryW) + 256 * sizeof(WCHAR); + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_SUCCESS, "%u: NtCreateKey failed %x\n", str.Length, status ); + pNtDeleteKey( ret ); + pNtClose( ret ); + str.Length++; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_OBJECT_NAME_INVALID || + status == STATUS_INVALID_PARAMETER || + broken( status == STATUS_SUCCESS ), /* win7 */ + "%u: NtCreateKey failed %x\n", str.Length, status ); + if (!status) + { + pNtDeleteKey( ret ); + pNtClose( ret ); + } + str.Length++; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "%u: NtCreateKey failed %x\n", str.Length, status ); + str.Length = 2000; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "%u: NtCreateKey failed %x\n", str.Length, status ); + /* some Windows versions change the error past 2050 chars, others past 4066 chars, some don't */ + str.Length = 5000; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_BUFFER_OVERFLOW || + status == STATUS_BUFFER_TOO_SMALL || + status == STATUS_INVALID_PARAMETER, + "%u: NtCreateKey failed %x\n", str.Length, status ); + str.Length = 65534; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_OBJECT_NAME_INVALID || + status == STATUS_BUFFER_OVERFLOW || + status == STATUS_BUFFER_TOO_SMALL, + "%u: NtCreateKey failed %x\n", str.Length, status ); + + pRtlFreeUnicodeString( &str ); + pRtlFreeUnicodeString( &target ); +} + static void test_directory(void) { NTSTATUS status; @@ -1206,6 +1404,10 @@ START_TEST(om) pRtlCreateUnicodeStringFromAsciiz = (void *)GetProcAddress(hntdll, "RtlCreateUnicodeStringFromAsciiz"); pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString"); pNtCreateEvent = (void *)GetProcAddress(hntdll, "NtCreateEvent"); + pNtCreateJobObject = (void *)GetProcAddress(hntdll, "NtCreateJobObject"); + pNtCreateKey = (void *)GetProcAddress(hntdll, "NtCreateKey"); + pNtDeleteKey = (void *)GetProcAddress(hntdll, "NtDeleteKey"); + pNtCreateMailslotFile = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile"); pNtCreateMutant = (void *)GetProcAddress(hntdll, "NtCreateMutant"); pNtOpenEvent = (void *)GetProcAddress(hntdll, "NtOpenEvent"); pNtQueryEvent = (void *)GetProcAddress(hntdll, "NtQueryEvent"); @@ -1234,6 +1436,7 @@ START_TEST(om) test_case_sensitive(); test_namespace_pipe(); test_name_collisions(); + test_name_limits(); test_directory(); test_symboliclink(); test_query_object(); diff --git a/server/registry.c b/server/registry.c index e1d66d31bb..5723824ff2 100644 --- a/server/registry.c +++ b/server/registry.c @@ -101,7 +101,7 @@ struct key_value #define MIN_SUBKEYS 8 /* min. number of allocated subkeys per key */ #define MIN_VALUES 8 /* min. number of allocated values per key */ -#define MAX_NAME_LEN 255 /* max. length of a key name */ +#define MAX_NAME_LEN 256 /* max. length of a key name */ #define MAX_VALUE_LEN 16383 /* max. length of a value name */ /* the root of the registry tree */ @@ -575,7 +575,7 @@ static struct key *alloc_subkey( struct key *parent, const struct unicode_str *n if (name->len > MAX_NAME_LEN * sizeof(WCHAR)) { - set_error( STATUS_NAME_TOO_LONG ); + set_error( STATUS_INVALID_PARAMETER ); return NULL; } if (parent->last_subkey + 1 == parent->nb_subkeys) diff --git a/server/request.c b/server/request.c index 942bc427eb..62e2b0304f 100644 --- a/server/request.c +++ b/server/request.c @@ -191,9 +191,13 @@ const struct object_attributes *get_req_object_attributes( const struct security set_error( STATUS_INVALID_SECURITY_DESCR ); return NULL; } - + if ((attr->name_len & (sizeof(WCHAR) - 1)) || attr->name_len >= 65534) + { + set_error( STATUS_OBJECT_NAME_INVALID ); + return NULL; + } *sd = attr->sd_len ? (const struct security_descriptor *)(attr + 1) : NULL; - name->len = (attr->name_len / sizeof(WCHAR)) * sizeof(WCHAR); + name->len = attr->name_len; name->str = (const WCHAR *)(attr + 1) + attr->sd_len / sizeof(WCHAR); return attr; }