Re: [PATCH v1] exfat: add cluster chain loop check for dir

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

 



> On Fri, Jun 13, 2025 at 7:39 PM Yuezhang Mo <Yuezhang.Mo@xxxxxxxx> wrote:
> >
> > An infinite loop may occur if the following conditions occur due to
> > file system corruption.
> >
> > (1) Condition for exfat_count_dir_entries() to loop infinitely.
> >     - The cluster chain includes a loop.
> >     - There is no UNUSED entry in the cluster chain.
> >
> > (2) Condition for exfat_create_upcase_table() to loop infinitely.
> >     - The cluster chain of the root directory includes a loop.
> >     - There are no UNUSED entry and up-case table entry in the cluster
> >       chain of the root directory.
> >
> > (3) Condition for exfat_load_bitmap() to loop infinitely.
> >     - The cluster chain of the root directory includes a loop.
> >     - There are no UNUSED entry and bitmap entry in the cluster chain
> >       of the root directory.
> >
> > This commit adds checks in exfat_count_num_clusters() and
> > exfat_count_dir_entries() to see if the cluster chain includes a loop,
> > thus avoiding the above infinite loops.
> >
> > Signed-off-by: Yuezhang Mo <Yuezhang.Mo@xxxxxxxx>
> > ---
> >  fs/exfat/dir.c    | 33 +++++++++++++++++++++------------
> >  fs/exfat/fatent.c | 10 ++++++++++
> >  fs/exfat/super.c  | 32 +++++++++++++++++++++-----------
> >  3 files changed, 52 insertions(+), 23 deletions(-)
> >
> > diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c
> > index 3103b932b674..467271ad4d71 100644
> > --- a/fs/exfat/dir.c
> > +++ b/fs/exfat/dir.c
> > @@ -1194,7 +1194,8 @@ int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir)
> >  {
> >         int i, count = 0;
> >         int dentries_per_clu;
> > -       unsigned int entry_type;
> > +       unsigned int entry_type = TYPE_FILE;
> > +       unsigned int clu_count = 0;
> >         struct exfat_chain clu;
> >         struct exfat_dentry *ep;
> >         struct exfat_sb_info *sbi = EXFAT_SB(sb);
> > @@ -1205,18 +1206,26 @@ int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir)
> >         exfat_chain_dup(&clu, p_dir);
> >
> >         while (clu.dir != EXFAT_EOF_CLUSTER) {
> > -               for (i = 0; i < dentries_per_clu; i++) {
> > -                       ep = exfat_get_dentry(sb, &clu, i, &bh);
> > -                       if (!ep)
> > -                               return -EIO;
> > -                       entry_type = exfat_get_entry_type(ep);
> > -                       brelse(bh);
> > +               clu_count++;
> > +               if (clu_count > sbi->used_clusters) {
>                     if (++clu_count > sbi->used_clusters) {

Well, that's more concise.

> > +                       exfat_fs_error(sb, "dir size or FAT or bitmap is corrupted");
> > +                       return -EIO;
> > +               }
> >
> > -                       if (entry_type == TYPE_UNUSED)
> > -                               return count;
> > -                       if (entry_type != TYPE_DIR)
> > -                               continue;
> > -                       count++;
> > +               if (entry_type != TYPE_UNUSED) {
> > +                       for (i = 0; i < dentries_per_clu; i++) {
> > +                               ep = exfat_get_dentry(sb, &clu, i, &bh);
> > +                               if (!ep)
> > +                                       return -EIO;
> > +                               entry_type = exfat_get_entry_type(ep);
> > +                               brelse(bh);
> > +
> > +                               if (entry_type == TYPE_UNUSED)
> > +                                       break;
> Is there any reason why you keep doing loop even though you found an
> unused entry?

There are unused directory entries when calling this func, but there
may be none after files are created. That will cause a infinite loop in
exfat_check_dir_empty() and exfat_find_dir_entry().

> 
> > +                               if (entry_type != TYPE_DIR)
> > +                                       continue;
> > +                               count++;
> > +                       }
> >                 }
> >
> >                 if (clu.flags == ALLOC_NO_FAT_CHAIN) {
> > diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c
> > index 23065f948ae7..2a2615ca320f 100644
> > --- a/fs/exfat/fatent.c
> > +++ b/fs/exfat/fatent.c
> > @@ -490,5 +490,15 @@ int exfat_count_num_clusters(struct super_block *sb,
> >         }
> >
> >         *ret_count = count;
> > +
> > +       /*
> > +        * since exfat_count_used_clusters() is not called, sbi->used_clusters
> > +        * cannot be used here.
> > +        */
> > +       if (i == sbi->num_clusters) {
> This is also right, But to make it more clear, wouldn't it be better
> to do clu != EXFAT_EOF_CLUSTER?

OK, I will add this.

> 
> Thanks.
> > +               exfat_fs_error(sb, "The cluster chain has a loop");
> > +               return -EIO;
> > +       }
> > +
> >         return 0;
> >  }





[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux