From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id CACD5C88E41 for ; Fri, 11 Sep 2026 01:02:19 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x4peI-0007ve-1T; Thu, 10 Sep 2026 21:01:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x4oQ5-0001kB-4Z for qemu-devel@nongnu.org; Thu, 10 Sep 2026 19:43:13 -0400 Received: from mail-wm1-x331.google.com ([2a00:1450:4864:20::331]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1x4oPy-0007Gl-Iv for qemu-devel@nongnu.org; Thu, 10 Sep 2026 19:43:03 -0400 Received: by mail-wm1-x331.google.com with SMTP id 5b1f17b1804b1-49cf4f81d86so2711035e9.2 for ; Thu, 10 Sep 2026 16:42:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvz.org; s=google; t=1789083774; x=1789688574; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=y+iZAgzaoiObj44pBZTJ06CwchhMM20VAZVaSA9mDmA=; b=hTC38LsJ2zOgO7ZUJRFgdsd5HYLHNE9buGKuAh+GEtTAIKEceDZbEvX1VQGkMMadFl a6jkeOa4EBh7or0tNwya4RYAiRkao2Sfb7nqnIIIkUImdwci4yEor1Cu2eesVowfpt0U V0DrTS2benToS6y9du3ZLpDhDnx6GDfaKWZaN9U00g0KH+GZo8ZUccSHNfK9PWUic7J5 FgsgBZM39wxFb8KDeFQZ0dn13sKUKAQF4JkRsd+xAk9abhOYuCnP07MAT/Yop9ocjEcq jrhrvOOHZtvvbnWGP+0x6Lh+5Ex0g2n21RDJy/uVDLBOPCX70Lqvhmrhan1AnZ5db4Ur UP1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1789083774; x=1789688574; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=y+iZAgzaoiObj44pBZTJ06CwchhMM20VAZVaSA9mDmA=; b=GWJMqhg7SdIxfklRs6hDIf0Q0lifvd0hp/wBExXpbW3+MDUTEk9jaXYAl5NMepIlkE uIrtiBuq0PMN+m4P1o00Ul4ceeVowwy1arv64xMzqhBKWS6eLyK/hrBP2D534HKWj5hp aUpVrJvkq59sSmIdKw2IQQ6tjHLhpjQRtlq/bn61N9GbMhKlM1Phqn1hCQY7S0fbo+PD ja/isqC4sKlnxBZtM+Qb0zwaEHlvNSHfK0SNenW09MuNwoi9WQdmOPutw9qkO6DpbaB4 81ycEWwvTeywDtWmT+pG4FvhXzUX4T6RhIxN3fwbnOHz1KStNoiDhnkQEIcYKhygjRBR HjMg== X-Gm-Message-State: AFuF++lU5BZNz86dS+i+VdaQCMGgnbF9yhdDjOG9ewx4RSW8rBAsU19z uvO1A9qRluPbgrphBBxWc6X2dTd7hVUAElF/YcVcvaYIYTEzFiwWm5kzgIobHNCjooQ= X-Gm-Gg: AYBFou33Avzgm6JY60RmlgX+EqPjN2DoapWOZVVQZapXSLMT8A+z+WJCCxCqmNBvw6n 6vukChoiGimsNuY4xcDUIDP1Vqm64NkgxV3l1J1OcC5U3Y6nWpyRIHtiFD0YvSY5JLfVdsZ1W5K VYAegdQLiOBAblfT2+oNjJ0qfUYLKVJi5TDckT5fo8zYwv19ezUUNYSuUbqdc6kaKemRvnZ0saG eB0BYjAkRqRMztCXxjhb+Lx7NU5Zv+HGxIsb4tYheJ4FOZJwlVsP97Gsr8BvaDI3fWLaI4/37iP 81JnJBt6ebNdYTNI6nw4iIkC7gQWzn77iu9zYl/Su2rmuw7UQA8jTnC0X3bgxbuFVe15V7ydVOY XSQ+Chk5BG8Klh3z/zwGfVOFik4irXTVkyvnBzsVdf8NyyRv2IVy/RUOqY9RwZy13jU+5B0as7Z nuX3HalKDizVv76gpnDijTGJmRZ0dfSnAWTYulnyc+Rqb7RA2rlxqmWDsgWHxUMgz5ki64 X-Received: by 2002:a05:600c:628e:b0:49c:fc6c:be13 with SMTP id 5b1f17b1804b1-49e619c6463mr14713435e9.25.1789083774266; Thu, 10 Sep 2026 16:42:54 -0700 (PDT) Received: from athena.sw.ru ([2a06:5b06:b600:300:54f3:cc87:964b:3604]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49e62231360sm7726775e9.4.2026.09.10.16.42.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Sep 2026 16:42:53 -0700 (PDT) From: "Denis V. Lunev" To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, "Denis V. Lunev" , Stefan Hajnoczi Subject: [PULL 23/29] parallels: reject a bitmap L1 entry outside the data area Date: Fri, 11 Sep 2026 01:42:16 +0200 Message-ID: <20260910234222.3039975-24-den@openvz.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260910234222.3039975-1-den@openvz.org> References: <20260910234222.3039975-1-den@openvz.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=2a00:1450:4864:20::331; envelope-from=den@openvz.org; helo=mail-wm1-x331.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Denis V. Lunev Nothing checks where a bitmap L1 entry points. The entry is turned into an offset and the cluster is read from there, so the image decides which part of the file, if any, is deserialized as bitmap data. A short read on the protocol node is zero filled rather than refused, so an entry beyond the end of the file does not even fail: the bitmap quietly loads as completely clean. An entry below data_off deserializes the header and the BAT as bitmap data instead. Both cases used to be harmless in the sense that the extension was only parsed for read-only images, but the bitmap becomes writable and is stored back as authoritative once the image can be opened read-write. Bound the entry the way parallels_check_outside_image() bounds a BAT entry: it has to address the data area of the image file. The offset computation is bounded first, as the entry is a 64 bit value coming from the image and the shift by BDRV_SECTOR_BITS would overflow. The overflow case was reported as an I/O error before, so the test expectation changes along with it. Fixes: baefd977002e ("parallels: support bitmap extension for read-only mode") Cc: Stefan Hajnoczi Signed-off-by: Denis V. Lunev --- block/parallels-ext.c | 30 ++++++++++++++++++- .../qemu-iotests/tests/parallels-read-bitmap | 23 +++++++++++--- .../tests/parallels-read-bitmap.out | 6 +++- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/block/parallels-ext.c b/block/parallels-ext.c index 6a889d86fa..17445d183b 100644 --- a/block/parallels-ext.c +++ b/block/parallels-ext.c @@ -71,9 +71,17 @@ parallels_load_bitmap_data(BlockDriverState *bs, const uint64_t *l1_table, int ret = 0; uint64_t offset, limit; uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap); + int64_t file_size, data_start_off; uint8_t *buf = NULL; uint64_t i; + file_size = bdrv_getlength(bs->file->bs); + if (file_size < 0) { + error_setg_errno(errp, -file_size, "Failed to get image file length"); + return file_size; + } + data_start_off = s->data_start << BDRV_SECTOR_BITS; + buf = qemu_try_blockalign(bs->file->bs, s->cluster_size); if (!buf) { error_setg(errp, "Failed to allocate a bitmap data cluster"); @@ -101,7 +109,27 @@ parallels_load_bitmap_data(BlockDriverState *bs, const uint64_t *l1_table, if (entry == 1) { bdrv_dirty_bitmap_deserialize_ones(bitmap, offset, count, false); } else { - int64_t host_off = entry << BDRV_SECTOR_BITS; + int64_t host_off; + + if (entry > INT64_MAX / BDRV_SECTOR_SIZE) { + error_setg(errp, "Bitmap L1 entry %" PRIu64 " is out of range", + i); + ret = -EINVAL; + goto finish; + } + host_off = entry * BDRV_SECTOR_SIZE; + if (host_off < data_start_off) { + error_setg(errp, "Bitmap L1 entry %" PRIu64 " points before " + "the data area of the image", i); + ret = -EINVAL; + goto finish; + } + if (host_off > file_size - (int64_t)s->cluster_size) { + error_setg(errp, "Bitmap L1 entry %" PRIu64 " points outside " + "the image file", i); + ret = -EINVAL; + goto finish; + } ret = bdrv_pread(bs->file, host_off, s->cluster_size, buf, 0); if (ret < 0) { diff --git a/tests/qemu-iotests/tests/parallels-read-bitmap b/tests/qemu-iotests/tests/parallels-read-bitmap index 6990926d60..f5a1f33907 100755 --- a/tests/qemu-iotests/tests/parallels-read-bitmap +++ b/tests/qemu-iotests/tests/parallels-read-bitmap @@ -93,9 +93,10 @@ def extension(body, magic=EXT_MAGIC, checksum=True): return struct.pack('