mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 16:35:02 +01:00
181 lines
5.1 KiB
Diff
181 lines
5.1 KiB
Diff
Hide unreachable mount points in /proc/mounts and /proc/$PID/mountstats
|
|
|
|
What's mounted on unreachable mount points isn't interesting to
|
|
processes: they can't get there in the first place. This patch hides
|
|
unreachable mounts from processes.
|
|
|
|
Processes living in the root namespace whill still see all mounts they
|
|
were seeing before except for the rootfs mount, which is never reachable
|
|
from an "ordinary" process.
|
|
|
|
Only the initial initrd init process will actually have access to the
|
|
rootfs mount. For this process that mount *is* reachable, and so it will
|
|
show in.
|
|
|
|
This patch also removes some code duplication between mounts_open() and
|
|
mountstats_open().
|
|
|
|
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|
|
|
Index: b/fs/namespace.c
|
|
===================================================================
|
|
--- a/fs/namespace.c
|
|
+++ b/fs/namespace.c
|
|
@@ -348,8 +348,16 @@ static inline void mangle(struct seq_fil
|
|
seq_escape(m, s, " \t\n\\");
|
|
}
|
|
|
|
+/* Keep in sync with fs/proc/base.c! */
|
|
+struct proc_mounts {
|
|
+ struct seq_file m;
|
|
+ void *page;
|
|
+ int event;
|
|
+};
|
|
+
|
|
static int show_vfsmnt(struct seq_file *m, void *v)
|
|
{
|
|
+ void *page = container_of(m, struct proc_mounts, m)->page;
|
|
struct vfsmount *mnt = v;
|
|
int err = 0;
|
|
static struct proc_fs_info {
|
|
@@ -372,9 +380,13 @@ static int show_vfsmnt(struct seq_file *
|
|
};
|
|
struct proc_fs_info *fs_infop;
|
|
|
|
+ char *path = d_path(mnt->mnt_root, mnt, page, PAGE_SIZE);
|
|
+ if (IS_ERR(path) || *path != '/')
|
|
+ return err;
|
|
+
|
|
mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
|
|
seq_putc(m, ' ');
|
|
- seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
|
|
+ mangle(m, path);
|
|
seq_putc(m, ' ');
|
|
mangle(m, mnt->mnt_sb->s_type->name);
|
|
seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
|
|
@@ -401,9 +413,14 @@ struct seq_operations mounts_op = {
|
|
|
|
static int show_vfsstat(struct seq_file *m, void *v)
|
|
{
|
|
+ void *page = container_of(m, struct proc_mounts, m)->page;
|
|
struct vfsmount *mnt = v;
|
|
int err = 0;
|
|
|
|
+ char *path = d_path(mnt->mnt_root, mnt, page, PAGE_SIZE);
|
|
+ if (IS_ERR(path) || *path != '/')
|
|
+ return err; /* error or path unreachable from chroot */
|
|
+
|
|
/* device */
|
|
if (mnt->mnt_devname) {
|
|
seq_puts(m, "device ");
|
|
@@ -413,7 +430,7 @@ static int show_vfsstat(struct seq_file
|
|
|
|
/* mount point */
|
|
seq_puts(m, " mounted on ");
|
|
- seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
|
|
+ mangle(m, path);
|
|
seq_putc(m, ' ');
|
|
|
|
/* file system type */
|
|
Index: b/fs/proc/base.c
|
|
===================================================================
|
|
--- a/fs/proc/base.c
|
|
+++ b/fs/proc/base.c
|
|
@@ -353,13 +353,16 @@ static const struct inode_operations pro
|
|
.setattr = proc_setattr,
|
|
};
|
|
|
|
+/* Keep in sync with fs/namespace.c! */
|
|
extern struct seq_operations mounts_op;
|
|
struct proc_mounts {
|
|
struct seq_file m;
|
|
+ void *page;
|
|
int event;
|
|
};
|
|
|
|
-static int mounts_open(struct inode *inode, struct file *file)
|
|
+static int __mounts_open(struct inode *inode, struct file *file,
|
|
+ struct seq_operations *seq_ops)
|
|
{
|
|
struct task_struct *task = get_proc_task(inode);
|
|
struct mnt_namespace *ns = NULL;
|
|
@@ -382,12 +385,16 @@ static int mounts_open(struct inode *ino
|
|
p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
|
|
if (p) {
|
|
file->private_data = &p->m;
|
|
- ret = seq_open(file, &mounts_op);
|
|
+ p->page = (void *)__get_free_page(GFP_KERNEL);
|
|
+ if (p->page)
|
|
+ ret = seq_open(file, seq_ops);
|
|
if (!ret) {
|
|
p->m.private = ns;
|
|
p->event = ns->event;
|
|
return 0;
|
|
}
|
|
+ if (p->page)
|
|
+ free_page((unsigned long)p->page);
|
|
kfree(p);
|
|
}
|
|
put_mnt_ns(ns);
|
|
@@ -395,17 +402,25 @@ static int mounts_open(struct inode *ino
|
|
return ret;
|
|
}
|
|
|
|
+static int mounts_open(struct inode *inode, struct file *file)
|
|
+{
|
|
+ return __mounts_open(inode, file, &mounts_op);
|
|
+}
|
|
+
|
|
static int mounts_release(struct inode *inode, struct file *file)
|
|
{
|
|
- struct seq_file *m = file->private_data;
|
|
- struct mnt_namespace *ns = m->private;
|
|
+ struct proc_mounts *p =
|
|
+ container_of(file->private_data, struct proc_mounts, m);
|
|
+ struct mnt_namespace *ns = p->m.private;
|
|
+ free_page((unsigned long)p->page);
|
|
put_mnt_ns(ns);
|
|
return seq_release(inode, file);
|
|
}
|
|
|
|
static unsigned mounts_poll(struct file *file, poll_table *wait)
|
|
{
|
|
- struct proc_mounts *p = file->private_data;
|
|
+ struct proc_mounts *p =
|
|
+ container_of(file->private_data, struct proc_mounts, m);
|
|
struct mnt_namespace *ns = p->m.private;
|
|
unsigned res = 0;
|
|
|
|
@@ -432,31 +447,7 @@ static const struct file_operations proc
|
|
extern struct seq_operations mountstats_op;
|
|
static int mountstats_open(struct inode *inode, struct file *file)
|
|
{
|
|
- int ret = seq_open(file, &mountstats_op);
|
|
-
|
|
- if (!ret) {
|
|
- struct seq_file *m = file->private_data;
|
|
- struct mnt_namespace *mnt_ns = NULL;
|
|
- struct task_struct *task = get_proc_task(inode);
|
|
-
|
|
- if (task) {
|
|
- task_lock(task);
|
|
- if (task->nsproxy)
|
|
- mnt_ns = task->nsproxy->mnt_ns;
|
|
- if (mnt_ns)
|
|
- get_mnt_ns(mnt_ns);
|
|
- task_unlock(task);
|
|
- put_task_struct(task);
|
|
- }
|
|
-
|
|
- if (mnt_ns)
|
|
- m->private = mnt_ns;
|
|
- else {
|
|
- seq_release(inode, file);
|
|
- ret = -EINVAL;
|
|
- }
|
|
- }
|
|
- return ret;
|
|
+ return __mounts_open(inode, file, &mountstats_op);
|
|
}
|
|
|
|
static const struct file_operations proc_mountstats_operations = {
|