[PATCH 1/5] server: Do not dereference symlinks specified as root directory.

Paul Gofman pgofman at codeweavers.com
Wed Nov 25 12:42:42 CST 2020


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
    Supersedes 196150 - 196153.

 dlls/ntdll/tests/om.c | 64 ++++++++++++++++++++++++++++++++++++++++++-
 server/console.c      | 24 ++++++++++------
 server/directory.c    |  4 +--
 server/file.c         |  6 ++--
 server/mailslot.c     |  4 +--
 server/named_pipe.c   |  4 +--
 server/object.c       |  5 ++--
 server/object.h       |  5 ++--
 server/sock.c         |  6 ++--
 server/symlink.c      |  5 ++--
 server/winstation.c   |  4 +--
 11 files changed, 104 insertions(+), 27 deletions(-)

diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c
index d3b932bec1d..99c77839b7c 100644
--- a/dlls/ntdll/tests/om.c
+++ b/dlls/ntdll/tests/om.c
@@ -1081,7 +1081,7 @@ static void test_symboliclink(void)
     NTSTATUS status;
     UNICODE_STRING str, target;
     OBJECT_ATTRIBUTES attr;
-    HANDLE dir, link, h;
+    HANDLE dir, link, h, h2;
     IO_STATUS_BLOCK iosb;
 
     /* No name and/or no attributes */
@@ -1178,6 +1178,68 @@ static void test_symboliclink(void)
     pNtClose(h);
     pNtClose(link);
     pNtClose(dir);
+
+    InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
+    RtlInitUnicodeString(&str, L"\\BaseNamedObjects\\om.c-test");
+    status = pNtCreateDirectoryObject(&dir, DIRECTORY_QUERY, &attr);
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
+
+    RtlInitUnicodeString(&str, L"\\DosDevices\\test_link");
+    RtlInitUnicodeString(&target, L"\\BaseNamedObjects");
+    status = pNtCreateSymbolicLinkObject(&link, SYMBOLIC_LINK_QUERY, &attr, &target);
+    ok(status == STATUS_SUCCESS && !!link, "Got unexpected status %#x.\n", status);
+
+    status = NtCreateFile(&h, GENERIC_READ | SYNCHRONIZE, &attr, &iosb, NULL, 0,
+            FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0, NULL, 0 );
+    ok(status == STATUS_OBJECT_TYPE_MISMATCH, "Got unexpected status %#x.\n", status);
+
+    status = pNtOpenSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr );
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
+    pNtClose(h);
+
+    InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
+    RtlInitUnicodeString( &str, L"\\BaseNamedObjects\\om.c-test\\" );
+    status = NtCreateFile(&h, GENERIC_READ | SYNCHRONIZE, &attr, &iosb, NULL, 0,
+            FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0, NULL, 0 );
+    ok(status == STATUS_OBJECT_NAME_INVALID, "Got unexpected status %#x.\n", status);
+
+    InitializeObjectAttributes(&attr, &str, 0, link, NULL);
+    RtlInitUnicodeString( &str, L"om.c-test\\test_object" );
+    status = pNtCreateMutant( &h, GENERIC_ALL, &attr, FALSE );
+    ok(status == STATUS_OBJECT_TYPE_MISMATCH, "Got unexpected status %#x.\n", status);
+
+    InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
+    RtlInitUnicodeString( &str, L"\\DosDevices\\test_link\\om.c-test\\test_object" );
+    status = pNtCreateMutant( &h, GENERIC_ALL, &attr, FALSE );
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
+    status = pNtOpenMutant( &h2, GENERIC_ALL, &attr );
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
+    pNtClose(h2);
+    RtlInitUnicodeString( &str, L"\\BaseNamedObjects\\om.c-test\\test_object" );
+    status = pNtCreateMutant( &h2, GENERIC_ALL, &attr, FALSE );
+    ok(status == STATUS_OBJECT_NAME_COLLISION, "Got unexpected status %#x.\n", status);
+
+    InitializeObjectAttributes(&attr, &str, 0, link, NULL);
+    RtlInitUnicodeString( &str, L"om.c-test\\test_object" );
+    status = pNtOpenMutant( &h2, GENERIC_ALL, &attr );
+    ok(status == STATUS_OBJECT_TYPE_MISMATCH, "Got unexpected status %#x.\n", status);
+
+    pNtClose(h);
+
+    status = pNtOpenMutant( &h, GENERIC_ALL, &attr );
+    ok(status == STATUS_OBJECT_TYPE_MISMATCH, "Got unexpected status %#x.\n", status);
+
+    InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
+    RtlInitUnicodeString( &str, L"test_object" );
+    status = pNtCreateMutant( &h, GENERIC_ALL, &attr, FALSE );
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
+    status = pNtOpenMutant( &h2, GENERIC_ALL, &attr );
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
+    pNtClose(h);
+    pNtClose(h2);
+
+    pNtClose(link);
+    pNtClose(dir);
 }
 
 #define test_file_info(a) _test_file_info(__LINE__,a)
diff --git a/server/console.c b/server/console.c
index 9190dcc02dd..eeb2a21fffb 100644
--- a/server/console.c
+++ b/server/console.c
@@ -69,7 +69,8 @@ static void console_input_dump( struct object *obj, int verbose );
 static void console_input_destroy( struct object *obj );
 static int console_input_signaled( struct object *obj, struct wait_queue_entry *entry );
 static struct fd *console_input_get_fd( struct object *obj );
-static struct object *console_input_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr );
+static struct object *console_input_lookup_name( struct object *obj, struct unicode_str *name,
+                                               unsigned int attr, struct object *root );
 static struct object *console_input_open_file( struct object *obj, unsigned int access,
                                                unsigned int sharing, unsigned int options );
 
@@ -143,7 +144,8 @@ static void console_server_dump( struct object *obj, int verbose );
 static void console_server_destroy( struct object *obj );
 static int console_server_signaled( struct object *obj, struct wait_queue_entry *entry );
 static struct fd *console_server_get_fd( struct object *obj );
-static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr );
+static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name,
+                                                unsigned int attr, struct object *root );
 static struct object *console_server_open_file( struct object *obj, unsigned int access,
                                                 unsigned int sharing, unsigned int options );
 
@@ -259,7 +261,8 @@ static const struct fd_ops screen_buffer_fd_ops =
 
 static struct object_type *console_device_get_type( struct object *obj );
 static void console_device_dump( struct object *obj, int verbose );
-static struct object *console_device_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr );
+static struct object *console_device_lookup_name( struct object *obj, struct unicode_str *name,
+                                                unsigned int attr, struct object *root );
 static struct object *console_device_open_file( struct object *obj, unsigned int access,
                                                 unsigned int sharing, unsigned int options );
 
@@ -355,7 +358,8 @@ struct console_connection
 
 static void console_connection_dump( struct object *obj, int verbose );
 static struct fd *console_connection_get_fd( struct object *obj );
-static struct object *console_connection_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr );
+static struct object *console_connection_lookup_name( struct object *obj, struct unicode_str *name,
+                                                    unsigned int attr, struct object *root );
 static struct object *console_connection_open_file( struct object *obj, unsigned int access,
                                                     unsigned int sharing, unsigned int options );
 static int console_connection_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
@@ -709,7 +713,8 @@ static struct object *create_console_connection( struct console_input *console )
     return &connection->obj;
 }
 
-static struct object *console_input_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr )
+static struct object *console_input_lookup_name( struct object *obj, struct unicode_str *name,
+                                                 unsigned int attr, struct object *root )
 {
     struct console_input *console = (struct console_input *)obj;
     static const WCHAR connectionW[]    = {'C','o','n','n','e','c','t','i','o','n'};
@@ -793,7 +798,8 @@ static void console_server_destroy( struct object *obj )
     if (server->fd) release_object( server->fd );
 }
 
-static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr )
+static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name,
+                                                  unsigned int attr, struct object *root )
 {
     struct console_server *server = (struct console_server*)obj;
     static const WCHAR referenceW[] = {'R','e','f','e','r','e','n','c','e'};
@@ -1117,7 +1123,8 @@ static struct fd *console_connection_get_fd( struct object *obj )
     return (struct fd *)grab_object( connection->fd );
 }
 
-static struct object *console_connection_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr )
+static struct object *console_connection_lookup_name( struct object *obj, struct unicode_str *name,
+                                                      unsigned int attr, struct object *root )
 {
     static const WCHAR referenceW[] = {'R','e','f','e','r','e','n','c','e'};
 
@@ -1165,7 +1172,8 @@ static void console_device_dump( struct object *obj, int verbose )
     fputs( "Console device\n", stderr );
 }
 
-static struct object *console_device_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr )
+static struct object *console_device_lookup_name( struct object *obj, struct unicode_str *name,
+                                                  unsigned int attr, struct object *root )
 {
     static const WCHAR connectionW[]    = {'C','o','n','n','e','c','t','i','o','n'};
     static const WCHAR consoleW[]       = {'C','o','n','s','o','l','e'};
diff --git a/server/directory.c b/server/directory.c
index 6f8fb179808..cd9afb3c457 100644
--- a/server/directory.c
+++ b/server/directory.c
@@ -83,7 +83,7 @@ struct directory
 static void directory_dump( struct object *obj, int verbose );
 static struct object_type *directory_get_type( struct object *obj );
 static struct object *directory_lookup_name( struct object *obj, struct unicode_str *name,
-                                             unsigned int attr );
+                                             unsigned int attr, struct object *root );
 static void directory_destroy( struct object *obj );
 
 static const struct object_ops directory_ops =
@@ -139,7 +139,7 @@ static struct object_type *directory_get_type( struct object *obj )
 }
 
 static struct object *directory_lookup_name( struct object *obj, struct unicode_str *name,
-                                             unsigned int attr )
+                                             unsigned int attr, struct object *root )
 {
     struct directory *dir = (struct directory *)obj;
     struct object *found;
diff --git a/server/file.c b/server/file.c
index 4690af2424e..2cc4a9d978c 100644
--- a/server/file.c
+++ b/server/file.c
@@ -68,7 +68,8 @@ static void file_dump( struct object *obj, int verbose );
 static struct fd *file_get_fd( struct object *obj );
 static struct security_descriptor *file_get_sd( struct object *obj );
 static int file_set_sd( struct object *obj, const struct security_descriptor *sd, unsigned int set_info );
-static struct object *file_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr );
+static struct object *file_lookup_name( struct object *obj, struct unicode_str *name,
+                                      unsigned int attr, struct object *root );
 static struct object *file_open_file( struct object *obj, unsigned int access,
                                       unsigned int sharing, unsigned int options );
 static struct list *file_get_kernel_obj_list( struct object *obj );
@@ -603,7 +604,8 @@ static int file_set_sd( struct object *obj, const struct security_descriptor *sd
     return 1;
 }
 
-static struct object *file_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr )
+static struct object *file_lookup_name( struct object *obj, struct unicode_str *name,
+                                        unsigned int attr, struct object *root )
 {
     if (!name || !name->len) return NULL;  /* open the file itself */
 
diff --git a/server/mailslot.c b/server/mailslot.c
index e0294d946e4..5d26c606080 100644
--- a/server/mailslot.c
+++ b/server/mailslot.c
@@ -186,7 +186,7 @@ struct mailslot_device_file
 static void mailslot_device_dump( struct object *obj, int verbose );
 static struct object_type *mailslot_device_get_type( struct object *obj );
 static struct object *mailslot_device_lookup_name( struct object *obj, struct unicode_str *name,
-                                                   unsigned int attr );
+                                                   unsigned int attr, struct object *root );
 static struct object *mailslot_device_open_file( struct object *obj, unsigned int access,
                                                  unsigned int sharing, unsigned int options );
 static void mailslot_device_destroy( struct object *obj );
@@ -395,7 +395,7 @@ static struct object_type *mailslot_device_get_type( struct object *obj )
 }
 
 static struct object *mailslot_device_lookup_name( struct object *obj, struct unicode_str *name,
-                                                   unsigned int attr )
+                                                   unsigned int attr, struct object *root )
 {
     struct mailslot_device *device = (struct mailslot_device*)obj;
     struct object *found;
diff --git a/server/named_pipe.c b/server/named_pipe.c
index 60bd059d93d..14868fad63a 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -239,7 +239,7 @@ static const struct fd_ops pipe_client_fd_ops =
 static void named_pipe_device_dump( struct object *obj, int verbose );
 static struct object_type *named_pipe_device_get_type( struct object *obj );
 static struct object *named_pipe_device_lookup_name( struct object *obj,
-    struct unicode_str *name, unsigned int attr );
+    struct unicode_str *name, unsigned int attr, struct object *root );
 static struct object *named_pipe_device_open_file( struct object *obj, unsigned int access,
                                                    unsigned int sharing, unsigned int options );
 static void named_pipe_device_destroy( struct object *obj );
@@ -468,7 +468,7 @@ static struct object_type *named_pipe_device_get_type( struct object *obj )
 }
 
 static struct object *named_pipe_device_lookup_name( struct object *obj, struct unicode_str *name,
-                                                     unsigned int attr )
+                                                     unsigned int attr, struct object *root )
 {
     struct named_pipe_device *device = (struct named_pipe_device*)obj;
     struct object *found;
diff --git a/server/object.c b/server/object.c
index 9f26a6fea36..c4772a57823 100644
--- a/server/object.c
+++ b/server/object.c
@@ -248,7 +248,8 @@ struct object *lookup_named_object( struct object *root, const struct unicode_st
 
     clear_error();
 
-    while ((obj = parent->ops->lookup_name( parent, ptr, attr )))
+    root = parent;
+    while ((obj = parent->ops->lookup_name( parent, ptr, attr, root )))
     {
         /* move to the next element */
         release_object ( parent );
@@ -670,7 +671,7 @@ WCHAR *no_get_full_name( struct object *obj, data_size_t *ret_len )
 }
 
 struct object *no_lookup_name( struct object *obj, struct unicode_str *name,
-                               unsigned int attr )
+                               unsigned int attr, struct object *root )
 {
     if (!name) set_error( STATUS_OBJECT_TYPE_MISMATCH );
     return NULL;
diff --git a/server/object.h b/server/object.h
index 394a4aac463..3b3e9084798 100644
--- a/server/object.h
+++ b/server/object.h
@@ -83,7 +83,7 @@ struct object_ops
     /* get the object full name */
     WCHAR *(*get_full_name)(struct object *, data_size_t *);
     /* lookup a name if an object has a namespace */
-    struct object *(*lookup_name)(struct object *, struct unicode_str *,unsigned int);
+    struct object *(*lookup_name)(struct object *, struct unicode_str *,unsigned int,struct object *);
     /* link an object's name into a parent object */
     int (*link_name)(struct object *, struct object_name *, struct object *);
     /* unlink an object's name from its parent */
@@ -165,7 +165,8 @@ extern int default_set_sd( struct object *obj, const struct security_descriptor
 extern int set_sd_defaults_from_token( struct object *obj, const struct security_descriptor *sd,
                                        unsigned int set_info, struct token *token );
 extern WCHAR *no_get_full_name( struct object *obj, data_size_t *ret_len );
-extern struct object *no_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attributes );
+extern struct object *no_lookup_name( struct object *obj, struct unicode_str *name,
+                                      unsigned int attributes, struct object *root );
 extern int no_link_name( struct object *obj, struct object_name *name, struct object *parent );
 extern void default_unlink_name( struct object *obj, struct object_name *name );
 extern struct object *no_open_file( struct object *obj, unsigned int access, unsigned int sharing,
diff --git a/server/sock.c b/server/sock.c
index 8f500adc68b..1ff56f7bbe5 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -1735,7 +1735,8 @@ static void sock_release_ifchange( struct sock *sock )
 
 static struct object_type *socket_device_get_type( struct object *obj );
 static void socket_device_dump( struct object *obj, int verbose );
-static struct object *socket_device_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr );
+static struct object *socket_device_lookup_name( struct object *obj, struct unicode_str *name,
+                                                 unsigned int attr, struct object *root );
 static struct object *socket_device_open_file( struct object *obj, unsigned int access,
                                                unsigned int sharing, unsigned int options );
 
@@ -1775,7 +1776,8 @@ static void socket_device_dump( struct object *obj, int verbose )
     fputs( "Socket device\n", stderr );
 }
 
-static struct object *socket_device_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr )
+static struct object *socket_device_lookup_name( struct object *obj, struct unicode_str *name,
+                                                 unsigned int attr, struct object *root )
 {
     return NULL;
 }
diff --git a/server/symlink.c b/server/symlink.c
index b620f2accb9..0b85350e1a5 100644
--- a/server/symlink.c
+++ b/server/symlink.c
@@ -49,7 +49,7 @@ static void symlink_dump( struct object *obj, int verbose );
 static struct object_type *symlink_get_type( struct object *obj );
 static unsigned int symlink_map_access( struct object *obj, unsigned int access );
 static struct object *symlink_lookup_name( struct object *obj, struct unicode_str *name,
-                                           unsigned int attr );
+                                           unsigned int attr, struct object *root );
 static void symlink_destroy( struct object *obj );
 
 static const struct object_ops symlink_ops =
@@ -94,7 +94,7 @@ static struct object_type *symlink_get_type( struct object *obj )
 }
 
 static struct object *symlink_lookup_name( struct object *obj, struct unicode_str *name,
-                                           unsigned int attr )
+                                           unsigned int attr, struct object *root )
 {
     struct symlink *symlink = (struct symlink *)obj;
     struct unicode_str target_str, name_left;
@@ -104,6 +104,7 @@ static struct object *symlink_lookup_name( struct object *obj, struct unicode_st
 
     if (!name) return NULL;
     if (!name->len && (attr & OBJ_OPENLINK)) return NULL;
+    if (obj == root) return NULL;
 
     target_str.str = symlink->target;
     target_str.len = symlink->len;
diff --git a/server/winstation.c b/server/winstation.c
index c9c85e50fff..95e5c0c7d0d 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -46,7 +46,7 @@ static void winstation_dump( struct object *obj, int verbose );
 static struct object_type *winstation_get_type( struct object *obj );
 static int winstation_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
 static struct object *winstation_lookup_name( struct object *obj, struct unicode_str *name,
-                                              unsigned int attr );
+                                              unsigned int attr, struct object *root );
 static void winstation_destroy( struct object *obj );
 static unsigned int winstation_map_access( struct object *obj, unsigned int access );
 static void desktop_dump( struct object *obj, int verbose );
@@ -155,7 +155,7 @@ static int winstation_close_handle( struct object *obj, struct process *process,
 }
 
 static struct object *winstation_lookup_name( struct object *obj, struct unicode_str *name,
-                                              unsigned int attr )
+                                              unsigned int attr, struct object *root )
 {
     struct winstation *winstation = (struct winstation *)obj;
     struct object *found;
-- 
2.28.0




More information about the wine-devel mailing list