mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
To: "Jérémy Jean" <Jeremy.Jean@oss.cyber.gouv.fr>
Cc: <ntfs3@lists.linux.dev>, <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] fs/ntfs3: validate log replay bitmap buffer spans
Date: Wed, 11 Nov 2026 09:48:49 +0100	[thread overview]
Message-ID: <b54d213e-dae1-4d4e-af1c-c28c5a6cf84c@paragon-software.com> (raw)
In-Reply-To: <20260817202941.1635505-2-Jeremy.Jean@oss.cyber.gouv.fr>

On 8/17/26 22:29, Jérémy Jean wrote:

> do_action() derives the read buffer size for bitmap replay records from
> lrh->lcns_follow in u64, then stores it in u32 bytes. A log record that
> covers more than U32_MAX bytes therefore allocates and reads only the
> truncated tail while the bitmap range checks still compare against the
> full u64 span. ntfs_bitmap_{set,clear}_le() can then access past
> buffer_le.
>
> Keep the span in u64 until the read size has been validated against the
> u32 ntfs_read_run_nb() interface. Also validate bitmap ranges in u64 and
> reject lengths that cannot be represented by the helpers' int len
> parameter, so crafted bitmap_off/bits values cannot wrap the existing
> u32 arithmetic before the bounds check.
>
> Fixes: b46acd6a6a62 ("fs/ntfs3: Add NTFS journal")
> Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
> Assisted-by: Codex:gpt-5
> ---
>   fs/ntfs3/fslog.c | 53 +++++++++++++++++++++++++++++++++++++-----------
>   1 file changed, 41 insertions(+), 12 deletions(-)
>
> diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c
> index f038c799e7ac..21d89de96ba1 100644
> --- a/fs/ntfs3/fslog.c
> +++ b/fs/ntfs3/fslog.c
> @@ -7,6 +7,8 @@
>
>   #include <linux/blkdev.h>
>   #include <linux/fs.h>
> +#include <linux/limits.h>
> +#include <linux/overflow.h>
>   #include <linux/random.h>
>   #include <linux/slab.h>
>
> @@ -2967,6 +2969,35 @@ static inline bool check_if_alloc_index(const struct INDEX_HDR *hdr,
>          return o == attr_off;
>   }
>
> +static inline bool calc_log_buffer_size(u32 min_bytes, u64 data_bytes,
> +                                       u16 roff, bool align, u32 *bytes)
> +{
> +       u64 bytes64 = min_bytes ? min_bytes : data_bytes;
> +
> +       if (check_add_overflow(bytes64, (u64)roff, &bytes64))
> +               return false;
> +
> +       if (align) {
> +               if (check_add_overflow(bytes64, 511ULL, &bytes64))
> +                       return false;
> +               bytes64 &= ~511ULL;
> +       }
> +
> +       if (bytes64 > U32_MAX)
> +               return false;
> +
> +       *bytes = bytes64;
> +       return true;
> +}
> +
> +static inline bool check_if_bitmap_range(u64 bytes, u32 off, u32 bits)
> +{
> +       u64 start = ((u64)off + 7) / 8;
> +       u64 end = ((u64)off + bits + 7) / 8;
> +
> +       return bits <= S32_MAX && start <= bytes && end <= bytes;
> +}
> +
>   static inline void change_attr_size(struct MFT_REC *rec, struct ATTRIB *attr,
>                                      u32 nsize)
>   {
> @@ -3114,6 +3145,7 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe,
>          u16 roff = le16_to_cpu(lrh->record_off);
>          u16 aoff = le16_to_cpu(lrh->attr_off);
>          u64 lco = 0;
> +       u64 data_bytes = 0;
>          u64 cbo = (u64)le16_to_cpu(lrh->cluster_off) << SECTOR_SHIFT;
>          u64 tvo = le64_to_cpu(lrh->target_vcn) << sbi->cluster_bits;
>          u64 vbo = cbo + tvo;
> @@ -3225,6 +3257,10 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe,
>                  attr = oa->attr;
>                  bytes = UpdateNonresidentValue == op ? dlen : 0;
>                  lco = (u64)le16_to_cpu(lrh->lcns_follow) << sbi->cluster_bits;
> +               if (lco < cbo)
> +                       goto dirty_vol;
> +
> +               data_bytes = lco - cbo;
>
>                  if (attr->type == ATTR_ALLOC) {
>                          t32 = le32_to_cpu(oe->bytes_per_index);
> @@ -3232,12 +3268,9 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe,
>                                  bytes = t32;
>                  }
>
> -               if (!bytes)
> -                       bytes = lco - cbo;
> -
> -               bytes += roff;
> -               if (attr->type == ATTR_ALLOC)
> -                       bytes = (bytes + 511) & ~511; // align
> +               if (!calc_log_buffer_size(bytes, data_bytes, roff,
> +                                         attr->type == ATTR_ALLOC, &bytes))
> +                       goto dirty_vol;
>
>                  buffer_le = kmalloc(bytes, GFP_NOFS);
>                  if (!buffer_le)
> @@ -3717,10 +3750,8 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe,
>                  off = le32_to_cpu(((struct BITMAP_RANGE *)data)->bitmap_off);
>                  bits = le32_to_cpu(((struct BITMAP_RANGE *)data)->bits);
>
> -               if (cbo + (off + 7) / 8 > lco ||
> -                   cbo + ((off + bits + 7) / 8) > lco) {
> +               if (!check_if_bitmap_range(data_bytes, off, bits))
>                          goto dirty_vol;
> -               }
>
>                  ntfs_bitmap_set_le(Add2Ptr(buffer_le, roff), off, bits);
>                  a_dirty = true;
> @@ -3730,10 +3761,8 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe,
>                  off = le32_to_cpu(((struct BITMAP_RANGE *)data)->bitmap_off);
>                  bits = le32_to_cpu(((struct BITMAP_RANGE *)data)->bits);
>
> -               if (cbo + (off + 7) / 8 > lco ||
> -                   cbo + ((off + bits + 7) / 8) > lco) {
> +               if (!check_if_bitmap_range(data_bytes, off, bits))
>                          goto dirty_vol;
> -               }
>
>                  ntfs_bitmap_clear_le(Add2Ptr(buffer_le, roff), off, bits);
>                  a_dirty = true;
> --
> 2.47.3

Hello,

Sorry for the delay.
The patch was applied, thank you.

Regards,
Konstantin


      parent reply	other threads:[~2026-11-11  8:48 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-17 20:29 Jérémy Jean
2026-11-03 18:21 ` Jérémy Jean
2026-11-11  8:48 ` Konstantin Komarov [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b54d213e-dae1-4d4e-af1c-c28c5a6cf84c@paragon-software.com \
    --to=almaz.alexandrovich@paragon-software.com \
    --cc=Jeremy.Jean@oss.cyber.gouv.fr \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ntfs3@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®