fs/ntfs3: add depth limit to indx_find_buffer to prevent stack overflow

indx_find_buffer() recursively descends the B+ tree index with no depth
limit.  A crafted NTFS image with circular index node references causes
unbounded recursion, overflowing the kernel stack and panicking the
system.

This is reachable by mounting a malicious NTFS filesystem (e.g. from a
USB drive via desktop automount) and deleting a file whose index entry
triggers the rebalancing fallback path in indx_delete_entry().

Add a depth parameter and bail out with -EINVAL when it reaches the
fnd->nodes array bound, matching the constraint already enforced by
fnd_push() in indx_find().

The related function indx_find() was previously patched for a similar
infinite-loop issue (commit 1732053c8a), but indx_find_buffer() was
missed.

Fixes: 82cae269cf ("fs/ntfs3: Add initialization of super block")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-6
Assisted-by: Codex:gpt-5-4
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
This commit is contained in:
Michael Bommarito 2026-04-13 09:31:17 -04:00 committed by Konstantin Komarov
parent 254f49634e
commit 1ebd684b8f
No known key found for this signature in database
GPG Key ID: A9B0331F832407B6

View File

@ -2022,13 +2022,21 @@ int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
static struct indx_node *indx_find_buffer(struct ntfs_index *indx,
struct ntfs_inode *ni,
const struct INDEX_ROOT *root,
__le64 vbn, struct indx_node *n)
__le64 vbn, struct indx_node *n,
int depth)
{
int err;
const struct NTFS_DE *e;
struct indx_node *r;
const struct INDEX_HDR *hdr = n ? &n->index->ihdr : &root->ihdr;
/*
* Limit recursion depth to prevent stack overflow from crafted
* images. Use the same bound as the fnd->nodes array (20).
*/
if (depth > ARRAY_SIZE(((struct ntfs_fnd *)NULL)->nodes))
return ERR_PTR(-EINVAL);
/* Step 1: Scan one level. */
for (e = hdr_first_de(hdr);; e = hdr_next_de(hdr, e)) {
if (!e)
@ -2049,7 +2057,8 @@ static struct indx_node *indx_find_buffer(struct ntfs_index *indx,
if (err)
return ERR_PTR(err);
r = indx_find_buffer(indx, ni, root, vbn, n);
r = indx_find_buffer(indx, ni, root, vbn, n,
depth + 1);
if (r)
return r;
}
@ -2462,7 +2471,7 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
fnd_clear(fnd);
in = indx_find_buffer(indx, ni, root, sub_vbn, NULL);
in = indx_find_buffer(indx, ni, root, sub_vbn, NULL, 0);
if (IS_ERR(in)) {
err = PTR_ERR(in);
goto out;