iOS in-the-wild vulnerability in vouchers [CVE-2021-1782]
There is a good deal of complexity in the object structure that is detailed in the post that I’m going to gloss over. Effectively you have an array of entry objects, and each entry has a pointer to a user_data_value_element
. Since there is generally a one-to-one mapping of entries to these user data values only the entry is reference counted.
There is a race condition in the allocation process for a new entry where a pointer to the user_data_value_element
has been claimed but not yet accounted for by the entry. During this window, another thread can drop the last reference to the entry resulting in the user_data_value_element
getting unexpectedly freed.
To prevent this the value element tracks the number of pointers handed out in an e_made
field, and the entry tracks the count. Then when the last reference is dropped before it free’s the user_data_value_element
it checks these two counts, and if there is a desync it knows that it is not safe to free the user_data_value_element
.
And so we have the core bug in that the e_made
field of user_data_value_element
is incremented without holding the appropriate lock. So you can have threads that should increment e_made
both read the same value and add one to it, resulting in an e_made
that is too low. Creating a situation where the value element can be inappropriately freed.