Wrapfs: fix NULL ptr deref in ->d_release and ->read_super
authorErez Zadok <ezk@cs.sunysb.edu>
Sun, 8 May 2022 01:31:59 +0000 (21:31 -0400)
committerErez Zadok <ezk@cs.sunysb.edu>
Sun, 8 May 2022 01:31:59 +0000 (21:31 -0400)
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>
fs/wrapfs/dentry.c
fs/wrapfs/main.c

index 08110aceb05b5385f57f1ec25f4608fb8cedc703..b2eb16859e3c6c631d78d9a4d98eff8668edf55a 100644 (file)
@@ -34,9 +34,17 @@ out:
 
 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;
 }
 
index b73a7d86084b04de7fe89040ddbfd642fedeba29..3df02cc778b383280090ca4a00a20c01b8e7af77 100644 (file)
@@ -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;
 }