From nobody Sat Jun 13 14:01:55 2026 Received: from mail-pj1-f53.google.com (mail-pj1-f53.google.com [209.85.216.53]) (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 86B3C213E9C for ; Thu, 7 May 2026 02:18:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778120318; cv=none; b=anFKxzx+0obw9EjkoGCO7tnqb/ukfl/AbLiL0EC/r/QbS1Lt/yyL6JhZ+qog1/4Xkee0mUd8pXcAw1qnLVt8+3fH3Y6IIZ4Ml4BWi5pMjqf4ALvqEdDH/ZA8ABwTw6MXNgSDajLe9WfQsU7QXnQo793mmI043AQNK7DBAdy2kPM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778120318; c=relaxed/simple; bh=ZrCFww4ECwWfkhoTbDCSwXoIXXrKkY8X/i5G6H9JP1o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=P0Iz7Sgxkvg+r6PXLgcuv+Xz41EWMb1yzgRQnO8gQY0YoVNF87bQvoCQgCpwrPy7UI/Z22gY1Ww9358tTopkNXN4KdxoBoZr5ljw1LN8LaPFRWvByZmZa4H4ZR4bZdMha64EYCGsb+IVMh9KFR4fJU78rzKUUicnNdzG9px3b0g= 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=bCjnghtu; arc=none smtp.client-ip=209.85.216.53 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="bCjnghtu" Received: by mail-pj1-f53.google.com with SMTP id 98e67ed59e1d1-365de41f8a1so47079a91.2 for ; Wed, 06 May 2026 19:18:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778120316; x=1778725116; 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=Fn/rXSpLj+R/ku7nBy1V0OPJZZmEvQ+YBVAy/f5BFj0=; b=bCjnghtu6AYIxTiJpjj9SoDw4PPdpANtR03JrDReJwR+MTQQ2hFTWjMVFh0jhFAAVD S1K09A1Nsu4qWqc4+wYfVEJn3lliahVQWY6UNI1kiJcuASaEjFTWdqU0SKn9+ofX0saz hzkFg2PGPA/K+gW+yl+TjAZjDWHtZN9BZi/Hj/9FMMvzYjD0Y6huxNq5pWPzwCy0wRxr fUPnln7sgdXQrbYTEw9Fa19N0EQP+cKGypBeFX0RIPlmXvTWKEto5tfhrPrNPX0lODMO VDmtJpLHwNLWigWNYPLfeZJYn3X+csOa4e9PHa5jpZXUxlYUIkSZYJP0zyJtfU06dSPg T7cg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778120316; x=1778725116; 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=Fn/rXSpLj+R/ku7nBy1V0OPJZZmEvQ+YBVAy/f5BFj0=; b=WPhglKcXFSqoJK3SdpR3URK6M043tMsClsYDtvbPINClkIcnF96qnvuDTu83Sa/i4q S+PqK5DUNoPPRy1M1avWO71nmHJi8UwyE18KQw+iVXaacfpPfKupcYYvw7K6ZCwrisoE z0Fe5w3ffogiFjIcCZyyBjKTlpJC708XJMuFIe9R648UTEXH40TjW8MxNIyt4ojp0WWf L9oqWFTGI6oJie4QIaucGS+LQdTGr+6TgizaXXhenddDGlyX8csyGqAu6xBp/HxstsYp 9WWyqxWU+6KXRD55afsY6ctn3pJq8d9BBRZFkvqo95yZL41XCsEGJR9FFvsxu4MFiTFx L/KQ== X-Forwarded-Encrypted: i=1; AFNElJ+TJUT2whZHVqAbMBGGs7QtGje+tcwGM5TeSu9bXhoP80qemdEgPVWhe+HHv8eo193REQl5YOIKDfo8zEA=@vger.kernel.org X-Gm-Message-State: AOJu0YyMFOKtpKzPqHowl/7bGWdN8Yx/0c9uGIGokafSdT3d0lX6OE6I SDqqbADGgl21/5vB/xr5kn6sRHJXVYzapyXUNZZCnFbUZhGc5PC85F9d X-Gm-Gg: AeBDies7hNL75Uboe/ZUTQx3fA80sMgEICoABvUhyvhW4slVGRChKiRX/PhwiMk9Tkc RFlRAoCnaED62Uo0W5Tpco7CZ4gU4wPYSmtDIgTjhU4xgY0X9hEFLvQsgo7l/0ygiM2SD+ilyxo ZA2xGddnvVSigO6VNFEt7cxk7aBrU4yDaaBcz2Q1MECFbcZmlpApaNuEKAkO0PdW9C/j/MwjZHk py5kal/ioRQxwmXaCIe/CFEPcaQ6lZ+i4ufRKFs7jgCUyCSkZklzDGkwbDxOvRi1nyiKTU0evxX NOU45+3LK9/RA8bgITG1GWjzGc1zfpkG0jz6h1ftmlFo3H01oP9W1+XEaeec8s0JTQtOgRcwIzR HZLHyfeMMxvLnao9gJqsWmHkq50XvaJS/fK7Qc5OFybS3Au99Alou/MQjUjL26Yn4+ZHagLqhvm hRlrfQ0RLCi5xC6o3js1L5rbjG4KnIiaSeFzmgxw== X-Received: by 2002:a17:90a:e60f:b0:366:1075:ba with SMTP id 98e67ed59e1d1-36610750520mr96545a91.0.1778120315720; Wed, 06 May 2026 19:18:35 -0700 (PDT) Received: from ser8.. ([221.156.231.192]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2babadd2314sm6002305ad.54.2026.05.06.19.18.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 May 2026 19:18:35 -0700 (PDT) From: DaeMyung Kang To: Namjae Jeon , Hyunchul Lee Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2] ntfs: fix out-of-bounds write in ntfs_index_walk_down() Date: Thu, 7 May 2026 11:18:31 +0900 Message-ID: <20260507021831.1196548-1-charsyam@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260506153850.774060-1-charsyam@gmail.com> References: <20260506153850.774060-1-charsyam@gmail.com> 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" ntfs_index_walk_down() used to update the index traversal depth directly before writing parent_pos[] and parent_vcn[]. A malformed directory index with too many child-node levels can therefore advance pindex past MAX_PARENT_VCN and write past the fixed arrays in struct ntfs_index_context, corrupting context state used by later index traversal. Use ntfs_icx_parent_inc() for walk-down transitions so the existing depth limit is enforced before the arrays are updated. Make the helper check the limit before incrementing pindex so failed callers do not leave the context at an out-of-range depth. This is reachable by iterating a crafted NTFS directory after the volume has been mounted, including read-only mounts. The reproducer uses getdents64() on an index root that points to an excessively deep chain of child index blocks. A crafted directory index with a chain of child-node entries reproduced UBSAN array-index-out-of-bounds reports in ntfs_index_walk_down() and subsequent KASAN reports in ntfs_index_walk_up(). With this change, the same image is rejected with "Index is over 32 level deep" and no KASAN or UBSAN report is emitted. Fixes: 0a8ac0c1fa0b ("ntfs: update directory operations") Suggested-by: Namjae Jeon Signed-off-by: DaeMyung Kang --- Changes since v1: - In the is_in_root walk-down branch, drop the ntfs_icx_parent_inc() call and the kvfree(ib) error handling; restore the direct ictx->pindex =3D 1 assignment, per review by Namjae Jeon. The helper call there was unnecessary because is_in_root =3D=3D true implies pindex =3D=3D 0, and the resulting error path was dead code. Add a comment documenting the invariant. The non-root walk-down branch keeps using ntfs_icx_parent_inc() since pindex can approach MAX_PARENT_VCN there. fs/ntfs/index.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c index a547bdcfa456..146e011c1a41 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c @@ -677,11 +677,11 @@ static int ntfs_ib_read(struct ntfs_index_context *ic= x, s64 vcn, struct index_bl =20 static int ntfs_icx_parent_inc(struct ntfs_index_context *icx) { - icx->pindex++; - if (icx->pindex >=3D MAX_PARENT_VCN) { + if (icx->pindex >=3D MAX_PARENT_VCN - 1) { ntfs_error(icx->idx_ni->vol->sb, "Index is over %d level deep", MAX_PARE= NT_VCN); return -EOPNOTSUPP; } + icx->pindex++; return 0; } =20 @@ -1970,6 +1970,7 @@ struct index_entry *ntfs_index_walk_down(struct index= _entry *ie, struct ntfs_ind { struct index_entry *entry; struct index_block *ib; + int err; s64 vcn; =20 entry =3D ie; @@ -1979,14 +1980,20 @@ struct index_entry *ntfs_index_walk_down(struct ind= ex_entry *ie, struct ntfs_ind ib =3D kvzalloc(ictx->block_size, GFP_NOFS); if (!ib) return ERR_PTR(-ENOMEM); - /* down from level zero */ + /* + * Descending from root index (level 0) to the first + * child level. is_in_root =3D=3D true implies pindex =3D=3D 0, + * so advance to level 1. + */ + ictx->pindex =3D 1; ictx->ir =3D NULL; ictx->ib =3D ib; - ictx->pindex =3D 1; ictx->is_in_root =3D false; } else { /* down from non-zero level */ - ictx->pindex++; + err =3D ntfs_icx_parent_inc(ictx); + if (err) + return ERR_PTR(err); } =20 ictx->parent_pos[ictx->pindex] =3D 0; --=20 2.43.0