[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 35/49] bql: check that the BQL is not dropped within marked sectio
From: |
Paolo Bonzini |
Subject: |
[PULL 35/49] bql: check that the BQL is not dropped within marked sections |
Date: |
Wed, 11 Dec 2024 17:27:05 +0100 |
The Big QEMU Lock (BQL) is used to provide interior mutability to Rust
code. While BqlCell performs indivisible accesses, an equivalent of
RefCell will allow the borrower to hold to the interior content for a
long time. If the BQL is dropped, another thread could come and mutate
the data from C code (Rust code would panic on borrow_mut() instead).
In order to prevent this, add a new BQL primitive that can mark
BQL-atomic sections and aborts if the BQL is dropped within them.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
include/qemu/main-loop.h | 15 +++++++++++++++
stubs/iothread-lock.c | 15 +++++++++++++++
system/cpus.c | 15 +++++++++++++++
3 files changed, 45 insertions(+)
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index 5764db157c9..646306c272f 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -262,6 +262,21 @@ AioContext *iohandler_get_aio_context(void);
*/
bool bql_locked(void);
+/**
+ * bql_block: Allow/deny releasing the BQL
+ *
+ * The Big QEMU Lock (BQL) is used to provide interior mutability to
+ * Rust code, but this only works if other threads cannot run while
+ * the Rust code has an active borrow. This is because C code in
+ * other threads could come in and mutate data under the Rust code's
+ * feet.
+ *
+ * @increase: Whether to increase or decrease the blocking counter.
+ * Releasing the BQL while the counter is nonzero triggers
+ * an assertion failure.
+ */
+void bql_block_unlock(bool increase);
+
/**
* qemu_in_main_thread: return whether it's possible to safely access
* the global state of the block layer.
diff --git a/stubs/iothread-lock.c b/stubs/iothread-lock.c
index d7890e5581c..54676598950 100644
--- a/stubs/iothread-lock.c
+++ b/stubs/iothread-lock.c
@@ -1,6 +1,8 @@
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
+static uint32_t bql_unlock_blocked;
+
bool bql_locked(void)
{
return false;
@@ -12,4 +14,17 @@ void bql_lock_impl(const char *file, int line)
void bql_unlock(void)
{
+ assert(!bql_unlock_blocked);
+}
+
+void bql_block_unlock(bool increase)
+{
+ uint32_t new_value;
+
+ assert(bql_locked());
+
+ /* check for overflow! */
+ new_value = bql_unlock_blocked + increase - !increase;
+ assert((new_value > bql_unlock_blocked) == increase);
+ bql_unlock_blocked = new_value;
}
diff --git a/system/cpus.c b/system/cpus.c
index 1c818ff6828..ba633c7688b 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -514,6 +514,20 @@ bool qemu_in_vcpu_thread(void)
QEMU_DEFINE_STATIC_CO_TLS(bool, bql_locked)
+static uint32_t bql_unlock_blocked;
+
+void bql_block_unlock(bool increase)
+{
+ uint32_t new_value;
+
+ assert(bql_locked());
+
+ /* check for overflow! */
+ new_value = bql_unlock_blocked + increase - !increase;
+ assert((new_value > bql_unlock_blocked) == increase);
+ bql_unlock_blocked = new_value;
+}
+
bool bql_locked(void)
{
return get_bql_locked();
@@ -540,6 +554,7 @@ void bql_lock_impl(const char *file, int line)
void bql_unlock(void)
{
g_assert(bql_locked());
+ g_assert(!bql_unlock_blocked);
set_bql_locked(false);
qemu_mutex_unlock(&bql);
}
--
2.47.1
- [PULL 26/49] hw/usb: Replace type_register() with type_register_static(), (continued)
- [PULL 26/49] hw/usb: Replace type_register() with type_register_static(), Paolo Bonzini, 2024/12/11
- [PULL 25/49] hw/sensor: Replace type_register() with type_register_static(), Paolo Bonzini, 2024/12/11
- [PULL 28/49] i386: Replace type_register() with type_register_static(), Paolo Bonzini, 2024/12/11
- [PULL 27/49] hw/virtio: Replace type_register() with type_register_static(), Paolo Bonzini, 2024/12/11
- [PULL 29/49] target/mips: Replace type_register() with type_register_static(), Paolo Bonzini, 2024/12/11
- [PULL 30/49] target/sparc: Replace type_register() with type_register_static(), Paolo Bonzini, 2024/12/11
- [PULL 31/49] target/xtensa: Replace type_register() with type_register_static(), Paolo Bonzini, 2024/12/11
- [PULL 32/49] ui: Replace type_register() with type_register_static(), Paolo Bonzini, 2024/12/11
- [PULL 33/49] script/codeconverter/qom_type_info: Deprecate MakeTypeRegisterStatic and MakeTypeRegisterNotStatic, Paolo Bonzini, 2024/12/11
- [PULL 34/49] qom/object: Remove type_register(), Paolo Bonzini, 2024/12/11
- [PULL 35/49] bql: check that the BQL is not dropped within marked sections,
Paolo Bonzini <=
- [PULL 36/49] rust: cell: add BQL-enforcing Cell variant, Paolo Bonzini, 2024/12/11
- [PULL 38/49] rust: define prelude, Paolo Bonzini, 2024/12/11
- [PULL 37/49] rust: cell: add BQL-enforcing RefCell variant, Paolo Bonzini, 2024/12/11
- [PULL 39/49] rust: add bindings for interrupt sources, Paolo Bonzini, 2024/12/11
- [PULL 40/49] rust: add a bit operation module, Paolo Bonzini, 2024/12/11
- [PULL 41/49] rust: qom: add default definitions for ObjectImpl, Paolo Bonzini, 2024/12/11
- [PULL 42/49] rust: qom: rename Class trait to ClassInitImpl, Paolo Bonzini, 2024/12/11
- [PULL 43/49] rust: qom: convert type_info! macro to an associated const, Paolo Bonzini, 2024/12/11
- [PULL 44/49] rust: qom: move ClassInitImpl to the instance side, Paolo Bonzini, 2024/12/11