From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pg1-f174.google.com (mail-pg1-f174.google.com [209.85.215.174]) (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 BE47D494A1B for ; Wed, 6 May 2026 15:38:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.174 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778081939; cv=none; b=BNwRxCN1n7DuY0eNPZHQXefVS7zCuBfOkQ8KI37FRkQFxgkogfcouRMUEwqDmGbYtRc8yvS48bnygVP+OLk9PhgyNV5vKnaPGaUYZw7DePJt8M7Lz1uguIqsHC2m5S2rP4DudYP8ZmqQCcaBdt2Ta6kehr2NARQ90/u24uIQZ1c= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778081939; c=relaxed/simple; bh=JPyPxRNX+uB/owPL/LjSAuqbSPUmaQZDlWm+cum3d9U=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=d6urloDXpLMPR1Y+1IDSkhLbEmxlHVbb1zwgaiV+n5/OJRXbfmA7nf+sZeLEUZR/Dhe+Sl4DdpjGd58I+OqgGs1Wi3khSvbP3+G4AVxOAYXf4w+T0kFYgYwsxCMUu97QS+xTfwffz85FoxtyTR2/mlj5ksV0aYxcXCQ7enk27YU= 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=iVmsCZkT; arc=none smtp.client-ip=209.85.215.174 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="iVmsCZkT" Received: by mail-pg1-f174.google.com with SMTP id 41be03b00d2f7-c80192af816so184155a12.2 for ; Wed, 06 May 2026 08:38:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778081936; x=1778686736; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=6OH4ziShIB2nW4667aVLH1Ypp1Iy/26GAj5mx4eXCQA=; b=iVmsCZkTW1HfWkl3+Bnv3809k3rF7mX4x0Cf2z3RUa7gHUx5La+uqKdVRjTNHvqHYR VjSkaVEF8e4LSsSnxGb+8kmH/981QtHNXJDw/sGZNgZD3oyT24W6Yd0yfBdrH+i/x+g1 7TrenUAyXrj27S4rsqmqtr/FF4i+3TbXGZE1I7OnLSW/SZBTX90MjuDLj0S5Unl4DBbc Dxega2bEzKKskDCKUPKfKTdAzPrbjs6eF95+lBW4DOxPwRwIbc827SlZWCUj25GAm2Qz z9Jw2d9Frle88j8ghkgqSgaeN9MzO9QM5DSTBGEmqlqb8z7FUgAC3HP0AFbK/6dRprym pxJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778081936; x=1778686736; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=6OH4ziShIB2nW4667aVLH1Ypp1Iy/26GAj5mx4eXCQA=; b=pUDzuuxBYD7QH4RZWOLNybs31qjCwYiLYB5twn1B+i45f8BBOucbqc4VSesnF27g36 qu/JSuN09F9xmAoYSDQ3LiPPx0zTrPVWUoaGznz5JFAHsYdCFZYMEn7NE3yPhMnRrR1s 706FAHNeHDWXi9xrZg+XQwh8rsF54Brh13zyO0CIURwJTZNsjClIMF7cSSRFll1n9p2N ek1NCvoAtGkaSXE6irHDbpNchC/2pG7jfh38wYkSgsmDWeYbY2lrTMQIVeHNu5atjlSb u9RnOPI4mIbq0P1RmciGi6xM2fU7/aCGuCTEr2mJxDiYUpyvuxWY0f2wbqcpViKLslmE rysQ== X-Forwarded-Encrypted: i=1; AFNElJ/x5KG5TbD+Ok93ywew01BPES/a3JlEwSQvbKVCHqzUMnn05Kkz9FsI3uLPiXDDNnrcjmqLJkmuV/26KX8=@vger.kernel.org X-Gm-Message-State: AOJu0Ywnc9uHLPAxqc+XIelvyfbifFkGoR9gdN+nUfUFyqeKDpT80Jg8 x/uu3viSbdYS8SHGqigKk+Zh6YbalqCcqp5gh0Pmer6MEW9UWT+2eA4V X-Gm-Gg: AeBDievNZAdxa+9kIaepO/TRwCO2ZvLPGUNQlPLL2PXHa26wM8w2Rbeht0sImR82vaX jCAkP+ti9GuEq8SBXAjTYFeIU9RTBRA4RH6RTegABP+NPkYL9c7LvF44+IB6rN9HeSQXwrRpN8L D34xNyVMl2tq+An6fpeNzoRiFz61EoB3a4L6rY3lP7n186PVj/XsG4PVvzHpFMdXZqplHL6y0CP PEcF4OOLh+AEtc/Gb07j4dwpy9vxpRz7f+buI/z0lqqJ3JoXkjZpHxwZ3CNBiVWmeVnyEgtJ1sb kQqX/81BPEMR1k7BGRDdsb6FNs5gnW8PzY5GLLDs8Kptay6nCyTWiIJQadBqRwgr7ZvvIYltO7L pf3A41LEDiiOQMk9Iffelo8sKAtXV7bB/mKC6m7IMNNvLRqPUmB18zonrVfzMzuOlJ8qtmUZ5l0 S9GBivwBo8mVb4kSuiSnIBYHkLbec= X-Received: by 2002:a05:6a00:2e86:b0:835:3611:848f with SMTP id d2e1a72fcca58-83a5844836fmr2087282b3a.0.1778081935707; Wed, 06 May 2026 08:38:55 -0700 (PDT) Received: from ser8.. ([221.156.231.192]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83962e7e3fcsm7412871b3a.0.2026.05.06.08.38.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 May 2026 08:38:55 -0700 (PDT) From: DaeMyung Kang To: Namjae Jeon , Hyunchul Lee Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] ntfs: fix out-of-bounds write in ntfs_index_walk_down() Date: Thu, 7 May 2026 00:38:50 +0900 Message-ID: <20260506153850.774060-1-charsyam@gmail.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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") Signed-off-by: DaeMyung Kang --- 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..35c4eaa4e394 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c @@ -677,11 +677,11 @@ static int ntfs_ib_read(struct ntfs_index_context *icx, s64 vcn, struct index_bl static int ntfs_icx_parent_inc(struct ntfs_index_context *icx) { - icx->pindex++; - if (icx->pindex >= MAX_PARENT_VCN) { + if (icx->pindex >= MAX_PARENT_VCN - 1) { ntfs_error(icx->idx_ni->vol->sb, "Index is over %d level deep", MAX_PARENT_VCN); return -EOPNOTSUPP; } + icx->pindex++; return 0; } @@ -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; entry = ie; @@ -1979,14 +1980,20 @@ struct index_entry *ntfs_index_walk_down(struct index_entry *ie, struct ntfs_ind ib = kvzalloc(ictx->block_size, GFP_NOFS); if (!ib) return ERR_PTR(-ENOMEM); - /* down from level zero */ + /* is_in_root implies pindex == 0; move to the first child level. */ + err = ntfs_icx_parent_inc(ictx); + if (err) { + kvfree(ib); + return ERR_PTR(err); + } ictx->ir = NULL; ictx->ib = ib; - ictx->pindex = 1; ictx->is_in_root = false; } else { /* down from non-zero level */ - ictx->pindex++; + err = ntfs_icx_parent_inc(ictx); + if (err) + return ERR_PTR(err); } ictx->parent_pos[ictx->pindex] = 0; -- 2.43.0