History

proc: use human-readable values for hidepid

The hidepid parameter values are becoming more and more and it becomes difficult to remember what each new magic number means. Backward compatibility is preserved since it is possible to specify numerical value for the hidepid parameter. This does not break the fsconfig since it is not possible to specify a numerical value through it. All numeric values are converted to a string. The type FSCONFIG_SET_BINARY cannot be used to indicate a numerical value. Selftest has been added to verify this behavior.

Alexey Gladkov committed 6 years ago

Commit 1c6c4d11 parent 37e76476 files · +126 −31Browse files

Unified · Split

6 files
  1. Documentation/filesystems/proc.rst +26 −26
  2. fs/proc/inode.c +14 −1
  3. fs/proc/root.c +34 −4
  4. tools/testing/selftests/proc/.gitignore +1 −0
  5. tools/testing/selftests/proc/Makefile +1 −0
  6. tools/testing/selftests/proc/proc-fsconfig-hidepid.c +50 −0
Documentation/filesystems/proc.rst+26−26
@@ -2147,28 +2147,28 @@ The following mount options are supported: · 2146 unmodified lines
21472147 subset= Show only the specified subset of procfs.
21482148 ========= ========================================================
21492149
2150−hidepid=0 means classic mode - everybody may access all /proc/<pid>/ directories
2151−(default).
2152−
2153−hidepid=1 means users may not access any /proc/<pid>/ directories but their
2154−own. Sensitive files like cmdline, sched*, status are now protected against
2155−other users. This makes it impossible to learn whether any user runs
2156−specific program (given the program doesn't reveal itself by its behaviour).
2157−As an additional bonus, as /proc/<pid>/cmdline is unaccessible for other users,
2158−poorly written programs passing sensitive information via program arguments are
2159−now protected against local eavesdroppers.
2160−
2161−hidepid=2 means hidepid=1 plus all /proc/<pid>/ will be fully invisible to other
2162−users. It doesn't mean that it hides a fact whether a process with a specific
2163−pid value exists (it can be learned by other means, e.g. by "kill -0 $PID"),
2164−but it hides process' uid and gid, which may be learned by stat()'ing
2165−/proc/<pid>/ otherwise. It greatly complicates an intruder's task of gathering
2166−information about running processes, whether some daemon runs with elevated
2167−privileges, whether other user runs some sensitive program, whether other users
2168−run any program at all, etc.
2169−
2170−hidepid=4 means that procfs should only contain /proc/<pid>/ directories
2171−that the caller can ptrace.
2150+hidepid=off or hidepid=0 means classic mode - everybody may access all
2151+/proc/<pid>/ directories (default).
2152+
2153+hidepid=noaccess or hidepid=1 means users may not access any /proc/<pid>/
2154+directories but their own. Sensitive files like cmdline, sched*, status are now
2155+protected against other users. This makes it impossible to learn whether any
2156+user runs specific program (given the program doesn't reveal itself by its
2157+behaviour). As an additional bonus, as /proc/<pid>/cmdline is unaccessible for
2158+other users, poorly written programs passing sensitive information via program
2159+arguments are now protected against local eavesdroppers.
2160+
2161+hidepid=invisible or hidepid=2 means hidepid=1 plus all /proc/<pid>/ will be
2162+fully invisible to other users. It doesn't mean that it hides a fact whether a
2163+process with a specific pid value exists (it can be learned by other means, e.g.
2164+by "kill -0 $PID"), but it hides process' uid and gid, which may be learned by
2165+stat()'ing /proc/<pid>/ otherwise. It greatly complicates an intruder's task of
2166+gathering information about running processes, whether some daemon runs with
2167+elevated privileges, whether other user runs some sensitive program, whether
2168+other users run any program at all, etc.
2169+
2170+hidepid=ptraceable or hidepid=4 means that procfs should only contain
2171+/proc/<pid>/ directories that the caller can ptrace.
21722172
21732173 gid= defines a group authorized to learn processes information otherwise
21742174 prohibited by hidepid=. If you use some daemon like identd which needs to learn
@@ -2216,8 +2216,8 @@ creates a new procfs instance. Mount options affect own procfs instance. · 41 unmodified lines
22162216 It means that it became possible to have several procfs instances
22172217 displaying tasks with different filtering options in one pid namespace.
22182218
2219−# mount -o hidepid=2 -t proc proc /proc
2220−# mount -o hidepid=1 -t proc proc /tmp/proc
2219+# mount -o hidepid=invisible -t proc proc /proc
2220+# mount -o hidepid=noaccess -t proc proc /tmp/proc
22212221 # grep ^proc /proc/mounts
2222−proc /proc proc rw,relatime,hidepid=2 0 0
2223−proc /tmp/proc proc rw,relatime,hidepid=1 0 0
2222+proc /proc proc rw,relatime,hidepid=invisible 0 0
2223+proc /tmp/proc proc rw,relatime,hidepid=noaccess 0 0
fs/proc/inode.c+14−1
@@ -24,6 +24,7 @@ · 23 unmodified lines
2424 #include <linux/seq_file.h>
2525 #include <linux/slab.h>
2626 #include <linux/mount.h>
27+#include <linux/bug.h>
2728
2829 #include <linux/uaccess.h>
2930
@@ -165,6 +166,18 @@ void proc_invalidate_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock · 135 unmodified lines
165166 deactivate_super(old_sb);
166167 }
167168
169+static inline const char *hidepid2str(int v)
170+{
171+ switch (v) {
172+ case HIDEPID_OFF: return "off";
173+ case HIDEPID_NO_ACCESS: return "noaccess";
174+ case HIDEPID_INVISIBLE: return "invisible";
175+ case HIDEPID_NOT_PTRACEABLE: return "ptraceable";
176+ }
177+ WARN_ONCE(1, "bad hide_pid value: %d\n", v);
178+ return "unknown";
179+}
180+
168181 static int proc_show_options(struct seq_file *seq, struct dentry *root)
169182 {
170183 struct proc_fs_info *fs_info = proc_sb_info(root->d_sb);
@@ -172,7 +185,7 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root) · 1 unmodified line
172185 if (!gid_eq(fs_info->pid_gid, GLOBAL_ROOT_GID))
173186 seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, fs_info->pid_gid));
174187 if (fs_info->hide_pid != HIDEPID_OFF)
175− seq_printf(seq, ",hidepid=%u", fs_info->hide_pid);
188+ seq_printf(seq, ",hidepid=%s", hidepid2str(fs_info->hide_pid));
176189 if (fs_info->pidonly != PROC_PIDONLY_OFF)
177190 seq_printf(seq, ",subset=pid");
178191
fs/proc/root.c+34−4
@@ -45,7 +45,7 @@ enum proc_param { · 44 unmodified lines
4545
4646 static const struct fs_parameter_spec proc_fs_parameters[] = {
4747 fsparam_u32("gid", Opt_gid),
48− fsparam_u32("hidepid", Opt_hidepid),
48+ fsparam_string("hidepid", Opt_hidepid),
4949 fsparam_string("subset", Opt_subset),
5050 {}
5151 };
@@ -58,6 +58,37 @@ static inline int valid_hidepid(unsigned int value) · 6 unmodified lines
5858 value == HIDEPID_NOT_PTRACEABLE);
5959 }
6060
61+static int proc_parse_hidepid_param(struct fs_context *fc, struct fs_parameter *param)
62+{
63+ struct proc_fs_context *ctx = fc->fs_private;
64+ struct fs_parameter_spec hidepid_u32_spec = fsparam_u32("hidepid", Opt_hidepid);
65+ struct fs_parse_result result;
66+ int base = (unsigned long)hidepid_u32_spec.data;
67+
68+ if (param->type != fs_value_is_string)
69+ return invalf(fc, "proc: unexpected type of hidepid value\n");
70+
71+ if (!kstrtouint(param->string, base, &result.uint_32)) {
72+ if (!valid_hidepid(result.uint_32))
73+ return invalf(fc, "proc: unknown value of hidepid - %s\n", param->string);
74+ ctx->hidepid = result.uint_32;
75+ return 0;
76+ }
77+
78+ if (!strcmp(param->string, "off"))
79+ ctx->hidepid = HIDEPID_OFF;
80+ else if (!strcmp(param->string, "noaccess"))
81+ ctx->hidepid = HIDEPID_NO_ACCESS;
82+ else if (!strcmp(param->string, "invisible"))
83+ ctx->hidepid = HIDEPID_INVISIBLE;
84+ else if (!strcmp(param->string, "ptraceable"))
85+ ctx->hidepid = HIDEPID_NOT_PTRACEABLE;
86+ else
87+ return invalf(fc, "proc: unknown value of hidepid - %s\n", param->string);
88+
89+ return 0;
90+}
91+
6192 static int proc_parse_subset_param(struct fs_context *fc, char *value)
6293 {
6394 struct proc_fs_context *ctx = fc->fs_private;
@@ -97,9 +128,8 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param) · 33 unmodified lines
97128 break;
98129
99130 case Opt_hidepid:
100− if (!valid_hidepid(result.uint_32))
101− return invalf(fc, "proc: unknown value of hidepid.\n");
102− ctx->hidepid = result.uint_32;
131+ if (proc_parse_hidepid_param(fc, param))
132+ return -EINVAL;
103133 break;
104134
105135 case Opt_subset:
tools/testing/selftests/proc/.gitignore+1−0
@@ -2,6 +2,7 @@ · 1 unmodified line
22 /fd-001-lookup
33 /fd-002-posix-eq
44 /fd-003-kthread
5+/proc-fsconfig-hidepid
56 /proc-loadavg-001
67 /proc-multiple-procfs
78 /proc-pid-vm
tools/testing/selftests/proc/Makefile+1−0
@@ -20,5 +20,6 @@ TEST_GEN_PROGS += setns-dcache · 19 unmodified lines
2020 TEST_GEN_PROGS += setns-sysvipc
2121 TEST_GEN_PROGS += thread-self
2222 TEST_GEN_PROGS += proc-multiple-procfs
23+TEST_GEN_PROGS += proc-fsconfig-hidepid
2324
2425 include ../lib.mk
tools/testing/selftests/proc/proc-fsconfig-hidepid.c+50−0
@@ -0,0 +1,50 @@
1+/*
2+ * Copyright © 2020 Alexey Gladkov <gladkov.alexey@gmail.com>
3+ *
4+ * Permission to use, copy, modify, and distribute this software for any
5+ * purpose with or without fee is hereby granted, provided that the above
6+ * copyright notice and this permission notice appear in all copies.
7+ *
8+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15+ */
16+#include <assert.h>
17+#include <unistd.h>
18+#include <stdlib.h>
19+#include <errno.h>
20+#include <linux/mount.h>
21+#include <linux/unistd.h>
22+
23+static inline int fsopen(const char *fsname, unsigned int flags)
24+{
25+ return syscall(__NR_fsopen, fsname, flags);
26+}
27+
28+static inline int fsconfig(int fd, unsigned int cmd, const char *key, const void *val, int aux)
29+{
30+ return syscall(__NR_fsconfig, fd, cmd, key, val, aux);
31+}
32+
33+int main(void)
34+{
35+ int fsfd, ret;
36+ int hidepid = 2;
37+
38+ assert((fsfd = fsopen("proc", 0)) != -1);
39+
40+ ret = fsconfig(fsfd, FSCONFIG_SET_BINARY, "hidepid", &hidepid, 0);
41+ assert(ret == -1);
42+ assert(errno == EINVAL);
43+
44+ assert(!fsconfig(fsfd, FSCONFIG_SET_STRING, "hidepid", "2", 0));
45+ assert(!fsconfig(fsfd, FSCONFIG_SET_STRING, "hidepid", "invisible", 0));
46+
47+ assert(!close(fsfd));
48+
49+ return 0;
50+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t