Re: [PATCH 7/7] rust: file: add abstraction for `poll_table`

From: Alice Ryhl
Date: Fri Dec 01 2023 - 06:50:58 EST


Boqun Feng <boqun.feng@xxxxxxxxx> writes:
>> That said, `synchronize_rcu` is rather expensive and is not needed in
>> all cases: If we have never registered a `poll_table` with the
>> `wait_list`, then we don't need to call `synchronize_rcu`. (And this is
>> a common case in Binder - not all processes use Binder with epoll.) The
>> current implementation does not account for this, but we could change it
>> to store a boolean next to the `wait_list` to keep track of whether a
>> `poll_table` has ever been registered. It is up to discussion whether
>> this is desireable.
>>
>> It is not clear to me whether we can implement the above without storing
>> an extra boolean. We could check whether the `wait_list` is empty, but
>> it is not clear that this is sufficient. Perhaps someone knows the
>> answer? If a `poll_table` has previously been registered with a
>
> That won't be sufficient, considering this:
>
> CPU 0 CPU 1
> ep_remove_wait_queue():
> whead = smp_load_acquire(&pwq->whead); // whead is not NULL
> PollCondVar::drop():
> self.inner.notify():
> <for each wait entry in the list>
> ep_poll_callback():
> <remove wait entry>
> smp_store_release(&ep_pwq_from_wait(wait)->whead, NULL);
> <lock the waitqueue>
> waitqueue_active() // return false, since the queue is emtpy
> <unlock>
> ...
> <free the waitqueue>
> if (whead) {
> remove_wait_queue(whead, &pwq->wait); // Use-after-free BOOM!
> }
>
>
> Note that moving the `wait_list` empty checking before
> `self.inner.notify()` won't change the result, since there might be a
> `notify` called by users before `PollCondVar::drop()`, hence the same
> result.
>
> Regards,
> Boqun

Thank you for confirming my suspicion.

Alice