* [PATCH] accel/tcg: Properly unlink a TB linked to itself
@ 2025-09-23 23:04 Richard Henderson
2025-09-24 9:44 ` Anton Johansson via
0 siblings, 1 reply; 4+ messages in thread
From: Richard Henderson @ 2025-09-23 23:04 UTC (permalink / raw)
To: qemu-devel; +Cc: kasperl, lazyparser, liwei1518, 李威威
When we remove dest from orig's links, we lose the link
that we rely on later to reset links. This can lead to
failure to release from spinlock with self-modifying code.
Reported-by: 李威威 <liweiwei@kubuds.cn>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
accel/tcg/tb-maint.c | 8 +++++
tests/tcg/riscv64/tb-link.c | 60 +++++++++++++++++++++++++++++++
tests/tcg/riscv64/Makefile.target | 1 +
3 files changed, 69 insertions(+)
create mode 100644 tests/tcg/riscv64/tb-link.c
diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c
index 0048316f99..e6d45c9c12 100644
--- a/accel/tcg/tb-maint.c
+++ b/accel/tcg/tb-maint.c
@@ -836,6 +836,14 @@ static inline void tb_remove_from_jmp_list(TranslationBlock *orig, int n_orig)
* We first acquired the lock, and since the destination pointer matches,
* we know for sure that @orig is in the jmp list.
*/
+ if (dest == orig) {
+ /*
+ * In the case of a TB that links to itself, removing the entry
+ * from the list means that it won't be present later during
+ * tb_jmp_unlink -- unlink now.
+ */
+ tb_reset_jump(orig, n_orig);
+ }
pprev = &dest->jmp_list_head;
TB_FOR_EACH_JMP(dest, tb, n) {
if (tb == orig && n == n_orig) {
diff --git a/tests/tcg/riscv64/tb-link.c b/tests/tcg/riscv64/tb-link.c
new file mode 100644
index 0000000000..b6fcca8668
--- /dev/null
+++ b/tests/tcg/riscv64/tb-link.c
@@ -0,0 +1,60 @@
+#include <assert.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <unistd.h>
+
+
+int main()
+{
+ /*
+ * ## 1. RISC-V machine code.
+ * Assembly:
+ * L: j L ; Jump to self (spin).
+ * li a0, 42 ; Place 42 into the return value register a0.
+ * ret ; Return to caller.
+ */
+ static const uint32_t machine_code[] = {
+ 0x0000006f, /* jal zero, #0 */
+ 0x02a00513, /* addi a0, zero, 42 */
+ 0x00008067 /* jalr zero, ra, 0 */
+ };
+ size_t code_size = sizeof(machine_code);
+ int tmp;
+ pthread_t thread_id;
+ void *thread_return_value;
+ uint32_t *buffer;
+
+ /* ## 2. Allocate executable memory. */
+ buffer = mmap(
+ NULL,
+ code_size,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ -1, 0
+ );
+ assert(buffer != MAP_FAILED);
+
+ /* ## 3. Copy machine code into buffer. */
+ memcpy(buffer, machine_code, code_size);
+
+ /* ## 4. Execute the code in a separate thread. */
+ tmp = pthread_create(&thread_id, NULL, (void *(*)(void *))buffer, NULL);
+ assert(tmp == 0);
+
+ /*
+ * Wait a second and then try to patch the generated code to get the
+ * runner thread to get unstuck by patching the spin jump.
+ */
+ sleep(1);
+ buffer[0] = 0x00000013; /* nop */
+ __builtin___clear_cache((char *)buffer, (char *)(buffer + 1));
+
+ tmp = pthread_join(thread_id, &thread_return_value);
+ assert(tmp == 0);
+
+ tmp = (intptr_t)thread_return_value;
+ assert(tmp == 42);
+ return 0;
+}
diff --git a/tests/tcg/riscv64/Makefile.target b/tests/tcg/riscv64/Makefile.target
index 4da5b9a3b3..ba684616fd 100644
--- a/tests/tcg/riscv64/Makefile.target
+++ b/tests/tcg/riscv64/Makefile.target
@@ -4,6 +4,7 @@
VPATH += $(SRC_PATH)/tests/tcg/riscv64
TESTS += test-div
TESTS += noexec
+TESTS += tb-link
# Disable compressed instructions for test-noc
TESTS += test-noc
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH] accel/tcg: Properly unlink a TB linked to itself
2025-09-24 2:07 [PATCH 0/2] linux-user: Support MADV_DONTDUMP, MADV_DODUMP Richard Henderson
@ 2025-09-24 2:07 ` Richard Henderson
2025-09-28 23:23 ` Alistair Francis
0 siblings, 1 reply; 4+ messages in thread
From: Richard Henderson @ 2025-09-24 2:07 UTC (permalink / raw)
To: qemu-devel; +Cc: jonwilson030981, 李威威
When we remove dest from orig's links, we lose the link
that we rely on later to reset links. This can lead to
failure to release from spinlock with self-modifying code.
Reported-by: 李威威 <liweiwei@kubuds.cn>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
accel/tcg/tb-maint.c | 8 +++++
tests/tcg/riscv64/tb-link.c | 60 +++++++++++++++++++++++++++++++
tests/tcg/riscv64/Makefile.target | 1 +
3 files changed, 69 insertions(+)
create mode 100644 tests/tcg/riscv64/tb-link.c
diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c
index 0048316f99..e6d45c9c12 100644
--- a/accel/tcg/tb-maint.c
+++ b/accel/tcg/tb-maint.c
@@ -836,6 +836,14 @@ static inline void tb_remove_from_jmp_list(TranslationBlock *orig, int n_orig)
* We first acquired the lock, and since the destination pointer matches,
* we know for sure that @orig is in the jmp list.
*/
+ if (dest == orig) {
+ /*
+ * In the case of a TB that links to itself, removing the entry
+ * from the list means that it won't be present later during
+ * tb_jmp_unlink -- unlink now.
+ */
+ tb_reset_jump(orig, n_orig);
+ }
pprev = &dest->jmp_list_head;
TB_FOR_EACH_JMP(dest, tb, n) {
if (tb == orig && n == n_orig) {
diff --git a/tests/tcg/riscv64/tb-link.c b/tests/tcg/riscv64/tb-link.c
new file mode 100644
index 0000000000..b6fcca8668
--- /dev/null
+++ b/tests/tcg/riscv64/tb-link.c
@@ -0,0 +1,60 @@
+#include <assert.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <unistd.h>
+
+
+int main()
+{
+ /*
+ * ## 1. RISC-V machine code.
+ * Assembly:
+ * L: j L ; Jump to self (spin).
+ * li a0, 42 ; Place 42 into the return value register a0.
+ * ret ; Return to caller.
+ */
+ static const uint32_t machine_code[] = {
+ 0x0000006f, /* jal zero, #0 */
+ 0x02a00513, /* addi a0, zero, 42 */
+ 0x00008067 /* jalr zero, ra, 0 */
+ };
+ size_t code_size = sizeof(machine_code);
+ int tmp;
+ pthread_t thread_id;
+ void *thread_return_value;
+ uint32_t *buffer;
+
+ /* ## 2. Allocate executable memory. */
+ buffer = mmap(
+ NULL,
+ code_size,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ -1, 0
+ );
+ assert(buffer != MAP_FAILED);
+
+ /* ## 3. Copy machine code into buffer. */
+ memcpy(buffer, machine_code, code_size);
+
+ /* ## 4. Execute the code in a separate thread. */
+ tmp = pthread_create(&thread_id, NULL, (void *(*)(void *))buffer, NULL);
+ assert(tmp == 0);
+
+ /*
+ * Wait a second and then try to patch the generated code to get the
+ * runner thread to get unstuck by patching the spin jump.
+ */
+ sleep(1);
+ buffer[0] = 0x00000013; /* nop */
+ __builtin___clear_cache((char *)buffer, (char *)(buffer + 1));
+
+ tmp = pthread_join(thread_id, &thread_return_value);
+ assert(tmp == 0);
+
+ tmp = (intptr_t)thread_return_value;
+ assert(tmp == 42);
+ return 0;
+}
diff --git a/tests/tcg/riscv64/Makefile.target b/tests/tcg/riscv64/Makefile.target
index 4da5b9a3b3..ba684616fd 100644
--- a/tests/tcg/riscv64/Makefile.target
+++ b/tests/tcg/riscv64/Makefile.target
@@ -4,6 +4,7 @@
VPATH += $(SRC_PATH)/tests/tcg/riscv64
TESTS += test-div
TESTS += noexec
+TESTS += tb-link
# Disable compressed instructions for test-noc
TESTS += test-noc
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] accel/tcg: Properly unlink a TB linked to itself
2025-09-23 23:04 [PATCH] accel/tcg: Properly unlink a TB linked to itself Richard Henderson
@ 2025-09-24 9:44 ` Anton Johansson via
0 siblings, 0 replies; 4+ messages in thread
From: Anton Johansson via @ 2025-09-24 9:44 UTC (permalink / raw)
To: Richard Henderson
Cc: qemu-devel, kasperl, lazyparser, liwei1518,
李威威
On 24/09/25, Richard Henderson wrote:
> When we remove dest from orig's links, we lose the link
> that we rely on later to reset links. This can lead to
> failure to release from spinlock with self-modifying code.
>
> Reported-by: 李威威 <liweiwei@kubuds.cn>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
> accel/tcg/tb-maint.c | 8 +++++
> tests/tcg/riscv64/tb-link.c | 60 +++++++++++++++++++++++++++++++
> tests/tcg/riscv64/Makefile.target | 1 +
> 3 files changed, 69 insertions(+)
> create mode 100644 tests/tcg/riscv64/tb-link.c
Nice, tried the fix/test.
Reviewed-by: Anton Johansson <anjo@rev.ng>
Tested-by: Anton Johansson <anjo@rev.ng>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] accel/tcg: Properly unlink a TB linked to itself
2025-09-24 2:07 ` [PATCH] accel/tcg: Properly unlink a TB linked to itself Richard Henderson
@ 2025-09-28 23:23 ` Alistair Francis
0 siblings, 0 replies; 4+ messages in thread
From: Alistair Francis @ 2025-09-28 23:23 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel, jonwilson030981, 李威威
On Wed, Sep 24, 2025 at 12:09 PM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> When we remove dest from orig's links, we lose the link
> that we rely on later to reset links. This can lead to
> failure to release from spinlock with self-modifying code.
>
> Reported-by: 李威威 <liweiwei@kubuds.cn>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> accel/tcg/tb-maint.c | 8 +++++
> tests/tcg/riscv64/tb-link.c | 60 +++++++++++++++++++++++++++++++
> tests/tcg/riscv64/Makefile.target | 1 +
> 3 files changed, 69 insertions(+)
> create mode 100644 tests/tcg/riscv64/tb-link.c
>
> diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c
> index 0048316f99..e6d45c9c12 100644
> --- a/accel/tcg/tb-maint.c
> +++ b/accel/tcg/tb-maint.c
> @@ -836,6 +836,14 @@ static inline void tb_remove_from_jmp_list(TranslationBlock *orig, int n_orig)
> * We first acquired the lock, and since the destination pointer matches,
> * we know for sure that @orig is in the jmp list.
> */
> + if (dest == orig) {
> + /*
> + * In the case of a TB that links to itself, removing the entry
> + * from the list means that it won't be present later during
> + * tb_jmp_unlink -- unlink now.
> + */
> + tb_reset_jump(orig, n_orig);
> + }
> pprev = &dest->jmp_list_head;
> TB_FOR_EACH_JMP(dest, tb, n) {
> if (tb == orig && n == n_orig) {
> diff --git a/tests/tcg/riscv64/tb-link.c b/tests/tcg/riscv64/tb-link.c
> new file mode 100644
> index 0000000000..b6fcca8668
> --- /dev/null
> +++ b/tests/tcg/riscv64/tb-link.c
> @@ -0,0 +1,60 @@
> +#include <assert.h>
> +#include <string.h>
> +#include <sys/mman.h>
> +#include <pthread.h>
> +#include <stdint.h>
> +#include <unistd.h>
> +
> +
> +int main()
> +{
> + /*
> + * ## 1. RISC-V machine code.
> + * Assembly:
> + * L: j L ; Jump to self (spin).
> + * li a0, 42 ; Place 42 into the return value register a0.
> + * ret ; Return to caller.
> + */
> + static const uint32_t machine_code[] = {
> + 0x0000006f, /* jal zero, #0 */
> + 0x02a00513, /* addi a0, zero, 42 */
> + 0x00008067 /* jalr zero, ra, 0 */
> + };
> + size_t code_size = sizeof(machine_code);
> + int tmp;
> + pthread_t thread_id;
> + void *thread_return_value;
> + uint32_t *buffer;
> +
> + /* ## 2. Allocate executable memory. */
> + buffer = mmap(
> + NULL,
> + code_size,
> + PROT_READ | PROT_WRITE | PROT_EXEC,
> + MAP_PRIVATE | MAP_ANONYMOUS,
> + -1, 0
> + );
> + assert(buffer != MAP_FAILED);
> +
> + /* ## 3. Copy machine code into buffer. */
> + memcpy(buffer, machine_code, code_size);
> +
> + /* ## 4. Execute the code in a separate thread. */
> + tmp = pthread_create(&thread_id, NULL, (void *(*)(void *))buffer, NULL);
> + assert(tmp == 0);
> +
> + /*
> + * Wait a second and then try to patch the generated code to get the
> + * runner thread to get unstuck by patching the spin jump.
> + */
> + sleep(1);
> + buffer[0] = 0x00000013; /* nop */
> + __builtin___clear_cache((char *)buffer, (char *)(buffer + 1));
> +
> + tmp = pthread_join(thread_id, &thread_return_value);
> + assert(tmp == 0);
> +
> + tmp = (intptr_t)thread_return_value;
> + assert(tmp == 42);
> + return 0;
> +}
> diff --git a/tests/tcg/riscv64/Makefile.target b/tests/tcg/riscv64/Makefile.target
> index 4da5b9a3b3..ba684616fd 100644
> --- a/tests/tcg/riscv64/Makefile.target
> +++ b/tests/tcg/riscv64/Makefile.target
> @@ -4,6 +4,7 @@
> VPATH += $(SRC_PATH)/tests/tcg/riscv64
> TESTS += test-div
> TESTS += noexec
> +TESTS += tb-link
>
> # Disable compressed instructions for test-noc
> TESTS += test-noc
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-09-28 23:25 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-23 23:04 [PATCH] accel/tcg: Properly unlink a TB linked to itself Richard Henderson
2025-09-24 9:44 ` Anton Johansson via
-- strict thread matches above, loose matches on Subject: below --
2025-09-24 2:07 [PATCH 0/2] linux-user: Support MADV_DONTDUMP, MADV_DODUMP Richard Henderson
2025-09-24 2:07 ` [PATCH] accel/tcg: Properly unlink a TB linked to itself Richard Henderson
2025-09-28 23:23 ` Alistair Francis
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).