Skip to content

Commit 9ff7258

Browse files
committed
Merge branch 'proc-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull proc updates from Eric Biederman: "This has four sets of changes: - modernize proc to support multiple private instances - ensure we see the exit of each process tid exactly - remove has_group_leader_pid - use pids not tasks in posix-cpu-timers lookup Alexey updated proc so each mount of proc uses a new superblock. This allows people to actually use mount options with proc with no fear of messing up another mount of proc. Given the kernel's internal mounts of proc for things like uml this was a real problem, and resulted in Android's hidepid mount options being ignored and introducing security issues. The rest of the changes are small cleanups and fixes that came out of my work to allow this change to proc. In essence it is swapping the pids in de_thread during exec which removes a special case the code had to handle. Then updating the code to stop handling that special case" * 'proc-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: proc: proc_pid_ns takes super_block as an argument remove the no longer needed pid_alive() check in __task_pid_nr_ns() posix-cpu-timers: Replace __get_task_for_clock with pid_for_clock posix-cpu-timers: Replace cpu_timer_pid_type with clock_pid_type posix-cpu-timers: Extend rcu_read_lock removing task_struct references signal: Remove has_group_leader_pid exec: Remove BUG_ON(has_group_leader_pid) posix-cpu-timer: Unify the now redundant code in lookup_task posix-cpu-timer: Tidy up group_leader logic in lookup_task proc: Ensure we see the exit of each process tid exactly once rculist: Add hlists_swap_heads_rcu proc: Use PIDTYPE_TGID in next_tgid Use proc_pid_ns() to get pid_namespace from the proc superblock proc: use named enums for better readability proc: use human-readable values for hidepid docs: proc: add documentation for "hidepid=4" and "subset=pid" options and new mount behavior proc: add option to mount only a pids subset proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option proc: allow to mount many instances of proc in one pid namespace proc: rename struct proc_fs_info to proc_fs_opts
2 parents 051c355 + 9d78ede commit 9ff7258

File tree

25 files changed

+492
-206
lines changed

25 files changed

+492
-206
lines changed

Documentation/filesystems/proc.rst

Lines changed: 73 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ fixes/update part 1.1 Stefani Seibold <[email protected]> June 9 2009
5151
4 Configuring procfs
5252
4.1 Mount options
5353
54+
5 Filesystem behavior
55+
5456
Preface
5557
=======
5658

@@ -2143,28 +2145,80 @@ The following mount options are supported:
21432145
========= ========================================================
21442146
hidepid= Set /proc/<pid>/ access mode.
21452147
gid= Set the group authorized to learn processes information.
2148+
subset= Show only the specified subset of procfs.
21462149
========= ========================================================
21472150

2148-
hidepid=0 means classic mode - everybody may access all /proc/<pid>/ directories
2149-
(default).
2150-
2151-
hidepid=1 means users may not access any /proc/<pid>/ directories but their
2152-
own. Sensitive files like cmdline, sched*, status are now protected against
2153-
other users. This makes it impossible to learn whether any user runs
2154-
specific program (given the program doesn't reveal itself by its behaviour).
2155-
As an additional bonus, as /proc/<pid>/cmdline is unaccessible for other users,
2156-
poorly written programs passing sensitive information via program arguments are
2157-
now protected against local eavesdroppers.
2158-
2159-
hidepid=2 means hidepid=1 plus all /proc/<pid>/ will be fully invisible to other
2160-
users. It doesn't mean that it hides a fact whether a process with a specific
2161-
pid value exists (it can be learned by other means, e.g. by "kill -0 $PID"),
2162-
but it hides process' uid and gid, which may be learned by stat()'ing
2163-
/proc/<pid>/ otherwise. It greatly complicates an intruder's task of gathering
2164-
information about running processes, whether some daemon runs with elevated
2165-
privileges, whether other user runs some sensitive program, whether other users
2166-
run any program at all, etc.
2151+
hidepid=off or hidepid=0 means classic mode - everybody may access all
2152+
/proc/<pid>/ directories (default).
2153+
2154+
hidepid=noaccess or hidepid=1 means users may not access any /proc/<pid>/
2155+
directories but their own. Sensitive files like cmdline, sched*, status are now
2156+
protected against other users. This makes it impossible to learn whether any
2157+
user runs specific program (given the program doesn't reveal itself by its
2158+
behaviour). As an additional bonus, as /proc/<pid>/cmdline is unaccessible for
2159+
other users, poorly written programs passing sensitive information via program
2160+
arguments are now protected against local eavesdroppers.
2161+
2162+
hidepid=invisible or hidepid=2 means hidepid=1 plus all /proc/<pid>/ will be
2163+
fully invisible to other users. It doesn't mean that it hides a fact whether a
2164+
process with a specific pid value exists (it can be learned by other means, e.g.
2165+
by "kill -0 $PID"), but it hides process' uid and gid, which may be learned by
2166+
stat()'ing /proc/<pid>/ otherwise. It greatly complicates an intruder's task of
2167+
gathering information about running processes, whether some daemon runs with
2168+
elevated privileges, whether other user runs some sensitive program, whether
2169+
other users run any program at all, etc.
2170+
2171+
hidepid=ptraceable or hidepid=4 means that procfs should only contain
2172+
/proc/<pid>/ directories that the caller can ptrace.
21672173

21682174
gid= defines a group authorized to learn processes information otherwise
21692175
prohibited by hidepid=. If you use some daemon like identd which needs to learn
21702176
information about processes information, just add identd to this group.
2177+
2178+
subset=pid hides all top level files and directories in the procfs that
2179+
are not related to tasks.
2180+
2181+
5 Filesystem behavior
2182+
----------------------------
2183+
2184+
Originally, before the advent of pid namepsace, procfs was a global file
2185+
system. It means that there was only one procfs instance in the system.
2186+
2187+
When pid namespace was added, a separate procfs instance was mounted in
2188+
each pid namespace. So, procfs mount options are global among all
2189+
mountpoints within the same namespace.
2190+
2191+
::
2192+
2193+
# grep ^proc /proc/mounts
2194+
proc /proc proc rw,relatime,hidepid=2 0 0
2195+
2196+
# strace -e mount mount -o hidepid=1 -t proc proc /tmp/proc
2197+
mount("proc", "/tmp/proc", "proc", 0, "hidepid=1") = 0
2198+
+++ exited with 0 +++
2199+
2200+
# grep ^proc /proc/mounts
2201+
proc /proc proc rw,relatime,hidepid=2 0 0
2202+
proc /tmp/proc proc rw,relatime,hidepid=2 0 0
2203+
2204+
and only after remounting procfs mount options will change at all
2205+
mountpoints.
2206+
2207+
# mount -o remount,hidepid=1 -t proc proc /tmp/proc
2208+
2209+
# grep ^proc /proc/mounts
2210+
proc /proc proc rw,relatime,hidepid=1 0 0
2211+
proc /tmp/proc proc rw,relatime,hidepid=1 0 0
2212+
2213+
This behavior is different from the behavior of other filesystems.
2214+
2215+
The new procfs behavior is more like other filesystems. Each procfs mount
2216+
creates a new procfs instance. Mount options affect own procfs instance.
2217+
It means that it became possible to have several procfs instances
2218+
displaying tasks with different filtering options in one pid namespace.
2219+
2220+
# mount -o hidepid=invisible -t proc proc /proc
2221+
# mount -o hidepid=noaccess -t proc proc /tmp/proc
2222+
# grep ^proc /proc/mounts
2223+
proc /proc proc rw,relatime,hidepid=invisible 0 0
2224+
proc /tmp/proc proc rw,relatime,hidepid=noaccess 0 0

fs/exec.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,7 +1176,6 @@ static int de_thread(struct task_struct *tsk)
11761176
tsk->start_boottime = leader->start_boottime;
11771177

11781178
BUG_ON(!same_thread_group(leader, tsk));
1179-
BUG_ON(has_group_leader_pid(tsk));
11801179
/*
11811180
* An exec() starts a new thread group with the
11821181
* TGID of the previous thread group. Rehash the
@@ -1186,11 +1185,8 @@ static int de_thread(struct task_struct *tsk)
11861185

11871186
/* Become a process group leader with the old leader's pid.
11881187
* The old leader becomes a thread of the this thread group.
1189-
* Note: The old leader also uses this pid until release_task
1190-
* is called. Odd but simple and correct.
11911188
*/
1192-
tsk->pid = leader->pid;
1193-
change_pid(tsk, PIDTYPE_PID, task_pid(leader));
1189+
exchange_tids(tsk, leader);
11941190
transfer_pid(leader, tsk, PIDTYPE_TGID);
11951191
transfer_pid(leader, tsk, PIDTYPE_PGID);
11961192
transfer_pid(leader, tsk, PIDTYPE_SID);

fs/locks.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2823,7 +2823,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
28232823
{
28242824
struct inode *inode = NULL;
28252825
unsigned int fl_pid;
2826-
struct pid_namespace *proc_pidns = file_inode(f->file)->i_sb->s_fs_info;
2826+
struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)->i_sb);
28272827

28282828
fl_pid = locks_translate_pid(fl, proc_pidns);
28292829
/*
@@ -2901,7 +2901,7 @@ static int locks_show(struct seq_file *f, void *v)
29012901
{
29022902
struct locks_iterator *iter = f->private;
29032903
struct file_lock *fl, *bfl;
2904-
struct pid_namespace *proc_pidns = file_inode(f->file)->i_sb->s_fs_info;
2904+
struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)->i_sb);
29052905

29062906
fl = hlist_entry(v, struct file_lock, fl_link);
29072907

fs/proc/array.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ static int children_seq_show(struct seq_file *seq, void *v)
728728
{
729729
struct inode *inode = file_inode(seq->file);
730730

731-
seq_printf(seq, "%d ", pid_nr_ns(v, proc_pid_ns(inode)));
731+
seq_printf(seq, "%d ", pid_nr_ns(v, proc_pid_ns(inode->i_sb)));
732732
return 0;
733733
}
734734

fs/proc/base.c

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -697,32 +697,40 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr)
697697
* May current process learn task's sched/cmdline info (for hide_pid_min=1)
698698
* or euid/egid (for hide_pid_min=2)?
699699
*/
700-
static bool has_pid_permissions(struct pid_namespace *pid,
700+
static bool has_pid_permissions(struct proc_fs_info *fs_info,
701701
struct task_struct *task,
702-
int hide_pid_min)
702+
enum proc_hidepid hide_pid_min)
703703
{
704-
if (pid->hide_pid < hide_pid_min)
704+
/*
705+
* If 'hidpid' mount option is set force a ptrace check,
706+
* we indicate that we are using a filesystem syscall
707+
* by passing PTRACE_MODE_READ_FSCREDS
708+
*/
709+
if (fs_info->hide_pid == HIDEPID_NOT_PTRACEABLE)
710+
return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
711+
712+
if (fs_info->hide_pid < hide_pid_min)
705713
return true;
706-
if (in_group_p(pid->pid_gid))
714+
if (in_group_p(fs_info->pid_gid))
707715
return true;
708716
return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
709717
}
710718

711719

712720
static int proc_pid_permission(struct inode *inode, int mask)
713721
{
714-
struct pid_namespace *pid = proc_pid_ns(inode);
722+
struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
715723
struct task_struct *task;
716724
bool has_perms;
717725

718726
task = get_proc_task(inode);
719727
if (!task)
720728
return -ESRCH;
721-
has_perms = has_pid_permissions(pid, task, HIDEPID_NO_ACCESS);
729+
has_perms = has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS);
722730
put_task_struct(task);
723731

724732
if (!has_perms) {
725-
if (pid->hide_pid == HIDEPID_INVISIBLE) {
733+
if (fs_info->hide_pid == HIDEPID_INVISIBLE) {
726734
/*
727735
* Let's make getdents(), stat(), and open()
728736
* consistent with each other. If a process
@@ -746,7 +754,7 @@ static const struct inode_operations proc_def_inode_operations = {
746754
static int proc_single_show(struct seq_file *m, void *v)
747755
{
748756
struct inode *inode = m->private;
749-
struct pid_namespace *ns = proc_pid_ns(inode);
757+
struct pid_namespace *ns = proc_pid_ns(inode->i_sb);
750758
struct pid *pid = proc_pid(inode);
751759
struct task_struct *task;
752760
int ret;
@@ -1415,7 +1423,7 @@ static const struct file_operations proc_fail_nth_operations = {
14151423
static int sched_show(struct seq_file *m, void *v)
14161424
{
14171425
struct inode *inode = m->private;
1418-
struct pid_namespace *ns = proc_pid_ns(inode);
1426+
struct pid_namespace *ns = proc_pid_ns(inode->i_sb);
14191427
struct task_struct *p;
14201428

14211429
p = get_proc_task(inode);
@@ -1909,7 +1917,7 @@ int pid_getattr(const struct path *path, struct kstat *stat,
19091917
u32 request_mask, unsigned int query_flags)
19101918
{
19111919
struct inode *inode = d_inode(path->dentry);
1912-
struct pid_namespace *pid = proc_pid_ns(inode);
1920+
struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
19131921
struct task_struct *task;
19141922

19151923
generic_fillattr(inode, stat);
@@ -1919,7 +1927,7 @@ int pid_getattr(const struct path *path, struct kstat *stat,
19191927
rcu_read_lock();
19201928
task = pid_task(proc_pid(inode), PIDTYPE_PID);
19211929
if (task) {
1922-
if (!has_pid_permissions(pid, task, HIDEPID_INVISIBLE)) {
1930+
if (!has_pid_permissions(fs_info, task, HIDEPID_INVISIBLE)) {
19231931
rcu_read_unlock();
19241932
/*
19251933
* This doesn't prevent learning whether PID exists,
@@ -2470,7 +2478,7 @@ static int proc_timers_open(struct inode *inode, struct file *file)
24702478
return -ENOMEM;
24712479

24722480
tp->pid = proc_pid(inode);
2473-
tp->ns = proc_pid_ns(inode);
2481+
tp->ns = proc_pid_ns(inode->i_sb);
24742482
return 0;
24752483
}
24762484

@@ -3312,14 +3320,16 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
33123320
{
33133321
struct task_struct *task;
33143322
unsigned tgid;
3323+
struct proc_fs_info *fs_info;
33153324
struct pid_namespace *ns;
33163325
struct dentry *result = ERR_PTR(-ENOENT);
33173326

33183327
tgid = name_to_int(&dentry->d_name);
33193328
if (tgid == ~0U)
33203329
goto out;
33213330

3322-
ns = dentry->d_sb->s_fs_info;
3331+
fs_info = proc_sb_info(dentry->d_sb);
3332+
ns = fs_info->pid_ns;
33233333
rcu_read_lock();
33243334
task = find_task_by_pid_ns(tgid, ns);
33253335
if (task)
@@ -3328,7 +3338,14 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
33283338
if (!task)
33293339
goto out;
33303340

3341+
/* Limit procfs to only ptraceable tasks */
3342+
if (fs_info->hide_pid == HIDEPID_NOT_PTRACEABLE) {
3343+
if (!has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS))
3344+
goto out_put_task;
3345+
}
3346+
33313347
result = proc_pid_instantiate(dentry, task, NULL);
3348+
out_put_task:
33323349
put_task_struct(task);
33333350
out:
33343351
return result;
@@ -3354,20 +3371,8 @@ static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter ite
33543371
pid = find_ge_pid(iter.tgid, ns);
33553372
if (pid) {
33563373
iter.tgid = pid_nr_ns(pid, ns);
3357-
iter.task = pid_task(pid, PIDTYPE_PID);
3358-
/* What we to know is if the pid we have find is the
3359-
* pid of a thread_group_leader. Testing for task
3360-
* being a thread_group_leader is the obvious thing
3361-
* todo but there is a window when it fails, due to
3362-
* the pid transfer logic in de_thread.
3363-
*
3364-
* So we perform the straight forward test of seeing
3365-
* if the pid we have found is the pid of a thread
3366-
* group leader, and don't worry if the task we have
3367-
* found doesn't happen to be a thread group leader.
3368-
* As we don't care in the case of readdir.
3369-
*/
3370-
if (!iter.task || !has_group_leader_pid(iter.task)) {
3374+
iter.task = pid_task(pid, PIDTYPE_TGID);
3375+
if (!iter.task) {
33713376
iter.tgid += 1;
33723377
goto retry;
33733378
}
@@ -3383,20 +3388,21 @@ static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter ite
33833388
int proc_pid_readdir(struct file *file, struct dir_context *ctx)
33843389
{
33853390
struct tgid_iter iter;
3386-
struct pid_namespace *ns = proc_pid_ns(file_inode(file));
3391+
struct proc_fs_info *fs_info = proc_sb_info(file_inode(file)->i_sb);
3392+
struct pid_namespace *ns = proc_pid_ns(file_inode(file)->i_sb);
33873393
loff_t pos = ctx->pos;
33883394

33893395
if (pos >= PID_MAX_LIMIT + TGID_OFFSET)
33903396
return 0;
33913397

33923398
if (pos == TGID_OFFSET - 2) {
3393-
struct inode *inode = d_inode(ns->proc_self);
3399+
struct inode *inode = d_inode(fs_info->proc_self);
33943400
if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK))
33953401
return 0;
33963402
ctx->pos = pos = pos + 1;
33973403
}
33983404
if (pos == TGID_OFFSET - 1) {
3399-
struct inode *inode = d_inode(ns->proc_thread_self);
3405+
struct inode *inode = d_inode(fs_info->proc_thread_self);
34003406
if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK))
34013407
return 0;
34023408
ctx->pos = pos = pos + 1;
@@ -3410,7 +3416,7 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx)
34103416
unsigned int len;
34113417

34123418
cond_resched();
3413-
if (!has_pid_permissions(ns, iter.task, HIDEPID_INVISIBLE))
3419+
if (!has_pid_permissions(fs_info, iter.task, HIDEPID_INVISIBLE))
34143420
continue;
34153421

34163422
len = snprintf(name, sizeof(name), "%u", iter.tgid);
@@ -3610,6 +3616,7 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry
36103616
struct task_struct *task;
36113617
struct task_struct *leader = get_proc_task(dir);
36123618
unsigned tid;
3619+
struct proc_fs_info *fs_info;
36133620
struct pid_namespace *ns;
36143621
struct dentry *result = ERR_PTR(-ENOENT);
36153622

@@ -3620,7 +3627,8 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry
36203627
if (tid == ~0U)
36213628
goto out;
36223629

3623-
ns = dentry->d_sb->s_fs_info;
3630+
fs_info = proc_sb_info(dentry->d_sb);
3631+
ns = fs_info->pid_ns;
36243632
rcu_read_lock();
36253633
task = find_task_by_pid_ns(tid, ns);
36263634
if (task)
@@ -3734,7 +3742,7 @@ static int proc_task_readdir(struct file *file, struct dir_context *ctx)
37343742
/* f_version caches the tgid value that the last readdir call couldn't
37353743
* return. lseek aka telldir automagically resets f_version to 0.
37363744
*/
3737-
ns = proc_pid_ns(inode);
3745+
ns = proc_pid_ns(inode->i_sb);
37383746
tid = (int)file->f_version;
37393747
file->f_version = 0;
37403748
for (task = first_tid(proc_pid(inode), tid, ctx->pos - 2, ns);

fs/proc/generic.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
269269
struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry,
270270
unsigned int flags)
271271
{
272+
struct proc_fs_info *fs_info = proc_sb_info(dir->i_sb);
273+
274+
if (fs_info->pidonly == PROC_PIDONLY_ON)
275+
return ERR_PTR(-ENOENT);
276+
272277
return proc_lookup_de(dir, dentry, PDE(dir));
273278
}
274279

@@ -325,6 +330,10 @@ int proc_readdir_de(struct file *file, struct dir_context *ctx,
325330
int proc_readdir(struct file *file, struct dir_context *ctx)
326331
{
327332
struct inode *inode = file_inode(file);
333+
struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
334+
335+
if (fs_info->pidonly == PROC_PIDONLY_ON)
336+
return 1;
328337

329338
return proc_readdir_de(file, ctx, PDE(inode));
330339
}

0 commit comments

Comments
 (0)