device-dax: fix 'dax' device filesystem inode destruction crash
authorDan Williams <dan.j.williams@intel.com>
Fri, 9 Jun 2017 15:50:49 +0000 (08:50 -0700)
committerDan Williams <dan.j.williams@intel.com>
Fri, 9 Jun 2017 15:50:49 +0000 (08:50 -0700)
The inode destruction path for the 'dax' device filesystem incorrectly
assumes that the inode was initialized through 'alloc_dax()'. However,
if someone attempts to directly mount the dax filesystem with 'mount -t
dax dax mnt' that will bypass 'alloc_dax()' and the following failure
signatures may occur as a result:

 kill_dax() must be called before final iput()
 WARNING: CPU: 2 PID: 1188 at drivers/dax/super.c:243 dax_destroy_inode+0x48/0x50
 RIP: 0010:dax_destroy_inode+0x48/0x50
 Call Trace:
  destroy_inode+0x3b/0x60
  evict+0x139/0x1c0
  iput+0x1f9/0x2d0
  dentry_unlink_inode+0xc3/0x160
  __dentry_kill+0xcf/0x180
  ? dput+0x37/0x3b0
  dput+0x3a3/0x3b0
  do_one_tree+0x36/0x40
  shrink_dcache_for_umount+0x2d/0x90
  generic_shutdown_super+0x1f/0x120
  kill_anon_super+0x12/0x20
  deactivate_locked_super+0x43/0x70
  deactivate_super+0x4e/0x60

 general protection fault: 0000 [#1] SMP DEBUG_PAGEALLOC
 RIP: 0010:kfree+0x6d/0x290
 Call Trace:
  <IRQ>
  dax_i_callback+0x22/0x60
  ? dax_destroy_inode+0x50/0x50
  rcu_process_callbacks+0x298/0x740

 ida_remove called for id=0 which is not allocated.
 WARNING: CPU: 0 PID: 0 at lib/idr.c:383 ida_remove+0x110/0x120
 [..]
 Call Trace:
  <IRQ>
  ida_simple_remove+0x2b/0x50
  ? dax_destroy_inode+0x50/0x50
  dax_i_callback+0x3c/0x60
  rcu_process_callbacks+0x298/0x740

Add missing initialization of the 'struct dax_device' and inode so that
the destruction path does not kfree() or ida_simple_remove()
uninitialized data.

Fixes: 7b6be8444e0f ("dax: refactor dax-fs into a generic provider of 'struct dax_device' instances")
Reported-by: Sasha Levin <alexander.levin@verizon.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/dax/super.c

index 6ed32aac8bbeec9f139d0ba622d4b5fb6d1aca4b..922d0823f8ec2b32e14ed6bef64bfe4bfdd268e1 100644 (file)
@@ -210,9 +210,12 @@ EXPORT_SYMBOL_GPL(kill_dax);
 static struct inode *dax_alloc_inode(struct super_block *sb)
 {
        struct dax_device *dax_dev;
+       struct inode *inode;
 
        dax_dev = kmem_cache_alloc(dax_cache, GFP_KERNEL);
-       return &dax_dev->inode;
+       inode = &dax_dev->inode;
+       inode->i_rdev = 0;
+       return inode;
 }
 
 static struct dax_device *to_dax_dev(struct inode *inode)
@@ -227,7 +230,8 @@ static void dax_i_callback(struct rcu_head *head)
 
        kfree(dax_dev->host);
        dax_dev->host = NULL;
-       ida_simple_remove(&dax_minor_ida, MINOR(inode->i_rdev));
+       if (inode->i_rdev)
+               ida_simple_remove(&dax_minor_ida, MINOR(inode->i_rdev));
        kmem_cache_free(dax_cache, dax_dev);
 }
 
@@ -423,6 +427,7 @@ static void init_once(void *_dax_dev)
        struct dax_device *dax_dev = _dax_dev;
        struct inode *inode = &dax_dev->inode;
 
+       memset(dax_dev, 0, sizeof(*dax_dev));
        inode_init_once(inode);
 }