[PATCH] server: Implement the \??\GLOBALROOT symbolic link.

Jinoh Kang jinoh.kang.kr at gmail.com
Wed Nov 24 10:29:29 CST 2021


\??\GLOBALROOT is a well-known NT symbolic link that allows applications
to access the NT object manager's root namespace via Win32 APIs.

Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---
 dlls/ntdll/tests/om.c | 59 +++++++++++++++++++++++++++++++++++++++++++
 server/directory.c    |  3 +++
 server/object.h       |  2 ++
 server/symlink.c      | 13 ++++++++++
 4 files changed, 77 insertions(+)

diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c
index 77eb58a23b5..250984ebdda 100644
--- a/dlls/ntdll/tests/om.c
+++ b/dlls/ntdll/tests/om.c
@@ -2388,6 +2388,64 @@ static void test_get_next_thread(void)
     CloseHandle(thread);
 }
 
+static void test_globalroot(void)
+{
+    NTSTATUS status;
+    IO_STATUS_BLOCK iosb;
+    UNICODE_STRING str;
+    OBJECT_ATTRIBUTES attr;
+    HANDLE h;
+    WCHAR buffer[256];
+    ULONG len, full_len, i;
+    static const struct { const WCHAR *name, *target; } symlinks[] = {
+        { L"\\??\\GLOBALROOT", L"" },
+        { L"\\??\\GLOBALROOT\\??\\GLOBALROOT", L"" },
+        { L"\\??\\GLOBALROOT\\??\\GLOBALROOT\\??\\GLOBALROOT", L"" },
+        { L"\\??\\GLOBALROOT\\DosDevices", L"\\??" },
+        { L"\\??\\GLOBALROOT\\BaseNamedObjects\\Global", NULL },
+    };
+
+    for (i = 0; i < ARRAY_SIZE(symlinks); i++)
+    {
+        pRtlInitUnicodeString(&str, symlinks[i].name);
+        InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
+        status = pNtOpenSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr );
+        ok(status == STATUS_SUCCESS, "NtOpenSymbolicLinkObject failed %08x\n", status);
+
+        str.Buffer = buffer;
+        str.MaximumLength = sizeof(buffer);
+        len = 0xdeadbeef;
+        memset( buffer, 0xaa, sizeof(buffer) );
+        status = pNtQuerySymbolicLinkObject( h, &str, &len);
+        ok( status == STATUS_SUCCESS, "NtQuerySymbolicLinkObject failed %08x\n", status );
+        full_len = str.Length + sizeof(WCHAR);
+        ok( len == full_len, "bad length %u (expected %u)\n", len, full_len );
+        ok( buffer[len / sizeof(WCHAR) - 1] == 0, "no terminating null\n" );
+
+        if (symlinks[i].target)
+        {
+            ok( compare_unicode_string( &str, symlinks[i].target ),
+                "symlink %s: target expected %s, got %s\n",
+                debugstr_w( symlinks[i].name ),
+                debugstr_w( symlinks[i].target ),
+                debugstr_w( str.Buffer ) );
+        }
+
+        pNtClose(h);
+    }
+
+    pRtlInitUnicodeString(&str, L"\\??\\GLOBALROOT\\Device\\Null");
+    InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL);
+    status = pNtOpenFile(&h, GENERIC_READ | GENERIC_WRITE, &attr, &iosb,
+                         FILE_SHARE_READ | FILE_SHARE_WRITE, 0);
+    ok(status == STATUS_SUCCESS,
+       "expected STATUS_SUCCESS, got %08x\n", status);
+
+    test_object_type(h, L"File");
+
+    pNtClose(h);
+}
+
 START_TEST(om)
 {
     HMODULE hntdll = GetModuleHandleA("ntdll.dll");
@@ -2446,4 +2504,5 @@ START_TEST(om)
     test_duplicate_object();
     test_object_types();
     test_get_next_thread();
+    test_globalroot();
 }
diff --git a/server/directory.c b/server/directory.c
index 70a34d3f1bb..2cd61be0838 100644
--- a/server/directory.c
+++ b/server/directory.c
@@ -378,6 +378,7 @@ void init_directories( struct fd *intl_fd )
 
     /* symlinks */
     static const WCHAR link_dosdevW[] = {'D','o','s','D','e','v','i','c','e','s'};
+    static const WCHAR link_globalrootW[] = {'G','L','O','B','A','L','R','O','O','T'};
     static const WCHAR link_globalW[] = {'G','l','o','b','a','l'};
     static const WCHAR link_nulW[]    = {'N','U','L'};
     static const WCHAR link_pipeW[]   = {'P','I','P','E'};
@@ -392,6 +393,7 @@ void init_directories( struct fd *intl_fd )
     static const WCHAR link_consoleW[]    = {'\\','D','e','v','i','c','e','\\','C','o','n','D','r','v',
         '\\','C','o','n','s','o','l','e'};
     static const struct unicode_str link_dosdev_str = {link_dosdevW, sizeof(link_dosdevW)};
+    static const struct unicode_str link_globalroot_str = {link_globalrootW, sizeof(link_globalrootW)};
     static const struct unicode_str link_global_str = {link_globalW, sizeof(link_globalW)};
     static const struct unicode_str link_nul_str    = {link_nulW, sizeof(link_nulW)};
     static const struct unicode_str link_pipe_str   = {link_pipeW, sizeof(link_pipeW)};
@@ -470,6 +472,7 @@ void init_directories( struct fd *intl_fd )
 
     /* symlinks */
     release_object( create_obj_symlink( &root_directory->obj, &link_dosdev_str, OBJ_PERMANENT, &dir_global->obj, NULL ));
+    release_object( create_root_symlink( &dir_global->obj, &link_globalroot_str, OBJ_PERMANENT, NULL ));
     release_object( create_obj_symlink( &dir_global->obj, &link_global_str, OBJ_PERMANENT, &dir_global->obj, NULL ));
     release_object( create_obj_symlink( &dir_global->obj, &link_nul_str, OBJ_PERMANENT, null_device, NULL ));
     release_object( create_obj_symlink( &dir_global->obj, &link_pipe_str, OBJ_PERMANENT, named_pipe_device, NULL ));
diff --git a/server/object.h b/server/object.h
index 97d6c0e91f8..f156f1d2f13 100644
--- a/server/object.h
+++ b/server/object.h
@@ -279,6 +279,8 @@ extern void init_directories( struct fd *intl_fd );
 
 /* symbolic link functions */
 
+extern struct object *create_root_symlink( struct object *root, const struct unicode_str *name,
+                                           unsigned int attr, const struct security_descriptor *sd );
 extern struct object *create_obj_symlink( struct object *root, const struct unicode_str *name,
                                           unsigned int attr, struct object *target,
                                           const struct security_descriptor *sd );
diff --git a/server/symlink.c b/server/symlink.c
index fa97d9155fa..27d48e2f994 100644
--- a/server/symlink.c
+++ b/server/symlink.c
@@ -110,6 +110,8 @@ static struct object *symlink_lookup_name( struct object *obj, struct unicode_st
     if (!name->len && (attr & OBJ_OPENLINK)) return NULL;
     if (obj == root) return NULL;
 
+    if (!symlink->len) return get_root_directory();
+
     target_str.str = symlink->target;
     target_str.len = symlink->len;
     if ((target = lookup_named_object( NULL, &target_str, attr, &name_left )))
@@ -131,6 +133,17 @@ static void symlink_destroy( struct object *obj )
     free( symlink->target );
 }
 
+struct object *create_root_symlink( struct object *root, const struct unicode_str *name,
+                                    unsigned int attr, const struct security_descriptor *sd )
+{
+    struct symlink *symlink;
+
+    if (!(symlink = create_named_object( root, &symlink_ops, name, attr, sd ))) return NULL;
+    symlink->target = NULL;
+    symlink->len = 0;
+    return &symlink->obj;
+}
+
 struct object *create_symlink( struct object *root, const struct unicode_str *name,
                                unsigned int attr, const struct unicode_str *target,
                                const struct security_descriptor *sd )
-- 
2.31.1




More information about the wine-devel mailing list