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 <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>
This commit is contained in:
Matthew Garrett 2019-08-19 17:18:03 -07:00 committed by James Morris
parent 5496197f9b
commit ccbd54ff54
3 changed files with 43 additions and 1 deletions

View 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);

View File

@ -121,6 +121,7 @@ enum lockdown_reason {
LOCKDOWN_KPROBES,
LOCKDOWN_BPF_READ,
LOCKDOWN_PERF,
LOCKDOWN_TRACEFS,
LOCKDOWN_CONFIDENTIALITY_MAX,
};

View 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",
};