Merge tag 'ubifs-for-linus-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Mar 2023 17:06:51 +0000 (09:06 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Mar 2023 17:06:51 +0000 (09:06 -0800)
Pull jffs2, ubi and ubifs updates from Richard Weinberger:
 "JFFS2:
   - Fix memory corruption in error path
   - Spelling and coding style fixes

  UBI:
   - Switch to BLK_MQ_F_BLOCKING in ubiblock
   - Wire up partent device (for sysfs)
   - Multiple UAF bugfixes
   - Fix for an infinite loop in WL error path

  UBIFS:
   - Fix for multiple memory leaks in error paths
   - Fixes for wrong space accounting
   - Minor cleanups
   - Spelling and coding style fixes"

* tag 'ubifs-for-linus-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs: (36 commits)
  ubi: block: Fix a possible use-after-free bug in ubiblock_create()
  ubifs: make kobj_type structures constant
  mtd: ubi: block: wire-up device parent
  mtd: ubi: wire-up parent MTD device
  ubi: use correct names in function kernel-doc comments
  ubi: block: set BLK_MQ_F_BLOCKING
  jffs2: Fix list_del corruption if compressors initialized failed
  jffs2: Use function instead of macro when initialize compressors
  jffs2: fix spelling mistake "neccecary"->"necessary"
  ubifs: Fix kernel-doc
  ubifs: Fix some kernel-doc comments
  UBI: Fastmap: Fix kernel-doc
  ubi: ubi_wl_put_peb: Fix infinite loop when wear-leveling work failed
  ubi: Fix UAF wear-leveling entry in eraseblk_count_seq_show()
  ubi: fastmap: Fix missed fm_anchor PEB in wear-leveling after disabling fastmap
  ubifs: ubifs_releasepage: Remove ubifs_assert(0) to valid this process
  ubifs: ubifs_writepage: Mark page dirty after writing inode failed
  ubifs: dirty_cow_znode: Fix memleak in error handling path
  ubifs: Re-statistic cleaned znode count if commit failed
  ubi: Fix permission display of the debugfs files
  ...

1  2 
fs/jffs2/fs.c
fs/ubifs/dir.c
fs/ubifs/file.c
fs/ubifs/ubifs.h

diff --combined fs/jffs2/fs.c
index 09174898efd008d1b9a2939ee48a3a736931aeff,e952b0bd548b6c10095f7f9df9f17e206057f149..038516bee1abaac6b8acb0ff8652cc12f474e848
@@@ -190,19 -190,19 +190,19 @@@ int jffs2_do_setattr (struct inode *ino
        return 0;
  }
  
 -int jffs2_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
 +int jffs2_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
                  struct iattr *iattr)
  {
        struct inode *inode = d_inode(dentry);
        int rc;
  
 -      rc = setattr_prepare(&init_user_ns, dentry, iattr);
 +      rc = setattr_prepare(&nop_mnt_idmap, dentry, iattr);
        if (rc)
                return rc;
  
        rc = jffs2_do_setattr(inode, iattr);
        if (!rc && (iattr->ia_valid & ATTR_MODE))
 -              rc = posix_acl_chmod(&init_user_ns, dentry, inode->i_mode);
 +              rc = posix_acl_chmod(&nop_mnt_idmap, dentry, inode->i_mode);
  
        return rc;
  }
@@@ -403,7 -403,7 +403,7 @@@ int jffs2_do_remount_fs(struct super_bl
        /* We stop if it was running, then restart if it needs to.
           This also catches the case where it was stopped and this
           is just a remount to restart it.
-          Flush the writebuffer, if neccecary, else we loose it */
+          Flush the writebuffer, if necessary, else we loose it */
        if (!sb_rdonly(sb)) {
                jffs2_stop_garbage_collect_thread(c);
                mutex_lock(&c->alloc_sem);
diff --combined fs/ubifs/dir.c
index 1e92c1730c16540cf804fa74299a7b1228eda45e,4509d9fa9e6e375528479222965994269abbf53d..1505539f6fe974ae73990e57773a8c96628136f4
@@@ -95,7 -95,7 +95,7 @@@ struct inode *ubifs_new_inode(struct ub
         */
        inode->i_flags |= S_NOCMTIME;
  
 -      inode_init_owner(&init_user_ns, inode, dir, mode);
 +      inode_init_owner(&nop_mnt_idmap, inode, dir, mode);
        inode->i_mtime = inode->i_atime = inode->i_ctime =
                         current_time(inode);
        inode->i_mapping->nrpages = 0;
@@@ -283,7 -283,7 +283,7 @@@ static int ubifs_prepare_create(struct 
        return fscrypt_setup_filename(dir, &dentry->d_name, 0, nm);
  }
  
 -static int ubifs_create(struct user_namespace *mnt_userns, struct inode *dir,
 +static int ubifs_create(struct mnt_idmap *idmap, struct inode *dir,
                        struct dentry *dentry, umode_t mode, bool excl)
  {
        struct inode *inode;
@@@ -426,7 -426,7 +426,7 @@@ static void unlock_2_inodes(struct inod
        mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
  }
  
 -static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
 +static int ubifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
                         struct file *file, umode_t mode)
  {
        struct dentry *dentry = file->f_path.dentry;
@@@ -979,7 -979,7 +979,7 @@@ out_fname
        return err;
  }
  
 -static int ubifs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 +static int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
                       struct dentry *dentry, umode_t mode)
  {
        struct inode *inode;
@@@ -1052,7 -1052,7 +1052,7 @@@ out_budg
        return err;
  }
  
 -static int ubifs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
 +static int ubifs_mknod(struct mnt_idmap *idmap, struct inode *dir,
                       struct dentry *dentry, umode_t mode, dev_t rdev)
  {
        struct inode *inode;
@@@ -1141,7 -1141,7 +1141,7 @@@ out_budg
        return err;
  }
  
 -static int ubifs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 +static int ubifs_symlink(struct mnt_idmap *idmap, struct inode *dir,
                         struct dentry *dentry, const char *symname)
  {
        struct inode *inode;
        int err, sz_change, len = strlen(symname);
        struct fscrypt_str disk_link;
        struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
-                                       .new_ino_d = ALIGN(len, 8),
                                        .dirtied_ino = 1 };
        struct fscrypt_name nm;
  
         * Budget request settings: new inode, new direntry and changing parent
         * directory inode.
         */
+       req.new_ino_d = ALIGN(disk_link.len - 1, 8);
        err = ubifs_budget_space(c, &req);
        if (err)
                return err;
@@@ -1324,6 -1324,8 +1324,8 @@@ static int do_rename(struct inode *old_
        if (unlink) {
                ubifs_assert(c, inode_is_locked(new_inode));
  
+               /* Budget for old inode's data when its nlink > 1. */
+               req.dirtied_ino_d = ALIGN(ubifs_inode(new_inode)->data_len, 8);
                err = ubifs_purge_xattrs(new_inode);
                if (err)
                        return err;
@@@ -1566,6 -1568,15 +1568,15 @@@ static int ubifs_xrename(struct inode *
  
        ubifs_assert(c, fst_inode && snd_inode);
  
+       /*
+        * Budget request settings: changing two direntries, changing the two
+        * parent directory inodes.
+        */
+       dbg_gen("dent '%pd' ino %lu in dir ino %lu exchange dent '%pd' ino %lu in dir ino %lu",
+               old_dentry, fst_inode->i_ino, old_dir->i_ino,
+               new_dentry, snd_inode->i_ino, new_dir->i_ino);
        err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &fst_nm);
        if (err)
                return err;
                return err;
        }
  
+       err = ubifs_budget_space(c, &req);
+       if (err)
+               goto out;
        lock_4_inodes(old_dir, new_dir, NULL, NULL);
  
        time = current_time(old_dir);
        unlock_4_inodes(old_dir, new_dir, NULL, NULL);
        ubifs_release_budget(c, &req);
  
+ out:
        fscrypt_free_filename(&fst_nm);
        fscrypt_free_filename(&snd_nm);
        return err;
  }
  
 -static int ubifs_rename(struct user_namespace *mnt_userns,
 +static int ubifs_rename(struct mnt_idmap *idmap,
                        struct inode *old_dir, struct dentry *old_dentry,
                        struct inode *new_dir, struct dentry *new_dentry,
                        unsigned int flags)
        return do_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
  }
  
 -int ubifs_getattr(struct user_namespace *mnt_userns, const struct path *path,
 +int ubifs_getattr(struct mnt_idmap *idmap, const struct path *path,
                  struct kstat *stat, u32 request_mask, unsigned int flags)
  {
        loff_t size;
                                STATX_ATTR_ENCRYPTED |
                                STATX_ATTR_IMMUTABLE);
  
 -      generic_fillattr(&init_user_ns, inode, stat);
 +      generic_fillattr(&nop_mnt_idmap, inode, stat);
        stat->blksize = UBIFS_BLOCK_SIZE;
        stat->size = ui->ui_size;
  
diff --combined fs/ubifs/file.c
index 8cb5d76b301ccde611be04b7662acdcbdb1ead82,10c1779af9c519067e54cabe311f3b67843231f0..979ab1d9d0c39ddf56ea9d9f8e1f5c2e4c30a3d3
@@@ -1032,7 -1032,7 +1032,7 @@@ static int ubifs_writepage(struct page 
                if (page->index >= synced_i_size >> PAGE_SHIFT) {
                        err = inode->i_sb->s_op->write_inode(inode, NULL);
                        if (err)
-                               goto out_unlock;
+                               goto out_redirty;
                        /*
                         * The inode has been written, but the write-buffer has
                         * not been synchronized, so in case of an unclean
        if (i_size > synced_i_size) {
                err = inode->i_sb->s_op->write_inode(inode, NULL);
                if (err)
-                       goto out_unlock;
+                       goto out_redirty;
        }
  
        return do_writepage(page, len);
+ out_redirty:
+       /*
+        * redirty_page_for_writepage() won't call ubifs_dirty_inode() because
+        * it passes I_DIRTY_PAGES flag while calling __mark_inode_dirty(), so
+        * there is no need to do space budget for dirty inode.
+        */
+       redirty_page_for_writepage(wbc, page);
  out_unlock:
        unlock_page(page);
        return err;
@@@ -1258,7 -1264,7 +1264,7 @@@ static int do_setattr(struct ubifs_inf
        return err;
  }
  
 -int ubifs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
 +int ubifs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
                  struct iattr *attr)
  {
        int err;
  
        dbg_gen("ino %lu, mode %#x, ia_valid %#x",
                inode->i_ino, inode->i_mode, attr->ia_valid);
 -      err = setattr_prepare(&init_user_ns, dentry, attr);
 +      err = setattr_prepare(&nop_mnt_idmap, dentry, attr);
        if (err)
                return err;
  
@@@ -1466,14 -1472,23 +1472,23 @@@ static bool ubifs_release_folio(struct 
        struct inode *inode = folio->mapping->host;
        struct ubifs_info *c = inode->i_sb->s_fs_info;
  
-       /*
-        * An attempt to release a dirty page without budgeting for it - should
-        * not happen.
-        */
        if (folio_test_writeback(folio))
                return false;
+       /*
+        * Page is private but not dirty, weird? There is one condition
+        * making it happened. ubifs_writepage skipped the page because
+        * page index beyonds isize (for example. truncated by other
+        * process named A), then the page is invalidated by fadvise64
+        * syscall before being truncated by process A.
+        */
        ubifs_assert(c, folio_test_private(folio));
-       ubifs_assert(c, 0);
+       if (folio_test_checked(folio))
+               release_new_page_budget(c);
+       else
+               release_existing_page_budget(c);
+       atomic_long_dec(&c->dirty_pg_cnt);
        folio_detach_private(folio);
        folio_clear_checked(folio);
        return true;
@@@ -1608,11 -1623,11 +1623,11 @@@ static const char *ubifs_get_link(struc
        return fscrypt_get_symlink(inode, ui->data, ui->data_len, done);
  }
  
 -static int ubifs_symlink_getattr(struct user_namespace *mnt_userns,
 +static int ubifs_symlink_getattr(struct mnt_idmap *idmap,
                                 const struct path *path, struct kstat *stat,
                                 u32 request_mask, unsigned int query_flags)
  {
 -      ubifs_getattr(mnt_userns, path, stat, request_mask, query_flags);
 +      ubifs_getattr(idmap, path, stat, request_mask, query_flags);
  
        if (IS_ENCRYPTED(d_inode(path->dentry)))
                return fscrypt_symlink_getattr(path, stat);
diff --combined fs/ubifs/ubifs.h
index 9063b73536f805cffecd8e5e25bdd8fa48d29fb8,2f1f31581094907081768a0e8743dfb0447f0073..4c36044140e7eba9234b87c3a4bc6ab4b73ec64b
@@@ -1623,8 -1623,13 +1623,13 @@@ static inline int ubifs_check_hmac(cons
        return crypto_memneq(expected, got, c->hmac_desc_len);
  }
  
+ #ifdef CONFIG_UBIFS_FS_AUTHENTICATION
  void ubifs_bad_hash(const struct ubifs_info *c, const void *node,
                    const u8 *hash, int lnum, int offs);
+ #else
+ static inline void ubifs_bad_hash(const struct ubifs_info *c, const void *node,
+                                 const u8 *hash, int lnum, int offs) {};
+ #endif
  
  int __ubifs_node_check_hash(const struct ubifs_info *c, const void *buf,
                          const u8 *expected);
@@@ -2020,15 -2025,15 +2025,15 @@@ int ubifs_calc_dark(const struct ubifs_
  
  /* file.c */
  int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync);
 -int ubifs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
 +int ubifs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
                  struct iattr *attr);
  int ubifs_update_time(struct inode *inode, struct timespec64 *time, int flags);
  
  /* dir.c */
  struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
                              umode_t mode, bool is_xattr);
 -int ubifs_getattr(struct user_namespace *mnt_userns, const struct path *path, struct kstat *stat,
 -                u32 request_mask, unsigned int flags);
 +int ubifs_getattr(struct mnt_idmap *idmap, const struct path *path,
 +                struct kstat *stat, u32 request_mask, unsigned int flags);
  int ubifs_check_dir_empty(struct inode *dir);
  
  /* xattr.c */
@@@ -2085,7 -2090,7 +2090,7 @@@ void ubifs_destroy_size_tree(struct ubi
  
  /* ioctl.c */
  int ubifs_fileattr_get(struct dentry *dentry, struct fileattr *fa);
 -int ubifs_fileattr_set(struct user_namespace *mnt_userns,
 +int ubifs_fileattr_set(struct mnt_idmap *idmap,
                       struct dentry *dentry, struct fileattr *fa);
  long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
  void ubifs_set_inode_flags(struct inode *inode);