summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYogita Urade <yogita.urade@windriver.com>2024-11-29 08:17:08 +0000
committerSteve Sakoman <steve@sakoman.com>2024-12-06 05:50:25 -0800
commit2775596cb24e22c016dca604c27b945a3c02514d (patch)
tree411f1c19b4d29e9426c11376653c3f5f8abb129a
parentc6ec0e1bfd648e7fcb345be6829bf1f663933a89 (diff)
downloadpoky-2775596cb24e22c016dca604c27b945a3c02514d.tar.gz
qemu: upgrade 8.2.3 -> 8.2.7
This includes fix for: CVE-2024-4693, CVE-2024-6505 and CVE-2024-7730 General changelog for 8.2: https://wiki.qemu.org/ChangeLog/8.2 Droped: 0001-target-riscv-kvm-change-KVM_REG_RISCV_FP_F-to-u32.patch 0002-target-riscv-kvm-change-KVM_REG_RISCV_FP_D-to-u64.patch 0003-target-riscv-kvm-change-timer-regs-size-to-u64.patch CVE-2024-4467 and CVE-2024-7409 since already contained the fix. (From OE-Core rev: 7983ad282c37f8c1125da5bab96489e5d0039948) Signed-off-by: Yogita Urade <yogita.urade@windriver.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
-rw-r--r--meta/recipes-devtools/qemu/qemu-native_8.2.7.bb (renamed from meta/recipes-devtools/qemu/qemu-native_8.2.3.bb)0
-rw-r--r--meta/recipes-devtools/qemu/qemu-system-native_8.2.7.bb (renamed from meta/recipes-devtools/qemu/qemu-system-native_8.2.3.bb)0
-rw-r--r--meta/recipes-devtools/qemu/qemu.inc14
-rw-r--r--meta/recipes-devtools/qemu/qemu/0001-target-riscv-kvm-change-KVM_REG_RISCV_FP_F-to-u32.patch75
-rw-r--r--meta/recipes-devtools/qemu/qemu/0002-target-riscv-kvm-change-KVM_REG_RISCV_FP_D-to-u64.patch73
-rw-r--r--meta/recipes-devtools/qemu/qemu/0003-target-riscv-kvm-change-timer-regs-size-to-u64.patch107
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0001.patch112
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0002.patch55
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0003.patch57
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0004.patch1187
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0005.patch239
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0001.patch167
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0002.patch175
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0003.patch126
-rw-r--r--meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0004.patch164
-rw-r--r--meta/recipes-devtools/qemu/qemu_8.2.7.bb (renamed from meta/recipes-devtools/qemu/qemu_8.2.3.bb)0
16 files changed, 1 insertions, 2550 deletions
diff --git a/meta/recipes-devtools/qemu/qemu-native_8.2.3.bb b/meta/recipes-devtools/qemu/qemu-native_8.2.7.bb
index a77953529b..a77953529b 100644
--- a/meta/recipes-devtools/qemu/qemu-native_8.2.3.bb
+++ b/meta/recipes-devtools/qemu/qemu-native_8.2.7.bb
diff --git a/meta/recipes-devtools/qemu/qemu-system-native_8.2.3.bb b/meta/recipes-devtools/qemu/qemu-system-native_8.2.7.bb
index 0634b34242..0634b34242 100644
--- a/meta/recipes-devtools/qemu/qemu-system-native_8.2.3.bb
+++ b/meta/recipes-devtools/qemu/qemu-system-native_8.2.7.bb
diff --git a/meta/recipes-devtools/qemu/qemu.inc b/meta/recipes-devtools/qemu/qemu.inc
index e9f63b9eaf..40ee267a42 100644
--- a/meta/recipes-devtools/qemu/qemu.inc
+++ b/meta/recipes-devtools/qemu/qemu.inc
@@ -40,18 +40,6 @@ SRC_URI = "https://download.qemu.org/${BPN}-${PV}.tar.xz \
40 file://0005-tests-tcg-Check-that-shmat-does-not-break-proc-self-.patch \ 40 file://0005-tests-tcg-Check-that-shmat-does-not-break-proc-self-.patch \
41 file://qemu-guest-agent.init \ 41 file://qemu-guest-agent.init \
42 file://qemu-guest-agent.udev \ 42 file://qemu-guest-agent.udev \
43 file://CVE-2024-4467-0001.patch \
44 file://CVE-2024-4467-0002.patch \
45 file://CVE-2024-4467-0003.patch \
46 file://CVE-2024-4467-0004.patch \
47 file://CVE-2024-4467-0005.patch \
48 file://CVE-2024-7409-0001.patch \
49 file://CVE-2024-7409-0002.patch \
50 file://CVE-2024-7409-0003.patch \
51 file://CVE-2024-7409-0004.patch \
52 file://0001-target-riscv-kvm-change-KVM_REG_RISCV_FP_F-to-u32.patch \
53 file://0002-target-riscv-kvm-change-KVM_REG_RISCV_FP_D-to-u64.patch \
54 file://0003-target-riscv-kvm-change-timer-regs-size-to-u64.patch \
55 " 43 "
56UPSTREAM_CHECK_REGEX = "qemu-(?P<pver>\d+(\.\d+)+)\.tar" 44UPSTREAM_CHECK_REGEX = "qemu-(?P<pver>\d+(\.\d+)+)\.tar"
57 45
@@ -68,7 +56,7 @@ SRC_URI:append:class-native = " \
68 file://0012-linux-user-workaround-for-missing-MAP_SHARED_VALIDAT.patch \ 56 file://0012-linux-user-workaround-for-missing-MAP_SHARED_VALIDAT.patch \
69 " 57 "
70 58
71SRC_URI[sha256sum] = "dc747fb366809455317601c4876bd1f6829a32a23e83fb76e45ab12c2a569964" 59SRC_URI[sha256sum] = "1f0604f296ab9acb4854c054764a1ba408643fc299bd54a6500cccfaaca65b55"
72 60
73CVE_STATUS[CVE-2007-0998] = "not-applicable-config: The VNC server can expose host files uder some circumstances. We don't enable it by default." 61CVE_STATUS[CVE-2007-0998] = "not-applicable-config: The VNC server can expose host files uder some circumstances. We don't enable it by default."
74 62
diff --git a/meta/recipes-devtools/qemu/qemu/0001-target-riscv-kvm-change-KVM_REG_RISCV_FP_F-to-u32.patch b/meta/recipes-devtools/qemu/qemu/0001-target-riscv-kvm-change-KVM_REG_RISCV_FP_F-to-u32.patch
deleted file mode 100644
index 39a6a85162..0000000000
--- a/meta/recipes-devtools/qemu/qemu/0001-target-riscv-kvm-change-KVM_REG_RISCV_FP_F-to-u32.patch
+++ /dev/null
@@ -1,75 +0,0 @@
1From bbdcc89678daa5cb131ef22a6cd41a5f7f9dcea9 Mon Sep 17 00:00:00 2001
2From: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
3Date: Fri, 8 Dec 2023 15:38:31 -0300
4Subject: [PATCH 1/3] target/riscv/kvm: change KVM_REG_RISCV_FP_F to u32
5
6KVM_REG_RISCV_FP_F regs have u32 size according to the API, but by using
7kvm_riscv_reg_id() in RISCV_FP_F_REG() we're returning u64 sizes when
8running with TARGET_RISCV64. The most likely reason why no one noticed
9this is because we're not implementing kvm_cpu_synchronize_state() in
10RISC-V yet.
11
12Create a new helper that returns a KVM ID with u32 size and use it in
13RISCV_FP_F_REG().
14
15Reported-by: Andrew Jones <ajones@ventanamicro.com>
16Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
17Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
18Message-ID: <20231208183835.2411523-2-dbarboza@ventanamicro.com>
19Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
20(cherry picked from commit 49c211ffca00fdf7c0c29072c224e88527a14838)
21Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
22
23Upstream-Status: Backport [bbdcc89678daa5cb131ef22a6cd41a5f7f9dcea9]
24
25Signed-off-by: Chen Qi <Qi.Chen@windriver.com>
26---
27 target/riscv/kvm/kvm-cpu.c | 11 ++++++++---
28 1 file changed, 8 insertions(+), 3 deletions(-)
29
30diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
31index c1675158fe..2eef2be86a 100644
32--- a/target/riscv/kvm/kvm-cpu.c
33+++ b/target/riscv/kvm/kvm-cpu.c
34@@ -72,6 +72,11 @@ static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type,
35 return id;
36 }
37
38+static uint64_t kvm_riscv_reg_id_u32(uint64_t type, uint64_t idx)
39+{
40+ return KVM_REG_RISCV | KVM_REG_SIZE_U32 | type | idx;
41+}
42+
43 #define RISCV_CORE_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, \
44 KVM_REG_RISCV_CORE_REG(name))
45
46@@ -81,7 +86,7 @@ static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type,
47 #define RISCV_TIMER_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_TIMER, \
48 KVM_REG_RISCV_TIMER_REG(name))
49
50-#define RISCV_FP_F_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_F, idx)
51+#define RISCV_FP_F_REG(idx) kvm_riscv_reg_id_u32(KVM_REG_RISCV_FP_F, idx)
52
53 #define RISCV_FP_D_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_D, idx)
54
55@@ -586,7 +591,7 @@ static int kvm_riscv_get_regs_fp(CPUState *cs)
56 if (riscv_has_ext(env, RVF)) {
57 uint32_t reg;
58 for (i = 0; i < 32; i++) {
59- ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(env, i), &reg);
60+ ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(i), &reg);
61 if (ret) {
62 return ret;
63 }
64@@ -620,7 +625,7 @@ static int kvm_riscv_put_regs_fp(CPUState *cs)
65 uint32_t reg;
66 for (i = 0; i < 32; i++) {
67 reg = env->fpr[i];
68- ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(env, i), &reg);
69+ ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(i), &reg);
70 if (ret) {
71 return ret;
72 }
73--
742.25.1
75
diff --git a/meta/recipes-devtools/qemu/qemu/0002-target-riscv-kvm-change-KVM_REG_RISCV_FP_D-to-u64.patch b/meta/recipes-devtools/qemu/qemu/0002-target-riscv-kvm-change-KVM_REG_RISCV_FP_D-to-u64.patch
deleted file mode 100644
index 9480d3e0b5..0000000000
--- a/meta/recipes-devtools/qemu/qemu/0002-target-riscv-kvm-change-KVM_REG_RISCV_FP_D-to-u64.patch
+++ /dev/null
@@ -1,73 +0,0 @@
1From 125b95d79e746cbab6b72683b3382dd372e38c61 Mon Sep 17 00:00:00 2001
2From: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
3Date: Fri, 8 Dec 2023 15:38:32 -0300
4Subject: [PATCH 2/3] target/riscv/kvm: change KVM_REG_RISCV_FP_D to u64
5
6KVM_REG_RISCV_FP_D regs are always u64 size. Using kvm_riscv_reg_id() in
7RISCV_FP_D_REG() ends up encoding the wrong size if we're running with
8TARGET_RISCV32.
9
10Create a new helper that returns a KVM ID with u64 size and use it with
11RISCV_FP_D_REG().
12
13Reported-by: Andrew Jones <ajones@ventanamicro.com>
14Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
15Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
16Message-ID: <20231208183835.2411523-3-dbarboza@ventanamicro.com>
17Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
18(cherry picked from commit 450bd6618fda3d2e2ab02b2fce1c79efd5b66084)
19Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
20
21Upstream-Status: Backport [125b95d79e746cbab6b72683b3382dd372e38c61]
22
23Signed-off-by: Chen Qi <Qi.Chen@windriver.com>
24---
25 target/riscv/kvm/kvm-cpu.c | 11 ++++++++---
26 1 file changed, 8 insertions(+), 3 deletions(-)
27
28diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
29index 2eef2be86a..82ed4455a5 100644
30--- a/target/riscv/kvm/kvm-cpu.c
31+++ b/target/riscv/kvm/kvm-cpu.c
32@@ -77,6 +77,11 @@ static uint64_t kvm_riscv_reg_id_u32(uint64_t type, uint64_t idx)
33 return KVM_REG_RISCV | KVM_REG_SIZE_U32 | type | idx;
34 }
35
36+static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx)
37+{
38+ return KVM_REG_RISCV | KVM_REG_SIZE_U64 | type | idx;
39+}
40+
41 #define RISCV_CORE_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, \
42 KVM_REG_RISCV_CORE_REG(name))
43
44@@ -88,7 +93,7 @@ static uint64_t kvm_riscv_reg_id_u32(uint64_t type, uint64_t idx)
45
46 #define RISCV_FP_F_REG(idx) kvm_riscv_reg_id_u32(KVM_REG_RISCV_FP_F, idx)
47
48-#define RISCV_FP_D_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_D, idx)
49+#define RISCV_FP_D_REG(idx) kvm_riscv_reg_id_u64(KVM_REG_RISCV_FP_D, idx)
50
51 #define KVM_RISCV_GET_CSR(cs, env, csr, reg) \
52 do { \
53@@ -579,7 +584,7 @@ static int kvm_riscv_get_regs_fp(CPUState *cs)
54 if (riscv_has_ext(env, RVD)) {
55 uint64_t reg;
56 for (i = 0; i < 32; i++) {
57- ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(env, i), &reg);
58+ ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(i), &reg);
59 if (ret) {
60 return ret;
61 }
62@@ -613,7 +618,7 @@ static int kvm_riscv_put_regs_fp(CPUState *cs)
63 uint64_t reg;
64 for (i = 0; i < 32; i++) {
65 reg = env->fpr[i];
66- ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(env, i), &reg);
67+ ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(i), &reg);
68 if (ret) {
69 return ret;
70 }
71--
722.25.1
73
diff --git a/meta/recipes-devtools/qemu/qemu/0003-target-riscv-kvm-change-timer-regs-size-to-u64.patch b/meta/recipes-devtools/qemu/qemu/0003-target-riscv-kvm-change-timer-regs-size-to-u64.patch
deleted file mode 100644
index 1ea1bcfe70..0000000000
--- a/meta/recipes-devtools/qemu/qemu/0003-target-riscv-kvm-change-timer-regs-size-to-u64.patch
+++ /dev/null
@@ -1,107 +0,0 @@
1From cbae1080988e0f1af0fb4c816205f7647f6de16f Mon Sep 17 00:00:00 2001
2From: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
3Date: Fri, 8 Dec 2023 15:38:33 -0300
4Subject: [PATCH 3/3] target/riscv/kvm: change timer regs size to u64
5
6KVM_REG_RISCV_TIMER regs are always u64 according to the KVM API, but at
7this moment we'll return u32 regs if we're running a RISCV32 target.
8
9Use the kvm_riscv_reg_id_u64() helper in RISCV_TIMER_REG() to fix it.
10
11Reported-by: Andrew Jones <ajones@ventanamicro.com>
12Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
13Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
14Message-ID: <20231208183835.2411523-4-dbarboza@ventanamicro.com>
15Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
16(cherry picked from commit 10f86d1b845087d14b58d65dd2a6e3411d1b6529)
17Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
18
19Upstream-Status: Backport [cbae1080988e0f1af0fb4c816205f7647f6de16f]
20
21Signed-off-by: Chen Qi <Qi.Chen@windriver.com>
22---
23 target/riscv/kvm/kvm-cpu.c | 26 +++++++++++++-------------
24 1 file changed, 13 insertions(+), 13 deletions(-)
25
26diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
27index 82ed4455a5..ddbe820e10 100644
28--- a/target/riscv/kvm/kvm-cpu.c
29+++ b/target/riscv/kvm/kvm-cpu.c
30@@ -88,7 +88,7 @@ static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx)
31 #define RISCV_CSR_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CSR, \
32 KVM_REG_RISCV_CSR_REG(name))
33
34-#define RISCV_TIMER_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_TIMER, \
35+#define RISCV_TIMER_REG(name) kvm_riscv_reg_id_u64(KVM_REG_RISCV_TIMER, \
36 KVM_REG_RISCV_TIMER_REG(name))
37
38 #define RISCV_FP_F_REG(idx) kvm_riscv_reg_id_u32(KVM_REG_RISCV_FP_F, idx)
39@@ -111,17 +111,17 @@ static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx)
40 } \
41 } while (0)
42
43-#define KVM_RISCV_GET_TIMER(cs, env, name, reg) \
44+#define KVM_RISCV_GET_TIMER(cs, name, reg) \
45 do { \
46- int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(env, name), &reg); \
47+ int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(name), &reg); \
48 if (ret) { \
49 abort(); \
50 } \
51 } while (0)
52
53-#define KVM_RISCV_SET_TIMER(cs, env, name, reg) \
54+#define KVM_RISCV_SET_TIMER(cs, name, reg) \
55 do { \
56- int ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(env, name), &reg); \
57+ int ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(name), &reg); \
58 if (ret) { \
59 abort(); \
60 } \
61@@ -649,10 +649,10 @@ static void kvm_riscv_get_regs_timer(CPUState *cs)
62 return;
63 }
64
65- KVM_RISCV_GET_TIMER(cs, env, time, env->kvm_timer_time);
66- KVM_RISCV_GET_TIMER(cs, env, compare, env->kvm_timer_compare);
67- KVM_RISCV_GET_TIMER(cs, env, state, env->kvm_timer_state);
68- KVM_RISCV_GET_TIMER(cs, env, frequency, env->kvm_timer_frequency);
69+ KVM_RISCV_GET_TIMER(cs, time, env->kvm_timer_time);
70+ KVM_RISCV_GET_TIMER(cs, compare, env->kvm_timer_compare);
71+ KVM_RISCV_GET_TIMER(cs, state, env->kvm_timer_state);
72+ KVM_RISCV_GET_TIMER(cs, frequency, env->kvm_timer_frequency);
73
74 env->kvm_timer_dirty = true;
75 }
76@@ -666,8 +666,8 @@ static void kvm_riscv_put_regs_timer(CPUState *cs)
77 return;
78 }
79
80- KVM_RISCV_SET_TIMER(cs, env, time, env->kvm_timer_time);
81- KVM_RISCV_SET_TIMER(cs, env, compare, env->kvm_timer_compare);
82+ KVM_RISCV_SET_TIMER(cs, time, env->kvm_timer_time);
83+ KVM_RISCV_SET_TIMER(cs, compare, env->kvm_timer_compare);
84
85 /*
86 * To set register of RISCV_TIMER_REG(state) will occur a error from KVM
87@@ -676,7 +676,7 @@ static void kvm_riscv_put_regs_timer(CPUState *cs)
88 * TODO If KVM changes, adapt here.
89 */
90 if (env->kvm_timer_state) {
91- KVM_RISCV_SET_TIMER(cs, env, state, env->kvm_timer_state);
92+ KVM_RISCV_SET_TIMER(cs, state, env->kvm_timer_state);
93 }
94
95 /*
96@@ -685,7 +685,7 @@ static void kvm_riscv_put_regs_timer(CPUState *cs)
97 * during the migration.
98 */
99 if (migration_is_running(migrate_get_current()->state)) {
100- KVM_RISCV_GET_TIMER(cs, env, frequency, reg);
101+ KVM_RISCV_GET_TIMER(cs, frequency, reg);
102 if (reg != env->kvm_timer_frequency) {
103 error_report("Dst Hosts timer frequency != Src Hosts");
104 }
105--
1062.25.1
107
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0001.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0001.patch
deleted file mode 100644
index dbcc71bb4e..0000000000
--- a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0001.patch
+++ /dev/null
@@ -1,112 +0,0 @@
1From bd385a5298d7062668e804d73944d52aec9549f1 Mon Sep 17 00:00:00 2001
2From: Kevin Wolf <kwolf@redhat.com>
3Date: Fri, 16 Aug 2024 08:29:04 +0000
4Subject: [PATCH] qcow2: Don't open data_file with BDRV_O_NO_IO
5
6One use case for 'qemu-img info' is verifying that untrusted images
7don't reference an unwanted external file, be it as a backing file or an
8external data file. To make sure that calling 'qemu-img info' can't
9already have undesired side effects with a malicious image, just don't
10open the data file at all with BDRV_O_NO_IO. If nothing ever tries to do
11I/O, we don't need to have it open.
12
13This changes the output of iotests case 061, which used 'qemu-img info'
14to show that opening an image with an invalid data file fails. After
15this patch, it succeeds. Replace this part of the test with a qemu-io
16call, but keep the final 'qemu-img info' to show that the invalid data
17file is correctly displayed in the output.
18
19Fixes: CVE-2024-4467
20Cc: qemu-stable@nongnu.org
21Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22Reviewed-by: Eric Blake <eblake@redhat.com>
23Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
24Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
25
26CVE: CVE-2024-4667
27Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/bd385a5298d7062668e804d73944d52aec9549f1]
28
29Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
30---
31 block/qcow2.c | 17 ++++++++++++++++-
32 tests/qemu-iotests/061 | 6 ++++--
33 tests/qemu-iotests/061.out | 8 ++++++--
34 3 files changed, 26 insertions(+), 5 deletions(-)
35
36diff --git a/block/qcow2.c b/block/qcow2.c
37index 13e032bd5..7af7c0bee 100644
38--- a/block/qcow2.c
39+++ b/block/qcow2.c
40@@ -1636,7 +1636,22 @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
41 goto fail;
42 }
43
44- if (open_data_file) {
45+ if (open_data_file && (flags & BDRV_O_NO_IO)) {
46+ /*
47+ * Don't open the data file for 'qemu-img info' so that it can be used
48+ * to verify that an untrusted qcow2 image doesn't refer to external
49+ * files.
50+ *
51+ * Note: This still makes has_data_file() return true.
52+ */
53+ if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
54+ s->data_file = NULL;
55+ } else {
56+ s->data_file = bs->file;
57+ }
58+ qdict_extract_subqdict(options, NULL, "data-file.");
59+ qdict_del(options, "data-file");
60+ } else if (open_data_file) {
61 /* Open external data file */
62 bdrv_graph_co_rdunlock();
63 s->data_file = bdrv_co_open_child(NULL, options, "data-file", bs,
64diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
65index 53c7d428e..b71ac097d 100755
66--- a/tests/qemu-iotests/061
67+++ b/tests/qemu-iotests/061
68@@ -326,12 +326,14 @@ $QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
69 echo
70 _make_test_img -o "compat=1.1,data_file=$TEST_IMG.data" 64M
71 $QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
72-_img_info --format-specific
73+$QEMU_IO -c "read 0 4k" "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
74+$QEMU_IO -c "open -o data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" -c "read 0 4k" | _filter_qemu_io
75 TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts
76
77 echo
78 $QEMU_IMG amend -o "data_file=" --image-opts "data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG"
79-_img_info --format-specific
80+$QEMU_IO -c "read 0 4k" "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
81+$QEMU_IO -c "open -o data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" -c "read 0 4k" | _filter_qemu_io
82 TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts
83
84 echo
85diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
86index 139fc6817..24c33add7 100644
87--- a/tests/qemu-iotests/061.out
88+++ b/tests/qemu-iotests/061.out
89@@ -545,7 +545,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
90 qemu-img: data-file can only be set for images that use an external data file
91
92 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data
93-qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Could not open 'foo': No such file or directory
94+qemu-io: can't open device TEST_DIR/t.IMGFMT: Could not open 'foo': No such file or directory
95+read 4096/4096 bytes at offset 0
96+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
97 image: TEST_DIR/t.IMGFMT
98 file format: IMGFMT
99 virtual size: 64 MiB (67108864 bytes)
100@@ -560,7 +562,9 @@ Format specific information:
101 corrupt: false
102 extended l2: false
103
104-qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'data-file' is required for this image
105+qemu-io: can't open device TEST_DIR/t.IMGFMT: 'data-file' is required for this image
106+read 4096/4096 bytes at offset 0
107+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
108 image: TEST_DIR/t.IMGFMT
109 file format: IMGFMT
110 virtual size: 64 MiB (67108864 bytes)
111--
1122.40.0
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0002.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0002.patch
deleted file mode 100644
index 686176189c..0000000000
--- a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0002.patch
+++ /dev/null
@@ -1,55 +0,0 @@
1From 2eb42a728d27a43fdcad5f37d3f65706ce6deba5 Mon Sep 17 00:00:00 2001
2From: Kevin Wolf <kwolf@redhat.com>
3Date: Fri, 16 Aug 2024 09:35:24 +0000
4Subject: [PATCH] iotests/244: Don't store data-file with protocol in image
5
6We want to disable filename parsing for data files because it's too easy
7to abuse in malicious image files. Make the test ready for the change by
8passing the data file explicitly in command line options.
9
10Cc: qemu-stable@nongnu.org
11Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12Reviewed-by: Eric Blake <eblake@redhat.com>
13Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
15
16CVE: CVE-2024-4467
17Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/2eb42a728d27a43fdcad5f37d3f65706ce6deba5]
18
19Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
20---
21 tests/qemu-iotests/244 | 19 ++++++++++++++++---
22 1 file changed, 16 insertions(+), 3 deletions(-)
23
24diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
25index 3e61fa25b..bb9cc6512 100755
26--- a/tests/qemu-iotests/244
27+++ b/tests/qemu-iotests/244
28@@ -215,9 +215,22 @@ $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$TEST_IMG"
29 $QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$TEST_IMG"
30
31 # blkdebug doesn't support copy offloading, so this tests the error path
32-$QEMU_IMG amend -f $IMGFMT -o "data_file=blkdebug::$TEST_IMG.data" "$TEST_IMG"
33-$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$TEST_IMG"
34-$QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$TEST_IMG"
35+test_img_with_blkdebug="json:{
36+ 'driver': 'qcow2',
37+ 'file': {
38+ 'driver': 'file',
39+ 'filename': '$TEST_IMG'
40+ },
41+ 'data-file': {
42+ 'driver': 'blkdebug',
43+ 'image': {
44+ 'driver': 'file',
45+ 'filename': '$TEST_IMG.data'
46+ }
47+ }
48+}"
49+$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$test_img_with_blkdebug"
50+$QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$test_img_with_blkdebug"
51
52 echo
53 echo "=== Flushing should flush the data file ==="
54--
552.40.0
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0003.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0003.patch
deleted file mode 100644
index 02611d6732..0000000000
--- a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0003.patch
+++ /dev/null
@@ -1,57 +0,0 @@
1From 7e1110664ecbc4826f3c978ccb06b6c1bce823e6 Mon Sep 17 00:00:00 2001
2From: Kevin Wolf <kwolf@redhat.com>
3Date: Fri, 16 Aug 2024 10:24:58 +0000
4Subject: [PATCH] iotests/270: Don't store data-file with json: prefix in image
5
6We want to disable filename parsing for data files because it's too easy
7to abuse in malicious image files. Make the test ready for the change by
8passing the data file explicitly in command line options.
9
10Cc: qemu-stable@nongnu.org
11Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12Reviewed-by: Eric Blake <eblake@redhat.com>
13Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
15
16CVE: CVE-2024-4467
17Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/7e1110664ecbc4826f3c978ccb06b6c1bce823e6]
18
19Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
20---
21 tests/qemu-iotests/270 | 14 +++++++++++---
22 1 file changed, 11 insertions(+), 3 deletions(-)
23
24diff --git a/tests/qemu-iotests/270 b/tests/qemu-iotests/270
25index 74352342d..c37b674aa 100755
26--- a/tests/qemu-iotests/270
27+++ b/tests/qemu-iotests/270
28@@ -60,8 +60,16 @@ _make_test_img -o cluster_size=2M,data_file="$TEST_IMG.orig" \
29 # "write" 2G of data without using any space.
30 # (qemu-img create does not like it, though, because null-co does not
31 # support image creation.)
32-$QEMU_IMG amend -o data_file="json:{'driver':'null-co',,'size':'4294967296'}" \
33- "$TEST_IMG"
34+test_img_with_null_data="json:{
35+ 'driver': '$IMGFMT',
36+ 'file': {
37+ 'filename': '$TEST_IMG'
38+ },
39+ 'data-file': {
40+ 'driver': 'null-co',
41+ 'size':'4294967296'
42+ }
43+}"
44
45 # This gives us a range of:
46 # 2^31 - 512 + 768 - 1 = 2^31 + 255 > 2^31
47@@ -74,7 +82,7 @@ $QEMU_IMG amend -o data_file="json:{'driver':'null-co',,'size':'4294967296'}" \
48 # on L2 boundaries, we need large L2 tables; hence the cluster size of
49 # 2 MB. (Anything from 256 kB should work, though, because then one L2
50 # table covers 8 GB.)
51-$QEMU_IO -c "write 768 $((2 ** 31 - 512))" "$TEST_IMG" | _filter_qemu_io
52+$QEMU_IO -c "write 768 $((2 ** 31 - 512))" "$test_img_with_null_data" | _filter_qemu_io
53
54 _check_test_img
55
56--
572.40.0
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0004.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0004.patch
deleted file mode 100644
index 7568a453c4..0000000000
--- a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0004.patch
+++ /dev/null
@@ -1,1187 +0,0 @@
1From 6bc30f19498547fac9cef98316a65cf6c1f14205 Mon Sep 17 00:00:00 2001
2From: Stefan Hajnoczi <stefanha@redhat.com>
3Date: Tue, 5 Dec 2023 13:20:02 -0500
4Subject: [PATCH] graph-lock: remove AioContext locking
5
6Stop acquiring/releasing the AioContext lock in
7bdrv_graph_wrlock()/bdrv_graph_unlock() since the lock no longer has any
8effect.
9
10The distinction between bdrv_graph_wrunlock() and
11bdrv_graph_wrunlock_ctx() becomes meaningless and they can be collapsed
12into one function.
13
14Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15Reviewed-by: Eric Blake <eblake@redhat.com>
16Reviewed-by: Kevin Wolf <kwolf@redhat.com>
17Message-ID: <20231205182011.1976568-6-stefanha@redhat.com>
18Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
20CVE: CVE-2024-4467
21Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/6bc30f19498547fac9cef98316a65cf6c1f14205]
22
23Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
24---
25 block.c | 50 +++++++++++++++---------------
26 block/backup.c | 4 +--
27 block/blklogwrites.c | 8 ++---
28 block/blkverify.c | 4 +--
29 block/block-backend.c | 11 +++----
30 block/commit.c | 16 +++++-----
31 block/graph-lock.c | 44 ++------------------------
32 block/mirror.c | 22 ++++++-------
33 block/qcow2.c | 4 +--
34 block/quorum.c | 8 ++---
35 block/replication.c | 14 ++++-----
36 block/snapshot.c | 4 +--
37 block/stream.c | 12 +++----
38 block/vmdk.c | 20 ++++++------
39 blockdev.c | 8 ++---
40 blockjob.c | 12 +++----
41 include/block/graph-lock.h | 21 ++-----------
42 scripts/block-coroutine-wrapper.py | 4 +--
43 tests/unit/test-bdrv-drain.c | 40 ++++++++++++------------
44 tests/unit/test-bdrv-graph-mod.c | 20 ++++++------
45 20 files changed, 133 insertions(+), 193 deletions(-)
46
47diff --git a/block.c b/block.c
48index bfb0861ec..25e1ebc60 100644
49--- a/block.c
50+++ b/block.c
51@@ -1708,12 +1708,12 @@ bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name,
52 open_failed:
53 bs->drv = NULL;
54
55- bdrv_graph_wrlock(NULL);
56+ bdrv_graph_wrlock();
57 if (bs->file != NULL) {
58 bdrv_unref_child(bs, bs->file);
59 assert(!bs->file);
60 }
61- bdrv_graph_wrunlock(NULL);
62+ bdrv_graph_wrunlock();
63
64 g_free(bs->opaque);
65 bs->opaque = NULL;
66@@ -3575,9 +3575,9 @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
67
68 bdrv_ref(drain_bs);
69 bdrv_drained_begin(drain_bs);
70- bdrv_graph_wrlock(backing_hd);
71+ bdrv_graph_wrlock();
72 ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp);
73- bdrv_graph_wrunlock(backing_hd);
74+ bdrv_graph_wrunlock();
75 bdrv_drained_end(drain_bs);
76 bdrv_unref(drain_bs);
77
78@@ -3790,13 +3790,13 @@ BdrvChild *bdrv_open_child(const char *filename,
79 return NULL;
80 }
81
82- bdrv_graph_wrlock(NULL);
83+ bdrv_graph_wrlock();
84 ctx = bdrv_get_aio_context(bs);
85 aio_context_acquire(ctx);
86 child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
87 errp);
88 aio_context_release(ctx);
89- bdrv_graph_wrunlock(NULL);
90+ bdrv_graph_wrunlock();
91
92 return child;
93 }
94@@ -4650,9 +4650,9 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
95 aio_context_release(ctx);
96 }
97
98- bdrv_graph_wrlock(NULL);
99+ bdrv_graph_wrlock();
100 tran_commit(tran);
101- bdrv_graph_wrunlock(NULL);
102+ bdrv_graph_wrunlock();
103
104 QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
105 BlockDriverState *bs = bs_entry->state.bs;
106@@ -4669,9 +4669,9 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
107 goto cleanup;
108
109 abort:
110- bdrv_graph_wrlock(NULL);
111+ bdrv_graph_wrlock();
112 tran_abort(tran);
113- bdrv_graph_wrunlock(NULL);
114+ bdrv_graph_wrunlock();
115
116 QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
117 if (bs_entry->prepared) {
118@@ -4852,12 +4852,12 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
119 }
120
121 bdrv_graph_rdunlock_main_loop();
122- bdrv_graph_wrlock(new_child_bs);
123+ bdrv_graph_wrlock();
124
125 ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
126 tran, errp);
127
128- bdrv_graph_wrunlock_ctx(ctx);
129+ bdrv_graph_wrunlock();
130
131 if (old_ctx != ctx) {
132 aio_context_release(ctx);
133@@ -5209,14 +5209,14 @@ static void bdrv_close(BlockDriverState *bs)
134 bs->drv = NULL;
135 }
136
137- bdrv_graph_wrlock(bs);
138+ bdrv_graph_wrlock();
139 QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
140 bdrv_unref_child(bs, child);
141 }
142
143 assert(!bs->backing);
144 assert(!bs->file);
145- bdrv_graph_wrunlock(bs);
146+ bdrv_graph_wrunlock();
147
148 g_free(bs->opaque);
149 bs->opaque = NULL;
150@@ -5509,9 +5509,9 @@ int bdrv_drop_filter(BlockDriverState *bs, Error **errp)
151 bdrv_graph_rdunlock_main_loop();
152
153 bdrv_drained_begin(child_bs);
154- bdrv_graph_wrlock(bs);
155+ bdrv_graph_wrlock();
156 ret = bdrv_replace_node_common(bs, child_bs, true, true, errp);
157- bdrv_graph_wrunlock(bs);
158+ bdrv_graph_wrunlock();
159 bdrv_drained_end(child_bs);
160
161 return ret;
162@@ -5561,7 +5561,7 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
163 aio_context_acquire(old_context);
164 new_context = NULL;
165
166- bdrv_graph_wrlock(bs_top);
167+ bdrv_graph_wrlock();
168
169 child = bdrv_attach_child_noperm(bs_new, bs_top, "backing",
170 &child_of_bds, bdrv_backing_role(bs_new),
171@@ -5593,7 +5593,7 @@ out:
172 tran_finalize(tran, ret);
173
174 bdrv_refresh_limits(bs_top, NULL, NULL);
175- bdrv_graph_wrunlock(bs_top);
176+ bdrv_graph_wrunlock();
177
178 bdrv_drained_end(bs_top);
179 bdrv_drained_end(bs_new);
180@@ -5620,7 +5620,7 @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
181 bdrv_ref(old_bs);
182 bdrv_drained_begin(old_bs);
183 bdrv_drained_begin(new_bs);
184- bdrv_graph_wrlock(new_bs);
185+ bdrv_graph_wrlock();
186
187 bdrv_replace_child_tran(child, new_bs, tran);
188
189@@ -5631,7 +5631,7 @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
190
191 tran_finalize(tran, ret);
192
193- bdrv_graph_wrunlock(new_bs);
194+ bdrv_graph_wrunlock();
195 bdrv_drained_end(old_bs);
196 bdrv_drained_end(new_bs);
197 bdrv_unref(old_bs);
198@@ -5718,9 +5718,9 @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options,
199 bdrv_ref(bs);
200 bdrv_drained_begin(bs);
201 bdrv_drained_begin(new_node_bs);
202- bdrv_graph_wrlock(new_node_bs);
203+ bdrv_graph_wrlock();
204 ret = bdrv_replace_node(bs, new_node_bs, errp);
205- bdrv_graph_wrunlock(new_node_bs);
206+ bdrv_graph_wrunlock();
207 bdrv_drained_end(new_node_bs);
208 bdrv_drained_end(bs);
209 bdrv_unref(bs);
210@@ -5975,7 +5975,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
211
212 bdrv_ref(top);
213 bdrv_drained_begin(base);
214- bdrv_graph_wrlock(base);
215+ bdrv_graph_wrlock();
216
217 if (!top->drv || !base->drv) {
218 goto exit_wrlock;
219@@ -6015,7 +6015,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
220 * That's a FIXME.
221 */
222 bdrv_replace_node_common(top, base, false, false, &local_err);
223- bdrv_graph_wrunlock(base);
224+ bdrv_graph_wrunlock();
225
226 if (local_err) {
227 error_report_err(local_err);
228@@ -6052,7 +6052,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
229 goto exit;
230
231 exit_wrlock:
232- bdrv_graph_wrunlock(base);
233+ bdrv_graph_wrunlock();
234 exit:
235 bdrv_drained_end(base);
236 bdrv_unref(top);
237diff --git a/block/backup.c b/block/backup.c
238index 8aae5836d..ec29d6b81 100644
239--- a/block/backup.c
240+++ b/block/backup.c
241@@ -496,10 +496,10 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
242 block_copy_set_speed(bcs, speed);
243
244 /* Required permissions are taken by copy-before-write filter target */
245- bdrv_graph_wrlock(target);
246+ bdrv_graph_wrlock();
247 block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
248 &error_abort);
249- bdrv_graph_wrunlock(target);
250+ bdrv_graph_wrunlock();
251
252 return &job->common;
253
254diff --git a/block/blklogwrites.c b/block/blklogwrites.c
255index 84e03f309..ba717dab4 100644
256--- a/block/blklogwrites.c
257+++ b/block/blklogwrites.c
258@@ -251,9 +251,9 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
259 ret = 0;
260 fail_log:
261 if (ret < 0) {
262- bdrv_graph_wrlock(NULL);
263+ bdrv_graph_wrlock();
264 bdrv_unref_child(bs, s->log_file);
265- bdrv_graph_wrunlock(NULL);
266+ bdrv_graph_wrunlock();
267 s->log_file = NULL;
268 }
269 fail:
270@@ -265,10 +265,10 @@ static void blk_log_writes_close(BlockDriverState *bs)
271 {
272 BDRVBlkLogWritesState *s = bs->opaque;
273
274- bdrv_graph_wrlock(NULL);
275+ bdrv_graph_wrlock();
276 bdrv_unref_child(bs, s->log_file);
277 s->log_file = NULL;
278- bdrv_graph_wrunlock(NULL);
279+ bdrv_graph_wrunlock();
280 }
281
282 static int64_t coroutine_fn GRAPH_RDLOCK
283diff --git a/block/blkverify.c b/block/blkverify.c
284index 9b17c4664..ec45d8335 100644
285--- a/block/blkverify.c
286+++ b/block/blkverify.c
287@@ -151,10 +151,10 @@ static void blkverify_close(BlockDriverState *bs)
288 {
289 BDRVBlkverifyState *s = bs->opaque;
290
291- bdrv_graph_wrlock(NULL);
292+ bdrv_graph_wrlock();
293 bdrv_unref_child(bs, s->test_file);
294 s->test_file = NULL;
295- bdrv_graph_wrunlock(NULL);
296+ bdrv_graph_wrunlock();
297 }
298
299 static int64_t coroutine_fn GRAPH_RDLOCK
300diff --git a/block/block-backend.c b/block/block-backend.c
301index 86315d62c..a2348b31e 100644
302--- a/block/block-backend.c
303+++ b/block/block-backend.c
304@@ -885,7 +885,6 @@ void blk_remove_bs(BlockBackend *blk)
305 {
306 ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
307 BdrvChild *root;
308- AioContext *ctx;
309
310 GLOBAL_STATE_CODE();
311
312@@ -915,10 +914,9 @@ void blk_remove_bs(BlockBackend *blk)
313 root = blk->root;
314 blk->root = NULL;
315
316- ctx = bdrv_get_aio_context(root->bs);
317- bdrv_graph_wrlock(root->bs);
318+ bdrv_graph_wrlock();
319 bdrv_root_unref_child(root);
320- bdrv_graph_wrunlock_ctx(ctx);
321+ bdrv_graph_wrunlock();
322 }
323
324 /*
325@@ -929,16 +927,15 @@ void blk_remove_bs(BlockBackend *blk)
326 int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
327 {
328 ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
329- AioContext *ctx = bdrv_get_aio_context(bs);
330
331 GLOBAL_STATE_CODE();
332 bdrv_ref(bs);
333- bdrv_graph_wrlock(bs);
334+ bdrv_graph_wrlock();
335 blk->root = bdrv_root_attach_child(bs, "root", &child_root,
336 BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
337 blk->perm, blk->shared_perm,
338 blk, errp);
339- bdrv_graph_wrunlock_ctx(ctx);
340+ bdrv_graph_wrunlock();
341 if (blk->root == NULL) {
342 return -EPERM;
343 }
344diff --git a/block/commit.c b/block/commit.c
345index 69cc75be0..1dd7a65ff 100644
346--- a/block/commit.c
347+++ b/block/commit.c
348@@ -100,9 +100,9 @@ static void commit_abort(Job *job)
349 bdrv_graph_rdunlock_main_loop();
350
351 bdrv_drained_begin(commit_top_backing_bs);
352- bdrv_graph_wrlock(commit_top_backing_bs);
353+ bdrv_graph_wrlock();
354 bdrv_replace_node(s->commit_top_bs, commit_top_backing_bs, &error_abort);
355- bdrv_graph_wrunlock(commit_top_backing_bs);
356+ bdrv_graph_wrunlock();
357 bdrv_drained_end(commit_top_backing_bs);
358
359 bdrv_unref(s->commit_top_bs);
360@@ -339,7 +339,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
361 * this is the responsibility of the interface (i.e. whoever calls
362 * commit_start()).
363 */
364- bdrv_graph_wrlock(top);
365+ bdrv_graph_wrlock();
366 s->base_overlay = bdrv_find_overlay(top, base);
367 assert(s->base_overlay);
368
369@@ -370,19 +370,19 @@ void commit_start(const char *job_id, BlockDriverState *bs,
370 ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
371 iter_shared_perms, errp);
372 if (ret < 0) {
373- bdrv_graph_wrunlock(top);
374+ bdrv_graph_wrunlock();
375 goto fail;
376 }
377 }
378
379 if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
380- bdrv_graph_wrunlock(top);
381+ bdrv_graph_wrunlock();
382 goto fail;
383 }
384 s->chain_frozen = true;
385
386 ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
387- bdrv_graph_wrunlock(top);
388+ bdrv_graph_wrunlock();
389
390 if (ret < 0) {
391 goto fail;
392@@ -434,9 +434,9 @@ fail:
393 * otherwise this would fail because of lack of permissions. */
394 if (commit_top_bs) {
395 bdrv_drained_begin(top);
396- bdrv_graph_wrlock(top);
397+ bdrv_graph_wrlock();
398 bdrv_replace_node(commit_top_bs, top, &error_abort);
399- bdrv_graph_wrunlock(top);
400+ bdrv_graph_wrunlock();
401 bdrv_drained_end(top);
402 }
403 }
404diff --git a/block/graph-lock.c b/block/graph-lock.c
405index 079e878d9..c81162b14 100644
406--- a/block/graph-lock.c
407+++ b/block/graph-lock.c
408@@ -106,27 +106,12 @@ static uint32_t reader_count(void)
409 return rd;
410 }
411
412-void no_coroutine_fn bdrv_graph_wrlock(BlockDriverState *bs)
413+void no_coroutine_fn bdrv_graph_wrlock(void)
414 {
415- AioContext *ctx = NULL;
416-
417 GLOBAL_STATE_CODE();
418 assert(!qatomic_read(&has_writer));
419 assert(!qemu_in_coroutine());
420
421- /*
422- * Release only non-mainloop AioContext. The mainloop often relies on the
423- * BQL and doesn't lock the main AioContext before doing things.
424- */
425- if (bs) {
426- ctx = bdrv_get_aio_context(bs);
427- if (ctx != qemu_get_aio_context()) {
428- aio_context_release(ctx);
429- } else {
430- ctx = NULL;
431- }
432- }
433-
434 /* Make sure that constantly arriving new I/O doesn't cause starvation */
435 bdrv_drain_all_begin_nopoll();
436
437@@ -155,27 +140,13 @@ void no_coroutine_fn bdrv_graph_wrlock(BlockDriverState *bs)
438 } while (reader_count() >= 1);
439
440 bdrv_drain_all_end();
441-
442- if (ctx) {
443- aio_context_acquire(bdrv_get_aio_context(bs));
444- }
445 }
446
447-void no_coroutine_fn bdrv_graph_wrunlock_ctx(AioContext *ctx)
448+void no_coroutine_fn bdrv_graph_wrunlock(void)
449 {
450 GLOBAL_STATE_CODE();
451 assert(qatomic_read(&has_writer));
452
453- /*
454- * Release only non-mainloop AioContext. The mainloop often relies on the
455- * BQL and doesn't lock the main AioContext before doing things.
456- */
457- if (ctx && ctx != qemu_get_aio_context()) {
458- aio_context_release(ctx);
459- } else {
460- ctx = NULL;
461- }
462-
463 WITH_QEMU_LOCK_GUARD(&aio_context_list_lock) {
464 /*
465 * No need for memory barriers, this works in pair with
466@@ -197,17 +168,6 @@ void no_coroutine_fn bdrv_graph_wrunlock_ctx(AioContext *ctx)
467 * progress.
468 */
469 aio_bh_poll(qemu_get_aio_context());
470-
471- if (ctx) {
472- aio_context_acquire(ctx);
473- }
474-}
475-
476-void no_coroutine_fn bdrv_graph_wrunlock(BlockDriverState *bs)
477-{
478- AioContext *ctx = bs ? bdrv_get_aio_context(bs) : NULL;
479-
480- bdrv_graph_wrunlock_ctx(ctx);
481 }
482
483 void coroutine_fn bdrv_graph_co_rdlock(void)
484diff --git a/block/mirror.c b/block/mirror.c
485index abbddb39e..f9db6f0f7 100644
486--- a/block/mirror.c
487+++ b/block/mirror.c
488@@ -768,7 +768,7 @@ static int mirror_exit_common(Job *job)
489 * check for an op blocker on @to_replace, and we have our own
490 * there.
491 */
492- bdrv_graph_wrlock(target_bs);
493+ bdrv_graph_wrlock();
494 if (bdrv_recurse_can_replace(src, to_replace)) {
495 bdrv_replace_node(to_replace, target_bs, &local_err);
496 } else {
497@@ -777,7 +777,7 @@ static int mirror_exit_common(Job *job)
498 "would not lead to an abrupt change of visible data",
499 to_replace->node_name, target_bs->node_name);
500 }
501- bdrv_graph_wrunlock(target_bs);
502+ bdrv_graph_wrunlock();
503 bdrv_drained_end(to_replace);
504 if (local_err) {
505 error_report_err(local_err);
506@@ -800,9 +800,9 @@ static int mirror_exit_common(Job *job)
507 * valid.
508 */
509 block_job_remove_all_bdrv(bjob);
510- bdrv_graph_wrlock(mirror_top_bs);
511+ bdrv_graph_wrlock();
512 bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort);
513- bdrv_graph_wrunlock(mirror_top_bs);
514+ bdrv_graph_wrunlock();
515
516 bdrv_drained_end(target_bs);
517 bdrv_unref(target_bs);
518@@ -1916,13 +1916,13 @@ static BlockJob *mirror_start_job(
519 */
520 bdrv_disable_dirty_bitmap(s->dirty_bitmap);
521
522- bdrv_graph_wrlock(bs);
523+ bdrv_graph_wrlock();
524 ret = block_job_add_bdrv(&s->common, "source", bs, 0,
525 BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE |
526 BLK_PERM_CONSISTENT_READ,
527 errp);
528 if (ret < 0) {
529- bdrv_graph_wrunlock(bs);
530+ bdrv_graph_wrunlock();
531 goto fail;
532 }
533
534@@ -1967,17 +1967,17 @@ static BlockJob *mirror_start_job(
535 ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
536 iter_shared_perms, errp);
537 if (ret < 0) {
538- bdrv_graph_wrunlock(bs);
539+ bdrv_graph_wrunlock();
540 goto fail;
541 }
542 }
543
544 if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) {
545- bdrv_graph_wrunlock(bs);
546+ bdrv_graph_wrunlock();
547 goto fail;
548 }
549 }
550- bdrv_graph_wrunlock(bs);
551+ bdrv_graph_wrunlock();
552
553 QTAILQ_INIT(&s->ops_in_flight);
554
555@@ -2003,12 +2003,12 @@ fail:
556
557 bs_opaque->stop = true;
558 bdrv_drained_begin(bs);
559- bdrv_graph_wrlock(bs);
560+ bdrv_graph_wrlock();
561 assert(mirror_top_bs->backing->bs == bs);
562 bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
563 &error_abort);
564 bdrv_replace_node(mirror_top_bs, bs, &error_abort);
565- bdrv_graph_wrunlock(bs);
566+ bdrv_graph_wrunlock();
567 bdrv_drained_end(bs);
568
569 bdrv_unref(mirror_top_bs);
570diff --git a/block/qcow2.c b/block/qcow2.c
571index 7af7c0bee..77dd49d4f 100644
572--- a/block/qcow2.c
573+++ b/block/qcow2.c
574@@ -2822,9 +2822,9 @@ qcow2_do_close(BlockDriverState *bs, bool close_data_file)
575 if (close_data_file && has_data_file(bs)) {
576 GLOBAL_STATE_CODE();
577 bdrv_graph_rdunlock_main_loop();
578- bdrv_graph_wrlock(NULL);
579+ bdrv_graph_wrlock();
580 bdrv_unref_child(bs, s->data_file);
581- bdrv_graph_wrunlock(NULL);
582+ bdrv_graph_wrunlock();
583 s->data_file = NULL;
584 bdrv_graph_rdlock_main_loop();
585 }
586diff --git a/block/quorum.c b/block/quorum.c
587index 505b8b3e1..db8fe891c 100644
588--- a/block/quorum.c
589+++ b/block/quorum.c
590@@ -1037,14 +1037,14 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
591
592 close_exit:
593 /* cleanup on error */
594- bdrv_graph_wrlock(NULL);
595+ bdrv_graph_wrlock();
596 for (i = 0; i < s->num_children; i++) {
597 if (!opened[i]) {
598 continue;
599 }
600 bdrv_unref_child(bs, s->children[i]);
601 }
602- bdrv_graph_wrunlock(NULL);
603+ bdrv_graph_wrunlock();
604 g_free(s->children);
605 g_free(opened);
606 exit:
607@@ -1057,11 +1057,11 @@ static void quorum_close(BlockDriverState *bs)
608 BDRVQuorumState *s = bs->opaque;
609 int i;
610
611- bdrv_graph_wrlock(NULL);
612+ bdrv_graph_wrlock();
613 for (i = 0; i < s->num_children; i++) {
614 bdrv_unref_child(bs, s->children[i]);
615 }
616- bdrv_graph_wrunlock(NULL);
617+ bdrv_graph_wrunlock();
618
619 g_free(s->children);
620 }
621diff --git a/block/replication.c b/block/replication.c
622index 5ded5f1ca..424b537ff 100644
623--- a/block/replication.c
624+++ b/block/replication.c
625@@ -560,7 +560,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
626 return;
627 }
628
629- bdrv_graph_wrlock(bs);
630+ bdrv_graph_wrlock();
631
632 bdrv_ref(hidden_disk->bs);
633 s->hidden_disk = bdrv_attach_child(bs, hidden_disk->bs, "hidden disk",
634@@ -568,7 +568,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
635 &local_err);
636 if (local_err) {
637 error_propagate(errp, local_err);
638- bdrv_graph_wrunlock(bs);
639+ bdrv_graph_wrunlock();
640 aio_context_release(aio_context);
641 return;
642 }
643@@ -579,7 +579,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
644 BDRV_CHILD_DATA, &local_err);
645 if (local_err) {
646 error_propagate(errp, local_err);
647- bdrv_graph_wrunlock(bs);
648+ bdrv_graph_wrunlock();
649 aio_context_release(aio_context);
650 return;
651 }
652@@ -592,7 +592,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
653 if (!top_bs || !bdrv_is_root_node(top_bs) ||
654 !check_top_bs(top_bs, bs)) {
655 error_setg(errp, "No top_bs or it is invalid");
656- bdrv_graph_wrunlock(bs);
657+ bdrv_graph_wrunlock();
658 reopen_backing_file(bs, false, NULL);
659 aio_context_release(aio_context);
660 return;
661@@ -600,7 +600,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
662 bdrv_op_block_all(top_bs, s->blocker);
663 bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker);
664
665- bdrv_graph_wrunlock(bs);
666+ bdrv_graph_wrunlock();
667
668 s->backup_job = backup_job_create(
669 NULL, s->secondary_disk->bs, s->hidden_disk->bs,
670@@ -691,12 +691,12 @@ static void replication_done(void *opaque, int ret)
671 if (ret == 0) {
672 s->stage = BLOCK_REPLICATION_DONE;
673
674- bdrv_graph_wrlock(NULL);
675+ bdrv_graph_wrlock();
676 bdrv_unref_child(bs, s->secondary_disk);
677 s->secondary_disk = NULL;
678 bdrv_unref_child(bs, s->hidden_disk);
679 s->hidden_disk = NULL;
680- bdrv_graph_wrunlock(NULL);
681+ bdrv_graph_wrunlock();
682
683 s->error = 0;
684 } else {
685diff --git a/block/snapshot.c b/block/snapshot.c
686index c4d40e80d..6fd720aef 100644
687--- a/block/snapshot.c
688+++ b/block/snapshot.c
689@@ -292,9 +292,9 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
690 }
691
692 /* .bdrv_open() will re-attach it */
693- bdrv_graph_wrlock(NULL);
694+ bdrv_graph_wrlock();
695 bdrv_unref_child(bs, fallback);
696- bdrv_graph_wrunlock(NULL);
697+ bdrv_graph_wrunlock();
698
699 ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp);
700 open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err);
701diff --git a/block/stream.c b/block/stream.c
702index 01fe7c0f1..048c2d282 100644
703--- a/block/stream.c
704+++ b/block/stream.c
705@@ -99,9 +99,9 @@ static int stream_prepare(Job *job)
706 }
707 }
708
709- bdrv_graph_wrlock(s->target_bs);
710+ bdrv_graph_wrlock();
711 bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err);
712- bdrv_graph_wrunlock(s->target_bs);
713+ bdrv_graph_wrunlock();
714
715 /*
716 * This call will do I/O, so the graph can change again from here on.
717@@ -366,10 +366,10 @@ void stream_start(const char *job_id, BlockDriverState *bs,
718 * already have our own plans. Also don't allow resize as the image size is
719 * queried only at the job start and then cached.
720 */
721- bdrv_graph_wrlock(bs);
722+ bdrv_graph_wrlock();
723 if (block_job_add_bdrv(&s->common, "active node", bs, 0,
724 basic_flags | BLK_PERM_WRITE, errp)) {
725- bdrv_graph_wrunlock(bs);
726+ bdrv_graph_wrunlock();
727 goto fail;
728 }
729
730@@ -389,11 +389,11 @@ void stream_start(const char *job_id, BlockDriverState *bs,
731 ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
732 basic_flags, errp);
733 if (ret < 0) {
734- bdrv_graph_wrunlock(bs);
735+ bdrv_graph_wrunlock();
736 goto fail;
737 }
738 }
739- bdrv_graph_wrunlock(bs);
740+ bdrv_graph_wrunlock();
741
742 s->base_overlay = base_overlay;
743 s->above_base = above_base;
744diff --git a/block/vmdk.c b/block/vmdk.c
745index d6971c706..bf78e1238 100644
746--- a/block/vmdk.c
747+++ b/block/vmdk.c
748@@ -272,7 +272,7 @@ static void vmdk_free_extents(BlockDriverState *bs)
749 BDRVVmdkState *s = bs->opaque;
750 VmdkExtent *e;
751
752- bdrv_graph_wrlock(NULL);
753+ bdrv_graph_wrlock();
754 for (i = 0; i < s->num_extents; i++) {
755 e = &s->extents[i];
756 g_free(e->l1_table);
757@@ -283,7 +283,7 @@ static void vmdk_free_extents(BlockDriverState *bs)
758 bdrv_unref_child(bs, e->file);
759 }
760 }
761- bdrv_graph_wrunlock(NULL);
762+ bdrv_graph_wrunlock();
763
764 g_free(s->extents);
765 }
766@@ -1247,9 +1247,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
767 0, 0, 0, 0, 0, &extent, errp);
768 if (ret < 0) {
769 bdrv_graph_rdunlock_main_loop();
770- bdrv_graph_wrlock(NULL);
771+ bdrv_graph_wrlock();
772 bdrv_unref_child(bs, extent_file);
773- bdrv_graph_wrunlock(NULL);
774+ bdrv_graph_wrunlock();
775 bdrv_graph_rdlock_main_loop();
776 goto out;
777 }
778@@ -1266,9 +1266,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
779 g_free(buf);
780 if (ret) {
781 bdrv_graph_rdunlock_main_loop();
782- bdrv_graph_wrlock(NULL);
783+ bdrv_graph_wrlock();
784 bdrv_unref_child(bs, extent_file);
785- bdrv_graph_wrunlock(NULL);
786+ bdrv_graph_wrunlock();
787 bdrv_graph_rdlock_main_loop();
788 goto out;
789 }
790@@ -1277,9 +1277,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
791 ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp);
792 if (ret) {
793 bdrv_graph_rdunlock_main_loop();
794- bdrv_graph_wrlock(NULL);
795+ bdrv_graph_wrlock();
796 bdrv_unref_child(bs, extent_file);
797- bdrv_graph_wrunlock(NULL);
798+ bdrv_graph_wrunlock();
799 bdrv_graph_rdlock_main_loop();
800 goto out;
801 }
802@@ -1287,9 +1287,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
803 } else {
804 error_setg(errp, "Unsupported extent type '%s'", type);
805 bdrv_graph_rdunlock_main_loop();
806- bdrv_graph_wrlock(NULL);
807+ bdrv_graph_wrlock();
808 bdrv_unref_child(bs, extent_file);
809- bdrv_graph_wrunlock(NULL);
810+ bdrv_graph_wrunlock();
811 bdrv_graph_rdlock_main_loop();
812 ret = -ENOTSUP;
813 goto out;
814diff --git a/blockdev.c b/blockdev.c
815index c91f49e7b..9e1381169 100644
816--- a/blockdev.c
817+++ b/blockdev.c
818@@ -1611,9 +1611,9 @@ static void external_snapshot_abort(void *opaque)
819 }
820
821 bdrv_drained_begin(state->new_bs);
822- bdrv_graph_wrlock(state->old_bs);
823+ bdrv_graph_wrlock();
824 bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
825- bdrv_graph_wrunlock(state->old_bs);
826+ bdrv_graph_wrunlock();
827 bdrv_drained_end(state->new_bs);
828
829 bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
830@@ -3657,7 +3657,7 @@ void qmp_x_blockdev_change(const char *parent, const char *child,
831 BlockDriverState *parent_bs, *new_bs = NULL;
832 BdrvChild *p_child;
833
834- bdrv_graph_wrlock(NULL);
835+ bdrv_graph_wrlock();
836
837 parent_bs = bdrv_lookup_bs(parent, parent, errp);
838 if (!parent_bs) {
839@@ -3693,7 +3693,7 @@ void qmp_x_blockdev_change(const char *parent, const char *child,
840 }
841
842 out:
843- bdrv_graph_wrunlock(NULL);
844+ bdrv_graph_wrunlock();
845 }
846
847 BlockJobInfoList *qmp_query_block_jobs(Error **errp)
848diff --git a/blockjob.c b/blockjob.c
849index b7a29052b..731041231 100644
850--- a/blockjob.c
851+++ b/blockjob.c
852@@ -199,7 +199,7 @@ void block_job_remove_all_bdrv(BlockJob *job)
853 * to process an already freed BdrvChild.
854 */
855 aio_context_release(job->job.aio_context);
856- bdrv_graph_wrlock(NULL);
857+ bdrv_graph_wrlock();
858 aio_context_acquire(job->job.aio_context);
859 while (job->nodes) {
860 GSList *l = job->nodes;
861@@ -212,7 +212,7 @@ void block_job_remove_all_bdrv(BlockJob *job)
862
863 g_slist_free_1(l);
864 }
865- bdrv_graph_wrunlock_ctx(job->job.aio_context);
866+ bdrv_graph_wrunlock();
867 }
868
869 bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs)
870@@ -514,7 +514,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
871 int ret;
872 GLOBAL_STATE_CODE();
873
874- bdrv_graph_wrlock(bs);
875+ bdrv_graph_wrlock();
876
877 if (job_id == NULL && !(flags & JOB_INTERNAL)) {
878 job_id = bdrv_get_device_name(bs);
879@@ -523,7 +523,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
880 job = job_create(job_id, &driver->job_driver, txn, bdrv_get_aio_context(bs),
881 flags, cb, opaque, errp);
882 if (job == NULL) {
883- bdrv_graph_wrunlock(bs);
884+ bdrv_graph_wrunlock();
885 return NULL;
886 }
887
888@@ -563,11 +563,11 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
889 goto fail;
890 }
891
892- bdrv_graph_wrunlock(bs);
893+ bdrv_graph_wrunlock();
894 return job;
895
896 fail:
897- bdrv_graph_wrunlock(bs);
898+ bdrv_graph_wrunlock();
899 job_early_fail(&job->job);
900 return NULL;
901 }
902diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h
903index 22b5db1ed..d7545e82d 100644
904--- a/include/block/graph-lock.h
905+++ b/include/block/graph-lock.h
906@@ -110,34 +110,17 @@ void unregister_aiocontext(AioContext *ctx);
907 *
908 * The wrlock can only be taken from the main loop, with BQL held, as only the
909 * main loop is allowed to modify the graph.
910- *
911- * If @bs is non-NULL, its AioContext is temporarily released.
912- *
913- * This function polls. Callers must not hold the lock of any AioContext other
914- * than the current one and the one of @bs.
915 */
916 void no_coroutine_fn TSA_ACQUIRE(graph_lock) TSA_NO_TSA
917-bdrv_graph_wrlock(BlockDriverState *bs);
918+bdrv_graph_wrlock(void);
919
920 /*
921 * bdrv_graph_wrunlock:
922 * Write finished, reset global has_writer to 0 and restart
923 * all readers that are waiting.
924- *
925- * If @bs is non-NULL, its AioContext is temporarily released.
926- */
927-void no_coroutine_fn TSA_RELEASE(graph_lock) TSA_NO_TSA
928-bdrv_graph_wrunlock(BlockDriverState *bs);
929-
930-/*
931- * bdrv_graph_wrunlock_ctx:
932- * Write finished, reset global has_writer to 0 and restart
933- * all readers that are waiting.
934- *
935- * If @ctx is non-NULL, its lock is temporarily released.
936 */
937 void no_coroutine_fn TSA_RELEASE(graph_lock) TSA_NO_TSA
938-bdrv_graph_wrunlock_ctx(AioContext *ctx);
939+bdrv_graph_wrunlock(void);
940
941 /*
942 * bdrv_graph_co_rdlock:
943diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
944index a38e5833f..38364fa55 100644
945--- a/scripts/block-coroutine-wrapper.py
946+++ b/scripts/block-coroutine-wrapper.py
947@@ -261,8 +261,8 @@ def gen_no_co_wrapper(func: FuncDecl) -> str:
948 graph_lock=' bdrv_graph_rdlock_main_loop();'
949 graph_unlock=' bdrv_graph_rdunlock_main_loop();'
950 elif func.graph_wrlock:
951- graph_lock=' bdrv_graph_wrlock(NULL);'
952- graph_unlock=' bdrv_graph_wrunlock(NULL);'
953+ graph_lock=' bdrv_graph_wrlock();'
954+ graph_unlock=' bdrv_graph_wrunlock();'
955
956 return f"""\
957 /*
958diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
959index 704d1a3f3..d9754dfeb 100644
960--- a/tests/unit/test-bdrv-drain.c
961+++ b/tests/unit/test-bdrv-drain.c
962@@ -807,9 +807,9 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
963 tjob->bs = src;
964 job = &tjob->common;
965
966- bdrv_graph_wrlock(target);
967+ bdrv_graph_wrlock();
968 block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort);
969- bdrv_graph_wrunlock(target);
970+ bdrv_graph_wrunlock();
971
972 switch (result) {
973 case TEST_JOB_SUCCESS:
974@@ -991,11 +991,11 @@ static void bdrv_test_top_close(BlockDriverState *bs)
975 {
976 BdrvChild *c, *next_c;
977
978- bdrv_graph_wrlock(NULL);
979+ bdrv_graph_wrlock();
980 QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) {
981 bdrv_unref_child(bs, c);
982 }
983- bdrv_graph_wrunlock(NULL);
984+ bdrv_graph_wrunlock();
985 }
986
987 static int coroutine_fn GRAPH_RDLOCK
988@@ -1085,10 +1085,10 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
989
990 null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
991 &error_abort);
992- bdrv_graph_wrlock(NULL);
993+ bdrv_graph_wrlock();
994 bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds,
995 BDRV_CHILD_DATA, &error_abort);
996- bdrv_graph_wrunlock(NULL);
997+ bdrv_graph_wrunlock();
998
999 /* This child will be the one to pass to requests through to, and
1000 * it will stall until a drain occurs */
1001@@ -1096,21 +1096,21 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
1002 &error_abort);
1003 child_bs->total_sectors = 65536 >> BDRV_SECTOR_BITS;
1004 /* Takes our reference to child_bs */
1005- bdrv_graph_wrlock(NULL);
1006+ bdrv_graph_wrlock();
1007 tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child",
1008 &child_of_bds,
1009 BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
1010 &error_abort);
1011- bdrv_graph_wrunlock(NULL);
1012+ bdrv_graph_wrunlock();
1013
1014 /* This child is just there to be deleted
1015 * (for detach_instead_of_delete == true) */
1016 null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
1017 &error_abort);
1018- bdrv_graph_wrlock(NULL);
1019+ bdrv_graph_wrlock();
1020 bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds, BDRV_CHILD_DATA,
1021 &error_abort);
1022- bdrv_graph_wrunlock(NULL);
1023+ bdrv_graph_wrunlock();
1024
1025 blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
1026 blk_insert_bs(blk, bs, &error_abort);
1027@@ -1193,14 +1193,14 @@ static void no_coroutine_fn detach_indirect_bh(void *opaque)
1028
1029 bdrv_dec_in_flight(data->child_b->bs);
1030
1031- bdrv_graph_wrlock(NULL);
1032+ bdrv_graph_wrlock();
1033 bdrv_unref_child(data->parent_b, data->child_b);
1034
1035 bdrv_ref(data->c);
1036 data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C",
1037 &child_of_bds, BDRV_CHILD_DATA,
1038 &error_abort);
1039- bdrv_graph_wrunlock(NULL);
1040+ bdrv_graph_wrunlock();
1041 }
1042
1043 static void coroutine_mixed_fn detach_by_parent_aio_cb(void *opaque, int ret)
1044@@ -1298,7 +1298,7 @@ static void TSA_NO_TSA test_detach_indirect(bool by_parent_cb)
1045 /* Set child relationships */
1046 bdrv_ref(b);
1047 bdrv_ref(a);
1048- bdrv_graph_wrlock(NULL);
1049+ bdrv_graph_wrlock();
1050 child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_of_bds,
1051 BDRV_CHILD_DATA, &error_abort);
1052 child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_of_bds,
1053@@ -1308,7 +1308,7 @@ static void TSA_NO_TSA test_detach_indirect(bool by_parent_cb)
1054 bdrv_attach_child(parent_a, a, "PA-A",
1055 by_parent_cb ? &child_of_bds : &detach_by_driver_cb_class,
1056 BDRV_CHILD_DATA, &error_abort);
1057- bdrv_graph_wrunlock(NULL);
1058+ bdrv_graph_wrunlock();
1059
1060 g_assert_cmpint(parent_a->refcnt, ==, 1);
1061 g_assert_cmpint(parent_b->refcnt, ==, 1);
1062@@ -1727,7 +1727,7 @@ static void test_drop_intermediate_poll(void)
1063 * Establish the chain last, so the chain links are the first
1064 * elements in the BDS.parents lists
1065 */
1066- bdrv_graph_wrlock(NULL);
1067+ bdrv_graph_wrlock();
1068 for (i = 0; i < 3; i++) {
1069 if (i) {
1070 /* Takes the reference to chain[i - 1] */
1071@@ -1735,7 +1735,7 @@ static void test_drop_intermediate_poll(void)
1072 &chain_child_class, BDRV_CHILD_COW, &error_abort);
1073 }
1074 }
1075- bdrv_graph_wrunlock(NULL);
1076+ bdrv_graph_wrunlock();
1077
1078 job = block_job_create("job", &test_simple_job_driver, NULL, job_node,
1079 0, BLK_PERM_ALL, 0, 0, NULL, NULL, &error_abort);
1080@@ -1982,10 +1982,10 @@ static void do_test_replace_child_mid_drain(int old_drain_count,
1081 new_child_bs->total_sectors = 1;
1082
1083 bdrv_ref(old_child_bs);
1084- bdrv_graph_wrlock(NULL);
1085+ bdrv_graph_wrlock();
1086 bdrv_attach_child(parent_bs, old_child_bs, "child", &child_of_bds,
1087 BDRV_CHILD_COW, &error_abort);
1088- bdrv_graph_wrunlock(NULL);
1089+ bdrv_graph_wrunlock();
1090 parent_s->setup_completed = true;
1091
1092 for (i = 0; i < old_drain_count; i++) {
1093@@ -2016,9 +2016,9 @@ static void do_test_replace_child_mid_drain(int old_drain_count,
1094 g_assert(parent_bs->quiesce_counter == old_drain_count);
1095 bdrv_drained_begin(old_child_bs);
1096 bdrv_drained_begin(new_child_bs);
1097- bdrv_graph_wrlock(NULL);
1098+ bdrv_graph_wrlock();
1099 bdrv_replace_node(old_child_bs, new_child_bs, &error_abort);
1100- bdrv_graph_wrunlock(NULL);
1101+ bdrv_graph_wrunlock();
1102 bdrv_drained_end(new_child_bs);
1103 bdrv_drained_end(old_child_bs);
1104 g_assert(parent_bs->quiesce_counter == new_drain_count);
1105diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
1106index 074adcbb9..8ee6ef38d 100644
1107--- a/tests/unit/test-bdrv-graph-mod.c
1108+++ b/tests/unit/test-bdrv-graph-mod.c
1109@@ -137,10 +137,10 @@ static void test_update_perm_tree(void)
1110
1111 blk_insert_bs(root, bs, &error_abort);
1112
1113- bdrv_graph_wrlock(NULL);
1114+ bdrv_graph_wrlock();
1115 bdrv_attach_child(filter, bs, "child", &child_of_bds,
1116 BDRV_CHILD_DATA, &error_abort);
1117- bdrv_graph_wrunlock(NULL);
1118+ bdrv_graph_wrunlock();
1119
1120 aio_context_acquire(qemu_get_aio_context());
1121 ret = bdrv_append(filter, bs, NULL);
1122@@ -206,11 +206,11 @@ static void test_should_update_child(void)
1123
1124 bdrv_set_backing_hd(target, bs, &error_abort);
1125
1126- bdrv_graph_wrlock(NULL);
1127+ bdrv_graph_wrlock();
1128 g_assert(target->backing->bs == bs);
1129 bdrv_attach_child(filter, target, "target", &child_of_bds,
1130 BDRV_CHILD_DATA, &error_abort);
1131- bdrv_graph_wrunlock(NULL);
1132+ bdrv_graph_wrunlock();
1133 aio_context_acquire(qemu_get_aio_context());
1134 bdrv_append(filter, bs, &error_abort);
1135 aio_context_release(qemu_get_aio_context());
1136@@ -248,7 +248,7 @@ static void test_parallel_exclusive_write(void)
1137 bdrv_ref(base);
1138 bdrv_ref(fl1);
1139
1140- bdrv_graph_wrlock(NULL);
1141+ bdrv_graph_wrlock();
1142 bdrv_attach_child(top, fl1, "backing", &child_of_bds,
1143 BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
1144 &error_abort);
1145@@ -260,7 +260,7 @@ static void test_parallel_exclusive_write(void)
1146 &error_abort);
1147
1148 bdrv_replace_node(fl1, fl2, &error_abort);
1149- bdrv_graph_wrunlock(NULL);
1150+ bdrv_graph_wrunlock();
1151
1152 bdrv_drained_end(fl2);
1153 bdrv_drained_end(fl1);
1154@@ -367,7 +367,7 @@ static void test_parallel_perm_update(void)
1155 */
1156 bdrv_ref(base);
1157
1158- bdrv_graph_wrlock(NULL);
1159+ bdrv_graph_wrlock();
1160 bdrv_attach_child(top, ws, "file", &child_of_bds, BDRV_CHILD_DATA,
1161 &error_abort);
1162 c_fl1 = bdrv_attach_child(ws, fl1, "first", &child_of_bds,
1163@@ -380,7 +380,7 @@ static void test_parallel_perm_update(void)
1164 bdrv_attach_child(fl2, base, "backing", &child_of_bds,
1165 BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
1166 &error_abort);
1167- bdrv_graph_wrunlock(NULL);
1168+ bdrv_graph_wrunlock();
1169
1170 /* Select fl1 as first child to be active */
1171 s->selected = c_fl1;
1172@@ -434,11 +434,11 @@ static void test_append_greedy_filter(void)
1173 BlockDriverState *base = no_perm_node("base");
1174 BlockDriverState *fl = exclusive_writer_node("fl1");
1175
1176- bdrv_graph_wrlock(NULL);
1177+ bdrv_graph_wrlock();
1178 bdrv_attach_child(top, base, "backing", &child_of_bds,
1179 BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
1180 &error_abort);
1181- bdrv_graph_wrunlock(NULL);
1182+ bdrv_graph_wrunlock();
1183
1184 aio_context_acquire(qemu_get_aio_context());
1185 bdrv_append(fl, base, &error_abort);
1186--
11872.40.0
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0005.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0005.patch
deleted file mode 100644
index bcdd0fbed8..0000000000
--- a/meta/recipes-devtools/qemu/qemu/CVE-2024-4467-0005.patch
+++ /dev/null
@@ -1,239 +0,0 @@
1From 7ead946998610657d38d1a505d5f25300d4ca613 Mon Sep 17 00:00:00 2001
2From: Kevin Wolf <kwolf@redhat.com>
3Date: Thu, 25 Apr 2024 14:56:02 +0000
4Subject: [PATCH] block: Parse filenames only when explicitly requested
5
6When handling image filenames from legacy options such as -drive or from
7tools, these filenames are parsed for protocol prefixes, including for
8the json:{} pseudo-protocol.
9
10This behaviour is intended for filenames that come directly from the
11command line and for backing files, which may come from the image file
12itself. Higher level management tools generally take care to verify that
13untrusted images don't contain a bad (or any) backing file reference;
14'qemu-img info' is a suitable tool for this.
15
16However, for other files that can be referenced in images, such as
17qcow2 data files or VMDK extents, the string from the image file is
18usually not verified by management tools - and 'qemu-img info' wouldn't
19be suitable because in contrast to backing files, it already opens these
20other referenced files. So here the string should be interpreted as a
21literal local filename. More complex configurations need to be specified
22explicitly on the command line or in QMP...
23
24CVE: CVE-2024-4467
25Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/7ead946998610657d38d1a505d5f25300d4ca613]
26
27Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
28---
29 block.c | 94 ++++++++++++++++++++++++++++++++++-----------------------
30 1 file changed, 57 insertions(+), 37 deletions(-)
31
32diff --git a/block.c b/block.c
33index 25e1ebc60..f3cb32cd7 100644
34--- a/block.c
35+++ b/block.c
36@@ -86,6 +86,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
37 BlockDriverState *parent,
38 const BdrvChildClass *child_class,
39 BdrvChildRole child_role,
40+ bool parse_filename,
41 Error **errp);
42
43 static bool bdrv_recurse_has_child(BlockDriverState *bs,
44@@ -2047,7 +2048,8 @@ static void parse_json_protocol(QDict *options, const char **pfilename,
45 * block driver has been specified explicitly.
46 */
47 static int bdrv_fill_options(QDict **options, const char *filename,
48- int *flags, Error **errp)
49+ int *flags, bool allow_parse_filename,
50+ Error **errp)
51 {
52 const char *drvname;
53 bool protocol = *flags & BDRV_O_PROTOCOL;
54@@ -2089,7 +2091,7 @@ static int bdrv_fill_options(QDict **options, const char *filename,
55 if (protocol && filename) {
56 if (!qdict_haskey(*options, "filename")) {
57 qdict_put_str(*options, "filename", filename);
58- parse_filename = true;
59+ parse_filename = allow_parse_filename;
60 } else {
61 error_setg(errp, "Can't specify 'file' and 'filename' options at "
62 "the same time");
63@@ -3675,7 +3677,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
64 }
65
66 backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs,
67- &child_of_bds, bdrv_backing_role(bs), errp);
68+ &child_of_bds, bdrv_backing_role(bs), true,
69+ errp);
70 if (!backing_hd) {
71 bs->open_flags |= BDRV_O_NO_BACKING;
72 error_prepend(errp, "Could not open backing file: ");
73@@ -3712,7 +3715,8 @@ free_exit:
74 static BlockDriverState *
75 bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
76 BlockDriverState *parent, const BdrvChildClass *child_class,
77- BdrvChildRole child_role, bool allow_none, Error **errp)
78+ BdrvChildRole child_role, bool allow_none,
79+ bool parse_filename, Error **errp)
80 {
81 BlockDriverState *bs = NULL;
82 QDict *image_options;
83@@ -3743,7 +3747,8 @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
84 }
85
86 bs = bdrv_open_inherit(filename, reference, image_options, 0,
87- parent, child_class, child_role, errp);
88+ parent, child_class, child_role, parse_filename,
89+ errp);
90 if (!bs) {
91 goto done;
92 }
93@@ -3753,6 +3758,33 @@ done:
94 return bs;
95 }
96
97+static BdrvChild *bdrv_open_child_common(const char *filename,
98+ QDict *options, const char *bdref_key,
99+ BlockDriverState *parent,
100+ const BdrvChildClass *child_class,
101+ BdrvChildRole child_role,
102+ bool allow_none, bool parse_filename,
103+ Error **errp)
104+{
105+ BlockDriverState *bs;
106+ BdrvChild *child;
107+
108+ GLOBAL_STATE_CODE();
109+
110+ bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class,
111+ child_role, allow_none, parse_filename, errp);
112+ if (bs == NULL) {
113+ return NULL;
114+ }
115+
116+ bdrv_graph_wrlock();
117+ child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
118+ errp);
119+ bdrv_graph_wrunlock();
120+
121+ return child;
122+}
123+
124 /*
125 * Opens a disk image whose options are given as BlockdevRef in another block
126 * device's options.
127@@ -3778,31 +3810,15 @@ BdrvChild *bdrv_open_child(const char *filename,
128 BdrvChildRole child_role,
129 bool allow_none, Error **errp)
130 {
131- BlockDriverState *bs;
132- BdrvChild *child;
133- AioContext *ctx;
134-
135- GLOBAL_STATE_CODE();
136-
137- bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class,
138- child_role, allow_none, errp);
139- if (bs == NULL) {
140- return NULL;
141- }
142-
143- bdrv_graph_wrlock();
144- ctx = bdrv_get_aio_context(bs);
145- aio_context_acquire(ctx);
146- child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
147- errp);
148- aio_context_release(ctx);
149- bdrv_graph_wrunlock();
150-
151- return child;
152+ return bdrv_open_child_common(filename, options, bdref_key, parent,
153+ child_class, child_role, allow_none, false,
154+ errp);
155 }
156
157 /*
158- * Wrapper on bdrv_open_child() for most popular case: open primary child of bs.
159+ * This does mostly the same as bdrv_open_child(), but for opening the primary
160+ * child of a node. A notable difference from bdrv_open_child() is that it
161+ * enables filename parsing for protocol names (including json:).
162 *
163 * The caller must hold the lock of the main AioContext and no other AioContext.
164 * @parent can move to a different AioContext in this function. Callers must
165@@ -3819,8 +3835,8 @@ int bdrv_open_file_child(const char *filename,
166 role = parent->drv->is_filter ?
167 (BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY) : BDRV_CHILD_IMAGE;
168
169- if (!bdrv_open_child(filename, options, bdref_key, parent,
170- &child_of_bds, role, false, errp))
171+ if (!bdrv_open_child_common(filename, options, bdref_key, parent,
172+ &child_of_bds, role, false, true, errp))
173 {
174 return -EINVAL;
175 }
176@@ -3865,7 +3881,8 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
177
178 }
179
180- bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, errp);
181+ bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, false,
182+ errp);
183 obj = NULL;
184 qobject_unref(obj);
185 visit_free(v);
186@@ -3962,7 +3979,7 @@ static BlockDriverState * no_coroutine_fn
187 bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
188 int flags, BlockDriverState *parent,
189 const BdrvChildClass *child_class, BdrvChildRole child_role,
190- Error **errp)
191+ bool parse_filename, Error **errp)
192 {
193 int ret;
194 BlockBackend *file = NULL;
195@@ -4011,9 +4028,11 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
196 }
197
198 /* json: syntax counts as explicit options, as if in the QDict */
199- parse_json_protocol(options, &filename, &local_err);
200- if (local_err) {
201- goto fail;
202+ if (parse_filename) {
203+ parse_json_protocol(options, &filename, &local_err);
204+ if (local_err) {
205+ goto fail;
206+ }
207 }
208
209 bs->explicit_options = qdict_clone_shallow(options);
210@@ -4038,7 +4057,8 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
211 parent->open_flags, parent->options);
212 }
213
214- ret = bdrv_fill_options(&options, filename, &flags, &local_err);
215+ ret = bdrv_fill_options(&options, filename, &flags, parse_filename,
216+ &local_err);
217 if (ret < 0) {
218 goto fail;
219 }
220@@ -4107,7 +4127,7 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
221
222 file_bs = bdrv_open_child_bs(filename, options, "file", bs,
223 &child_of_bds, BDRV_CHILD_IMAGE,
224- true, &local_err);
225+ true, true, &local_err);
226 if (local_err) {
227 goto fail;
228 }
229@@ -4270,7 +4290,7 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
230 GLOBAL_STATE_CODE();
231
232 return bdrv_open_inherit(filename, reference, options, flags, NULL,
233- NULL, 0, errp);
234+ NULL, 0, true, errp);
235 }
236
237 /* Return true if the NULL-terminated @list contains @str */
238--
2392.40.0
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0001.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0001.patch
deleted file mode 100644
index 631e93a6d2..0000000000
--- a/meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0001.patch
+++ /dev/null
@@ -1,167 +0,0 @@
1From fb1c2aaa981e0a2fa6362c9985f1296b74f055ac Mon Sep 17 00:00:00 2001
2From: Eric Blake <eblake@redhat.com>
3Date: Wed, 7 Aug 2024 08:50:01 -0500
4Subject: [PATCH] nbd/server: Plumb in new args to nbd_client_add()
5
6Upcoming patches to fix a CVE need to track an opaque pointer passed
7in by the owner of a client object, as well as request for a time
8limit on how fast negotiation must complete. Prepare for that by
9changing the signature of nbd_client_new() and adding an accessor to
10get at the opaque pointer, although for now the two servers
11(qemu-nbd.c and blockdev-nbd.c) do not change behavior even though
12they pass in a new default timeout value.
13
14Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
15Signed-off-by: Eric Blake <eblake@redhat.com>
16Message-ID: <20240807174943.771624-11-eblake@redhat.com>
17Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
18[eblake: s/LIMIT/MAX_SECS/ as suggested by Dan]
19Signed-off-by: Eric Blake <eblake@redhat.com>
20
21CVE: CVE-2024-7409
22
23Upstream-Status: Backport [https://github.com/qemu/qemu/commit/fb1c2aaa981e0a2fa6362c9985f1296b74f055ac]
24
25Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
26---
27 blockdev-nbd.c | 6 ++++--
28 include/block/nbd.h | 11 ++++++++++-
29 nbd/server.c | 20 +++++++++++++++++---
30 qemu-nbd.c | 4 +++-
31 4 files changed, 34 insertions(+), 7 deletions(-)
32
33diff --git a/blockdev-nbd.c b/blockdev-nbd.c
34index 213012435..267a1de90 100644
35--- a/blockdev-nbd.c
36+++ b/blockdev-nbd.c
37@@ -64,8 +64,10 @@ static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
38 nbd_update_server_watch(nbd_server);
39
40 qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
41- nbd_client_new(cioc, nbd_server->tlscreds, nbd_server->tlsauthz,
42- nbd_blockdev_client_closed);
43+ /* TODO - expose handshake timeout as QMP option */
44+ nbd_client_new(cioc, NBD_DEFAULT_HANDSHAKE_MAX_SECS,
45+ nbd_server->tlscreds, nbd_server->tlsauthz,
46+ nbd_blockdev_client_closed, NULL);
47 }
48
49 static void nbd_update_server_watch(NBDServerData *s)
50diff --git a/include/block/nbd.h b/include/block/nbd.h
51index 4e7bd6342..1d4d65922 100644
52--- a/include/block/nbd.h
53+++ b/include/block/nbd.h
54@@ -33,6 +33,12 @@ typedef struct NBDMetaContexts NBDMetaContexts;
55
56 extern const BlockExportDriver blk_exp_nbd;
57
58+/*
59+ * NBD_DEFAULT_HANDSHAKE_MAX_SECS: Number of seconds in which client must
60+ * succeed at NBD_OPT_GO before being forcefully dropped as too slow.
61+ */
62+#define NBD_DEFAULT_HANDSHAKE_MAX_SECS 10
63+
64 /* Handshake phase structs - this struct is passed on the wire */
65
66 typedef struct NBDOption {
67@@ -403,9 +409,12 @@ AioContext *nbd_export_aio_context(NBDExport *exp);
68 NBDExport *nbd_export_find(const char *name);
69
70 void nbd_client_new(QIOChannelSocket *sioc,
71+ uint32_t handshake_max_secs,
72 QCryptoTLSCreds *tlscreds,
73 const char *tlsauthz,
74- void (*close_fn)(NBDClient *, bool));
75+ void (*close_fn)(NBDClient *, bool),
76+ void *owner);
77+void *nbd_client_owner(NBDClient *client);
78 void nbd_client_get(NBDClient *client);
79 void nbd_client_put(NBDClient *client);
80
81diff --git a/nbd/server.c b/nbd/server.c
82index 091b57119..f8881936e 100644
83--- a/nbd/server.c
84+++ b/nbd/server.c
85@@ -124,12 +124,14 @@ struct NBDMetaContexts {
86 struct NBDClient {
87 int refcount; /* atomic */
88 void (*close_fn)(NBDClient *client, bool negotiated);
89+ void *owner;
90
91 QemuMutex lock;
92
93 NBDExport *exp;
94 QCryptoTLSCreds *tlscreds;
95 char *tlsauthz;
96+ uint32_t handshake_max_secs;
97 QIOChannelSocket *sioc; /* The underlying data channel */
98 QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
99
100@@ -3160,6 +3162,7 @@ static coroutine_fn void nbd_co_client_start(void *opaque)
101
102 qemu_co_mutex_init(&client->send_lock);
103
104+ /* TODO - utilize client->handshake_max_secs */
105 if (nbd_negotiate(client, &local_err)) {
106 if (local_err) {
107 error_report_err(local_err);
108@@ -3174,14 +3177,17 @@ static coroutine_fn void nbd_co_client_start(void *opaque)
109 }
110
111 /*
112- * Create a new client listener using the given channel @sioc.
113+ * Create a new client listener using the given channel @sioc and @owner.
114 * Begin servicing it in a coroutine. When the connection closes, call
115- * @close_fn with an indication of whether the client completed negotiation.
116+ * @close_fn with an indication of whether the client completed negotiation
117+ * within @handshake_max_secs seconds (0 for unbounded).
118 */
119 void nbd_client_new(QIOChannelSocket *sioc,
120+ uint32_t handshake_max_secs,
121 QCryptoTLSCreds *tlscreds,
122 const char *tlsauthz,
123- void (*close_fn)(NBDClient *, bool))
124+ void (*close_fn)(NBDClient *, bool),
125+ void *owner)
126 {
127 NBDClient *client;
128 Coroutine *co;
129@@ -3194,13 +3200,21 @@ void nbd_client_new(QIOChannelSocket *sioc,
130 object_ref(OBJECT(client->tlscreds));
131 }
132 client->tlsauthz = g_strdup(tlsauthz);
133+ client->handshake_max_secs = handshake_max_secs;
134 client->sioc = sioc;
135 qio_channel_set_delay(QIO_CHANNEL(sioc), false);
136 object_ref(OBJECT(client->sioc));
137 client->ioc = QIO_CHANNEL(sioc);
138 object_ref(OBJECT(client->ioc));
139 client->close_fn = close_fn;
140+ client->owner = owner;
141
142 co = qemu_coroutine_create(nbd_co_client_start, client);
143 qemu_coroutine_enter(co);
144 }
145+
146+void *
147+nbd_client_owner(NBDClient *client)
148+{
149+ return client->owner;
150+}
151diff --git a/qemu-nbd.c b/qemu-nbd.c
152index 186e6468b..5fa399c0b 100644
153--- a/qemu-nbd.c
154+++ b/qemu-nbd.c
155@@ -389,7 +389,9 @@ static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
156
157 nb_fds++;
158 nbd_update_server_watch();
159- nbd_client_new(cioc, tlscreds, tlsauthz, nbd_client_closed);
160+ /* TODO - expose handshake timeout as command line option */
161+ nbd_client_new(cioc, NBD_DEFAULT_HANDSHAKE_MAX_SECS,
162+ tlscreds, tlsauthz, nbd_client_closed, NULL);
163 }
164
165 static void nbd_update_server_watch(void)
166--
1672.40.0
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0002.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0002.patch
deleted file mode 100644
index ca8ef0b44d..0000000000
--- a/meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0002.patch
+++ /dev/null
@@ -1,175 +0,0 @@
1From c8a76dbd90c2f48df89b75bef74917f90a59b623 Mon Sep 17 00:00:00 2001
2From: Eric Blake <eblake@redhat.com>
3Date: Tue, 6 Aug 2024 13:53:00 -0500
4Subject: [PATCH] nbd/server: CVE-2024-7409: Cap default max-connections to 100
5
6Allowing an unlimited number of clients to any web service is a recipe
7for a rudimentary denial of service attack: the client merely needs to
8open lots of sockets without closing them, until qemu no longer has
9any more fds available to allocate.
10
11For qemu-nbd, we default to allowing only 1 connection unless more are
12explicitly asked for (-e or --shared); this was historically picked as
13a nice default (without an explicit -t, a non-persistent qemu-nbd goes
14away after a client disconnects, without needing any additional
15follow-up commands), and we are not going to change that interface now
16(besides, someday we want to point people towards qemu-storage-daemon
17instead of qemu-nbd).
18
19But for qemu proper, and the newer qemu-storage-daemon, the QMP
20nbd-server-start command has historically had a default of unlimited
21number of connections, in part because unlike qemu-nbd it is
22inherently persistent until nbd-server-stop. Allowing multiple client
23sockets is particularly useful for clients that can take advantage of
24MULTI_CONN (creating parallel sockets to increase throughput),
25although known clients that do so (such as libnbd's nbdcopy) typically
26use only 8 or 16 connections (the benefits of scaling diminish once
27more sockets are competing for kernel attention). Picking a number
28large enough for typical use cases, but not unlimited, makes it
29slightly harder for a malicious client to perform a denial of service
30merely by opening lots of connections withot progressing through the
31handshake.
32
33This change does not eliminate CVE-2024-7409 on its own, but reduces
34the chance for fd exhaustion or unlimited memory usage as an attack
35surface. On the other hand, by itself, it makes it more obvious that
36with a finite limit, we have the problem of an unauthenticated client
37holding 100 fds opened as a way to block out a legitimate client from
38being able to connect; thus, later patches will further add timeouts
39to reject clients that are not making progress.
40
41This is an INTENTIONAL change in behavior, and will break any client
42of nbd-server-start that was not passing an explicit max-connections
43parameter, yet expects more than 100 simultaneous connections. We are
44not aware of any such client (as stated above, most clients aware of
45MULTI_CONN get by just fine on 8 or 16 connections, and probably cope
46with later connections failing by relying on the earlier connections;
47libvirt has not yet been passing max-connections, but generally
48creates NBD servers with the intent for a single client for the sake
49of live storage migration; meanwhile, the KubeSAN project anticipates
50a large cluster sharing multiple clients [up to 8 per node, and up to
51100 nodes in a cluster], but it currently uses qemu-nbd with an
52explicit --shared=0 rather than qemu-storage-daemon with
53nbd-server-start).
54
55We considered using a deprecation period (declare that omitting
56max-parameters is deprecated, and make it mandatory in 3 releases -
57then we don't need to pick an arbitrary default); that has zero risk
58of breaking any apps that accidentally depended on more than 100
59connections, and where such breakage might not be noticed under unit
60testing but only under the larger loads of production usage. But it
61does not close the denial-of-service hole until far into the future,
62and requires all apps to change to add the parameter even if 100 was
63good enough. It also has a drawback that any app (like libvirt) that
64is accidentally relying on an unlimited default should seriously
65consider their own CVE now, at which point they are going to change to
66pass explicit max-connections sooner than waiting for 3 qemu releases.
67Finally, if our changed default breaks an app, that app can always
68pass in an explicit max-parameters with a larger value.
69
70It is also intentional that the HMP interface to nbd-server-start is
71not changed to expose max-connections (any client needing to fine-tune
72things should be using QMP).
73
74Suggested-by: Daniel P. Berrangé <berrange@redhat.com>
75Signed-off-by: Eric Blake <eblake@redhat.com>
76Message-ID: <20240807174943.771624-12-eblake@redhat.com>
77Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
78[ericb: Expand commit message to summarize Dan's argument for why we
79break corner-case back-compat behavior without a deprecation period]
80Signed-off-by: Eric Blake <eblake@redhat.com>
81
82CVE: CVE-2024-7409
83
84Upstream-Status: Backport [https://github.com/qemu/qemu/commit/c8a76dbd90c2f48df89b75bef74917f90a59b623]
85
86Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
87---
88 block/monitor/block-hmp-cmds.c | 3 ++-
89 blockdev-nbd.c | 8 ++++++++
90 include/block/nbd.h | 7 +++++++
91 qapi/block-export.json | 4 ++--
92 4 files changed, 19 insertions(+), 3 deletions(-)
93
94diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
95index c729cbf1e..78a697585 100644
96--- a/block/monitor/block-hmp-cmds.c
97+++ b/block/monitor/block-hmp-cmds.c
98@@ -415,7 +415,8 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
99 goto exit;
100 }
101
102- nbd_server_start(addr, NULL, NULL, 0, &local_err);
103+ nbd_server_start(addr, NULL, NULL, NBD_DEFAULT_MAX_CONNECTIONS,
104+ &local_err);
105 qapi_free_SocketAddress(addr);
106 if (local_err != NULL) {
107 goto exit;
108diff --git a/blockdev-nbd.c b/blockdev-nbd.c
109index 267a1de90..24ba5382d 100644
110--- a/blockdev-nbd.c
111+++ b/blockdev-nbd.c
112@@ -170,6 +170,10 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds,
113
114 void nbd_server_start_options(NbdServerOptions *arg, Error **errp)
115 {
116+ if (!arg->has_max_connections) {
117+ arg->max_connections = NBD_DEFAULT_MAX_CONNECTIONS;
118+ }
119+
120 nbd_server_start(arg->addr, arg->tls_creds, arg->tls_authz,
121 arg->max_connections, errp);
122 }
123@@ -182,6 +186,10 @@ void qmp_nbd_server_start(SocketAddressLegacy *addr,
124 {
125 SocketAddress *addr_flat = socket_address_flatten(addr);
126
127+ if (!has_max_connections) {
128+ max_connections = NBD_DEFAULT_MAX_CONNECTIONS;
129+ }
130+
131 nbd_server_start(addr_flat, tls_creds, tls_authz, max_connections, errp);
132 qapi_free_SocketAddress(addr_flat);
133 }
134diff --git a/include/block/nbd.h b/include/block/nbd.h
135index 1d4d65922..d4f8b21ae 100644
136--- a/include/block/nbd.h
137+++ b/include/block/nbd.h
138@@ -39,6 +39,13 @@ extern const BlockExportDriver blk_exp_nbd;
139 */
140 #define NBD_DEFAULT_HANDSHAKE_MAX_SECS 10
141
142+/*
143+ * NBD_DEFAULT_MAX_CONNECTIONS: Number of client sockets to allow at
144+ * once; must be large enough to allow a MULTI_CONN-aware client like
145+ * nbdcopy to create its typical number of 8-16 sockets.
146+ */
147+#define NBD_DEFAULT_MAX_CONNECTIONS 100
148+
149 /* Handshake phase structs - this struct is passed on the wire */
150
151 typedef struct NBDOption {
152diff --git a/qapi/block-export.json b/qapi/block-export.json
153index 7874a49ba..1d255d77e 100644
154--- a/qapi/block-export.json
155+++ b/qapi/block-export.json
156@@ -28,7 +28,7 @@
157 # @max-connections: The maximum number of connections to allow at the
158 # same time, 0 for unlimited. Setting this to 1 also stops the
159 # server from advertising multiple client support (since 5.2;
160-# default: 0)
161+# default: 100)
162 #
163 # Since: 4.2
164 ##
165@@ -63,7 +63,7 @@
166 # @max-connections: The maximum number of connections to allow at the
167 # same time, 0 for unlimited. Setting this to 1 also stops the
168 # server from advertising multiple client support (since 5.2;
169-# default: 0).
170+# default: 100).
171 #
172 # Returns: error if the server is already running.
173 #
174--
1752.40.0
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0003.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0003.patch
deleted file mode 100644
index b2b9b15c54..0000000000
--- a/meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0003.patch
+++ /dev/null
@@ -1,126 +0,0 @@
1From b9b72cb3ce15b693148bd09cef7e50110566d8a0 Mon Sep 17 00:00:00 2001
2From: Eric Blake <eblake@redhat.com>
3Date: Thu, 8 Aug 2024 16:05:08 -0500
4Subject: [PATCH] nbd/server: CVE-2024-7409: Drop non-negotiating clients
5
6A client that opens a socket but does not negotiate is merely hogging
7qemu's resources (an open fd and a small amount of memory); and a
8malicious client that can access the port where NBD is listening can
9attempt a denial of service attack by intentionally opening and
10abandoning lots of unfinished connections. The previous patch put a
11default bound on the number of such ongoing connections, but once that
12limit is hit, no more clients can connect (including legitimate ones).
13The solution is to insist that clients complete handshake within a
14reasonable time limit, defaulting to 10 seconds. A client that has
15not successfully completed NBD_OPT_GO by then (including the case of
16where the client didn't know TLS credentials to even reach the point
17of NBD_OPT_GO) is wasting our time and does not deserve to stay
18connected. Later patches will allow fine-tuning the limit away from
19the default value (including disabling it for doing integration
20testing of the handshake process itself).
21
22Note that this patch in isolation actually makes it more likely to see
23qemu SEGV after nbd-server-stop, as any client socket still connected
24when the server shuts down will now be closed after 10 seconds rather
25than at the client's whims. That will be addressed in the next patch.
26
27For a demo of this patch in action:
28$ qemu-nbd -f raw -r -t -e 10 file &
29$ nbdsh --opt-mode -c '
30H = list()
31for i in range(20):
32 print(i)
33 H.insert(i, nbd.NBD())
34 H[i].set_opt_mode(True)
35 H[i].connect_uri("nbd://localhost")
36'
37$ kill $!
38
39where later connections get to start progressing once earlier ones are
40forcefully dropped for taking too long, rather than hanging.
41
42Suggested-by: Daniel P. Berrangé <berrange@redhat.com>
43Signed-off-by: Eric Blake <eblake@redhat.com>
44Message-ID: <20240807174943.771624-13-eblake@redhat.com>
45Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
46[eblake: rebase to changes earlier in series, reduce scope of timer]
47Signed-off-by: Eric Blake <eblake@redhat.com>
48
49CVE: CVE-2024-7409
50
51Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/b9b72cb3ce15b693148bd09cef7e50110566d8a0]
52
53Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
54---
55 nbd/server.c | 28 +++++++++++++++++++++++++++-
56 nbd/trace-events | 1 +
57 2 files changed, 28 insertions(+), 1 deletion(-)
58
59diff --git a/nbd/server.c b/nbd/server.c
60index f8881936e..6155e329a 100644
61--- a/nbd/server.c
62+++ b/nbd/server.c
63@@ -3155,22 +3155,48 @@ static void nbd_client_receive_next_request(NBDClient *client)
64 }
65 }
66
67+static void nbd_handshake_timer_cb(void *opaque)
68+{
69+ QIOChannel *ioc = opaque;
70+
71+ trace_nbd_handshake_timer_cb();
72+ qio_channel_shutdown(ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
73+}
74+
75 static coroutine_fn void nbd_co_client_start(void *opaque)
76 {
77 NBDClient *client = opaque;
78 Error *local_err = NULL;
79+ QEMUTimer *handshake_timer = NULL;
80
81 qemu_co_mutex_init(&client->send_lock);
82
83- /* TODO - utilize client->handshake_max_secs */
84+ /*
85+ * Create a timer to bound the time spent in negotiation. If the
86+ * timer expires, it is likely nbd_negotiate will fail because the
87+ * socket was shutdown.
88+ */
89+ if (client->handshake_max_secs > 0) {
90+ handshake_timer = aio_timer_new(qemu_get_aio_context(),
91+ QEMU_CLOCK_REALTIME,
92+ SCALE_NS,
93+ nbd_handshake_timer_cb,
94+ client->sioc);
95+ timer_mod(handshake_timer,
96+ qemu_clock_get_ns(QEMU_CLOCK_REALTIME) +
97+ client->handshake_max_secs * NANOSECONDS_PER_SECOND);
98+ }
99+
100 if (nbd_negotiate(client, &local_err)) {
101 if (local_err) {
102 error_report_err(local_err);
103 }
104+ timer_free(handshake_timer);
105 client_close(client, false);
106 return;
107 }
108
109+ timer_free(handshake_timer);
110 WITH_QEMU_LOCK_GUARD(&client->lock) {
111 nbd_client_receive_next_request(client);
112 }
113diff --git a/nbd/trace-events b/nbd/trace-events
114index 00ae3216a..cbd0a4ab7 100644
115--- a/nbd/trace-events
116+++ b/nbd/trace-events
117@@ -76,6 +76,7 @@ nbd_co_receive_request_payload_received(uint64_t cookie, uint64_t len) "Payload
118 nbd_co_receive_ext_payload_compliance(uint64_t from, uint64_t len) "client sent non-compliant write without payload flag: from=0x%" PRIx64 ", len=0x%" PRIx64
119 nbd_co_receive_align_compliance(const char *op, uint64_t from, uint64_t len, uint32_t align) "client sent non-compliant unaligned %s request: from=0x%" PRIx64 ", len=0x%" PRIx64 ", align=0x%" PRIx32
120 nbd_trip(void) "Reading request"
121+nbd_handshake_timer_cb(void) "client took too long to negotiate"
122
123 # client-connection.c
124 nbd_connect_thread_sleep(uint64_t timeout) "timeout %" PRIu64
125--
1262.40.0
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0004.patch b/meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0004.patch
deleted file mode 100644
index 9515c631ad..0000000000
--- a/meta/recipes-devtools/qemu/qemu/CVE-2024-7409-0004.patch
+++ /dev/null
@@ -1,164 +0,0 @@
1From 3e7ef738c8462c45043a1d39f702a0990406a3b3 Mon Sep 17 00:00:00 2001
2From: Eric Blake <eblake@redhat.com>
3Date: Wed, 7 Aug 2024 12:23:13 -0500
4Subject: [PATCH] nbd/server: CVE-2024-7409: Close stray clients at server-stop
5
6A malicious client can attempt to connect to an NBD server, and then
7intentionally delay progress in the handshake, including if it does
8not know the TLS secrets. Although the previous two patches reduce
9this behavior by capping the default max-connections parameter and
10killing slow clients, they did not eliminate the possibility of a
11client waiting to close the socket until after the QMP nbd-server-stop
12command is executed, at which point qemu would SEGV when trying to
13dereference the NULL nbd_server global which is no longer present.
14This amounts to a denial of service attack. Worse, if another NBD
15server is started before the malicious client disconnects, I cannot
16rule out additional adverse effects when the old client interferes
17with the connection count of the new server (although the most likely
18is a crash due to an assertion failure when checking
19nbd_server->connections > 0).
20
21For environments without this patch, the CVE can be mitigated by
22ensuring (such as via a firewall) that only trusted clients can
23connect to an NBD server. Note that using frameworks like libvirt
24that ensure that TLS is used and that nbd-server-stop is not executed
25while any trusted clients are still connected will only help if there
26is also no possibility for an untrusted client to open a connection
27but then stall on the NBD handshake.
28
29Given the previous patches, it would be possible to guarantee that no
30clients remain connected by having nbd-server-stop sleep for longer
31than the default handshake deadline before finally freeing the global
32nbd_server object, but that could make QMP non-responsive for a long
33time. So intead, this patch fixes the problem by tracking all client
34sockets opened while the server is running, and forcefully closing any
35such sockets remaining without a completed handshake at the time of
36nbd-server-stop, then waiting until the coroutines servicing those
37sockets notice the state change. nbd-server-stop now has a second
38AIO_WAIT_WHILE_UNLOCKED (the first is indirectly through the
39blk_exp_close_all_type() that disconnects all clients that completed
40handshakes), but forced socket shutdown is enough to progress the
41coroutines and quickly tear down all clients before the server is
42freed, thus finally fixing the CVE.
43
44This patch relies heavily on the fact that nbd/server.c guarantees
45that it only calls nbd_blockdev_client_closed() from the main loop
46(see the assertion in nbd_client_put() and the hoops used in
47nbd_client_put_nonzero() to achieve that); if we did not have that
48guarantee, we would also need a mutex protecting our accesses of the
49list of connections to survive re-entrancy from independent iothreads.
50
51Although I did not actually try to test old builds, it looks like this
52problem has existed since at least commit 862172f45c (v2.12.0, 2017) -
53even back when that patch started using a QIONetListener to handle
54listening on multiple sockets, nbd_server_free() was already unaware
55that the nbd_blockdev_client_closed callback can be reached later by a
56client thread that has not completed handshakes (and therefore the
57client's socket never got added to the list closed in
58nbd_export_close_all), despite that patch intentionally tearing down
59the QIONetListener to prevent new clients.
60
61Reported-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
62Fixes: CVE-2024-7409
63CC: qemu-stable@nongnu.org
64Signed-off-by: Eric Blake <eblake@redhat.com>
65Message-ID: <20240807174943.771624-14-eblake@redhat.com>
66Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
67
68CVE: CVE-2024-7409
69
70Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/3e7ef738c8462c45043a1d39f702a0990406a3b3]
71
72Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
73---
74 blockdev-nbd.c | 35 ++++++++++++++++++++++++++++++++++-
75 1 file changed, 34 insertions(+), 1 deletion(-)
76
77diff --git a/blockdev-nbd.c b/blockdev-nbd.c
78index 24ba5382d..f73409ae4 100644
79--- a/blockdev-nbd.c
80+++ b/blockdev-nbd.c
81@@ -21,12 +21,18 @@
82 #include "io/channel-socket.h"
83 #include "io/net-listener.h"
84
85+typedef struct NBDConn {
86+ QIOChannelSocket *cioc;
87+ QLIST_ENTRY(NBDConn) next;
88+} NBDConn;
89+
90 typedef struct NBDServerData {
91 QIONetListener *listener;
92 QCryptoTLSCreds *tlscreds;
93 char *tlsauthz;
94 uint32_t max_connections;
95 uint32_t connections;
96+ QLIST_HEAD(, NBDConn) conns;
97 } NBDServerData;
98
99 static NBDServerData *nbd_server;
100@@ -51,6 +57,14 @@ int nbd_server_max_connections(void)
101
102 static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
103 {
104+ NBDConn *conn = nbd_client_owner(client);
105+
106+ assert(qemu_in_main_thread() && nbd_server);
107+
108+ object_unref(OBJECT(conn->cioc));
109+ QLIST_REMOVE(conn, next);
110+ g_free(conn);
111+
112 nbd_client_put(client);
113 assert(nbd_server->connections > 0);
114 nbd_server->connections--;
115@@ -60,14 +74,20 @@ static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
116 static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
117 gpointer opaque)
118 {
119+ NBDConn *conn = g_new0(NBDConn, 1);
120+
121+ assert(qemu_in_main_thread() && nbd_server);
122 nbd_server->connections++;
123+ object_ref(OBJECT(cioc));
124+ conn->cioc = cioc;
125+ QLIST_INSERT_HEAD(&nbd_server->conns, conn, next);
126 nbd_update_server_watch(nbd_server);
127
128 qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
129 /* TODO - expose handshake timeout as QMP option */
130 nbd_client_new(cioc, NBD_DEFAULT_HANDSHAKE_MAX_SECS,
131 nbd_server->tlscreds, nbd_server->tlsauthz,
132- nbd_blockdev_client_closed, NULL);
133+ nbd_blockdev_client_closed, conn);
134 }
135
136 static void nbd_update_server_watch(NBDServerData *s)
137@@ -81,12 +101,25 @@ static void nbd_update_server_watch(NBDServerData *s)
138
139 static void nbd_server_free(NBDServerData *server)
140 {
141+ NBDConn *conn, *tmp;
142+
143 if (!server) {
144 return;
145 }
146
147+ /*
148+ * Forcefully close the listener socket, and any clients that have
149+ * not yet disconnected on their own.
150+ */
151 qio_net_listener_disconnect(server->listener);
152 object_unref(OBJECT(server->listener));
153+ QLIST_FOREACH_SAFE(conn, &server->conns, next, tmp) {
154+ qio_channel_shutdown(QIO_CHANNEL(conn->cioc), QIO_CHANNEL_SHUTDOWN_BOTH,
155+ NULL);
156+ }
157+
158+ AIO_WAIT_WHILE_UNLOCKED(NULL, server->connections > 0);
159+
160 if (server->tlscreds) {
161 object_unref(OBJECT(server->tlscreds));
162 }
163--
1642.40.0
diff --git a/meta/recipes-devtools/qemu/qemu_8.2.3.bb b/meta/recipes-devtools/qemu/qemu_8.2.7.bb
index dc1352232e..dc1352232e 100644
--- a/meta/recipes-devtools/qemu/qemu_8.2.3.bb
+++ b/meta/recipes-devtools/qemu/qemu_8.2.7.bb