From nobody Wed Jun 17 04:06:28 2026 Received: from mail-pf1-f176.google.com (mail-pf1-f176.google.com [209.85.210.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6DA8D1E0E14 for ; Thu, 23 Apr 2026 04:52:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776919954; cv=none; b=PPCyOtjvSK0vUVy+SD/xBphEHBsHXGu0oWv4TyT5BeTBuMXdKUBiQyIzyG5PnPTEFltOjTjEy75Iw5/l8wzETpzFYbnVLUhbY80E0O+SjYzzkiiXpMkPVvvcqa4IYZABt6HWYSOh3kOMHfcOeXfDyZwOsUkFN9bHyHNp/DoVO0E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776919954; c=relaxed/simple; bh=l0q0Wswwbf/svX24Vnceqb+NYxKPSnHD65k5fuCePQg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uFcjaCR4iZ912QSAEPHO2CWspKsan5xs8Cms8zr3TlP9MrAUbCuEk1vy354dGb1NwrR5PV8j1J+WdDj/fySsiHA7BaUNB1+iIxzq6FJsvUHa0HlXQJi7i9zlgGTd7ss1+7ooPE3PQBEfFqAr/S/+ai7FbJ48X+ONWJpwlrG0QKo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=nOKG6FrE; arc=none smtp.client-ip=209.85.210.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="nOKG6FrE" Received: by mail-pf1-f176.google.com with SMTP id d2e1a72fcca58-82f69a286dbso4821585b3a.2 for ; Wed, 22 Apr 2026 21:52:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776919953; x=1777524753; darn=vger.kernel.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; bh=o7BiTksjMg59q4qQzQFMNldHGqQNisz/WW/fujBtrpg=; b=nOKG6FrEB+CwRKwfRZiEErG0ybsS+2J2rTseAXKOZnKs5V/ou1XnbwoW00vg0XmACF ZlKeEZq06L4cgnyu/hVb7wkwJLU6X6dho5MW2opkc9DoQRKY/IcMNL8r9UAWDGONvUkb JzQ6vNC0CxqcKbfzjny9BS+IXpylsO6Bf8D8tFw+1W7jptP310O4a/hKlExEY4a+FDrv 7waeIAalG0uoVctKq7bt2xdVS/xhb51jvFvqml+OAOR8jMV5HkAjlIHfIoNZVTg6PZ/H RSeS56TGI7tJHxhI2BLofd5ey6q6Acjrl+XS6Gx5RTtXLVqNlSglEh3ccKIiiBWXazXc Qt+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776919953; x=1777524753; 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; bh=o7BiTksjMg59q4qQzQFMNldHGqQNisz/WW/fujBtrpg=; b=VzrehzpM49mKg0/455K9jEPyoHgtsN7wRMsYU8C5g+NTAh7Yxxd3KkgZ9D3NXEqR+0 KC/paQH005QMhIpAwhkLIZkL2wsxNQ1udrevk7WhUrb2d4oAW3Hb8uYs0NYcTfuejOjO RttPy81T5mQdimnWOuGd9dFeVvXSfMPnTMRHFesl9tx9ZTCi47f4q5LgI4Md7nzNiB6n Iqv2BFP63BcX8PRF8PQUIRL1Kl5cD2VBfwghy0mWzbq8iiZiTlBZuhdxd2qQIn5qOIOl le1/cFPIOb8e2Vc7syKGzV30sMBkQHpabjoGK558yOPcF0r6XjmMcZpnF95jm13IVhVH 9Hwg== X-Gm-Message-State: AOJu0YwWkpklzjrTHTJs/9RfiXGgEN4EVhmpDuFsAEP9VtJy52EwzO/D toi49kh0Bi5tGYGq1FPXkcU+DTSabOJWrC+MpZlxX8TWo/SCH50ill99A7KEfg== X-Gm-Gg: AeBDies0a+cxoNXAcZZdPxHStnmtkPNHFmtZwfdw0PDSuDIkSA4HdEvzRYdcPFukera anMdWYfYF3MqMMf0mWzkxRfhJG6Om3N+IryAfdgIM8NTBLLkpAuhAXL/M/lshnxGLvqrLDAWRkK Qmpa1rVMZIxRTiT5ipQ1PpI/xD3HFVUGnMFNw6MafHB8Uk1yHZ64v4/TvuVFOtZTDPb2zt1fJ2Z FN3zMaUHOlMrIATk1p4t9z9Y+lWUUemx2mesryZbcKcp0rZMMGWf1WOytTRj/hzMnF9VZba1uIt 8VuBVdMuqMplu6K+8AMy7wNixyUzsbIdsj8GMz1BCgAOx76ZgwMw6+VGEz3jNRLJCsP9XeRGABO DM47Nk37wS6ZCGzavcyxxipZpqF2TuC2qoqRxF5ehuGfO33hmzW1ZZfjD4mrZ0gnlZRkcXhUfkW KhG5c35tF0PBSTCBZCwf2IXoPviTxbNjzUNnyh1U1jWSrCZnuOZU1NByM8SA== X-Received: by 2002:a05:6a00:2ea5:b0:82f:8a29:e3e0 with SMTP id d2e1a72fcca58-82f8c91bc7dmr29944152b3a.42.1776919952641; Wed, 22 Apr 2026 21:52:32 -0700 (PDT) Received: from DESKTOP-MOQC9AF.mioffice.cn ([43.224.245.246]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82f8ebe74d8sm19177514b3a.46.2026.04.22.21.52.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 22 Apr 2026 21:52:32 -0700 (PDT) From: Zhan Xusheng X-Google-Original-From: Zhan Xusheng To: Konstantin Komarov Cc: linux-kernel@vger.kernel.org, Zhan Xusheng Subject: [PATCH v3] ntfs: fix VCN overflow in ntfs_mapping_pairs_decompress() Date: Thu, 23 Apr 2026 12:52:26 +0800 Message-ID: <20260423045227.249857-1-zhanxusheng@xiaomi.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" In ntfs_mapping_pairs_decompress(), lowest_vcn is read from on-disk metadata and used as the initial vcn without validation. A malformed value can introduce an invalid (e.g. negative) vcn, corrupting the runlist from the start. Additionally, the accumulation vcn +=3D deltaxcn does not check for s64 overflow. A crafted mapping pairs array can wrap vcn to a negative value, breaking the monotonically- increasing invariant relied upon by ntfs_rl_vcn_to_lcn() and related helpers. Fix this by validating lowest_vcn and using check_add_overflow() for vcn accumulation. Signed-off-by: Zhan Xusheng Reviewed-by: Hyunchul Lee --- v3: - Use overflows_type() for lowest_vcn validation (Hyunchul) v2: - Validate lowest_vcn from on-disk metadata - Use check_add_overflow() for vcn accumulation --- fs/ntfs/runlist.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c index b213b4976d2b..be6ca3d374bb 100644 --- a/fs/ntfs/runlist.c +++ b/fs/ntfs/runlist.c @@ -15,6 +15,8 @@ * Copyright (c) 2007-2022 Jean-Pierre Andre */ =20 +#include + #include "ntfs.h" #include "attrib.h" =20 @@ -739,6 +741,7 @@ struct runlist_element *ntfs_mapping_pairs_decompress(c= onst struct ntfs_volume * int rlsize; /* Size of runlist buffer. */ u16 rlpos; /* Current runlist position in units of struct runlist_elemen= ts. */ u8 b; /* Current byte offset in buf. */ + u64 lowest_vcn; /* Raw on-disk lowest_vcn. */ =20 #ifdef DEBUG /* Make sure attr exists and is non-resident. */ @@ -747,8 +750,14 @@ struct runlist_element *ntfs_mapping_pairs_decompress(= const struct ntfs_volume * return ERR_PTR(-EINVAL); } #endif + lowest_vcn =3D le64_to_cpu(attr->data.non_resident.lowest_vcn); + /* Validate lowest_vcn from on-disk metadata to ensure it is sane. */ + if (overflows_type(lowest_vcn, vcn)) { + ntfs_error(vol->sb, "Invalid lowest_vcn in mapping pairs."); + goto err_out; + } /* Start at vcn =3D lowest_vcn and lcn 0. */ - vcn =3D le64_to_cpu(attr->data.non_resident.lowest_vcn); + vcn =3D lowest_vcn; lcn =3D 0; /* Get start of the mapping pairs array. */ buf =3D (u8 *)attr + @@ -823,8 +832,17 @@ struct runlist_element *ntfs_mapping_pairs_decompress(= const struct ntfs_volume * * element. */ rl[rlpos].length =3D deltaxcn; - /* Increment the current vcn by the current run length. */ - vcn +=3D deltaxcn; + /* + * Increment the current vcn by the current run length. + * Guard against s64 overflow from a crafted mapping + * pairs array to preserve the monotonically-increasing + * vcn invariant. + */ + if (unlikely(check_add_overflow(vcn, deltaxcn, &vcn))) { + ntfs_error(vol->sb, "VCN overflow in mapping pairs array."); + goto err_out; + } + /* * There might be no lcn change at all, as is the case for * sparse clusters on NTFS 3.0+, in which case we set the lcn --=20 2.43.0