[ovs-dev] [PATCH v2] ovs rcu: update rcu pointer first
Ilya Maximets
i.maximets at ovn.org
Wed Jun 3 16:01:06 UTC 2020
On 6/3/20 7:26 AM, Ben Pfaff wrote:
> On Wed, Jun 03, 2020 at 01:22:52AM +0000, Linhaifeng wrote:
>>
>>
>> -----Original Message-----
>> From: Ben Pfaff [mailto:blp at ovn.org]
>> Sent: Wednesday, June 3, 2020 1:28 AM
>> To: Linhaifeng <haifeng.lin at huawei.com>
>> Cc: Yanqin Wei <Yanqin.Wei at arm.com>; dev at openvswitch.org; nd <nd at arm.com>; Lilijun (Jerry) <jerry.lilijun at huawei.com>; chenchanghu <chenchanghu at huawei.com>; Lichunhe <lichunhe at huawei.com>
>> Subject: Re: [ovs-dev] [PATCH v2] ovs rcu: update rcu pointer first
>>
>> On Tue, Jun 02, 2020 at 07:27:59AM +0000, Linhaifeng wrote:
>>> We should update rcu pointer first then use ovsrcu_postpone to free
>>> otherwise maybe cause use-after-free.
>>> e.g.,reader indicates momentary quiescent and access old pointer after
>>> writer postpone free old pointer and before setting new pointer.
>>>
>>> Signed-off-by: Linhaifeng <haifeng.lin at huawei.com>
>>
>> I don't see how that's possible, since the writer hasn't quiesced.
>>
>> I think the logic is as follow, Could you help me find out where is incorrect?
>>
>> 1.1 -> 1.2 -> 3.1 -> 3.2 -> 2.1 -> 2.2 -> 2.3 -> 2.1 -> 1.3 -> 1.4 -> 3.3 -> 2.2(use after free)
>>
>> wirter:
>> 1.1 use postone to free old pointer
>> 1.2 flush cbsets to flushed_cbsets
>> 1.3 update new pointer
>> 1.4 quiesced
>>
>> Read:
>> 2.1. read pointer
>> 2.2. use pointer
>> 2.3. quiesced
>>
>> Rcu:
>> 3.1 pop flushed_cbsets
>> 3.2 ovsrcu_synchronize
>> 3.3 call all cb to free
>
> So you're saying this:
>
> 1.1 use postone to free old pointer (A)
> 1.2 flush cbsets to flushed_cbsets
>
> 3.1 pop flushed_cbsets
> 3.2 ovsrcu_synchronize
>
> 2.1. read pointer (A)
> 2.2. use pointer (A)
> 2.3. quiesced
>
> 2.1. read pointer (A)
IIUC, 'Read' thread should enter quiescent state here at least
one more time in order to trigger the issue (or, maybe, some other
thread could advance global_seqno before step 2.3 and after
reading target_seqno by RCU thread on step 3.2). Otherwise,
target_seqno will be equal to thread->seqno of the 'Read' thread
and RCU thread will wait for the next quiescent state before
calling callbacks.
>
> 1.3 update new pointer (B)
> 1.4 quiesced
>
> 3.3 call all cb to free (A)
>
> 2.2. use pointer (A)
>
> Wow, you are absolutely right. This had never occurred to me. Thank
> you! I'll review your patch.
Sharing my more detailed diagram of the execution flow that should
trigger the issue here:
------------------ ------------------ -------------------
Thread 1 Thread 2 RCU Thread
------------------ ------------------ -------------------
pointer = A
ovsrcu_quiesce():
thread->seqno = 30
global_seqno = 31
quiesced
read pointer A
postpone(free(A)):
flush cbset
pop flushed_cbsets
ovsrcu_synchronize:
target_seqno = 31
ovsrcu_quiesce():
thread->seqno = 31
global_seqno = 32
quiesced
read pointer A
use pointer A
ovsrcu_quiesce():
thread->seqno = 32
global_seqno = 33
quiesced
read pointer A
pointer = B
ovsrcu_quiesce():
thread->seqno = 33
global_seqno = 34
quiesced
target_seqno exceeded
by all threads
call cbs to free A
use pointer A
(use after free)
-----------------------------------------------------------
Best regards, Ilya Maximets.
More information about the dev
mailing list