Commit ccbd54ff authored by Matthew Garrett's avatar Matthew Garrett Committed by James Morris

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: default avatarMatthew Garrett <mjg59@google.com>
Reviewed-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
Cc: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 5496197f
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/parser.h> #include <linux/parser.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/security.h>
#define TRACEFS_DEFAULT_MODE 0700 #define TRACEFS_DEFAULT_MODE 0700
...@@ -27,6 +28,25 @@ static struct vfsmount *tracefs_mount; ...@@ -27,6 +28,25 @@ static struct vfsmount *tracefs_mount;
static int tracefs_mount_count; static int tracefs_mount_count;
static bool tracefs_registered; 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, static ssize_t default_read_file(struct file *file, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
...@@ -221,6 +241,12 @@ static int tracefs_apply_options(struct super_block *sb) ...@@ -221,6 +241,12 @@ static int tracefs_apply_options(struct super_block *sb)
return 0; 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) static int tracefs_remount(struct super_block *sb, int *flags, char *data)
{ {
int err; int err;
...@@ -257,6 +283,7 @@ static int tracefs_show_options(struct seq_file *m, struct dentry *root) ...@@ -257,6 +283,7 @@ static int tracefs_show_options(struct seq_file *m, struct dentry *root)
static const struct super_operations tracefs_super_operations = { static const struct super_operations tracefs_super_operations = {
.statfs = simple_statfs, .statfs = simple_statfs,
.remount_fs = tracefs_remount, .remount_fs = tracefs_remount,
.destroy_inode = tracefs_destroy_inode,
.show_options = tracefs_show_options, .show_options = tracefs_show_options,
}; };
...@@ -387,6 +414,7 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, ...@@ -387,6 +414,7 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
struct dentry *parent, void *data, struct dentry *parent, void *data,
const struct file_operations *fops) const struct file_operations *fops)
{ {
struct file_operations *proxy_fops;
struct dentry *dentry; struct dentry *dentry;
struct inode *inode; struct inode *inode;
...@@ -402,8 +430,20 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, ...@@ -402,8 +430,20 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
if (unlikely(!inode)) if (unlikely(!inode))
return failed_creating(dentry); 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_mode = mode;
inode->i_fop = fops ? fops : &tracefs_file_operations; inode->i_fop = proxy_fops;
inode->i_private = data; inode->i_private = data;
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
fsnotify_create(dentry->d_parent->d_inode, dentry); fsnotify_create(dentry->d_parent->d_inode, dentry);
......
...@@ -121,6 +121,7 @@ enum lockdown_reason { ...@@ -121,6 +121,7 @@ enum lockdown_reason {
LOCKDOWN_KPROBES, LOCKDOWN_KPROBES,
LOCKDOWN_BPF_READ, LOCKDOWN_BPF_READ,
LOCKDOWN_PERF, LOCKDOWN_PERF,
LOCKDOWN_TRACEFS,
LOCKDOWN_CONFIDENTIALITY_MAX, LOCKDOWN_CONFIDENTIALITY_MAX,
}; };
......
...@@ -36,6 +36,7 @@ static char *lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = { ...@@ -36,6 +36,7 @@ static char *lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = {
[LOCKDOWN_KPROBES] = "use of kprobes", [LOCKDOWN_KPROBES] = "use of kprobes",
[LOCKDOWN_BPF_READ] = "use of bpf to read kernel RAM", [LOCKDOWN_BPF_READ] = "use of bpf to read kernel RAM",
[LOCKDOWN_PERF] = "unsafe use of perf", [LOCKDOWN_PERF] = "unsafe use of perf",
[LOCKDOWN_TRACEFS] = "use of tracefs",
[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality", [LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment