]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
tracefs: Restrict tracefs when the kernel is locked down
authorMatthew Garrett <matthewgarrett@google.com>
Tue, 20 Aug 2019 00:18:03 +0000 (17:18 -0700)
committerJames Morris <jmorris@namei.org>
Tue, 20 Aug 2019 04:54:17 +0000 (21:54 -0700)
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 <mjg59@google.com>
Reviewed-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Cc: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: James Morris <jmorris@namei.org>
fs/tracefs/inode.c
include/linux/security.h
security/lockdown/lockdown.c

index a5bab190a2972c015b0f4eec15c239856a2f4d05..761af8ce40153d02387c4174f4ff6cad89f25031 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/parser.h>
 #include <linux/magic.h>
 #include <linux/slab.h>
+#include <linux/security.h>
 
 #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);
index 152824b6f4565802865b09b1ffe55d4c2e54327d..429f9f03372b3fc2256efd94bbf0b47e7c9551dc 100644 (file)
@@ -121,6 +121,7 @@ enum lockdown_reason {
        LOCKDOWN_KPROBES,
        LOCKDOWN_BPF_READ,
        LOCKDOWN_PERF,
+       LOCKDOWN_TRACEFS,
        LOCKDOWN_CONFIDENTIALITY_MAX,
 };
 
index edd1fff0147d4a337d531f889f1e5620f12fd087..84df03b1f5a75bc9f288faa122aba2d054147cc1 100644 (file)
@@ -36,6 +36,7 @@ static char *lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = {
        [LOCKDOWN_KPROBES] = "use of kprobes",
        [LOCKDOWN_BPF_READ] = "use of bpf to read kernel RAM",
        [LOCKDOWN_PERF] = "unsafe use of perf",
+       [LOCKDOWN_TRACEFS] = "use of tracefs",
        [LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
 };