server: Fix constraints on the length of NT object names.
authorAlexandre Julliard <julliard@winehq.org>
Tue, 19 Jan 2016 06:52:35 +0000 (15:52 +0900)
committerAlexandre Julliard <julliard@winehq.org>
Tue, 19 Jan 2016 11:48:08 +0000 (20:48 +0900)
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
dlls/ntdll/reg.c
dlls/ntdll/sync.c
dlls/ntdll/tests/om.c
server/registry.c
server/request.c

index c0e213ab929c4cc1ddd1d5dd217c3e4adfab2243..9223cb4cc976add5163d47f9840d7aab5fe37470 100644 (file)
@@ -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 );
     }
index a6de6a17ec5dcc72b45baf3a282a5566b8765ff7..47b27d3c293b04dd2ecc319e9639f3a2c0a50b58 100644 (file)
@@ -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 );
     }
 
index 0f9008ac8130ff127b7e703ea1d28a045cfa5e77..a736c1edc31700889574c22e1b7104e4f20b6578 100644 (file)
@@ -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();
index e1d66d31bb7dc91bc86eba837966b2a9fddea7bb..5723824ff2389755cdd9ca1d8d2c95cc9bfda467 100644 (file)
@@ -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)
index 942bc427eb1f45d3c1db9c02d25678fdabd33203..62e2b0304ff46b721cc0f78a40ea0009feed9d0c 100644 (file)
@@ -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;
 }