[asterisk-dev] [Code Review]: Fix memory leak, possible crash in sip show peers

Matt Jordan reviewboard at asterisk.org
Tue Feb 14 10:35:31 CST 2012



> On Feb. 14, 2012, 10:19 a.m., Mark Michelson wrote:
> > This part has me a bit confused:
> > "If an item is added to the container prior to/while traversing it, the version number of that item will be greater then the version of iterator, and will be ignored"
> > 
> > If I'm reading internal_ao2_iterator_next() correctly, we specifically pay attention to objects with a higher version number than the iterator. So if something were to be added to the container while we are traversing, we won't ignore the new object if its version number is higher than the iterator's. This can lead to the same illegal writes past the end of peerarray that were possible before.
> > 
> > I don't think the change to ao2_iterator_init() actually helps anything. The only thing that the c_version of an ao2_iterator is used for is as an optimization to keep searching within the current bucket if the container can be detected as not having changed between calls to ao2_iterator_next(). The only time this optimization can be used is if the ao2_iterator's obj field is non-NULL. In the first call to ao2_iterator_next() after the initial ao2_iterator_init(), the obj field will be NULL, so the container version optimization couldn't be used anyway.

Yup, this doesn't work.  I thought the handling of the version in the iterator was handled differently - upon rereading it, it doesn't work how I thought it did.  Nuts.

The only way to keep the array from being overrun is either to lock the peers container, or bail out once we've added the number of items we initially counted when we sized the array.  I'm inclined to go with the second approach, even if it means the output of the "sip show peers" command isn't going to be terribly accurate.  With a large number of peers, locking the container through the entire traversal may be prohibitive, which I think is what this was initially trying to avoid.


- Matt


-----------------------------------------------------------
This is an automatically generated e-mail. To reply, visit:
https://reviewboard.asterisk.org/r/1738/#review5498
-----------------------------------------------------------


On Feb. 14, 2012, 6:51 a.m., Matt Jordan wrote:
> 
> -----------------------------------------------------------
> This is an automatically generated e-mail. To reply, visit:
> https://reviewboard.asterisk.org/r/1738/
> -----------------------------------------------------------
> 
> (Updated Feb. 14, 2012, 6:51 a.m.)
> 
> 
> Review request for Asterisk Developers, Mark Michelson and rmudgett.
> 
> 
> Summary
> -------
> 
> The SIP show peers command stores pointers to the current peers in the peers container in a fixed size array.  The size of this array is determined a bit before iterating through the peers container.  The container is not locked during the array initialization, nor while the iterator is initialized.  There are at least two problems with this:
> 1) The array is allocated at the beginning of the method.  There are a number of exit points from the function that occur before the array is deallocated, resulting in a memory leak.
> 2) The array size is supposed to be the current number of peers in the container.  However, the peers container is not locked when the size is determined, and the version of the iterator is not set until ao2_iterator_next is called.  Thus, any items added to the peers container prior to the first traversal of the container will be "counted" during the traversal, and the array can be overrun.
> 
> This would typically occur if some other thread performed a sip reload at the same time as the sip show peers command, and additional peers were added in between when the array was sized and when the peers were traversed.
> 
> This patch takes a bit more of a pessimistic view of the thread-safety involved with showing the peers.  We lock the container during the period that we build the array for sorting and when we initialize the ao2_iterator.  The ao2_iterator initialization has been modified as well to set the version to the container version, as opposed to waiting for the first traversal of the container.  This should be safe:
> 1) If an item is added to the container prior to/while traversing it, the version number of that item will be greater then the version of iterator, and will be ignored
> 2) If an item is removed from the container prior to/while traversing it, the number of items added to the array will be less then the array size, which is acceptable
> 
> Note that you can still have a situation where a reload occurs during a sip show peers which changes what the command will output while it is building the peer array; however, that's no different then the current behavior.  The only way to prevent that would be to lock the peers container during the entire traversal, which would potentially impact performance on normal SIP operations.
> 
> 
> Diffs
> -----
> 
>   /branches/1.8/channels/chan_sip.c 355135 
>   /branches/1.8/main/astobj2.c 355135 
> 
> Diff: https://reviewboard.asterisk.org/r/1738/diff
> 
> 
> Testing
> -------
> 
> Basic testing involving running sip show peers and reloading.  More testing will need to be done by the issue reporter, who was performing "sip reloads" alongside a script that ran "sip show peers" once a second.
> 
> 
> Thanks,
> 
> Matt
> 
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-dev/attachments/20120214/13868267/attachment.htm>


More information about the asterisk-dev mailing list