Re: [PATCH] ntfs3: Add bounds checking to enum_rstbl()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Jul 2, 2024 at 10:17 AM lei lu <llfamsec@xxxxxxxxx> wrote:
>
> Added bounds checking to make sure rsize is not less than the entry
> size and make sure the remaining bytes are large enough to hold an
> entry before accessing in the caller.
>
> Signed-off-by: lei lu <llfamsec@xxxxxxxxx>
> ---
>  fs/ntfs3/fslog.c | 33 +++++++++++++++++++--------------
>  1 file changed, 19 insertions(+), 14 deletions(-)
>
> diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c
> index 855519713bf7..75d31bc11567 100644
> --- a/fs/ntfs3/fslog.c
> +++ b/fs/ntfs3/fslog.c
> @@ -609,12 +609,15 @@ static inline void add_client(struct CLIENT_REC *ca, u16 index, __le16 *head)
>         *head = cpu_to_le16(index);
>  }
>
> -static inline void *enum_rstbl(struct RESTART_TABLE *t, void *c)
> +static inline void *enum_rstbl(struct RESTART_TABLE *t, void *c, u16 esize)
>  {
>         __le32 *e;
>         u32 bprt;
>         u16 rsize = t ? le16_to_cpu(t->size) : 0;
>
> +       if (rsize < esize)
> +               return NULL;

There is a special scene here.
1) In label check_dirty_page_table, "while ((dp = enum_rstbl(dptbl,
dp)))" thinks
rsize is the size of DIR_PAGE_ENTRY_32 (esize1)
2) In label end_conv_1, "while ((dp = enum_rstbl(dptbl, dp)))" thinks
the same rsize
is the size of DIR_PAGE_ENTRY (esize2)

it seems that “esize2 + 4 = esize1”. So if rsize >= esize1, also rsize
>= esize2.

> +
>         if (!c) {
>                 if (!t || !t->total)
>                         return NULL;
> @@ -626,6 +629,8 @@ static inline void *enum_rstbl(struct RESTART_TABLE *t, void *c)
>         /* Loop until we hit the first one allocated, or the end of the list. */
>         for (bprt = bytes_per_rt(t); PtrOffset(t, e) < bprt;
>              e = Add2Ptr(e, rsize)) {
> +               if (PtrOffset(t, Add2Ptr(e, esize)) > bprt)
> +                       return NULL;
>                 if (*e == RESTART_ENTRY_ALLOCATED_LE)
>                         return e;
>         }
> @@ -641,7 +646,7 @@ static inline struct DIR_PAGE_ENTRY *find_dp(struct RESTART_TABLE *dptbl,
>         __le32 ta = cpu_to_le32(target_attr);
>         struct DIR_PAGE_ENTRY *dp = NULL;
>
> -       while ((dp = enum_rstbl(dptbl, dp))) {
> +       while ((dp = enum_rstbl(dptbl, dp, sizeof(*dp)))) {
>                 u64 dp_vcn = le64_to_cpu(dp->vcn);
>
>                 if (dp->target_attr == ta && vcn >= dp_vcn &&
> @@ -2950,7 +2955,7 @@ static struct OpenAttr *find_loaded_attr(struct ntfs_log *log,
>  {
>         struct OPEN_ATTR_ENRTY *oe = NULL;
>
> -       while ((oe = enum_rstbl(log->open_attr_tbl, oe))) {
> +       while ((oe = enum_rstbl(log->open_attr_tbl, oe, sizeof(*oe)))) {
>                 struct OpenAttr *op_attr;
>
>                 if (ino_get(&oe->ref) != rno)
> @@ -4182,7 +4187,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
>                 goto end_conv_1;
>
>         dp = NULL;
> -       while ((dp = enum_rstbl(dptbl, dp))) {
> +       while ((dp = enum_rstbl(dptbl, dp, sizeof(*dp)))) {

The code should be modified to
"while ((dp = enum_rstbl(dptbl, dp, sizeof(struct DIR_PAGE_ENTRY_32))))".


>                 struct DIR_PAGE_ENTRY_32 *dp0 = (struct DIR_PAGE_ENTRY_32 *)dp;
>                 // NOTE: Danger. Check for of boundary.
>                 memmove(&dp->vcn, &dp0->vcn_low,
> @@ -4202,10 +4207,10 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
>                 goto trace_dp_table;
>
>         dp = NULL;
> -       while ((dp = enum_rstbl(dptbl, dp))) {
> +       while ((dp = enum_rstbl(dptbl, dp, sizeof(*dp)))) {
>                 struct DIR_PAGE_ENTRY *next = dp;
>
> -               while ((next = enum_rstbl(dptbl, next))) {
> +               while ((next = enum_rstbl(dptbl, next, sizeof(*next)))) {
>                         if (next->target_attr == dp->target_attr &&
>                             next->vcn == dp->vcn) {
>                                 if (le64_to_cpu(next->oldest_lsn) <
> @@ -4290,7 +4295,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
>
>         /* Clear all of the Attr pointers. */
>         oe = NULL;
> -       while ((oe = enum_rstbl(oatbl, oe))) {
> +       while ((oe = enum_rstbl(oatbl, oe, sizeof(*oe)))) {
>                 if (!rst->major_ver) {
>                         struct OPEN_ATTR_ENRTY_32 oe0;
>
> @@ -4507,7 +4512,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
>                         u64 lcn_e = lcn0 + le64_to_cpu(r->len) - 1;
>
>                         dp = NULL;
> -                       while ((dp = enum_rstbl(dptbl, dp))) {
> +                       while ((dp = enum_rstbl(dptbl, dp, sizeof(*dp)))) {
>                                 u32 j;
>
>                                 t32 = le32_to_cpu(dp->lcns_follow);
> @@ -4640,14 +4645,14 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
>          * the lowest lsn, and return it as the Redo lsn.
>          */
>         dp = NULL;
> -       while ((dp = enum_rstbl(dptbl, dp))) {
> +       while ((dp = enum_rstbl(dptbl, dp, sizeof(*dp)))) {
>                 t64 = le64_to_cpu(dp->oldest_lsn);
>                 if (t64 && t64 < rlsn)
>                         rlsn = t64;
>         }
>
>         tr = NULL;
> -       while ((tr = enum_rstbl(trtbl, tr))) {
> +       while ((tr = enum_rstbl(trtbl, tr, sizeof(*tr)))) {
>                 t64 = le64_to_cpu(tr->first_lsn);
>                 if (t64 && t64 < rlsn)
>                         rlsn = t64;
> @@ -4668,7 +4673,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
>         oe = NULL;
>  next_open_attribute:
>
> -       oe = enum_rstbl(oatbl, oe);
> +       oe = enum_rstbl(oatbl, oe, sizeof(*oe));
>         if (!oe) {
>                 err = 0;
>                 dp = NULL;
> @@ -4770,7 +4775,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
>          * Mapping that we have, and insert it into the appropriate run.
>          */
>  next_dirty_page:
> -       dp = enum_rstbl(dptbl, dp);
> +       dp = enum_rstbl(dptbl, dp, sizeof(*dp));
>         if (!dp)
>                 goto do_redo_1;
>
> @@ -4968,7 +4973,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
>         /* Scan Transaction Table. */
>         tr = NULL;
>  transaction_table_next:
> -       tr = enum_rstbl(trtbl, tr);
> +       tr = enum_rstbl(trtbl, tr, sizeof(*tr));
>         if (!tr)
>                 goto undo_action_done;
>
> @@ -5142,7 +5147,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
>          * the open attributes.
>          */
>         oe = NULL;
> -       while ((oe = enum_rstbl(oatbl, oe))) {
> +       while ((oe = enum_rstbl(oatbl, oe, sizeof(*oe)))) {
>                 rno = ino_get(&oe->ref);
>
>                 if (oe->is_attr_name == 1) {
> --
> 2.34.1
>





[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux