Rob Shearman : server: Check object's security when creating handles.

Alexandre Julliard julliard at wine.codeweavers.com
Wed Feb 21 13:18:31 CST 2007


Module: wine
Branch: master
Commit: 6a76a0ac7a891ffac54bad82ef742c1ca18fd2aa
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=6a76a0ac7a891ffac54bad82ef742c1ca18fd2aa

Author: Rob Shearman <rob at codeweavers.com>
Date:   Wed Feb 21 13:59:59 2007 +0000

server: Check object's security when creating handles.

Don't check object's security when duplicating a handle of the same or 
lower access rights. Based on a patch by Vitaliy Margolen.

---

 dlls/advapi32/tests/security.c |    2 +-
 server/handle.c                |   66 +++++++++++++++++++++++++++++++---------
 server/security.h              |    1 +
 server/token.c                 |   30 ++++++++++++++++++
 4 files changed, 83 insertions(+), 16 deletions(-)

diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
index ef342b5..201c649 100644
--- a/dlls/advapi32/tests/security.c
+++ b/dlls/advapi32/tests/security.c
@@ -857,7 +857,7 @@ static void test_token_attr(void)
         BYTE buf[1024];
         DWORD bufsize = sizeof(buf);
         ret = GetTokenInformation(Token, TokenUser,(void*)buf, bufsize, &bufsize);
-        todo_wine ok(ret, "GetTokenInformation failed with error %d\n", GetLastError());
+        ok(ret, "GetTokenInformation failed with error %d\n", GetLastError());
         CloseHandle(Token);
     }
 
diff --git a/server/handle.c b/server/handle.c
index 4b52280..852b3f5 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -36,6 +36,7 @@
 #include "handle.h"
 #include "process.h"
 #include "thread.h"
+#include "security.h"
 #include "request.h"
 
 struct handle_entry
@@ -222,11 +223,10 @@ static obj_handle_t alloc_entry( struct handle_table *table, void *obj, unsigned
 
 /* allocate a handle for an object, incrementing its refcount */
 /* return the handle, or 0 on error */
-obj_handle_t alloc_handle( struct process *process, void *ptr, unsigned int access, unsigned int attr )
+static obj_handle_t alloc_handle_no_access_check( struct process *process, void *ptr, unsigned int access, unsigned int attr )
 {
     struct object *obj = ptr;
 
-    access = obj->ops->map_access( obj, access );
     access &= ~RESERVED_ALL;
     if (attr & OBJ_INHERIT) access |= RESERVED_INHERIT;
     if (!process->handles)
@@ -237,9 +237,20 @@ obj_handle_t alloc_handle( struct process *process, void *ptr, unsigned int acce
     return alloc_entry( process->handles, obj, access );
 }
 
+/* allocate a handle for an object, checking the dacl allows the process to */
+/* access it and incrementing its refcount */
+/* return the handle, or 0 on error */
+obj_handle_t alloc_handle( struct process *process, void *ptr, unsigned int access, unsigned int attr )
+{
+    struct object *obj = ptr;
+    access = obj->ops->map_access( obj, access );
+    if (access && !check_object_access( obj, &access )) return 0;
+    return alloc_handle_no_access_check( process, ptr, access, attr );
+}
+
 /* allocate a global handle for an object, incrementing its refcount */
 /* return the handle, or 0 on error */
-static obj_handle_t alloc_global_handle( void *obj, unsigned int access )
+static obj_handle_t alloc_global_handle_no_access_check( void *obj, unsigned int access )
 {
     if (!global_table)
     {
@@ -250,6 +261,15 @@ static obj_handle_t alloc_global_handle( void *obj, unsigned int access )
     return handle_local_to_global( alloc_entry( global_table, obj, access ));
 }
 
+/* allocate a global handle for an object, checking the dacl allows the */
+/* process to access it and incrementing its refcount and incrementing its refcount */
+/* return the handle, or 0 on error */
+static obj_handle_t alloc_global_handle( void *obj, unsigned int access )
+{
+    if (access && !check_object_access( obj, &access )) return 0;
+    return alloc_global_handle_no_access_check( obj, access );
+}
+
 /* return a handle entry, or NULL if the handle is invalid */
 static struct handle_entry *get_handle( struct process *process, obj_handle_t handle )
 {
@@ -449,25 +469,41 @@ obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, str
                                unsigned int access, unsigned int attr, unsigned int options )
 {
     obj_handle_t res;
+    struct handle_entry *entry;
+    unsigned int src_access;
     struct object *obj = get_handle_obj( src, src_handle, 0, NULL );
 
     if (!obj) return 0;
+    if ((entry = get_handle( src, src_handle )))
+        src_access = entry->access;
+    else  /* pseudo-handle, give it full access */
+    {
+        src_access = obj->ops->map_access( obj, GENERIC_ALL );
+        clear_error();
+    }
+    src_access &= ~RESERVED_ALL;
+
     if (options & DUP_HANDLE_SAME_ACCESS)
+        access = src_access;
+    else
+        access = obj->ops->map_access( obj, access ) & ~RESERVED_ALL;
+
+    /* asking for the more access rights than src_access? */
+    if (access & ~src_access)
     {
-        struct handle_entry *entry = get_handle( src, src_handle );
-        if (entry)
-            access = entry->access;
-        else  /* pseudo-handle, give it full access */
-        {
-            access = obj->ops->map_access( obj, GENERIC_ALL );
-            clear_error();
-        }
+        if (options & DUP_HANDLE_MAKE_GLOBAL)
+            res = alloc_global_handle( obj, access );
+        else
+            res = alloc_handle( dst, obj, access, attr );
     }
-    access &= ~RESERVED_ALL;
-    if (options & DUP_HANDLE_MAKE_GLOBAL)
-        res = alloc_global_handle( obj, access );
     else
-        res = alloc_handle( dst, obj, access, attr );
+    {
+        if (options & DUP_HANDLE_MAKE_GLOBAL)
+            res = alloc_global_handle_no_access_check( obj, access );
+        else
+            res = alloc_handle_no_access_check( dst, obj, access, attr );
+    }
+
     release_object( obj );
     return res;
 }
diff --git a/server/security.h b/server/security.h
index 191688d..20f42e3 100644
--- a/server/security.h
+++ b/server/security.h
@@ -47,6 +47,7 @@ extern int token_check_privileges( struct token *token, int all_required,
                                    unsigned int count, LUID_AND_ATTRIBUTES *usedprivs);
 extern const ACL *token_get_default_dacl( struct token *token );
 extern void security_set_thread_token( struct thread *thread, obj_handle_t handle );
+extern int check_object_access( struct object *obj, unsigned int *access );
 
 static inline int thread_single_check_privilege( struct thread *thread, const LUID *priv)
 {
diff --git a/server/token.c b/server/token.c
index f49b355..c4906a5 100644
--- a/server/token.c
+++ b/server/token.c
@@ -1005,6 +1005,36 @@ static void set_object_sd( struct object *obj, const struct security_descriptor
     obj->sd = pnew_sd;
 }
 
+int check_object_access(struct object *obj, unsigned int *access)
+{
+    GENERIC_MAPPING mapping;
+    struct token *token = current->token ? current->token : current->process->token;
+    LUID_AND_ATTRIBUTES priv;
+    unsigned int status, priv_count = 1;
+    int res;
+
+    mapping.GenericAll = obj->ops->map_access( obj, GENERIC_ALL );
+
+    if (!obj->sd)
+    {
+        if (*access & MAXIMUM_ALLOWED)
+            *access = mapping.GenericAll;
+        return TRUE;
+    }
+
+    mapping.GenericRead  = obj->ops->map_access( obj, GENERIC_READ );
+    mapping.GenericWrite = obj->ops->map_access( obj, GENERIC_WRITE );
+    mapping.GenericExecute = obj->ops->map_access( obj, GENERIC_EXECUTE );
+
+    res = token_access_check( token, obj->sd, *access, &priv, &priv_count,
+                              &mapping, access, &status ) == STATUS_SUCCESS &&
+          status == STATUS_SUCCESS;
+
+    if (!res) set_error( STATUS_ACCESS_DENIED );
+    return res;
+}
+
+
 /* open a security token */
 DECL_HANDLER(open_token)
 {




More information about the wine-cvs mailing list