| From 88add4be9198143358e9817a728ff4dfa48d729f Mon Sep 17 00:00:00 2001 |
| From: Al Viro <viro@zeniv.linux.org.uk> |
| Date: Tue, 26 Mar 2019 01:43:37 +0000 |
| Subject: debugfs: fix use-after-free on symlink traversal |
| |
| [ Upstream commit 93b919da64c15b90953f96a536e5e61df896ca57 ] |
| |
| symlink body shouldn't be freed without an RCU delay. Switch debugfs to |
| ->destroy_inode() and use of call_rcu(); free both the inode and symlink |
| body in the callback. Similar to solution for bpf, only here it's even |
| more obvious that ->evict_inode() can be dropped. |
| |
| Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> |
| Signed-off-by: Sasha Levin (Microsoft) <sashal@kernel.org> |
| --- |
| fs/debugfs/inode.c | 13 +++++++++---- |
| 1 file changed, 9 insertions(+), 4 deletions(-) |
| |
| diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c |
| index 29c68c5d44d5..c4a4fc6f1a95 100644 |
| --- a/fs/debugfs/inode.c |
| +++ b/fs/debugfs/inode.c |
| @@ -163,19 +163,24 @@ static int debugfs_show_options(struct seq_file *m, struct dentry *root) |
| return 0; |
| } |
| |
| -static void debugfs_evict_inode(struct inode *inode) |
| +static void debugfs_i_callback(struct rcu_head *head) |
| { |
| - truncate_inode_pages_final(&inode->i_data); |
| - clear_inode(inode); |
| + struct inode *inode = container_of(head, struct inode, i_rcu); |
| if (S_ISLNK(inode->i_mode)) |
| kfree(inode->i_link); |
| + free_inode_nonrcu(inode); |
| +} |
| + |
| +static void debugfs_destroy_inode(struct inode *inode) |
| +{ |
| + call_rcu(&inode->i_rcu, debugfs_i_callback); |
| } |
| |
| static const struct super_operations debugfs_super_operations = { |
| .statfs = simple_statfs, |
| .remount_fs = debugfs_remount, |
| .show_options = debugfs_show_options, |
| - .evict_inode = debugfs_evict_inode, |
| + .destroy_inode = debugfs_destroy_inode, |
| }; |
| |
| static void debugfs_release_dentry(struct dentry *dentry) |
| -- |
| 2.20.1 |
| |