[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH qemu v5 04/18] memory: Move AddressSpaceDispatch
From: |
Paolo Bonzini |
Subject: |
Re: [Qemu-devel] [PATCH qemu v5 04/18] memory: Move AddressSpaceDispatch from AddressSpace to FlatView |
Date: |
Thu, 21 Sep 2017 15:54:56 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.3.0 |
On 21/09/2017 15:44, Alexey Kardashevskiy wrote:
> On 21/09/17 21:51, Paolo Bonzini wrote:
>> On 21/09/2017 10:50, Alexey Kardashevskiy wrote:
>>> * since FlatView::rcu is used now to dispose FV, call_rcu() in
>>> address_space_update_topology() is replaced with direct call to
>>> flatview_unref()
>>
>> Hmm, this is not correct, as you could have
>>
>>
>> thread 1 thread 2 RCU thread
>> -------------------------------------------------------------
>> rcu_read_lock
>> read as->current_map
>> set as->current_map
>> flatview_unref
>> '--> call_rcu
>> flatview_ref
>> rcu_read_unlock
>> flatview_destroy
>>
>> I need to think a bit more about this (and possibly ask Paul...).
>>
>> Paolo
>>
>
> Nah, you're right, it should be like this:
>
>
> diff --git a/memory.c b/memory.c
> index 35b2fc5f7f..689bf53866 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -317,7 +317,7 @@ static void flatview_ref(FlatView *view)
> static void flatview_unref(FlatView *view)
> {
> if (atomic_fetch_dec(&view->ref) == 1) {
> - call_rcu(view, flatview_destroy, rcu);
> + flatview_destroy(view);
> }
> }
>
> @@ -768,7 +768,7 @@ static FlatView *generate_memory_topology(MemoryRegion
> *mr)
> flatview_simplify(view);
>
> if (!view->nr) {
> - flatview_destroy(view);
> + flatview_unref(view);
> use_empty = true;
> }
> }
> @@ -1026,7 +1026,7 @@ static void address_space_set_flatview(AddressSpace *as)
> /* Writes are protected by the BQL. */
> atomic_rcu_set(&as->current_map, new_view);
> if (old_view) {
> - flatview_unref(old_view);
> + call_rcu(view, flatview_unref, rcu);
> }
This still doesn't cover address_space_get_flatview, i.e. it is a
pre-existing bug.
I found a similar case in Linux, here is how they solved it:
commit 358136532dd29e9ed96e0e523d2d510e71bda003
Author: Paolo Bonzini <address@hidden>
Date: Thu Sep 21 14:32:47 2017 +0200
memory: avoid "resurrection" of dead FlatViews
It's possible for address_space_get_flatview() as it currently stands
to cause a use-after-free for the returned FlatView, if the reference
count is incremented after the FlatView has been replaced by a writer:
thread 1 thread 2 RCU thread
-------------------------------------------------------------
rcu_read_lock
read as->current_map
set as->current_map
flatview_unref
'--> call_rcu
flatview_ref
[ref=1]
rcu_read_unlock
flatview_destroy
<badness>
Since FlatViews are not updated very often, we can just detect the
situation using a new atomic op atomic_fetch_inc_nonzero, similar to
Linux's atomic_inc_not_zero, which performs the refcount increment only if
it hasn't already hit zero. This is similar to Linux commit de09a9771a53
("CRED: Fix get_task_cred() and task_state() to not resurrect dead
credentials", 2010-07-29).
Signed-off-by: Paolo Bonzini <address@hidden>
diff --git a/docs/devel/atomics.txt b/docs/devel/atomics.txt
index 048e5f23cb..10c5fa37e8 100644
--- a/docs/devel/atomics.txt
+++ b/docs/devel/atomics.txt
@@ -64,6 +64,7 @@ operations:
typeof(*ptr) atomic_fetch_and(ptr, val)
typeof(*ptr) atomic_fetch_or(ptr, val)
typeof(*ptr) atomic_fetch_xor(ptr, val)
+ typeof(*ptr) atomic_fetch_inc_nonzero(ptr)
typeof(*ptr) atomic_xchg(ptr, val)
typeof(*ptr) atomic_cmpxchg(ptr, old, new)
diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h
index b6b62fb771..44ad1e6c32 100644
--- a/include/qemu/atomic.h
+++ b/include/qemu/atomic.h
@@ -197,6 +197,15 @@
atomic_cmpxchg__nocheck(ptr, old, new); \
})
+#define atomic_fetch_inc_nonzero(ptr) ({ \
+ QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \
+ typeof_strip_qual(*ptr) _oldn = atomic_read(ptr); \
+ while (_oldn && atomic_cmpxchg(ptr, _oldn, _oldn + 1) != _oldn) { \
+ _oldn = atomic_read(ptr); \
+ } \
+ _oldn; \
+})
+
/* Provide shorter names for GCC atomic builtins, return old value */
#define atomic_fetch_inc(ptr) __atomic_fetch_add(ptr, 1, __ATOMIC_SEQ_CST)
#define atomic_fetch_dec(ptr) __atomic_fetch_sub(ptr, 1, __ATOMIC_SEQ_CST)
diff --git a/memory.c b/memory.c
index 2b90117c60..51f54ab430 100644
--- a/memory.c
+++ b/memory.c
@@ -294,9 +294,9 @@ static void flatview_destroy(FlatView *view)
g_free(view);
}
-static void flatview_ref(FlatView *view)
+static bool flatview_ref(FlatView *view)
{
- atomic_inc(&view->ref);
+ return atomic_fetch_inc_nonzero(&view->ref) > 0;
}
static void flatview_unref(FlatView *view)
@@ -773,8 +773,12 @@ static FlatView *address_space_get_flatview(AddressSpace
*as)
FlatView *view;
rcu_read_lock();
- view = atomic_rcu_read(&as->current_map);
- flatview_ref(view);
+ do {
+ view = atomic_rcu_read(&as->current_map);
+ /* If somebody has replaced as->current_map concurrently,
+ * flatview_ref returns false.
+ */
+ } while (!flatview_ref(view));
rcu_read_unlock();
return view;
}
- [Qemu-devel] [PATCH qemu v5 00/18] memory: Store physical root MR in FlatView, Alexey Kardashevskiy, 2017/09/21
- [Qemu-devel] [PATCH qemu v5 07/18] memory: Cleanup after switching to FlatView, Alexey Kardashevskiy, 2017/09/21
- [Qemu-devel] [PATCH qemu v5 09/18] memory: Store physical root MR in FlatView, Alexey Kardashevskiy, 2017/09/21
- [Qemu-devel] [PATCH qemu v5 06/18] memory: Switch memory from using AddressSpace to FlatView, Alexey Kardashevskiy, 2017/09/21
- [Qemu-devel] [PATCH qemu v5 12/18] memory: Share FlatView's and dispatch trees between address spaces, Alexey Kardashevskiy, 2017/09/21
- [Qemu-devel] [PATCH qemu v5 08/18] memory: Rename mem_begin/mem_commit/mem_add helpers, Alexey Kardashevskiy, 2017/09/21
- [Qemu-devel] [PATCH qemu v5 11/18] memory: Move address_space_update_ioeventfds, Alexey Kardashevskiy, 2017/09/21
- [Qemu-devel] [PATCH qemu v5 13/18] memory: Do not allocate FlatView in address_space_init, Alexey Kardashevskiy, 2017/09/21
- [Qemu-devel] [PATCH qemu v5 10/18] memory: Alloc dispatch tree where topology is generared, Alexey Kardashevskiy, 2017/09/21
- [Qemu-devel] [PATCH qemu v5 18/18] memory: Avoid temporary FlatView allocation in a single child case, Alexey Kardashevskiy, 2017/09/21
- [Qemu-devel] [PATCH qemu v5 14/18] memory: Rework "info mtree" to print flat views and dispatch trees, Alexey Kardashevskiy, 2017/09/21