From ccbd54ff54e8b1880456b81c4aea352ebe208843 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 19 Aug 2019 17:18:03 -0700 Subject: tracefs: Restrict tracefs when the kernel is locked down Tracefs may release more information about the kernel than desirable, so restrict it when the kernel is locked down in confidentiality mode by preventing open(). (Fixed by Ben Hutchings to avoid a null dereference in default_file_open()) Signed-off-by: Matthew Garrett Reviewed-by: Steven Rostedt (VMware) Cc: Ben Hutchings Signed-off-by: James Morris --- fs/tracefs/inode.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'fs/tracefs') diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index a5bab190a297..761af8ce4015 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -20,6 +20,7 @@ #include #include #include +#include #define TRACEFS_DEFAULT_MODE 0700 @@ -27,6 +28,25 @@ static struct vfsmount *tracefs_mount; static int tracefs_mount_count; static bool tracefs_registered; +static int default_open_file(struct inode *inode, struct file *filp) +{ + struct dentry *dentry = filp->f_path.dentry; + struct file_operations *real_fops; + int ret; + + if (!dentry) + return -EINVAL; + + ret = security_locked_down(LOCKDOWN_TRACEFS); + if (ret) + return ret; + + real_fops = dentry->d_fsdata; + if (!real_fops->open) + return 0; + return real_fops->open(inode, filp); +} + static ssize_t default_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -221,6 +241,12 @@ static int tracefs_apply_options(struct super_block *sb) return 0; } +static void tracefs_destroy_inode(struct inode *inode) +{ + if (S_ISREG(inode->i_mode)) + kfree(inode->i_fop); +} + static int tracefs_remount(struct super_block *sb, int *flags, char *data) { int err; @@ -257,6 +283,7 @@ static int tracefs_show_options(struct seq_file *m, struct dentry *root) static const struct super_operations tracefs_super_operations = { .statfs = simple_statfs, .remount_fs = tracefs_remount, + .destroy_inode = tracefs_destroy_inode, .show_options = tracefs_show_options, }; @@ -387,6 +414,7 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops) { + struct file_operations *proxy_fops; struct dentry *dentry; struct inode *inode; @@ -402,8 +430,20 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, if (unlikely(!inode)) return failed_creating(dentry); + proxy_fops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); + if (unlikely(!proxy_fops)) { + iput(inode); + return failed_creating(dentry); + } + + if (!fops) + fops = &tracefs_file_operations; + + dentry->d_fsdata = (void *)fops; + memcpy(proxy_fops, fops, sizeof(*proxy_fops)); + proxy_fops->open = default_open_file; inode->i_mode = mode; - inode->i_fop = fops ? fops : &tracefs_file_operations; + inode->i_fop = proxy_fops; inode->i_private = data; d_instantiate(dentry, inode); fsnotify_create(dentry->d_parent->d_inode, dentry); -- cgit v1.2.3