diff options
| author | Dan Williams <dan.j.williams@intel.com> | 2017-06-09 11:50:49 -0400 |
|---|---|---|
| committer | Dan Williams <dan.j.williams@intel.com> | 2017-06-09 11:50:49 -0400 |
| commit | b9d39d17e4819ca2e69ad1f14acaad12240a1de5 (patch) | |
| tree | 53b1bebbf4d3c9c0303e70b1549795f4111e5462 | |
| parent | 3c2993b8c6143d8a5793746a54eba8f86f95240f (diff) | |
device-dax: fix 'dax' device filesystem inode destruction crash
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>
| -rw-r--r-- | drivers/dax/super.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 6ed32aac8bbe..922d0823f8ec 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c | |||
| @@ -210,9 +210,12 @@ EXPORT_SYMBOL_GPL(kill_dax); | |||
| 210 | static struct inode *dax_alloc_inode(struct super_block *sb) | 210 | static struct inode *dax_alloc_inode(struct super_block *sb) |
| 211 | { | 211 | { |
| 212 | struct dax_device *dax_dev; | 212 | struct dax_device *dax_dev; |
| 213 | struct inode *inode; | ||
| 213 | 214 | ||
| 214 | dax_dev = kmem_cache_alloc(dax_cache, GFP_KERNEL); | 215 | dax_dev = kmem_cache_alloc(dax_cache, GFP_KERNEL); |
| 215 | return &dax_dev->inode; | 216 | inode = &dax_dev->inode; |
| 217 | inode->i_rdev = 0; | ||
| 218 | return inode; | ||
| 216 | } | 219 | } |
| 217 | 220 | ||
| 218 | static struct dax_device *to_dax_dev(struct inode *inode) | 221 | static struct dax_device *to_dax_dev(struct inode *inode) |
| @@ -227,7 +230,8 @@ static void dax_i_callback(struct rcu_head *head) | |||
| 227 | 230 | ||
| 228 | kfree(dax_dev->host); | 231 | kfree(dax_dev->host); |
| 229 | dax_dev->host = NULL; | 232 | dax_dev->host = NULL; |
| 230 | ida_simple_remove(&dax_minor_ida, MINOR(inode->i_rdev)); | 233 | if (inode->i_rdev) |
| 234 | ida_simple_remove(&dax_minor_ida, MINOR(inode->i_rdev)); | ||
| 231 | kmem_cache_free(dax_cache, dax_dev); | 235 | kmem_cache_free(dax_cache, dax_dev); |
| 232 | } | 236 | } |
| 233 | 237 | ||
| @@ -423,6 +427,7 @@ static void init_once(void *_dax_dev) | |||
| 423 | struct dax_device *dax_dev = _dax_dev; | 427 | struct dax_device *dax_dev = _dax_dev; |
| 424 | struct inode *inode = &dax_dev->inode; | 428 | struct inode *inode = &dax_dev->inode; |
| 425 | 429 | ||
| 430 | memset(dax_dev, 0, sizeof(*dax_dev)); | ||
| 426 | inode_init_once(inode); | 431 | inode_init_once(inode); |
| 427 | } | 432 | } |
| 428 | 433 | ||
