aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2015-09-04 18:44:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-09-04 19:54:41 -0400
commita068acf2ee77693e0bf39d6e07139ba704f461c3 (patch)
tree760636f774a9ad528168fa7ceaaf34529167b085 /kernel/cgroup.c
parent46359295a352e01a5a017297c70b7ee0c5da6de6 (diff)
fs: create and use seq_show_option for escaping
Many file systems that implement the show_options hook fail to correctly escape their output which could lead to unescaped characters (e.g. new lines) leaking into /proc/mounts and /proc/[pid]/mountinfo files. This could lead to confusion, spoofed entries (resulting in things like systemd issuing false d-bus "mount" notifications), and who knows what else. This looks like it would only be the root user stepping on themselves, but it's possible weird things could happen in containers or in other situations with delegated mount privileges. Here's an example using overlay with setuid fusermount trusting the contents of /proc/mounts (via the /etc/mtab symlink). Imagine the use of "sudo" is something more sneaky: $ BASE="ovl" $ MNT="$BASE/mnt" $ LOW="$BASE/lower" $ UP="$BASE/upper" $ WORK="$BASE/work/ 0 0 none /proc fuse.pwn user_id=1000" $ mkdir -p "$LOW" "$UP" "$WORK" $ sudo mount -t overlay -o "lowerdir=$LOW,upperdir=$UP,workdir=$WORK" none /mnt $ cat /proc/mounts none /root/ovl/mnt overlay rw,relatime,lowerdir=ovl/lower,upperdir=ovl/upper,workdir=ovl/work/ 0 0 none /proc fuse.pwn user_id=1000 0 0 $ fusermount -u /proc $ cat /proc/mounts cat: /proc/mounts: No such file or directory This fixes the problem by adding new seq_show_option and seq_show_option_n helpers, and updating the vulnerable show_option handlers to use them as needed. Some, like SELinux, need to be open coded due to unusual existing escape mechanisms. [akpm@linux-foundation.org: add lost chunk, per Kees] [keescook@chromium.org: seq_show_option should be using const parameters] Signed-off-by: Kees Cook <keescook@chromium.org> Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Acked-by: Jan Kara <jack@suse.com> Acked-by: Paul Moore <paul@paul-moore.com> Cc: J. R. Okajima <hooanon05g@gmail.com> Signed-off-by: Kees Cook <keescook@chromium.org> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r--kernel/cgroup.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index f3f5cd5e2c0d..a8538e443784 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1342,7 +1342,7 @@ static int cgroup_show_options(struct seq_file *seq,
1342 if (root != &cgrp_dfl_root) 1342 if (root != &cgrp_dfl_root)
1343 for_each_subsys(ss, ssid) 1343 for_each_subsys(ss, ssid)
1344 if (root->subsys_mask & (1 << ssid)) 1344 if (root->subsys_mask & (1 << ssid))
1345 seq_printf(seq, ",%s", ss->legacy_name); 1345 seq_show_option(seq, ss->name, NULL);
1346 if (root->flags & CGRP_ROOT_NOPREFIX) 1346 if (root->flags & CGRP_ROOT_NOPREFIX)
1347 seq_puts(seq, ",noprefix"); 1347 seq_puts(seq, ",noprefix");
1348 if (root->flags & CGRP_ROOT_XATTR) 1348 if (root->flags & CGRP_ROOT_XATTR)
@@ -1350,13 +1350,14 @@ static int cgroup_show_options(struct seq_file *seq,
1350 1350
1351 spin_lock(&release_agent_path_lock); 1351 spin_lock(&release_agent_path_lock);
1352 if (strlen(root->release_agent_path)) 1352 if (strlen(root->release_agent_path))
1353 seq_printf(seq, ",release_agent=%s", root->release_agent_path); 1353 seq_show_option(seq, "release_agent",
1354 root->release_agent_path);
1354 spin_unlock(&release_agent_path_lock); 1355 spin_unlock(&release_agent_path_lock);
1355 1356
1356 if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags)) 1357 if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags))
1357 seq_puts(seq, ",clone_children"); 1358 seq_puts(seq, ",clone_children");
1358 if (strlen(root->name)) 1359 if (strlen(root->name))
1359 seq_printf(seq, ",name=%s", root->name); 1360 seq_show_option(seq, "name", root->name);
1360 return 0; 1361 return 0;
1361} 1362}
1362 1363