X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6d2010ae8f7a6078e10b361c6962983bab233e0f..d190cdc3f5544636abb56dc1874be391d3e1b148:/osfmk/ipc/ipc_object.h?ds=sidebyside diff --git a/osfmk/ipc/ipc_object.h b/osfmk/ipc/ipc_object.h index a813b29bf..63f533dfa 100644 --- a/osfmk/ipc/ipc_object.h +++ b/osfmk/ipc/ipc_object.h @@ -73,14 +73,15 @@ #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; @@ -100,8 +101,8 @@ typedef natural_t ipc_object_type_t; struct ipc_object { ipc_object_bits_t io_bits; ipc_object_refs_t io_references; - decl_lck_mtx_data(, io_lock_data) -}; + lck_spin_t io_lock_data; +} __attribute__((__packed__)); /* * If another object type needs to participate in io_kotype()-based @@ -136,7 +137,7 @@ struct ipc_object_header { #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) @@ -165,31 +166,25 @@ extern void io_free( * (ipc_port and ipc_pset). */ #define io_lock_init(io) \ - lck_mtx_init(&(io)->io_lock_data, &ipc_lck_grp, &ipc_lck_attr) + lck_spin_init(&(io)->io_lock_data, &ipc_lck_grp, &ipc_lck_attr) #define io_lock_destroy(io) \ - lck_mtx_destroy(&(io)->io_lock_data, &ipc_lck_grp) + lck_spin_destroy(&(io)->io_lock_data, &ipc_lck_grp) #define io_lock(io) \ - lck_mtx_lock(&(io)->io_lock_data) + lck_spin_lock(&(io)->io_lock_data) #define io_lock_try(io) \ - lck_mtx_try_lock(&(io)->io_lock_data) + lck_spin_try_lock(&(io)->io_lock_data) #define io_unlock(io) \ - lck_mtx_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, @@ -198,18 +193,48 @@ 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 - -#define io_release(io) \ -MACRO_BEGIN \ - assert((io)->io_references > 0 && \ - (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 @@ -334,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_ */