From 6a76a0ac7a891ffac54bad82ef742c1ca18fd2aa Mon Sep 17 00:00:00 2001 From: Rob Shearman Date: Wed, 21 Feb 2007 13:59:59 +0000 Subject: [PATCH] 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 | 68 ++++++++++++++++++++++++++-------- server/security.h | 1 + server/token.c | 30 +++++++++++++++ 4 files changed, 84 insertions(+), 17 deletions(-) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index ef342b5d3c..201c649b93 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 4b5228029f..852b3f514f 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 (options & DUP_HANDLE_SAME_ACCESS) + if ((entry = get_handle( src, src_handle ))) + src_access = entry->access; + else /* pseudo-handle, give it full 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(); - } + src_access = obj->ops->map_access( obj, GENERIC_ALL ); + clear_error(); } - access &= ~RESERVED_ALL; - if (options & DUP_HANDLE_MAKE_GLOBAL) - res = alloc_global_handle( obj, access ); + src_access &= ~RESERVED_ALL; + + if (options & DUP_HANDLE_SAME_ACCESS) + access = src_access; else - res = alloc_handle( dst, obj, access, attr ); + access = obj->ops->map_access( obj, access ) & ~RESERVED_ALL; + + /* asking for the more access rights than src_access? */ + if (access & ~src_access) + { + if (options & DUP_HANDLE_MAKE_GLOBAL) + res = alloc_global_handle( obj, access ); + else + res = alloc_handle( dst, obj, access, attr ); + } + else + { + 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 191688d3f1..20f42e355b 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 f49b35592d..c4906a5fd7 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) {