* [PATCH] fs/ntfs3: add depth limit to indx_find_buffer to prevent stack overflow
@ 2026-04-13 13:31 Michael Bommarito
2026-04-30 11:58 ` Konstantin Komarov
0 siblings, 1 reply; 2+ messages in thread
From: Michael Bommarito @ 2026-04-13 13:31 UTC (permalink / raw)
To: Konstantin Komarov; +Cc: ntfs3, linux-fsdevel, stable
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 1732053c8a6b), but indx_find_buffer() was
missed.
Fixes: 82cae269cfa9 ("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>
---
Found during a broader arch/um/ and filesystem security audit.
This is the same class of bug as the one fixed by commit
1732053c8a6b ("fs: ntfs3: check return value of indx_find to
avoid infinite loop"), which added a depth limit to indx_find()
but missed indx_find_buffer().
Reproduced on UML (ARCH=um) with a crafted NTFS image containing
a circular B+ tree directory index. Mounting the image and
deleting a specific file triggers indx_delete_entry() ->
indx_find_buffer() -> unbounded recursion -> stack overflow:
Kernel panic - not syncing: Kernel tried to access user memory
at addr 0x606128c4, ip 0x6012907e
Call Trace:
[<60611ec2>] ? indx_read_ra+0x0/0x677
At 168+ bytes per frame, ~97 recursions overflow the 16KB kernel
stack. Desktop automount (udisks2 + ntfs3) means a crafted USB
drive can trigger this without privilege.
Note: the pre-existing indx_node allocated by indx_read() during
the DFS is leaked when the new depth limit fires. This is a
pre-existing issue (the node was also leaked on any other error
return from indx_find_buffer); fixing it cleanly requires
restructuring the node ownership model and is left for a
follow-up patch.
Reproducer script and crafted image builder available on request.
fs/ntfs3/index.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c
index 97f06c26fe1a..2c43e7c27861 100644
--- a/fs/ntfs3/index.c
+++ b/fs/ntfs3/index.c
@@ -2013,13 +2013,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)
@@ -2040,7 +2048,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;
}
@@ -2446,7 +2455,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;
--
2.53.0
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH] fs/ntfs3: add depth limit to indx_find_buffer to prevent stack overflow
2026-04-13 13:31 [PATCH] fs/ntfs3: add depth limit to indx_find_buffer to prevent stack overflow Michael Bommarito
@ 2026-04-30 11:58 ` Konstantin Komarov
0 siblings, 0 replies; 2+ messages in thread
From: Konstantin Komarov @ 2026-04-30 11:58 UTC (permalink / raw)
To: Michael Bommarito; +Cc: ntfs3, linux-fsdevel, stable
On 4/13/26 15:31, Michael Bommarito wrote:
> [You don't often get email from michael.bommarito@gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> 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 1732053c8a6b), but indx_find_buffer() was
> missed.
>
> Fixes: 82cae269cfa9 ("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>
> ---
> Found during a broader arch/um/ and filesystem security audit.
> This is the same class of bug as the one fixed by commit
> 1732053c8a6b ("fs: ntfs3: check return value of indx_find to
> avoid infinite loop"), which added a depth limit to indx_find()
> but missed indx_find_buffer().
>
> Reproduced on UML (ARCH=um) with a crafted NTFS image containing
> a circular B+ tree directory index. Mounting the image and
> deleting a specific file triggers indx_delete_entry() ->
> indx_find_buffer() -> unbounded recursion -> stack overflow:
>
> Kernel panic - not syncing: Kernel tried to access user memory
> at addr 0x606128c4, ip 0x6012907e
> Call Trace:
> [<60611ec2>] ? indx_read_ra+0x0/0x677
>
> At 168+ bytes per frame, ~97 recursions overflow the 16KB kernel
> stack. Desktop automount (udisks2 + ntfs3) means a crafted USB
> drive can trigger this without privilege.
>
> Note: the pre-existing indx_node allocated by indx_read() during
> the DFS is leaked when the new depth limit fires. This is a
> pre-existing issue (the node was also leaked on any other error
> return from indx_find_buffer); fixing it cleanly requires
> restructuring the node ownership model and is left for a
> follow-up patch.
>
> Reproducer script and crafted image builder available on request.
>
> fs/ntfs3/index.c | 15 ++++++++++++---
> 1 file changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c
> index 97f06c26fe1a..2c43e7c27861 100644
> --- a/fs/ntfs3/index.c
> +++ b/fs/ntfs3/index.c
> @@ -2013,13 +2013,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)
> @@ -2040,7 +2048,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;
> }
> @@ -2446,7 +2455,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;
> --
> 2.53.0
>
Hello,
Sorry for the delay.
Your patch was applied, thanks.
Regards,
Konstantin
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-04-30 11:58 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-13 13:31 [PATCH] fs/ntfs3: add depth limit to indx_find_buffer to prevent stack overflow Michael Bommarito
2026-04-30 11:58 ` Konstantin Komarov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox