update bug-fixes/andrew-bugfix.log bug-fixes/andrew-bugfix.patch
authorErez Zadok <ezk@cs.sunysb.edu>
Sun, 8 May 2022 01:14:41 +0000 (21:14 -0400)
committerErez Zadok <ezk@cs.sunysb.edu>
Sun, 8 May 2022 01:14:41 +0000 (21:14 -0400)
bug-fixes/andrew-bugfix.log [new file with mode: 0644]
bug-fixes/andrew-bugfix.patch [new file with mode: 0644]

diff --git a/bug-fixes/andrew-bugfix.log b/bug-fixes/andrew-bugfix.log
new file mode 100644 (file)
index 0000000..5dd6701
--- /dev/null
@@ -0,0 +1,9 @@
+Wrapfs: fix NULL ptr deref in ->d_release and ->read_super
+
+It is possible that the dentry private data is NULL in case we ran out of
+memory while initializing it in new_dentry_private_data.  So check for NULL
+before attempting to release resources.  Similarly, in ->read_super, only
+cleanu resources actually needed (the VFS cleans up the rest indirectly).
+
+Signed-off-by: Andrew Burford <aburford@cs.stonybrook.edu>
+Signed-off-by: Erez Zadok <ezk@cs.stonybrook.edu>
diff --git a/bug-fixes/andrew-bugfix.patch b/bug-fixes/andrew-bugfix.patch
new file mode 100644 (file)
index 0000000..1eee2b2
--- /dev/null
@@ -0,0 +1,90 @@
+diff --git a/fs/wrapfs/dentry.c b/fs/wrapfs/dentry.c
+index 08110aceb05b..45498e4a4804 100644
+--- a/fs/wrapfs/dentry.c
++++ b/fs/wrapfs/dentry.c
+@@ -34,9 +34,17 @@ static int wrapfs_d_revalidate(struct dentry *dentry, unsigned int flags)
+ static void wrapfs_d_release(struct dentry *dentry)
+ {
+-      /* release and reset the lower paths */
+-      wrapfs_put_reset_lower_path(dentry);
+-      free_dentry_private_data(dentry);
++      /*
++       * It is possible that the dentry private data is NULL in case we
++       * ran out of memory while initializing it in
++       * new_dentry_private_data.  So check for NULL before attempting to
++       * release resources.
++       */
++      if (WRAPFS_D(dentry)) {
++              /* release and reset the lower paths */
++              wrapfs_put_reset_lower_path(dentry);
++              free_dentry_private_data(dentry);
++      }
+       return;
+ }
+diff --git a/fs/wrapfs/main.c b/fs/wrapfs/main.c
+index b73a7d86084b..3df02cc778b3 100644
+--- a/fs/wrapfs/main.c
++++ b/fs/wrapfs/main.c
+@@ -42,7 +42,7 @@ static int wrapfs_read_super(struct super_block *sb, void *raw_data, int silent)
+       if (!WRAPFS_SB(sb)) {
+               printk(KERN_CRIT "wrapfs: read_super: out of memory\n");
+               err = -ENOMEM;
+-              goto out_free;
++              goto out_pput;
+       }
+       /* set the lower superblock field of upper superblock */
+@@ -68,12 +68,12 @@ static int wrapfs_read_super(struct super_block *sb, void *raw_data, int silent)
+       inode = wrapfs_iget(sb, d_inode(lower_path.dentry));
+       if (IS_ERR(inode)) {
+               err = PTR_ERR(inode);
+-              goto out_sput;
++              goto out_pput;
+       }
+       sb->s_root = d_make_root(inode);
+       if (!sb->s_root) {
+               err = -ENOMEM;
+-              goto out_iput;
++              goto out_pput;
+       }
+       d_set_d_op(sb->s_root, &wrapfs_dops);
+@@ -81,7 +81,7 @@ static int wrapfs_read_super(struct super_block *sb, void *raw_data, int silent)
+       sb->s_root->d_fsdata = NULL;
+       err = new_dentry_private_data(sb->s_root);
+       if (err)
+-              goto out_freeroot;
++              goto out_pput;
+       /* if get here: cannot have error */
+@@ -100,19 +100,15 @@ static int wrapfs_read_super(struct super_block *sb, void *raw_data, int silent)
+                      dev_name, lower_sb->s_type->name);
+       goto out; /* all is well */
+-      /* no longer needed: free_dentry_private_data(sb->s_root); */
+-out_freeroot:
+-      dput(sb->s_root);
+-out_iput:
+-      iput(inode);
+-out_sput:
+-      /* drop refs we took earlier */
+-      atomic_dec(&lower_sb->s_active);
+-      kfree(WRAPFS_SB(sb));
+-      sb->s_fs_info = NULL;
+-out_free:
++      /*
++       * path_put is the only resource we need to free if an error occurred
++       * because returning an error from this function will cause
++       * generic_shutdown_super to be called, which will call
++       * wrapfs_put_super, and that function will release any other
++       * resources we took.
++       */
++out_pput:
+       path_put(&lower_path);
+-
+ out:
+       return err;
+ }