X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6601e61aa18bf4f09af135ff61fc7f4771d23b06..eee3565979933af707c711411001ba11fe406a3c:/osfmk/ipc/ipc_object.h diff --git a/osfmk/ipc/ipc_object.h b/osfmk/ipc/ipc_object.h index 1eb392c29..63f533dfa 100644 --- a/osfmk/ipc/ipc_object.h +++ b/osfmk/ipc/ipc_object.h @@ -1,23 +1,29 @@ /* - * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ @@ -47,6 +53,12 @@ * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ +/* + * NOTICE: This file was modified by McAfee Research in 2004 to introduce + * support for mandatory and extensible security protections. This notice + * is included in support of clause 2.2 (b) of the Apple Public License, + * Version 2.0. + */ /* */ /* @@ -61,22 +73,21 @@ #define _IPC_IPC_OBJECT_H_ #include -#include #include #include -#include +#include #include +#include #include #include +#include typedef natural_t ipc_object_refs_t; /* for ipc/ipc_object.h */ typedef natural_t ipc_object_bits_t; typedef natural_t ipc_object_type_t; /* - * There is no lock in the ipc_object; it is in the enclosing kernel - * data structure (rpc_common_data) used by both ipc_port and ipc_pset. * The ipc_object is used to both tag and reference count these two data * structures, and (Noto Bene!) pointers to either of these or the * ipc_object at the head of these are freely cast back and forth; hence @@ -88,17 +99,28 @@ typedef natural_t ipc_object_type_t; * (with which lock size varies). */ struct ipc_object { + ipc_object_bits_t io_bits; ipc_object_refs_t io_references; + lck_spin_t io_lock_data; +} __attribute__((__packed__)); + +/* + * If another object type needs to participate in io_kotype()-based + * dispatching, it must include a stub structure as the first + * element + */ +struct ipc_object_header { ipc_object_bits_t io_bits; - mach_port_name_t io_receiver_name; - decl_mutex_data(, io_lock_data) +#ifdef __LP64__ + natural_t io_padding; /* pad to natural boundary */ +#endif }; /* * Legacy defines. Should use IPC_OBJECT_NULL, etc... */ #define IO_NULL ((ipc_object_t) 0) -#define IO_DEAD ((ipc_object_t) -1) +#define IO_DEAD ((ipc_object_t) ~0UL) #define IO_VALID(io) (((io) != IO_NULL) && ((io) != IO_DEAD)) /* @@ -115,7 +137,7 @@ struct ipc_object { #define IO_BITS_OTYPE 0x7fff0000 /* determines a zone */ #define IO_BITS_ACTIVE 0x80000000 /* is object alive? */ -#define io_active(io) ((io)->io_bits & IO_BITS_ACTIVE) +#define io_active(io) (((io)->io_bits & IO_BITS_ACTIVE) != 0) #define io_otype(io) (((io)->io_bits & IO_BITS_OTYPE) >> 16) #define io_kotype(io) ((io)->io_bits & IO_BITS_KOTYPE) @@ -135,49 +157,34 @@ extern zone_t ipc_object_zones[IOT_NUMBER]; #define io_alloc(otype) \ ((ipc_object_t) zalloc(ipc_object_zones[(otype)])) -#if MACH_ASSERT -/* - * Call the routine for io_free so that checking can be performed. - */ extern void io_free( unsigned int otype, ipc_object_t object); -#else /* MACH_ASSERT */ -#define io_free(otype, io) \ - zfree(ipc_object_zones[(otype)], (io)) -#endif /* MACH_ASSERT */ - /* - * Here we depend on the ipc_object being first within the ipc_common_data, - * which is first within the rpc_common_data, which in turn must be first - * within any kernel data structure needing to lock an ipc_object + * Here we depend on the ipc_object being first within the kernel struct * (ipc_port and ipc_pset). */ #define io_lock_init(io) \ - mutex_init(&(io)->io_lock_data, 0) + lck_spin_init(&(io)->io_lock_data, &ipc_lck_grp, &ipc_lck_attr) +#define io_lock_destroy(io) \ + lck_spin_destroy(&(io)->io_lock_data, &ipc_lck_grp) #define io_lock(io) \ - mutex_lock(&(io)->io_lock_data) + lck_spin_lock(&(io)->io_lock_data) #define io_lock_try(io) \ - mutex_try(&(io)->io_lock_data) + lck_spin_try_lock(&(io)->io_lock_data) #define io_unlock(io) \ - mutex_unlock(&(io)->io_lock_data) + lck_spin_unlock(&(io)->io_lock_data) #define _VOLATILE_ volatile -#define io_check_unlock(io) \ -MACRO_BEGIN \ - _VOLATILE_ ipc_object_refs_t _refs = (io)->io_references; \ - \ - io_unlock(io); \ - if (_refs == 0) \ - io_free(io_otype(io), io); \ -MACRO_END - /* Sanity check the ref count. If it is 0, we may be doubly zfreeing. - * If it is larger than max int, it has been corrupted, probably by being - * modified into an address (this is architecture dependent, but it's - * safe to assume there cannot really be max int references). + * If it is larger than max int, it has been corrupted or leaked, + * probably by being modified into an address (this is architecture + * dependent, but it's safe to assume there cannot really be max int + * references unless some code is leaking the io_reference without leaking + * object). Saturate the io_reference on release kernel if it reaches + * max int to avoid use after free. * * NOTE: The 0 test alone will not catch double zfreeing of ipc_port * structs, because the io_references field is the first word of the struct, @@ -186,18 +193,58 @@ MACRO_END #define IO_MAX_REFERENCES \ (unsigned)(~0 ^ (1 << (sizeof(int)*BYTE_SIZE - 1))) -#define io_reference(io) \ -MACRO_BEGIN \ - assert((io)->io_references < IO_MAX_REFERENCES); \ - (io)->io_references++; \ -MACRO_END +static inline void +io_reference(ipc_object_t io) { + ipc_object_refs_t new_io_references; + ipc_object_refs_t old_io_references; + + assert((io)->io_references > 0 && + (io)->io_references < IO_MAX_REFERENCES); + + do { + old_io_references = (io)->io_references; + new_io_references = old_io_references + 1; + if (old_io_references == IO_MAX_REFERENCES) { + break; + } + } while (OSCompareAndSwap(old_io_references, new_io_references, + &((io)->io_references)) == FALSE); +} + + +static inline void +io_release(ipc_object_t io) { + ipc_object_refs_t new_io_references; + ipc_object_refs_t old_io_references; + + assert((io)->io_references > 0 && + (io)->io_references < IO_MAX_REFERENCES); + + do { + old_io_references = (io)->io_references; + new_io_references = old_io_references - 1; + if (old_io_references == IO_MAX_REFERENCES) { + break; + } + } while (OSCompareAndSwap(old_io_references, new_io_references, + &((io)->io_references)) == FALSE); + + /* If we just removed the last reference count */ + if (1 == old_io_references) { + /* Free the object */ + io_free(io_otype((io)), (io)); + } +} + +/* + * Retrieve a label for use in a kernel call that takes a security + * label as a parameter. If necessary, io_getlabel acquires internal + * (not io_lock) locks, and io_unlocklabel releases them. + */ -#define io_release(io) \ -MACRO_BEGIN \ - assert((io)->io_references > 0 && \ - (io)->io_references <= IO_MAX_REFERENCES); \ - (io)->io_references--; \ -MACRO_END +struct label; +extern struct label *io_getlabel (ipc_object_t obj); +#define io_unlocklabel(obj) /* * Exported interfaces @@ -278,6 +325,11 @@ extern void ipc_object_destroy( ipc_object_t object, mach_msg_type_name_t msgt_name); +/* Destroy a naked destination capability */ +extern void ipc_object_destroy_dest( + ipc_object_t object, + mach_msg_type_name_t msgt_name); + /* Copyout a capability, placing it into a space */ extern kern_return_t ipc_object_copyout( ipc_space_t space, @@ -307,12 +359,4 @@ extern kern_return_t ipc_object_rename( mach_port_name_t oname, mach_port_name_t nname); -#if MACH_KDB -/* Pretty-print an ipc object */ - -extern void ipc_object_print( - ipc_object_t object); - -#endif /* MACH_KDB */ - #endif /* _IPC_IPC_OBJECT_H_ */