diff options
author | Yogita Urade <yogita.urade@windriver.com> | 2024-11-29 08:17:08 +0000 |
---|---|---|
committer | Steve Sakoman <steve@sakoman.com> | 2024-12-06 05:50:25 -0800 |
commit | 2775596cb24e22c016dca604c27b945a3c02514d (patch) | |
tree | 411f1c19b4d29e9426c11376653c3f5f8abb129a | |
parent | c6ec0e1bfd648e7fcb345be6829bf1f663933a89 (diff) | |
download | poky-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>
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 | " |
56 | UPSTREAM_CHECK_REGEX = "qemu-(?P<pver>\d+(\.\d+)+)\.tar" | 44 | UPSTREAM_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 | ||
71 | SRC_URI[sha256sum] = "dc747fb366809455317601c4876bd1f6829a32a23e83fb76e45ab12c2a569964" | 59 | SRC_URI[sha256sum] = "1f0604f296ab9acb4854c054764a1ba408643fc299bd54a6500cccfaaca65b55" |
72 | 60 | ||
73 | CVE_STATUS[CVE-2007-0998] = "not-applicable-config: The VNC server can expose host files uder some circumstances. We don't enable it by default." | 61 | CVE_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 @@ | |||
1 | From bbdcc89678daa5cb131ef22a6cd41a5f7f9dcea9 Mon Sep 17 00:00:00 2001 | ||
2 | From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> | ||
3 | Date: Fri, 8 Dec 2023 15:38:31 -0300 | ||
4 | Subject: [PATCH 1/3] target/riscv/kvm: change KVM_REG_RISCV_FP_F to u32 | ||
5 | |||
6 | KVM_REG_RISCV_FP_F regs have u32 size according to the API, but by using | ||
7 | kvm_riscv_reg_id() in RISCV_FP_F_REG() we're returning u64 sizes when | ||
8 | running with TARGET_RISCV64. The most likely reason why no one noticed | ||
9 | this is because we're not implementing kvm_cpu_synchronize_state() in | ||
10 | RISC-V yet. | ||
11 | |||
12 | Create a new helper that returns a KVM ID with u32 size and use it in | ||
13 | RISCV_FP_F_REG(). | ||
14 | |||
15 | Reported-by: Andrew Jones <ajones@ventanamicro.com> | ||
16 | Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> | ||
17 | Reviewed-by: Andrew Jones <ajones@ventanamicro.com> | ||
18 | Message-ID: <20231208183835.2411523-2-dbarboza@ventanamicro.com> | ||
19 | Signed-off-by: Alistair Francis <alistair.francis@wdc.com> | ||
20 | (cherry picked from commit 49c211ffca00fdf7c0c29072c224e88527a14838) | ||
21 | Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> | ||
22 | |||
23 | Upstream-Status: Backport [bbdcc89678daa5cb131ef22a6cd41a5f7f9dcea9] | ||
24 | |||
25 | Signed-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 | |||
30 | diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c | ||
31 | index 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), ®); | ||
60 | + ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(i), ®); | ||
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), ®); | ||
69 | + ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(i), ®); | ||
70 | if (ret) { | ||
71 | return ret; | ||
72 | } | ||
73 | -- | ||
74 | 2.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 @@ | |||
1 | From 125b95d79e746cbab6b72683b3382dd372e38c61 Mon Sep 17 00:00:00 2001 | ||
2 | From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> | ||
3 | Date: Fri, 8 Dec 2023 15:38:32 -0300 | ||
4 | Subject: [PATCH 2/3] target/riscv/kvm: change KVM_REG_RISCV_FP_D to u64 | ||
5 | |||
6 | KVM_REG_RISCV_FP_D regs are always u64 size. Using kvm_riscv_reg_id() in | ||
7 | RISCV_FP_D_REG() ends up encoding the wrong size if we're running with | ||
8 | TARGET_RISCV32. | ||
9 | |||
10 | Create a new helper that returns a KVM ID with u64 size and use it with | ||
11 | RISCV_FP_D_REG(). | ||
12 | |||
13 | Reported-by: Andrew Jones <ajones@ventanamicro.com> | ||
14 | Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> | ||
15 | Reviewed-by: Andrew Jones <ajones@ventanamicro.com> | ||
16 | Message-ID: <20231208183835.2411523-3-dbarboza@ventanamicro.com> | ||
17 | Signed-off-by: Alistair Francis <alistair.francis@wdc.com> | ||
18 | (cherry picked from commit 450bd6618fda3d2e2ab02b2fce1c79efd5b66084) | ||
19 | Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> | ||
20 | |||
21 | Upstream-Status: Backport [125b95d79e746cbab6b72683b3382dd372e38c61] | ||
22 | |||
23 | Signed-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 | |||
28 | diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c | ||
29 | index 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), ®); | ||
58 | + ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(i), ®); | ||
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), ®); | ||
67 | + ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(i), ®); | ||
68 | if (ret) { | ||
69 | return ret; | ||
70 | } | ||
71 | -- | ||
72 | 2.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 @@ | |||
1 | From cbae1080988e0f1af0fb4c816205f7647f6de16f Mon Sep 17 00:00:00 2001 | ||
2 | From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> | ||
3 | Date: Fri, 8 Dec 2023 15:38:33 -0300 | ||
4 | Subject: [PATCH 3/3] target/riscv/kvm: change timer regs size to u64 | ||
5 | |||
6 | KVM_REG_RISCV_TIMER regs are always u64 according to the KVM API, but at | ||
7 | this moment we'll return u32 regs if we're running a RISCV32 target. | ||
8 | |||
9 | Use the kvm_riscv_reg_id_u64() helper in RISCV_TIMER_REG() to fix it. | ||
10 | |||
11 | Reported-by: Andrew Jones <ajones@ventanamicro.com> | ||
12 | Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> | ||
13 | Reviewed-by: Andrew Jones <ajones@ventanamicro.com> | ||
14 | Message-ID: <20231208183835.2411523-4-dbarboza@ventanamicro.com> | ||
15 | Signed-off-by: Alistair Francis <alistair.francis@wdc.com> | ||
16 | (cherry picked from commit 10f86d1b845087d14b58d65dd2a6e3411d1b6529) | ||
17 | Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> | ||
18 | |||
19 | Upstream-Status: Backport [cbae1080988e0f1af0fb4c816205f7647f6de16f] | ||
20 | |||
21 | Signed-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 | |||
26 | diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c | ||
27 | index 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), ®); \ | ||
47 | + int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(name), ®); \ | ||
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), ®); \ | ||
57 | + int ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(name), ®); \ | ||
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 | -- | ||
106 | 2.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 @@ | |||
1 | From bd385a5298d7062668e804d73944d52aec9549f1 Mon Sep 17 00:00:00 2001 | ||
2 | From: Kevin Wolf <kwolf@redhat.com> | ||
3 | Date: Fri, 16 Aug 2024 08:29:04 +0000 | ||
4 | Subject: [PATCH] qcow2: Don't open data_file with BDRV_O_NO_IO | ||
5 | |||
6 | One use case for 'qemu-img info' is verifying that untrusted images | ||
7 | don't reference an unwanted external file, be it as a backing file or an | ||
8 | external data file. To make sure that calling 'qemu-img info' can't | ||
9 | already have undesired side effects with a malicious image, just don't | ||
10 | open the data file at all with BDRV_O_NO_IO. If nothing ever tries to do | ||
11 | I/O, we don't need to have it open. | ||
12 | |||
13 | This changes the output of iotests case 061, which used 'qemu-img info' | ||
14 | to show that opening an image with an invalid data file fails. After | ||
15 | this patch, it succeeds. Replace this part of the test with a qemu-io | ||
16 | call, but keep the final 'qemu-img info' to show that the invalid data | ||
17 | file is correctly displayed in the output. | ||
18 | |||
19 | Fixes: CVE-2024-4467 | ||
20 | Cc: qemu-stable@nongnu.org | ||
21 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
22 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
23 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
24 | Reviewed-by: Hanna Czenczek <hreitz@redhat.com> | ||
25 | |||
26 | CVE: CVE-2024-4667 | ||
27 | Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/bd385a5298d7062668e804d73944d52aec9549f1] | ||
28 | |||
29 | Signed-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 | |||
36 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
37 | index 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, | ||
64 | diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061 | ||
65 | index 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 | ||
85 | diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out | ||
86 | index 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 | -- | ||
112 | 2.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 @@ | |||
1 | From 2eb42a728d27a43fdcad5f37d3f65706ce6deba5 Mon Sep 17 00:00:00 2001 | ||
2 | From: Kevin Wolf <kwolf@redhat.com> | ||
3 | Date: Fri, 16 Aug 2024 09:35:24 +0000 | ||
4 | Subject: [PATCH] iotests/244: Don't store data-file with protocol in image | ||
5 | |||
6 | We want to disable filename parsing for data files because it's too easy | ||
7 | to abuse in malicious image files. Make the test ready for the change by | ||
8 | passing the data file explicitly in command line options. | ||
9 | |||
10 | Cc: qemu-stable@nongnu.org | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
13 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | Reviewed-by: Hanna Czenczek <hreitz@redhat.com> | ||
15 | |||
16 | CVE: CVE-2024-4467 | ||
17 | Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/2eb42a728d27a43fdcad5f37d3f65706ce6deba5] | ||
18 | |||
19 | Signed-off-by: Yogita Urade <yogita.urade@windriver.com> | ||
20 | --- | ||
21 | tests/qemu-iotests/244 | 19 ++++++++++++++++--- | ||
22 | 1 file changed, 16 insertions(+), 3 deletions(-) | ||
23 | |||
24 | diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244 | ||
25 | index 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 | -- | ||
55 | 2.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 @@ | |||
1 | From 7e1110664ecbc4826f3c978ccb06b6c1bce823e6 Mon Sep 17 00:00:00 2001 | ||
2 | From: Kevin Wolf <kwolf@redhat.com> | ||
3 | Date: Fri, 16 Aug 2024 10:24:58 +0000 | ||
4 | Subject: [PATCH] iotests/270: Don't store data-file with json: prefix in image | ||
5 | |||
6 | We want to disable filename parsing for data files because it's too easy | ||
7 | to abuse in malicious image files. Make the test ready for the change by | ||
8 | passing the data file explicitly in command line options. | ||
9 | |||
10 | Cc: qemu-stable@nongnu.org | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
13 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | Reviewed-by: Hanna Czenczek <hreitz@redhat.com> | ||
15 | |||
16 | CVE: CVE-2024-4467 | ||
17 | Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/7e1110664ecbc4826f3c978ccb06b6c1bce823e6] | ||
18 | |||
19 | Signed-off-by: Yogita Urade <yogita.urade@windriver.com> | ||
20 | --- | ||
21 | tests/qemu-iotests/270 | 14 +++++++++++--- | ||
22 | 1 file changed, 11 insertions(+), 3 deletions(-) | ||
23 | |||
24 | diff --git a/tests/qemu-iotests/270 b/tests/qemu-iotests/270 | ||
25 | index 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 | -- | ||
57 | 2.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 @@ | |||
1 | From 6bc30f19498547fac9cef98316a65cf6c1f14205 Mon Sep 17 00:00:00 2001 | ||
2 | From: Stefan Hajnoczi <stefanha@redhat.com> | ||
3 | Date: Tue, 5 Dec 2023 13:20:02 -0500 | ||
4 | Subject: [PATCH] graph-lock: remove AioContext locking | ||
5 | |||
6 | Stop acquiring/releasing the AioContext lock in | ||
7 | bdrv_graph_wrlock()/bdrv_graph_unlock() since the lock no longer has any | ||
8 | effect. | ||
9 | |||
10 | The distinction between bdrv_graph_wrunlock() and | ||
11 | bdrv_graph_wrunlock_ctx() becomes meaningless and they can be collapsed | ||
12 | into one function. | ||
13 | |||
14 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
15 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
16 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
17 | Message-ID: <20231205182011.1976568-6-stefanha@redhat.com> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
19 | |||
20 | CVE: CVE-2024-4467 | ||
21 | Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/6bc30f19498547fac9cef98316a65cf6c1f14205] | ||
22 | |||
23 | Signed-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 | |||
47 | diff --git a/block.c b/block.c | ||
48 | index 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); | ||
237 | diff --git a/block/backup.c b/block/backup.c | ||
238 | index 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 | |||
254 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | ||
255 | index 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 | ||
283 | diff --git a/block/blkverify.c b/block/blkverify.c | ||
284 | index 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 | ||
300 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
301 | index 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 | } | ||
344 | diff --git a/block/commit.c b/block/commit.c | ||
345 | index 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 | } | ||
404 | diff --git a/block/graph-lock.c b/block/graph-lock.c | ||
405 | index 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) | ||
484 | diff --git a/block/mirror.c b/block/mirror.c | ||
485 | index 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); | ||
570 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
571 | index 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 | } | ||
586 | diff --git a/block/quorum.c b/block/quorum.c | ||
587 | index 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 | } | ||
621 | diff --git a/block/replication.c b/block/replication.c | ||
622 | index 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 { | ||
685 | diff --git a/block/snapshot.c b/block/snapshot.c | ||
686 | index 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); | ||
701 | diff --git a/block/stream.c b/block/stream.c | ||
702 | index 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; | ||
744 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
745 | index 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; | ||
814 | diff --git a/blockdev.c b/blockdev.c | ||
815 | index 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) | ||
848 | diff --git a/blockjob.c b/blockjob.c | ||
849 | index 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 | } | ||
902 | diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h | ||
903 | index 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: | ||
943 | diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py | ||
944 | index 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 | /* | ||
958 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c | ||
959 | index 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); | ||
1105 | diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c | ||
1106 | index 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 | -- | ||
1187 | 2.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 @@ | |||
1 | From 7ead946998610657d38d1a505d5f25300d4ca613 Mon Sep 17 00:00:00 2001 | ||
2 | From: Kevin Wolf <kwolf@redhat.com> | ||
3 | Date: Thu, 25 Apr 2024 14:56:02 +0000 | ||
4 | Subject: [PATCH] block: Parse filenames only when explicitly requested | ||
5 | |||
6 | When handling image filenames from legacy options such as -drive or from | ||
7 | tools, these filenames are parsed for protocol prefixes, including for | ||
8 | the json:{} pseudo-protocol. | ||
9 | |||
10 | This behaviour is intended for filenames that come directly from the | ||
11 | command line and for backing files, which may come from the image file | ||
12 | itself. Higher level management tools generally take care to verify that | ||
13 | untrusted images don't contain a bad (or any) backing file reference; | ||
14 | 'qemu-img info' is a suitable tool for this. | ||
15 | |||
16 | However, for other files that can be referenced in images, such as | ||
17 | qcow2 data files or VMDK extents, the string from the image file is | ||
18 | usually not verified by management tools - and 'qemu-img info' wouldn't | ||
19 | be suitable because in contrast to backing files, it already opens these | ||
20 | other referenced files. So here the string should be interpreted as a | ||
21 | literal local filename. More complex configurations need to be specified | ||
22 | explicitly on the command line or in QMP... | ||
23 | |||
24 | CVE: CVE-2024-4467 | ||
25 | Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/7ead946998610657d38d1a505d5f25300d4ca613] | ||
26 | |||
27 | Signed-off-by: Yogita Urade <yogita.urade@windriver.com> | ||
28 | --- | ||
29 | block.c | 94 ++++++++++++++++++++++++++++++++++----------------------- | ||
30 | 1 file changed, 57 insertions(+), 37 deletions(-) | ||
31 | |||
32 | diff --git a/block.c b/block.c | ||
33 | index 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 | -- | ||
239 | 2.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 @@ | |||
1 | From fb1c2aaa981e0a2fa6362c9985f1296b74f055ac Mon Sep 17 00:00:00 2001 | ||
2 | From: Eric Blake <eblake@redhat.com> | ||
3 | Date: Wed, 7 Aug 2024 08:50:01 -0500 | ||
4 | Subject: [PATCH] nbd/server: Plumb in new args to nbd_client_add() | ||
5 | |||
6 | Upcoming patches to fix a CVE need to track an opaque pointer passed | ||
7 | in by the owner of a client object, as well as request for a time | ||
8 | limit on how fast negotiation must complete. Prepare for that by | ||
9 | changing the signature of nbd_client_new() and adding an accessor to | ||
10 | get at the opaque pointer, although for now the two servers | ||
11 | (qemu-nbd.c and blockdev-nbd.c) do not change behavior even though | ||
12 | they pass in a new default timeout value. | ||
13 | |||
14 | Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
15 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
16 | Message-ID: <20240807174943.771624-11-eblake@redhat.com> | ||
17 | Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> | ||
18 | [eblake: s/LIMIT/MAX_SECS/ as suggested by Dan] | ||
19 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
20 | |||
21 | CVE: CVE-2024-7409 | ||
22 | |||
23 | Upstream-Status: Backport [https://github.com/qemu/qemu/commit/fb1c2aaa981e0a2fa6362c9985f1296b74f055ac] | ||
24 | |||
25 | Signed-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 | |||
33 | diff --git a/blockdev-nbd.c b/blockdev-nbd.c | ||
34 | index 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) | ||
50 | diff --git a/include/block/nbd.h b/include/block/nbd.h | ||
51 | index 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 | |||
81 | diff --git a/nbd/server.c b/nbd/server.c | ||
82 | index 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 | +} | ||
151 | diff --git a/qemu-nbd.c b/qemu-nbd.c | ||
152 | index 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 | -- | ||
167 | 2.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 @@ | |||
1 | From c8a76dbd90c2f48df89b75bef74917f90a59b623 Mon Sep 17 00:00:00 2001 | ||
2 | From: Eric Blake <eblake@redhat.com> | ||
3 | Date: Tue, 6 Aug 2024 13:53:00 -0500 | ||
4 | Subject: [PATCH] nbd/server: CVE-2024-7409: Cap default max-connections to 100 | ||
5 | |||
6 | Allowing an unlimited number of clients to any web service is a recipe | ||
7 | for a rudimentary denial of service attack: the client merely needs to | ||
8 | open lots of sockets without closing them, until qemu no longer has | ||
9 | any more fds available to allocate. | ||
10 | |||
11 | For qemu-nbd, we default to allowing only 1 connection unless more are | ||
12 | explicitly asked for (-e or --shared); this was historically picked as | ||
13 | a nice default (without an explicit -t, a non-persistent qemu-nbd goes | ||
14 | away after a client disconnects, without needing any additional | ||
15 | follow-up commands), and we are not going to change that interface now | ||
16 | (besides, someday we want to point people towards qemu-storage-daemon | ||
17 | instead of qemu-nbd). | ||
18 | |||
19 | But for qemu proper, and the newer qemu-storage-daemon, the QMP | ||
20 | nbd-server-start command has historically had a default of unlimited | ||
21 | number of connections, in part because unlike qemu-nbd it is | ||
22 | inherently persistent until nbd-server-stop. Allowing multiple client | ||
23 | sockets is particularly useful for clients that can take advantage of | ||
24 | MULTI_CONN (creating parallel sockets to increase throughput), | ||
25 | although known clients that do so (such as libnbd's nbdcopy) typically | ||
26 | use only 8 or 16 connections (the benefits of scaling diminish once | ||
27 | more sockets are competing for kernel attention). Picking a number | ||
28 | large enough for typical use cases, but not unlimited, makes it | ||
29 | slightly harder for a malicious client to perform a denial of service | ||
30 | merely by opening lots of connections withot progressing through the | ||
31 | handshake. | ||
32 | |||
33 | This change does not eliminate CVE-2024-7409 on its own, but reduces | ||
34 | the chance for fd exhaustion or unlimited memory usage as an attack | ||
35 | surface. On the other hand, by itself, it makes it more obvious that | ||
36 | with a finite limit, we have the problem of an unauthenticated client | ||
37 | holding 100 fds opened as a way to block out a legitimate client from | ||
38 | being able to connect; thus, later patches will further add timeouts | ||
39 | to reject clients that are not making progress. | ||
40 | |||
41 | This is an INTENTIONAL change in behavior, and will break any client | ||
42 | of nbd-server-start that was not passing an explicit max-connections | ||
43 | parameter, yet expects more than 100 simultaneous connections. We are | ||
44 | not aware of any such client (as stated above, most clients aware of | ||
45 | MULTI_CONN get by just fine on 8 or 16 connections, and probably cope | ||
46 | with later connections failing by relying on the earlier connections; | ||
47 | libvirt has not yet been passing max-connections, but generally | ||
48 | creates NBD servers with the intent for a single client for the sake | ||
49 | of live storage migration; meanwhile, the KubeSAN project anticipates | ||
50 | a large cluster sharing multiple clients [up to 8 per node, and up to | ||
51 | 100 nodes in a cluster], but it currently uses qemu-nbd with an | ||
52 | explicit --shared=0 rather than qemu-storage-daemon with | ||
53 | nbd-server-start). | ||
54 | |||
55 | We considered using a deprecation period (declare that omitting | ||
56 | max-parameters is deprecated, and make it mandatory in 3 releases - | ||
57 | then we don't need to pick an arbitrary default); that has zero risk | ||
58 | of breaking any apps that accidentally depended on more than 100 | ||
59 | connections, and where such breakage might not be noticed under unit | ||
60 | testing but only under the larger loads of production usage. But it | ||
61 | does not close the denial-of-service hole until far into the future, | ||
62 | and requires all apps to change to add the parameter even if 100 was | ||
63 | good enough. It also has a drawback that any app (like libvirt) that | ||
64 | is accidentally relying on an unlimited default should seriously | ||
65 | consider their own CVE now, at which point they are going to change to | ||
66 | pass explicit max-connections sooner than waiting for 3 qemu releases. | ||
67 | Finally, if our changed default breaks an app, that app can always | ||
68 | pass in an explicit max-parameters with a larger value. | ||
69 | |||
70 | It is also intentional that the HMP interface to nbd-server-start is | ||
71 | not changed to expose max-connections (any client needing to fine-tune | ||
72 | things should be using QMP). | ||
73 | |||
74 | Suggested-by: Daniel P. Berrangé <berrange@redhat.com> | ||
75 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
76 | Message-ID: <20240807174943.771624-12-eblake@redhat.com> | ||
77 | Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> | ||
78 | [ericb: Expand commit message to summarize Dan's argument for why we | ||
79 | break corner-case back-compat behavior without a deprecation period] | ||
80 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
81 | |||
82 | CVE: CVE-2024-7409 | ||
83 | |||
84 | Upstream-Status: Backport [https://github.com/qemu/qemu/commit/c8a76dbd90c2f48df89b75bef74917f90a59b623] | ||
85 | |||
86 | Signed-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 | |||
94 | diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c | ||
95 | index 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; | ||
108 | diff --git a/blockdev-nbd.c b/blockdev-nbd.c | ||
109 | index 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 | } | ||
134 | diff --git a/include/block/nbd.h b/include/block/nbd.h | ||
135 | index 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 { | ||
152 | diff --git a/qapi/block-export.json b/qapi/block-export.json | ||
153 | index 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 | -- | ||
175 | 2.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 @@ | |||
1 | From b9b72cb3ce15b693148bd09cef7e50110566d8a0 Mon Sep 17 00:00:00 2001 | ||
2 | From: Eric Blake <eblake@redhat.com> | ||
3 | Date: Thu, 8 Aug 2024 16:05:08 -0500 | ||
4 | Subject: [PATCH] nbd/server: CVE-2024-7409: Drop non-negotiating clients | ||
5 | |||
6 | A client that opens a socket but does not negotiate is merely hogging | ||
7 | qemu's resources (an open fd and a small amount of memory); and a | ||
8 | malicious client that can access the port where NBD is listening can | ||
9 | attempt a denial of service attack by intentionally opening and | ||
10 | abandoning lots of unfinished connections. The previous patch put a | ||
11 | default bound on the number of such ongoing connections, but once that | ||
12 | limit is hit, no more clients can connect (including legitimate ones). | ||
13 | The solution is to insist that clients complete handshake within a | ||
14 | reasonable time limit, defaulting to 10 seconds. A client that has | ||
15 | not successfully completed NBD_OPT_GO by then (including the case of | ||
16 | where the client didn't know TLS credentials to even reach the point | ||
17 | of NBD_OPT_GO) is wasting our time and does not deserve to stay | ||
18 | connected. Later patches will allow fine-tuning the limit away from | ||
19 | the default value (including disabling it for doing integration | ||
20 | testing of the handshake process itself). | ||
21 | |||
22 | Note that this patch in isolation actually makes it more likely to see | ||
23 | qemu SEGV after nbd-server-stop, as any client socket still connected | ||
24 | when the server shuts down will now be closed after 10 seconds rather | ||
25 | than at the client's whims. That will be addressed in the next patch. | ||
26 | |||
27 | For a demo of this patch in action: | ||
28 | $ qemu-nbd -f raw -r -t -e 10 file & | ||
29 | $ nbdsh --opt-mode -c ' | ||
30 | H = list() | ||
31 | for 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 | |||
39 | where later connections get to start progressing once earlier ones are | ||
40 | forcefully dropped for taking too long, rather than hanging. | ||
41 | |||
42 | Suggested-by: Daniel P. Berrangé <berrange@redhat.com> | ||
43 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
44 | Message-ID: <20240807174943.771624-13-eblake@redhat.com> | ||
45 | Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> | ||
46 | [eblake: rebase to changes earlier in series, reduce scope of timer] | ||
47 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
48 | |||
49 | CVE: CVE-2024-7409 | ||
50 | |||
51 | Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/b9b72cb3ce15b693148bd09cef7e50110566d8a0] | ||
52 | |||
53 | Signed-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 | |||
59 | diff --git a/nbd/server.c b/nbd/server.c | ||
60 | index 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 | } | ||
113 | diff --git a/nbd/trace-events b/nbd/trace-events | ||
114 | index 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 | -- | ||
126 | 2.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 @@ | |||
1 | From 3e7ef738c8462c45043a1d39f702a0990406a3b3 Mon Sep 17 00:00:00 2001 | ||
2 | From: Eric Blake <eblake@redhat.com> | ||
3 | Date: Wed, 7 Aug 2024 12:23:13 -0500 | ||
4 | Subject: [PATCH] nbd/server: CVE-2024-7409: Close stray clients at server-stop | ||
5 | |||
6 | A malicious client can attempt to connect to an NBD server, and then | ||
7 | intentionally delay progress in the handshake, including if it does | ||
8 | not know the TLS secrets. Although the previous two patches reduce | ||
9 | this behavior by capping the default max-connections parameter and | ||
10 | killing slow clients, they did not eliminate the possibility of a | ||
11 | client waiting to close the socket until after the QMP nbd-server-stop | ||
12 | command is executed, at which point qemu would SEGV when trying to | ||
13 | dereference the NULL nbd_server global which is no longer present. | ||
14 | This amounts to a denial of service attack. Worse, if another NBD | ||
15 | server is started before the malicious client disconnects, I cannot | ||
16 | rule out additional adverse effects when the old client interferes | ||
17 | with the connection count of the new server (although the most likely | ||
18 | is a crash due to an assertion failure when checking | ||
19 | nbd_server->connections > 0). | ||
20 | |||
21 | For environments without this patch, the CVE can be mitigated by | ||
22 | ensuring (such as via a firewall) that only trusted clients can | ||
23 | connect to an NBD server. Note that using frameworks like libvirt | ||
24 | that ensure that TLS is used and that nbd-server-stop is not executed | ||
25 | while any trusted clients are still connected will only help if there | ||
26 | is also no possibility for an untrusted client to open a connection | ||
27 | but then stall on the NBD handshake. | ||
28 | |||
29 | Given the previous patches, it would be possible to guarantee that no | ||
30 | clients remain connected by having nbd-server-stop sleep for longer | ||
31 | than the default handshake deadline before finally freeing the global | ||
32 | nbd_server object, but that could make QMP non-responsive for a long | ||
33 | time. So intead, this patch fixes the problem by tracking all client | ||
34 | sockets opened while the server is running, and forcefully closing any | ||
35 | such sockets remaining without a completed handshake at the time of | ||
36 | nbd-server-stop, then waiting until the coroutines servicing those | ||
37 | sockets notice the state change. nbd-server-stop now has a second | ||
38 | AIO_WAIT_WHILE_UNLOCKED (the first is indirectly through the | ||
39 | blk_exp_close_all_type() that disconnects all clients that completed | ||
40 | handshakes), but forced socket shutdown is enough to progress the | ||
41 | coroutines and quickly tear down all clients before the server is | ||
42 | freed, thus finally fixing the CVE. | ||
43 | |||
44 | This patch relies heavily on the fact that nbd/server.c guarantees | ||
45 | that it only calls nbd_blockdev_client_closed() from the main loop | ||
46 | (see the assertion in nbd_client_put() and the hoops used in | ||
47 | nbd_client_put_nonzero() to achieve that); if we did not have that | ||
48 | guarantee, we would also need a mutex protecting our accesses of the | ||
49 | list of connections to survive re-entrancy from independent iothreads. | ||
50 | |||
51 | Although I did not actually try to test old builds, it looks like this | ||
52 | problem has existed since at least commit 862172f45c (v2.12.0, 2017) - | ||
53 | even back when that patch started using a QIONetListener to handle | ||
54 | listening on multiple sockets, nbd_server_free() was already unaware | ||
55 | that the nbd_blockdev_client_closed callback can be reached later by a | ||
56 | client thread that has not completed handshakes (and therefore the | ||
57 | client's socket never got added to the list closed in | ||
58 | nbd_export_close_all), despite that patch intentionally tearing down | ||
59 | the QIONetListener to prevent new clients. | ||
60 | |||
61 | Reported-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com> | ||
62 | Fixes: CVE-2024-7409 | ||
63 | CC: qemu-stable@nongnu.org | ||
64 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
65 | Message-ID: <20240807174943.771624-14-eblake@redhat.com> | ||
66 | Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> | ||
67 | |||
68 | CVE: CVE-2024-7409 | ||
69 | |||
70 | Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/3e7ef738c8462c45043a1d39f702a0990406a3b3] | ||
71 | |||
72 | Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com> | ||
73 | --- | ||
74 | blockdev-nbd.c | 35 ++++++++++++++++++++++++++++++++++- | ||
75 | 1 file changed, 34 insertions(+), 1 deletion(-) | ||
76 | |||
77 | diff --git a/blockdev-nbd.c b/blockdev-nbd.c | ||
78 | index 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 | -- | ||
164 | 2.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 | |||