From mboxrd@z Thu Jan 1 00:00:00 1970 From: Konstantin Khorenko Date: Wed, 5 Aug 2026 22:20:02 +0200 Subject: [Devel] [PATCH RHEL10 COMMIT] dm-qcow2: fix NULL deref in merge_backward complete without an active merge In-Reply-To: <20260706110002.1024515-22-khorenko@virtuozzo.com> Message-ID: <202608052020.675KK2TG543291@f0.sw.ru> List-Id: The commit is pushed to "branch-rh10-6.12.0-211.39.1.16.x.vz10-ovz" and will appear at git at bitbucket.org:openvz/vzkernel.git after rh10-6.12.0-211.39.1.16.2.vz10 ------> commit 0b0514cc0ada5c48fe5d239f54c3ba803d4fa4a1 Author: Konstantin Khorenko Date: Mon Jul 6 12:59:59 2026 +0200 dm-qcow2: fix NULL deref in merge_backward complete without an active merge qcow2_merge_backward_complete() loaded *tgt->backward_merge.pqcow2 in its variable initializer, before checking the merge state: struct qcow2 *qcow2 = *tgt->backward_merge.pqcow2, *i; ... if (tgt->backward_merge.state != BACKWARD_MERGE_WAIT_COMPLETION) return -EBUSY; tgt->backward_merge.pqcow2 stays NULL until a "merge_backward start" message sets it, so a `dmsetup message 0 "merge_backward complete"` on a device that never started a backward merge dereferences NULL in the kernel and crashes the host (NULL-ptr deref at qcow2_merge_backward_complete+0x19, offset backward_merge(632)+pqcow2(72) = 0x2c0). Any unprivileged-of-the-VE holder of the dm control device can trigger it. Move the pqcow2 load below the state check. When the state really is BACKWARD_MERGE_WAIT_COMPLETION, pqcow2 was set by "start" under the same ctl_mutex and is never cleared while in that state, so the normal start->...->complete path is unchanged; the no-active-merge case now returns -EBUSY (the driver's existing "wrong merge state" convention) instead of oopsing. The sibling verbs (cancel/update_eventfd/progress) already guard their pqcow2 use behind the state and are not affected. Fixes: 11ba92733c99a ("dm-qcow2: allow specifying depth to merge intermediate images") Feature: dm-qcow2: block device over QCOW2 files driver https://virtuozzo.atlassian.net/browse/VSTOR-137234 Signed-off-by: Konstantin Khorenko Reviewed-by: Pavel Tikhomirov --- drivers/md/dm-qcow2-cmd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-qcow2-cmd.c b/drivers/md/dm-qcow2-cmd.c index c15c46a0fe8b7..e1a94bc4a140c 100644 --- a/drivers/md/dm-qcow2-cmd.c +++ b/drivers/md/dm-qcow2-cmd.c @@ -366,14 +366,19 @@ void qcow2_merge_backward_work(struct work_struct *work) static int qcow2_merge_backward_complete(struct qcow2_target *tgt) { - struct qcow2 *qcow2 = *tgt->backward_merge.pqcow2, *i; + struct qcow2 *qcow2, *i; int ret; lockdep_assert_held(&tgt->ctl_mutex); + /* + * .pqcow2 is NULL until the first "merge_backward start" and + * is valid while the state is BACKWARD_MERGE_WAIT_COMPLETION. + */ if (tgt->backward_merge.state != BACKWARD_MERGE_WAIT_COMPLETION) return -EBUSY; + qcow2 = *tgt->backward_merge.pqcow2; *tgt->backward_merge.pqcow2 = qcow2->lower; i = tgt->top;