License cleanup: add SPDX GPL-2.0 license identifier to files with no license
Many source files in the tree are missing licensing information, which
makes it harder for compliance tools to determine the correct license.
By default all files without license information are under the default
license of the kernel, which is GPL version 2.
Update the files which contain no license information with the 'GPL-2.0'
SPDX license identifier. The SPDX identifier is a legally binding
shorthand, which can be used instead of the full boiler plate text.
This patch is based on work done by Thomas Gleixner and Kate Stewart and
Philippe Ombredanne.
How this work was done:
Patches were generated and checked against linux-4.14-rc6 for a subset of
the use cases:
- file had no licensing information it it.
- file was a */uapi/* one with no licensing information in it,
- file was a */uapi/* one with existing licensing information,
Further patches will be generated in subsequent months to fix up cases
where non-standard license headers were used, and references to license
had to be inferred by heuristics based on keywords.
The analysis to determine which SPDX License Identifier to be applied to
a file was done in a spreadsheet of side by side results from of the
output of two independent scanners (ScanCode & Windriver) producing SPDX
tag:value files created by Philippe Ombredanne. Philippe prepared the
base worksheet, and did an initial spot review of a few 1000 files.
The 4.13 kernel was the starting point of the analysis with 60,537 files
assessed. Kate Stewart did a file by file comparison of the scanner
results in the spreadsheet to determine which SPDX license identifier(s)
to be applied to the file. She confirmed any determination that was not
immediately clear with lawyers working with the Linux Foundation.
Criteria used to select files for SPDX license identifier tagging was:
- Files considered eligible had to be source code files.
- Make and config files were included as candidates if they contained >5
lines of source
- File already had some variant of a license header in it (even if <5
lines).
All documentation files were explicitly excluded.
The following heuristics were used to determine which SPDX license
identifiers to apply.
- when both scanners couldn't find any license traces, file was
considered to have no license information in it, and the top level
COPYING file license applied.
For non */uapi/* files that summary was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 11139
and resulted in the first patch in this series.
If that file was a */uapi/* path one, it was "GPL-2.0 WITH
Linux-syscall-note" otherwise it was "GPL-2.0". Results of that was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 WITH Linux-syscall-note 930
and resulted in the second patch in this series.
- if a file had some form of licensing information in it, and was one
of the */uapi/* ones, it was denoted with the Linux-syscall-note if
any GPL family license was found in the file or had no licensing in
it (per prior point). Results summary:
SPDX license identifier # files
---------------------------------------------------|------
GPL-2.0 WITH Linux-syscall-note 270
GPL-2.0+ WITH Linux-syscall-note 169
((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) 21
((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 17
LGPL-2.1+ WITH Linux-syscall-note 15
GPL-1.0+ WITH Linux-syscall-note 14
((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) 5
LGPL-2.0+ WITH Linux-syscall-note 4
LGPL-2.1 WITH Linux-syscall-note 3
((GPL-2.0 WITH Linux-syscall-note) OR MIT) 3
((GPL-2.0 WITH Linux-syscall-note) AND MIT) 1
and that resulted in the third patch in this series.
- when the two scanners agreed on the detected license(s), that became
the concluded license(s).
- when there was disagreement between the two scanners (one detected a
license but the other didn't, or they both detected different
licenses) a manual inspection of the file occurred.
- In most cases a manual inspection of the information in the file
resulted in a clear resolution of the license that should apply (and
which scanner probably needed to revisit its heuristics).
- When it was not immediately clear, the license identifier was
confirmed with lawyers working with the Linux Foundation.
- If there was any question as to the appropriate license identifier,
the file was flagged for further research and to be revisited later
in time.
In total, over 70 hours of logged manual review was done on the
spreadsheet to determine the SPDX license identifiers to apply to the
source files by Kate, Philippe, Thomas and, in some cases, confirmation
by lawyers working with the Linux Foundation.
Kate also obtained a third independent scan of the 4.13 code base from
FOSSology, and compared selected files where the other two scanners
disagreed against that SPDX file, to see if there was new insights. The
Windriver scanner is based on an older version of FOSSology in part, so
they are related.
Thomas did random spot checks in about 500 files from the spreadsheets
for the uapi headers and agreed with SPDX license identifier in the
files he inspected. For the non-uapi files Thomas did random spot checks
in about 15000 files.
In initial set of patches against 4.14-rc6, 3 files were found to have
copy/paste license identifier errors, and have been fixed to reflect the
correct identifier.
Additionally Philippe spent 10 hours this week doing a detailed manual
inspection and review of the 12,461 patched files from the initial patch
version early this week with:
- a full scancode scan run, collecting the matched texts, detected
license ids and scores
- reviewing anything where there was a license detected (about 500+
files) to ensure that the applied SPDX license was correct
- reviewing anything where there was no detection but the patch license
was not GPL-2.0 WITH Linux-syscall-note to ensure that the applied
SPDX license was correct
This produced a worksheet with 20 files needing minor correction. This
worksheet was then exported into 3 different .csv files for the
different types of files to be modified.
These .csv files were then reviewed by Greg. Thomas wrote a script to
parse the csv files and add the proper SPDX tag to the file, in the
format that the file expected. This script was further refined by Greg
based on the output to detect more types of files automatically and to
distinguish between header and source .c files (which need different
comment types.) Finally Greg ran the script using the .csv files to
generate the patches.
Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org>
Reviewed-by: Philippe Ombredanne <pombredanne@nexb.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-11-01 22:07:57 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* linux/fs/proc/array.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 1992 by Linus Torvalds
|
|
|
|
* based on ideas by Darren Senn
|
|
|
|
*
|
|
|
|
* Fixes:
|
|
|
|
* Michael. K. Johnson: stat,statm extensions.
|
|
|
|
* <johnsonm@stolaf.edu>
|
|
|
|
*
|
|
|
|
* Pauline Middelink : Made cmdline,envline only break at '\0's, to
|
|
|
|
* make sure SET_PROCTITLE works. Also removed
|
|
|
|
* bad '!' which forced address recalculation for
|
|
|
|
* EVERY character on the current page.
|
|
|
|
* <middelin@polyware.iaf.nl>
|
|
|
|
*
|
|
|
|
* Danny ter Haar : added cpuinfo
|
|
|
|
* <dth@cistron.nl>
|
|
|
|
*
|
|
|
|
* Alessandro Rubini : profile extension.
|
|
|
|
* <rubini@ipvvis.unipv.it>
|
|
|
|
*
|
|
|
|
* Jeff Tranter : added BogoMips field to cpuinfo
|
|
|
|
* <Jeff_Tranter@Mitel.COM>
|
|
|
|
*
|
|
|
|
* Bruno Haible : remove 4K limit for the maps file
|
|
|
|
* <haible@ma2s2.mathematik.uni-karlsruhe.de>
|
|
|
|
*
|
|
|
|
* Yves Arrouye : remove removal of trailing spaces in get_array.
|
|
|
|
* <Yves.Arrouye@marin.fdn.fr>
|
|
|
|
*
|
|
|
|
* Jerome Forissier : added per-CPU time information to /proc/stat
|
|
|
|
* and /proc/<pid>/cpu extension
|
|
|
|
* <forissier@isia.cma.fr>
|
|
|
|
* - Incorporation and non-SMP safe operation
|
|
|
|
* of forissier patch in 2.1.78 by
|
|
|
|
* Hans Marcus <crowbar@concepts.nl>
|
|
|
|
*
|
|
|
|
* aeb@cwi.nl : /proc/partitions
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Alan Cox : security fixes.
|
2008-10-27 23:19:48 +08:00
|
|
|
* <alan@lxorguk.ukuu.org.uk>
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* Al Viro : safe handling of mm_struct
|
|
|
|
*
|
|
|
|
* Gerhard Wichert : added BIGMEM support
|
|
|
|
* Siemens AG <Gerhard.Wichert@pdb.siemens.de>
|
|
|
|
*
|
|
|
|
* Al Viro & Jeff Garzik : moved most of the thing into base.c and
|
|
|
|
* : proc_misc.c. The rest may eventually go into
|
|
|
|
* : base.c too.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/time.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/kernel_stat.h>
|
|
|
|
#include <linux/tty.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/mman.h>
|
2017-02-09 01:51:29 +08:00
|
|
|
#include <linux/sched/mm.h>
|
2017-02-09 01:51:31 +08:00
|
|
|
#include <linux/sched/numa_balancing.h>
|
2017-09-14 17:42:17 +08:00
|
|
|
#include <linux/sched/task_stack.h>
|
2017-02-09 01:51:36 +08:00
|
|
|
#include <linux/sched/task.h>
|
2017-02-05 18:48:36 +08:00
|
|
|
#include <linux/sched/cputime.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/proc_fs.h>
|
|
|
|
#include <linux/ioport.h>
|
2007-07-16 15:46:31 +08:00
|
|
|
#include <linux/uaccess.h>
|
|
|
|
#include <linux/io.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/hugetlb.h>
|
|
|
|
#include <linux/pagemap.h>
|
|
|
|
#include <linux/swap.h>
|
|
|
|
#include <linux/smp.h>
|
|
|
|
#include <linux/signal.h>
|
|
|
|
#include <linux/highmem.h>
|
|
|
|
#include <linux/file.h>
|
2008-04-24 19:44:08 +08:00
|
|
|
#include <linux/fdtable.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/times.h>
|
|
|
|
#include <linux/cpuset.h>
|
2005-09-17 10:28:13 +08:00
|
|
|
#include <linux/rcupdate.h>
|
2006-07-14 15:24:43 +08:00
|
|
|
#include <linux/delayacct.h>
|
2008-02-08 20:18:31 +08:00
|
|
|
#include <linux/seq_file.h>
|
2007-10-19 14:40:14 +08:00
|
|
|
#include <linux/pid_namespace.h>
|
2018-05-02 06:31:45 +08:00
|
|
|
#include <linux/prctl.h>
|
2009-05-05 02:51:14 +08:00
|
|
|
#include <linux/ptrace.h>
|
2008-07-26 10:45:49 +08:00
|
|
|
#include <linux/tracehook.h>
|
2015-02-13 07:01:11 +08:00
|
|
|
#include <linux/string_helpers.h>
|
2011-11-15 07:56:38 +08:00
|
|
|
#include <linux/user_namespace.h>
|
2016-05-21 08:00:05 +08:00
|
|
|
#include <linux/fs_struct.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#include <asm/pgtable.h>
|
|
|
|
#include <asm/processor.h>
|
|
|
|
#include "internal.h"
|
|
|
|
|
2018-05-18 23:47:13 +08:00
|
|
|
void proc_task_name(struct seq_file *m, struct task_struct *p, bool escape)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2015-02-13 07:01:11 +08:00
|
|
|
char *buf;
|
2015-11-07 08:30:03 +08:00
|
|
|
size_t size;
|
2018-05-18 23:47:13 +08:00
|
|
|
char tcomm[64];
|
2015-11-07 08:30:03 +08:00
|
|
|
int ret;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2018-05-18 23:47:13 +08:00
|
|
|
if (p->flags & PF_WQ_WORKER)
|
|
|
|
wq_worker_comm(tcomm, sizeof(tcomm), p);
|
|
|
|
else
|
|
|
|
__get_task_comm(tcomm, sizeof(tcomm), p);
|
2015-02-13 07:01:11 +08:00
|
|
|
|
2015-11-07 08:30:03 +08:00
|
|
|
size = seq_get_buf(m, &buf);
|
2018-05-18 23:47:13 +08:00
|
|
|
if (escape) {
|
|
|
|
ret = string_escape_str(tcomm, buf, size,
|
|
|
|
ESCAPE_SPACE | ESCAPE_SPECIAL, "\n\\");
|
|
|
|
if (ret >= size)
|
|
|
|
ret = -1;
|
|
|
|
} else {
|
|
|
|
ret = strscpy(buf, tcomm, size);
|
|
|
|
}
|
2015-02-13 07:01:11 +08:00
|
|
|
|
2018-05-18 23:47:13 +08:00
|
|
|
seq_commit(m, ret);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The task state array is a strange "bitmap" of
|
|
|
|
* reasons to sleep. Thus "running" is zero, and
|
|
|
|
* you can test for combinations of others with
|
|
|
|
* simple bit tests.
|
|
|
|
*/
|
2011-05-27 07:25:51 +08:00
|
|
|
static const char * const task_state_array[] = {
|
2017-09-23 00:30:40 +08:00
|
|
|
|
|
|
|
/* states in TASK_REPORT: */
|
|
|
|
"R (running)", /* 0x00 */
|
|
|
|
"S (sleeping)", /* 0x01 */
|
|
|
|
"D (disk sleep)", /* 0x02 */
|
|
|
|
"T (stopped)", /* 0x04 */
|
|
|
|
"t (tracing stop)", /* 0x08 */
|
|
|
|
"X (dead)", /* 0x10 */
|
|
|
|
"Z (zombie)", /* 0x20 */
|
2017-09-23 00:37:28 +08:00
|
|
|
"P (parked)", /* 0x40 */
|
2017-09-23 00:30:40 +08:00
|
|
|
|
|
|
|
/* states beyond TASK_REPORT: */
|
2017-09-23 00:37:28 +08:00
|
|
|
"I (idle)", /* 0x80 */
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2007-07-16 15:46:31 +08:00
|
|
|
static inline const char *get_task_state(struct task_struct *tsk)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-09-23 00:30:40 +08:00
|
|
|
BUILD_BUG_ON(1 + ilog2(TASK_REPORT_MAX) != ARRAY_SIZE(task_state_array));
|
2017-09-29 19:50:16 +08:00
|
|
|
return task_state_array[task_state_index(tsk)];
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-02-08 20:18:33 +08:00
|
|
|
static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
|
|
|
|
struct pid *pid, struct task_struct *p)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2012-08-12 03:38:26 +08:00
|
|
|
struct user_namespace *user_ns = seq_user_ns(m);
|
2005-04-17 06:20:36 +08:00
|
|
|
struct group_info *group_info;
|
2018-04-11 07:30:51 +08:00
|
|
|
int g, umask = -1;
|
2014-12-11 07:45:18 +08:00
|
|
|
struct task_struct *tracer;
|
2008-11-14 07:39:19 +08:00
|
|
|
const struct cred *cred;
|
2014-12-11 07:45:18 +08:00
|
|
|
pid_t ppid, tpid = 0, tgid, ngid;
|
2014-12-11 07:45:12 +08:00
|
|
|
unsigned int max_fds = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-10-02 17:18:54 +08:00
|
|
|
rcu_read_lock();
|
2007-10-19 14:40:14 +08:00
|
|
|
ppid = pid_alive(p) ?
|
|
|
|
task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0;
|
2014-12-11 07:45:18 +08:00
|
|
|
|
|
|
|
tracer = ptrace_parent(p);
|
|
|
|
if (tracer)
|
|
|
|
tpid = task_pid_nr_ns(tracer, ns);
|
2014-12-11 07:45:15 +08:00
|
|
|
|
|
|
|
tgid = task_tgid_nr_ns(p, ns);
|
|
|
|
ngid = task_numa_group_id(p);
|
CRED: Fix get_task_cred() and task_state() to not resurrect dead credentials
It's possible for get_task_cred() as it currently stands to 'corrupt' a set of
credentials by incrementing their usage count after their replacement by the
task being accessed.
What happens is that get_task_cred() can race with commit_creds():
TASK_1 TASK_2 RCU_CLEANER
-->get_task_cred(TASK_2)
rcu_read_lock()
__cred = __task_cred(TASK_2)
-->commit_creds()
old_cred = TASK_2->real_cred
TASK_2->real_cred = ...
put_cred(old_cred)
call_rcu(old_cred)
[__cred->usage == 0]
get_cred(__cred)
[__cred->usage == 1]
rcu_read_unlock()
-->put_cred_rcu()
[__cred->usage == 1]
panic()
However, since a tasks credentials are generally not changed very often, we can
reasonably make use of a loop involving reading the creds pointer and using
atomic_inc_not_zero() to attempt to increment it if it hasn't already hit zero.
If successful, we can safely return the credentials in the knowledge that, even
if the task we're accessing has released them, they haven't gone to the RCU
cleanup code.
We then change task_state() in procfs to use get_task_cred() rather than
calling get_cred() on the result of __task_cred(), as that suffers from the
same problem.
Without this change, a BUG_ON in __put_cred() or in put_cred_rcu() can be
tripped when it is noticed that the usage count is not zero as it ought to be,
for example:
kernel BUG at kernel/cred.c:168!
invalid opcode: 0000 [#1] SMP
last sysfs file: /sys/kernel/mm/ksm/run
CPU 0
Pid: 2436, comm: master Not tainted 2.6.33.3-85.fc13.x86_64 #1 0HR330/OptiPlex
745
RIP: 0010:[<ffffffff81069881>] [<ffffffff81069881>] __put_cred+0xc/0x45
RSP: 0018:ffff88019e7e9eb8 EFLAGS: 00010202
RAX: 0000000000000001 RBX: ffff880161514480 RCX: 00000000ffffffff
RDX: 00000000ffffffff RSI: ffff880140c690c0 RDI: ffff880140c690c0
RBP: ffff88019e7e9eb8 R08: 00000000000000d0 R09: 0000000000000000
R10: 0000000000000001 R11: 0000000000000040 R12: ffff880140c690c0
R13: ffff88019e77aea0 R14: 00007fff336b0a5c R15: 0000000000000001
FS: 00007f12f50d97c0(0000) GS:ffff880007400000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f8f461bc000 CR3: 00000001b26ce000 CR4: 00000000000006f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process master (pid: 2436, threadinfo ffff88019e7e8000, task ffff88019e77aea0)
Stack:
ffff88019e7e9ec8 ffffffff810698cd ffff88019e7e9ef8 ffffffff81069b45
<0> ffff880161514180 ffff880161514480 ffff880161514180 0000000000000000
<0> ffff88019e7e9f28 ffffffff8106aace 0000000000000001 0000000000000246
Call Trace:
[<ffffffff810698cd>] put_cred+0x13/0x15
[<ffffffff81069b45>] commit_creds+0x16b/0x175
[<ffffffff8106aace>] set_current_groups+0x47/0x4e
[<ffffffff8106ac89>] sys_setgroups+0xf6/0x105
[<ffffffff81009b02>] system_call_fastpath+0x16/0x1b
Code: 48 8d 71 ff e8 7e 4e 15 00 85 c0 78 0b 8b 75 ec 48 89 df e8 ef 4a 15 00
48 83 c4 18 5b c9 c3 55 8b 07 8b 07 48 89 e5 85 c0 74 04 <0f> 0b eb fe 65 48 8b
04 25 00 cc 00 00 48 3b b8 58 04 00 00 75
RIP [<ffffffff81069881>] __put_cred+0xc/0x45
RSP <ffff88019e7e9eb8>
---[ end trace df391256a100ebdd ]---
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2010-07-29 19:45:49 +08:00
|
|
|
cred = get_task_cred(p);
|
2014-12-11 07:45:12 +08:00
|
|
|
|
|
|
|
task_lock(p);
|
2018-04-11 07:30:51 +08:00
|
|
|
if (p->fs)
|
|
|
|
umask = p->fs->umask;
|
2014-12-11 07:45:12 +08:00
|
|
|
if (p->files)
|
|
|
|
max_fds = files_fdtable(p->files)->max_fds;
|
|
|
|
task_unlock(p);
|
2014-12-11 07:45:15 +08:00
|
|
|
rcu_read_unlock();
|
2014-12-11 07:45:12 +08:00
|
|
|
|
2018-04-11 07:30:51 +08:00
|
|
|
if (umask >= 0)
|
|
|
|
seq_printf(m, "Umask:\t%#04o\n", umask);
|
2018-04-11 07:31:26 +08:00
|
|
|
seq_puts(m, "State:\t");
|
|
|
|
seq_puts(m, get_task_state(p));
|
proc: faster /proc/*/status
top(1) opens the following files for every PID:
/proc/*/stat
/proc/*/statm
/proc/*/status
This patch switches /proc/*/status away from seq_printf().
The result is 13.5% speedup.
Benchmark is open("/proc/self/status")+read+close 1.000.000 million times.
BEFORE
$ perf stat -r 10 taskset -c 3 ./proc-self-status
Performance counter stats for 'taskset -c 3 ./proc-self-status' (10 runs):
10748.474301 task-clock (msec) # 0.954 CPUs utilized ( +- 0.91% )
12 context-switches # 0.001 K/sec ( +- 1.09% )
1 cpu-migrations # 0.000 K/sec
104 page-faults # 0.010 K/sec ( +- 0.45% )
37,424,127,876 cycles # 3.482 GHz ( +- 0.04% )
8,453,010,029 stalled-cycles-frontend # 22.59% frontend cycles idle ( +- 0.12% )
3,747,609,427 stalled-cycles-backend # 10.01% backend cycles idle ( +- 0.68% )
65,632,764,147 instructions # 1.75 insn per cycle
# 0.13 stalled cycles per insn ( +- 0.00% )
13,981,324,775 branches # 1300.773 M/sec ( +- 0.00% )
138,967,110 branch-misses # 0.99% of all branches ( +- 0.18% )
11.263885428 seconds time elapsed ( +- 0.04% )
^^^^^^^^^^^^
AFTER
$ perf stat -r 10 taskset -c 3 ./proc-self-status
Performance counter stats for 'taskset -c 3 ./proc-self-status' (10 runs):
9010.521776 task-clock (msec) # 0.925 CPUs utilized ( +- 1.54% )
11 context-switches # 0.001 K/sec ( +- 1.54% )
1 cpu-migrations # 0.000 K/sec ( +- 11.11% )
103 page-faults # 0.011 K/sec ( +- 0.60% )
32,352,310,603 cycles # 3.591 GHz ( +- 0.07% )
7,849,199,578 stalled-cycles-frontend # 24.26% frontend cycles idle ( +- 0.27% )
3,269,738,842 stalled-cycles-backend # 10.11% backend cycles idle ( +- 0.73% )
56,012,163,567 instructions # 1.73 insn per cycle
# 0.14 stalled cycles per insn ( +- 0.00% )
11,735,778,795 branches # 1302.453 M/sec ( +- 0.00% )
98,084,459 branch-misses # 0.84% of all branches ( +- 0.28% )
9.741247736 seconds time elapsed ( +- 0.07% )
^^^^^^^^^^^
Link: http://lkml.kernel.org/r/20160806125608.GB1187@p183.telecom.by
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Joe Perches <joe@perches.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-10-08 08:02:17 +08:00
|
|
|
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ull(m, "\nTgid:\t", tgid);
|
|
|
|
seq_put_decimal_ull(m, "\nNgid:\t", ngid);
|
|
|
|
seq_put_decimal_ull(m, "\nPid:\t", pid_nr_ns(pid, ns));
|
|
|
|
seq_put_decimal_ull(m, "\nPPid:\t", ppid);
|
|
|
|
seq_put_decimal_ull(m, "\nTracerPid:\t", tpid);
|
|
|
|
seq_put_decimal_ull(m, "\nUid:\t", from_kuid_munged(user_ns, cred->uid));
|
|
|
|
seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->euid));
|
|
|
|
seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->suid));
|
|
|
|
seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->fsuid));
|
|
|
|
seq_put_decimal_ull(m, "\nGid:\t", from_kgid_munged(user_ns, cred->gid));
|
|
|
|
seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->egid));
|
|
|
|
seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->sgid));
|
|
|
|
seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->fsgid));
|
|
|
|
seq_put_decimal_ull(m, "\nFDSize:\t", max_fds);
|
proc: faster /proc/*/status
top(1) opens the following files for every PID:
/proc/*/stat
/proc/*/statm
/proc/*/status
This patch switches /proc/*/status away from seq_printf().
The result is 13.5% speedup.
Benchmark is open("/proc/self/status")+read+close 1.000.000 million times.
BEFORE
$ perf stat -r 10 taskset -c 3 ./proc-self-status
Performance counter stats for 'taskset -c 3 ./proc-self-status' (10 runs):
10748.474301 task-clock (msec) # 0.954 CPUs utilized ( +- 0.91% )
12 context-switches # 0.001 K/sec ( +- 1.09% )
1 cpu-migrations # 0.000 K/sec
104 page-faults # 0.010 K/sec ( +- 0.45% )
37,424,127,876 cycles # 3.482 GHz ( +- 0.04% )
8,453,010,029 stalled-cycles-frontend # 22.59% frontend cycles idle ( +- 0.12% )
3,747,609,427 stalled-cycles-backend # 10.01% backend cycles idle ( +- 0.68% )
65,632,764,147 instructions # 1.75 insn per cycle
# 0.13 stalled cycles per insn ( +- 0.00% )
13,981,324,775 branches # 1300.773 M/sec ( +- 0.00% )
138,967,110 branch-misses # 0.99% of all branches ( +- 0.18% )
11.263885428 seconds time elapsed ( +- 0.04% )
^^^^^^^^^^^^
AFTER
$ perf stat -r 10 taskset -c 3 ./proc-self-status
Performance counter stats for 'taskset -c 3 ./proc-self-status' (10 runs):
9010.521776 task-clock (msec) # 0.925 CPUs utilized ( +- 1.54% )
11 context-switches # 0.001 K/sec ( +- 1.54% )
1 cpu-migrations # 0.000 K/sec ( +- 11.11% )
103 page-faults # 0.011 K/sec ( +- 0.60% )
32,352,310,603 cycles # 3.591 GHz ( +- 0.07% )
7,849,199,578 stalled-cycles-frontend # 24.26% frontend cycles idle ( +- 0.27% )
3,269,738,842 stalled-cycles-backend # 10.11% backend cycles idle ( +- 0.73% )
56,012,163,567 instructions # 1.73 insn per cycle
# 0.14 stalled cycles per insn ( +- 0.00% )
11,735,778,795 branches # 1302.453 M/sec ( +- 0.00% )
98,084,459 branch-misses # 0.84% of all branches ( +- 0.28% )
9.741247736 seconds time elapsed ( +- 0.07% )
^^^^^^^^^^^
Link: http://lkml.kernel.org/r/20160806125608.GB1187@p183.telecom.by
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Joe Perches <joe@perches.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-10-08 08:02:17 +08:00
|
|
|
|
|
|
|
seq_puts(m, "\nGroups:\t");
|
2008-11-14 07:39:19 +08:00
|
|
|
group_info = cred->group_info;
|
2012-12-18 08:03:17 +08:00
|
|
|
for (g = 0; g < group_info->ngroups; g++)
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ull(m, g ? " " : "",
|
cred: simpler, 1D supplementary groups
Current supplementary groups code can massively overallocate memory and
is implemented in a way so that access to individual gid is done via 2D
array.
If number of gids is <= 32, memory allocation is more or less tolerable
(140/148 bytes). But if it is not, code allocates full page (!)
regardless and, what's even more fun, doesn't reuse small 32-entry
array.
2D array means dependent shifts, loads and LEAs without possibility to
optimize them (gid is never known at compile time).
All of the above is unnecessary. Switch to the usual
trailing-zero-len-array scheme. Memory is allocated with
kmalloc/vmalloc() and only as much as needed. Accesses become simpler
(LEA 8(gi,idx,4) or even without displacement).
Maximum number of gids is 65536 which translates to 256KB+8 bytes. I
think kernel can handle such allocation.
On my usual desktop system with whole 9 (nine) aux groups, struct
group_info shrinks from 148 bytes to 44 bytes, yay!
Nice side effects:
- "gi->gid[i]" is shorter than "GROUP_AT(gi, i)", less typing,
- fix little mess in net/ipv4/ping.c
should have been using GROUP_AT macro but this point becomes moot,
- aux group allocation is persistent and should be accounted as such.
Link: http://lkml.kernel.org/r/20160817201927.GA2096@p183.telecom.by
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Vasily Kulikov <segoon@openwall.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-10-08 08:03:12 +08:00
|
|
|
from_kgid_munged(user_ns, group_info->gid[g]));
|
2008-11-14 07:39:19 +08:00
|
|
|
put_cred(cred);
|
proc: faster /proc/*/status
top(1) opens the following files for every PID:
/proc/*/stat
/proc/*/statm
/proc/*/status
This patch switches /proc/*/status away from seq_printf().
The result is 13.5% speedup.
Benchmark is open("/proc/self/status")+read+close 1.000.000 million times.
BEFORE
$ perf stat -r 10 taskset -c 3 ./proc-self-status
Performance counter stats for 'taskset -c 3 ./proc-self-status' (10 runs):
10748.474301 task-clock (msec) # 0.954 CPUs utilized ( +- 0.91% )
12 context-switches # 0.001 K/sec ( +- 1.09% )
1 cpu-migrations # 0.000 K/sec
104 page-faults # 0.010 K/sec ( +- 0.45% )
37,424,127,876 cycles # 3.482 GHz ( +- 0.04% )
8,453,010,029 stalled-cycles-frontend # 22.59% frontend cycles idle ( +- 0.12% )
3,747,609,427 stalled-cycles-backend # 10.01% backend cycles idle ( +- 0.68% )
65,632,764,147 instructions # 1.75 insn per cycle
# 0.13 stalled cycles per insn ( +- 0.00% )
13,981,324,775 branches # 1300.773 M/sec ( +- 0.00% )
138,967,110 branch-misses # 0.99% of all branches ( +- 0.18% )
11.263885428 seconds time elapsed ( +- 0.04% )
^^^^^^^^^^^^
AFTER
$ perf stat -r 10 taskset -c 3 ./proc-self-status
Performance counter stats for 'taskset -c 3 ./proc-self-status' (10 runs):
9010.521776 task-clock (msec) # 0.925 CPUs utilized ( +- 1.54% )
11 context-switches # 0.001 K/sec ( +- 1.54% )
1 cpu-migrations # 0.000 K/sec ( +- 11.11% )
103 page-faults # 0.011 K/sec ( +- 0.60% )
32,352,310,603 cycles # 3.591 GHz ( +- 0.07% )
7,849,199,578 stalled-cycles-frontend # 24.26% frontend cycles idle ( +- 0.27% )
3,269,738,842 stalled-cycles-backend # 10.11% backend cycles idle ( +- 0.73% )
56,012,163,567 instructions # 1.73 insn per cycle
# 0.14 stalled cycles per insn ( +- 0.00% )
11,735,778,795 branches # 1302.453 M/sec ( +- 0.00% )
98,084,459 branch-misses # 0.84% of all branches ( +- 0.28% )
9.741247736 seconds time elapsed ( +- 0.07% )
^^^^^^^^^^^
Link: http://lkml.kernel.org/r/20160806125608.GB1187@p183.telecom.by
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Joe Perches <joe@perches.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-10-08 08:02:17 +08:00
|
|
|
/* Trailing space shouldn't have been added in the first place. */
|
|
|
|
seq_putc(m, ' ');
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-04-16 07:16:30 +08:00
|
|
|
#ifdef CONFIG_PID_NS
|
|
|
|
seq_puts(m, "\nNStgid:");
|
|
|
|
for (g = ns->level; g <= pid->level; g++)
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ull(m, "\t", task_tgid_nr_ns(p, pid->numbers[g].ns));
|
2015-04-16 07:16:30 +08:00
|
|
|
seq_puts(m, "\nNSpid:");
|
|
|
|
for (g = ns->level; g <= pid->level; g++)
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ull(m, "\t", task_pid_nr_ns(p, pid->numbers[g].ns));
|
2015-04-16 07:16:30 +08:00
|
|
|
seq_puts(m, "\nNSpgid:");
|
|
|
|
for (g = ns->level; g <= pid->level; g++)
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ull(m, "\t", task_pgrp_nr_ns(p, pid->numbers[g].ns));
|
2015-04-16 07:16:30 +08:00
|
|
|
seq_puts(m, "\nNSsid:");
|
|
|
|
for (g = ns->level; g <= pid->level; g++)
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ull(m, "\t", task_session_nr_ns(p, pid->numbers[g].ns));
|
2015-04-16 07:16:30 +08:00
|
|
|
#endif
|
2011-01-13 09:00:32 +08:00
|
|
|
seq_putc(m, '\n');
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2012-12-18 08:05:02 +08:00
|
|
|
void render_sigset_t(struct seq_file *m, const char *header,
|
2008-02-08 20:18:33 +08:00
|
|
|
sigset_t *set)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-02-08 20:18:33 +08:00
|
|
|
int i;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2011-01-13 09:00:32 +08:00
|
|
|
seq_puts(m, header);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
i = _NSIG;
|
|
|
|
do {
|
|
|
|
int x = 0;
|
|
|
|
|
|
|
|
i -= 4;
|
|
|
|
if (sigismember(set, i+1)) x |= 1;
|
|
|
|
if (sigismember(set, i+2)) x |= 2;
|
|
|
|
if (sigismember(set, i+3)) x |= 4;
|
|
|
|
if (sigismember(set, i+4)) x |= 8;
|
2016-12-13 08:45:25 +08:00
|
|
|
seq_putc(m, hex_asc[x]);
|
2005-04-17 06:20:36 +08:00
|
|
|
} while (i >= 4);
|
|
|
|
|
2011-01-13 09:00:32 +08:00
|
|
|
seq_putc(m, '\n');
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
|
|
|
|
sigset_t *catch)
|
|
|
|
{
|
|
|
|
struct k_sigaction *k;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
k = p->sighand->action;
|
|
|
|
for (i = 1; i <= _NSIG; ++i, ++k) {
|
|
|
|
if (k->sa.sa_handler == SIG_IGN)
|
|
|
|
sigaddset(ign, i);
|
|
|
|
else if (k->sa.sa_handler != SIG_DFL)
|
|
|
|
sigaddset(catch, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-08 20:18:33 +08:00
|
|
|
static inline void task_sig(struct seq_file *m, struct task_struct *p)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2006-10-02 17:18:52 +08:00
|
|
|
unsigned long flags;
|
2005-04-17 06:20:36 +08:00
|
|
|
sigset_t pending, shpending, blocked, ignored, caught;
|
|
|
|
int num_threads = 0;
|
2018-06-08 08:10:13 +08:00
|
|
|
unsigned int qsize = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
unsigned long qlim = 0;
|
|
|
|
|
|
|
|
sigemptyset(&pending);
|
|
|
|
sigemptyset(&shpending);
|
|
|
|
sigemptyset(&blocked);
|
|
|
|
sigemptyset(&ignored);
|
|
|
|
sigemptyset(&caught);
|
|
|
|
|
2006-10-02 17:18:52 +08:00
|
|
|
if (lock_task_sighand(p, &flags)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
pending = p->pending.signal;
|
|
|
|
shpending = p->signal->shared_pending.signal;
|
|
|
|
blocked = p->blocked;
|
|
|
|
collect_sigign_sigcatch(p, &ignored, &caught);
|
2010-05-27 05:43:22 +08:00
|
|
|
num_threads = get_nr_threads(p);
|
2010-02-23 09:04:52 +08:00
|
|
|
rcu_read_lock(); /* FIXME: is this correct? */
|
2008-11-14 07:39:19 +08:00
|
|
|
qsize = atomic_read(&__task_cred(p)->user->sigpending);
|
2010-02-23 09:04:52 +08:00
|
|
|
rcu_read_unlock();
|
2010-03-06 05:42:42 +08:00
|
|
|
qlim = task_rlimit(p, RLIMIT_SIGPENDING);
|
2006-10-02 17:18:52 +08:00
|
|
|
unlock_task_sighand(p, &flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ull(m, "Threads:\t", num_threads);
|
|
|
|
seq_put_decimal_ull(m, "\nSigQ:\t", qsize);
|
|
|
|
seq_put_decimal_ull(m, "/", qlim);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* render them all */
|
proc: faster /proc/*/status
top(1) opens the following files for every PID:
/proc/*/stat
/proc/*/statm
/proc/*/status
This patch switches /proc/*/status away from seq_printf().
The result is 13.5% speedup.
Benchmark is open("/proc/self/status")+read+close 1.000.000 million times.
BEFORE
$ perf stat -r 10 taskset -c 3 ./proc-self-status
Performance counter stats for 'taskset -c 3 ./proc-self-status' (10 runs):
10748.474301 task-clock (msec) # 0.954 CPUs utilized ( +- 0.91% )
12 context-switches # 0.001 K/sec ( +- 1.09% )
1 cpu-migrations # 0.000 K/sec
104 page-faults # 0.010 K/sec ( +- 0.45% )
37,424,127,876 cycles # 3.482 GHz ( +- 0.04% )
8,453,010,029 stalled-cycles-frontend # 22.59% frontend cycles idle ( +- 0.12% )
3,747,609,427 stalled-cycles-backend # 10.01% backend cycles idle ( +- 0.68% )
65,632,764,147 instructions # 1.75 insn per cycle
# 0.13 stalled cycles per insn ( +- 0.00% )
13,981,324,775 branches # 1300.773 M/sec ( +- 0.00% )
138,967,110 branch-misses # 0.99% of all branches ( +- 0.18% )
11.263885428 seconds time elapsed ( +- 0.04% )
^^^^^^^^^^^^
AFTER
$ perf stat -r 10 taskset -c 3 ./proc-self-status
Performance counter stats for 'taskset -c 3 ./proc-self-status' (10 runs):
9010.521776 task-clock (msec) # 0.925 CPUs utilized ( +- 1.54% )
11 context-switches # 0.001 K/sec ( +- 1.54% )
1 cpu-migrations # 0.000 K/sec ( +- 11.11% )
103 page-faults # 0.011 K/sec ( +- 0.60% )
32,352,310,603 cycles # 3.591 GHz ( +- 0.07% )
7,849,199,578 stalled-cycles-frontend # 24.26% frontend cycles idle ( +- 0.27% )
3,269,738,842 stalled-cycles-backend # 10.11% backend cycles idle ( +- 0.73% )
56,012,163,567 instructions # 1.73 insn per cycle
# 0.14 stalled cycles per insn ( +- 0.00% )
11,735,778,795 branches # 1302.453 M/sec ( +- 0.00% )
98,084,459 branch-misses # 0.84% of all branches ( +- 0.28% )
9.741247736 seconds time elapsed ( +- 0.07% )
^^^^^^^^^^^
Link: http://lkml.kernel.org/r/20160806125608.GB1187@p183.telecom.by
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Joe Perches <joe@perches.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-10-08 08:02:17 +08:00
|
|
|
render_sigset_t(m, "\nSigPnd:\t", &pending);
|
2008-02-08 20:18:33 +08:00
|
|
|
render_sigset_t(m, "ShdPnd:\t", &shpending);
|
|
|
|
render_sigset_t(m, "SigBlk:\t", &blocked);
|
|
|
|
render_sigset_t(m, "SigIgn:\t", &ignored);
|
|
|
|
render_sigset_t(m, "SigCgt:\t", &caught);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-02-08 20:18:33 +08:00
|
|
|
static void render_cap_t(struct seq_file *m, const char *header,
|
|
|
|
kernel_cap_t *a)
|
2008-02-05 14:29:42 +08:00
|
|
|
{
|
|
|
|
unsigned __capi;
|
|
|
|
|
2011-01-13 09:00:32 +08:00
|
|
|
seq_puts(m, header);
|
2008-02-05 14:29:42 +08:00
|
|
|
CAP_FOR_EACH_U32(__capi) {
|
2018-04-11 07:31:26 +08:00
|
|
|
seq_put_hex_ll(m, NULL,
|
|
|
|
a->cap[CAP_LAST_U32 - __capi], 8);
|
2008-02-05 14:29:42 +08:00
|
|
|
}
|
2011-01-13 09:00:32 +08:00
|
|
|
seq_putc(m, '\n');
|
2008-02-05 14:29:42 +08:00
|
|
|
}
|
|
|
|
|
2008-02-08 20:18:33 +08:00
|
|
|
static inline void task_cap(struct seq_file *m, struct task_struct *p)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-14 07:39:19 +08:00
|
|
|
const struct cred *cred;
|
capabilities: ambient capabilities
Credit where credit is due: this idea comes from Christoph Lameter with
a lot of valuable input from Serge Hallyn. This patch is heavily based
on Christoph's patch.
===== The status quo =====
On Linux, there are a number of capabilities defined by the kernel. To
perform various privileged tasks, processes can wield capabilities that
they hold.
Each task has four capability masks: effective (pE), permitted (pP),
inheritable (pI), and a bounding set (X). When the kernel checks for a
capability, it checks pE. The other capability masks serve to modify
what capabilities can be in pE.
Any task can remove capabilities from pE, pP, or pI at any time. If a
task has a capability in pP, it can add that capability to pE and/or pI.
If a task has CAP_SETPCAP, then it can add any capability to pI, and it
can remove capabilities from X.
Tasks are not the only things that can have capabilities; files can also
have capabilities. A file can have no capabilty information at all [1].
If a file has capability information, then it has a permitted mask (fP)
and an inheritable mask (fI) as well as a single effective bit (fE) [2].
File capabilities modify the capabilities of tasks that execve(2) them.
A task that successfully calls execve has its capabilities modified for
the file ultimately being excecuted (i.e. the binary itself if that
binary is ELF or for the interpreter if the binary is a script.) [3] In
the capability evolution rules, for each mask Z, pZ represents the old
value and pZ' represents the new value. The rules are:
pP' = (X & fP) | (pI & fI)
pI' = pI
pE' = (fE ? pP' : 0)
X is unchanged
For setuid binaries, fP, fI, and fE are modified by a moderately
complicated set of rules that emulate POSIX behavior. Similarly, if
euid == 0 or ruid == 0, then fP, fI, and fE are modified differently
(primary, fP and fI usually end up being the full set). For nonroot
users executing binaries with neither setuid nor file caps, fI and fP
are empty and fE is false.
As an extra complication, if you execute a process as nonroot and fE is
set, then the "secure exec" rules are in effect: AT_SECURE gets set,
LD_PRELOAD doesn't work, etc.
This is rather messy. We've learned that making any changes is
dangerous, though: if a new kernel version allows an unprivileged
program to change its security state in a way that persists cross
execution of a setuid program or a program with file caps, this
persistent state is surprisingly likely to allow setuid or file-capped
programs to be exploited for privilege escalation.
===== The problem =====
Capability inheritance is basically useless.
If you aren't root and you execute an ordinary binary, fI is zero, so
your capabilities have no effect whatsoever on pP'. This means that you
can't usefully execute a helper process or a shell command with elevated
capabilities if you aren't root.
On current kernels, you can sort of work around this by setting fI to
the full set for most or all non-setuid executable files. This causes
pP' = pI for nonroot, and inheritance works. No one does this because
it's a PITA and it isn't even supported on most filesystems.
If you try this, you'll discover that every nonroot program ends up with
secure exec rules, breaking many things.
This is a problem that has bitten many people who have tried to use
capabilities for anything useful.
===== The proposed change =====
This patch adds a fifth capability mask called the ambient mask (pA).
pA does what most people expect pI to do.
pA obeys the invariant that no bit can ever be set in pA if it is not
set in both pP and pI. Dropping a bit from pP or pI drops that bit from
pA. This ensures that existing programs that try to drop capabilities
still do so, with a complication. Because capability inheritance is so
broken, setting KEEPCAPS, using setresuid to switch to nonroot uids, and
then calling execve effectively drops capabilities. Therefore,
setresuid from root to nonroot conditionally clears pA unless
SECBIT_NO_SETUID_FIXUP is set. Processes that don't like this can
re-add bits to pA afterwards.
The capability evolution rules are changed:
pA' = (file caps or setuid or setgid ? 0 : pA)
pP' = (X & fP) | (pI & fI) | pA'
pI' = pI
pE' = (fE ? pP' : pA')
X is unchanged
If you are nonroot but you have a capability, you can add it to pA. If
you do so, your children get that capability in pA, pP, and pE. For
example, you can set pA = CAP_NET_BIND_SERVICE, and your children can
automatically bind low-numbered ports. Hallelujah!
Unprivileged users can create user namespaces, map themselves to a
nonzero uid, and create both privileged (relative to their namespace)
and unprivileged process trees. This is currently more or less
impossible. Hallelujah!
You cannot use pA to try to subvert a setuid, setgid, or file-capped
program: if you execute any such program, pA gets cleared and the
resulting evolution rules are unchanged by this patch.
Users with nonzero pA are unlikely to unintentionally leak that
capability. If they run programs that try to drop privileges, dropping
privileges will still work.
It's worth noting that the degree of paranoia in this patch could
possibly be reduced without causing serious problems. Specifically, if
we allowed pA to persist across executing non-pA-aware setuid binaries
and across setresuid, then, naively, the only capabilities that could
leak as a result would be the capabilities in pA, and any attacker
*already* has those capabilities. This would make me nervous, though --
setuid binaries that tried to privilege-separate might fail to do so,
and putting CAP_DAC_READ_SEARCH or CAP_DAC_OVERRIDE into pA could have
unexpected side effects. (Whether these unexpected side effects would
be exploitable is an open question.) I've therefore taken the more
paranoid route. We can revisit this later.
An alternative would be to require PR_SET_NO_NEW_PRIVS before setting
ambient capabilities. I think that this would be annoying and would
make granting otherwise unprivileged users minor ambient capabilities
(CAP_NET_BIND_SERVICE or CAP_NET_RAW for example) much less useful than
it is with this patch.
===== Footnotes =====
[1] Files that are missing the "security.capability" xattr or that have
unrecognized values for that xattr end up with has_cap set to false.
The code that does that appears to be complicated for no good reason.
[2] The libcap capability mask parsers and formatters are dangerously
misleading and the documentation is flat-out wrong. fE is *not* a mask;
it's a single bit. This has probably confused every single person who
has tried to use file capabilities.
[3] Linux very confusingly processes both the script and the interpreter
if applicable, for reasons that elude me. The results from thinking
about a script's file capabilities and/or setuid bits are mostly
discarded.
Preliminary userspace code is here, but it needs updating:
https://git.kernel.org/cgit/linux/kernel/git/luto/util-linux-playground.git/commit/?h=cap_ambient&id=7f5afbd175d2
Here is a test program that can be used to verify the functionality
(from Christoph):
/*
* Test program for the ambient capabilities. This program spawns a shell
* that allows running processes with a defined set of capabilities.
*
* (C) 2015 Christoph Lameter <cl@linux.com>
* Released under: GPL v3 or later.
*
*
* Compile using:
*
* gcc -o ambient_test ambient_test.o -lcap-ng
*
* This program must have the following capabilities to run properly:
* Permissions for CAP_NET_RAW, CAP_NET_ADMIN, CAP_SYS_NICE
*
* A command to equip the binary with the right caps is:
*
* setcap cap_net_raw,cap_net_admin,cap_sys_nice+p ambient_test
*
*
* To get a shell with additional caps that can be inherited by other processes:
*
* ./ambient_test /bin/bash
*
*
* Verifying that it works:
*
* From the bash spawed by ambient_test run
*
* cat /proc/$$/status
*
* and have a look at the capabilities.
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <cap-ng.h>
#include <sys/prctl.h>
#include <linux/capability.h>
/*
* Definitions from the kernel header files. These are going to be removed
* when the /usr/include files have these defined.
*/
#define PR_CAP_AMBIENT 47
#define PR_CAP_AMBIENT_IS_SET 1
#define PR_CAP_AMBIENT_RAISE 2
#define PR_CAP_AMBIENT_LOWER 3
#define PR_CAP_AMBIENT_CLEAR_ALL 4
static void set_ambient_cap(int cap)
{
int rc;
capng_get_caps_process();
rc = capng_update(CAPNG_ADD, CAPNG_INHERITABLE, cap);
if (rc) {
printf("Cannot add inheritable cap\n");
exit(2);
}
capng_apply(CAPNG_SELECT_CAPS);
/* Note the two 0s at the end. Kernel checks for these */
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) {
perror("Cannot set cap");
exit(1);
}
}
int main(int argc, char **argv)
{
int rc;
set_ambient_cap(CAP_NET_RAW);
set_ambient_cap(CAP_NET_ADMIN);
set_ambient_cap(CAP_SYS_NICE);
printf("Ambient_test forking shell\n");
if (execv(argv[1], argv + 1))
perror("Cannot exec");
return 0;
}
Signed-off-by: Christoph Lameter <cl@linux.com> # Original author
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
Acked-by: Kees Cook <keescook@chromium.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Aaron Jones <aaronmdjones@gmail.com>
Cc: Ted Ts'o <tytso@mit.edu>
Cc: Andrew G. Morgan <morgan@kernel.org>
Cc: Mimi Zohar <zohar@linux.vnet.ibm.com>
Cc: Austin S Hemmelgarn <ahferroin7@gmail.com>
Cc: Markku Savela <msa@moth.iki.fi>
Cc: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Cc: James Morris <james.l.morris@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-09-05 06:42:45 +08:00
|
|
|
kernel_cap_t cap_inheritable, cap_permitted, cap_effective,
|
|
|
|
cap_bset, cap_ambient;
|
2008-11-14 07:39:16 +08:00
|
|
|
|
2008-11-14 07:39:19 +08:00
|
|
|
rcu_read_lock();
|
|
|
|
cred = __task_cred(p);
|
|
|
|
cap_inheritable = cred->cap_inheritable;
|
|
|
|
cap_permitted = cred->cap_permitted;
|
|
|
|
cap_effective = cred->cap_effective;
|
|
|
|
cap_bset = cred->cap_bset;
|
capabilities: ambient capabilities
Credit where credit is due: this idea comes from Christoph Lameter with
a lot of valuable input from Serge Hallyn. This patch is heavily based
on Christoph's patch.
===== The status quo =====
On Linux, there are a number of capabilities defined by the kernel. To
perform various privileged tasks, processes can wield capabilities that
they hold.
Each task has four capability masks: effective (pE), permitted (pP),
inheritable (pI), and a bounding set (X). When the kernel checks for a
capability, it checks pE. The other capability masks serve to modify
what capabilities can be in pE.
Any task can remove capabilities from pE, pP, or pI at any time. If a
task has a capability in pP, it can add that capability to pE and/or pI.
If a task has CAP_SETPCAP, then it can add any capability to pI, and it
can remove capabilities from X.
Tasks are not the only things that can have capabilities; files can also
have capabilities. A file can have no capabilty information at all [1].
If a file has capability information, then it has a permitted mask (fP)
and an inheritable mask (fI) as well as a single effective bit (fE) [2].
File capabilities modify the capabilities of tasks that execve(2) them.
A task that successfully calls execve has its capabilities modified for
the file ultimately being excecuted (i.e. the binary itself if that
binary is ELF or for the interpreter if the binary is a script.) [3] In
the capability evolution rules, for each mask Z, pZ represents the old
value and pZ' represents the new value. The rules are:
pP' = (X & fP) | (pI & fI)
pI' = pI
pE' = (fE ? pP' : 0)
X is unchanged
For setuid binaries, fP, fI, and fE are modified by a moderately
complicated set of rules that emulate POSIX behavior. Similarly, if
euid == 0 or ruid == 0, then fP, fI, and fE are modified differently
(primary, fP and fI usually end up being the full set). For nonroot
users executing binaries with neither setuid nor file caps, fI and fP
are empty and fE is false.
As an extra complication, if you execute a process as nonroot and fE is
set, then the "secure exec" rules are in effect: AT_SECURE gets set,
LD_PRELOAD doesn't work, etc.
This is rather messy. We've learned that making any changes is
dangerous, though: if a new kernel version allows an unprivileged
program to change its security state in a way that persists cross
execution of a setuid program or a program with file caps, this
persistent state is surprisingly likely to allow setuid or file-capped
programs to be exploited for privilege escalation.
===== The problem =====
Capability inheritance is basically useless.
If you aren't root and you execute an ordinary binary, fI is zero, so
your capabilities have no effect whatsoever on pP'. This means that you
can't usefully execute a helper process or a shell command with elevated
capabilities if you aren't root.
On current kernels, you can sort of work around this by setting fI to
the full set for most or all non-setuid executable files. This causes
pP' = pI for nonroot, and inheritance works. No one does this because
it's a PITA and it isn't even supported on most filesystems.
If you try this, you'll discover that every nonroot program ends up with
secure exec rules, breaking many things.
This is a problem that has bitten many people who have tried to use
capabilities for anything useful.
===== The proposed change =====
This patch adds a fifth capability mask called the ambient mask (pA).
pA does what most people expect pI to do.
pA obeys the invariant that no bit can ever be set in pA if it is not
set in both pP and pI. Dropping a bit from pP or pI drops that bit from
pA. This ensures that existing programs that try to drop capabilities
still do so, with a complication. Because capability inheritance is so
broken, setting KEEPCAPS, using setresuid to switch to nonroot uids, and
then calling execve effectively drops capabilities. Therefore,
setresuid from root to nonroot conditionally clears pA unless
SECBIT_NO_SETUID_FIXUP is set. Processes that don't like this can
re-add bits to pA afterwards.
The capability evolution rules are changed:
pA' = (file caps or setuid or setgid ? 0 : pA)
pP' = (X & fP) | (pI & fI) | pA'
pI' = pI
pE' = (fE ? pP' : pA')
X is unchanged
If you are nonroot but you have a capability, you can add it to pA. If
you do so, your children get that capability in pA, pP, and pE. For
example, you can set pA = CAP_NET_BIND_SERVICE, and your children can
automatically bind low-numbered ports. Hallelujah!
Unprivileged users can create user namespaces, map themselves to a
nonzero uid, and create both privileged (relative to their namespace)
and unprivileged process trees. This is currently more or less
impossible. Hallelujah!
You cannot use pA to try to subvert a setuid, setgid, or file-capped
program: if you execute any such program, pA gets cleared and the
resulting evolution rules are unchanged by this patch.
Users with nonzero pA are unlikely to unintentionally leak that
capability. If they run programs that try to drop privileges, dropping
privileges will still work.
It's worth noting that the degree of paranoia in this patch could
possibly be reduced without causing serious problems. Specifically, if
we allowed pA to persist across executing non-pA-aware setuid binaries
and across setresuid, then, naively, the only capabilities that could
leak as a result would be the capabilities in pA, and any attacker
*already* has those capabilities. This would make me nervous, though --
setuid binaries that tried to privilege-separate might fail to do so,
and putting CAP_DAC_READ_SEARCH or CAP_DAC_OVERRIDE into pA could have
unexpected side effects. (Whether these unexpected side effects would
be exploitable is an open question.) I've therefore taken the more
paranoid route. We can revisit this later.
An alternative would be to require PR_SET_NO_NEW_PRIVS before setting
ambient capabilities. I think that this would be annoying and would
make granting otherwise unprivileged users minor ambient capabilities
(CAP_NET_BIND_SERVICE or CAP_NET_RAW for example) much less useful than
it is with this patch.
===== Footnotes =====
[1] Files that are missing the "security.capability" xattr or that have
unrecognized values for that xattr end up with has_cap set to false.
The code that does that appears to be complicated for no good reason.
[2] The libcap capability mask parsers and formatters are dangerously
misleading and the documentation is flat-out wrong. fE is *not* a mask;
it's a single bit. This has probably confused every single person who
has tried to use file capabilities.
[3] Linux very confusingly processes both the script and the interpreter
if applicable, for reasons that elude me. The results from thinking
about a script's file capabilities and/or setuid bits are mostly
discarded.
Preliminary userspace code is here, but it needs updating:
https://git.kernel.org/cgit/linux/kernel/git/luto/util-linux-playground.git/commit/?h=cap_ambient&id=7f5afbd175d2
Here is a test program that can be used to verify the functionality
(from Christoph):
/*
* Test program for the ambient capabilities. This program spawns a shell
* that allows running processes with a defined set of capabilities.
*
* (C) 2015 Christoph Lameter <cl@linux.com>
* Released under: GPL v3 or later.
*
*
* Compile using:
*
* gcc -o ambient_test ambient_test.o -lcap-ng
*
* This program must have the following capabilities to run properly:
* Permissions for CAP_NET_RAW, CAP_NET_ADMIN, CAP_SYS_NICE
*
* A command to equip the binary with the right caps is:
*
* setcap cap_net_raw,cap_net_admin,cap_sys_nice+p ambient_test
*
*
* To get a shell with additional caps that can be inherited by other processes:
*
* ./ambient_test /bin/bash
*
*
* Verifying that it works:
*
* From the bash spawed by ambient_test run
*
* cat /proc/$$/status
*
* and have a look at the capabilities.
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <cap-ng.h>
#include <sys/prctl.h>
#include <linux/capability.h>
/*
* Definitions from the kernel header files. These are going to be removed
* when the /usr/include files have these defined.
*/
#define PR_CAP_AMBIENT 47
#define PR_CAP_AMBIENT_IS_SET 1
#define PR_CAP_AMBIENT_RAISE 2
#define PR_CAP_AMBIENT_LOWER 3
#define PR_CAP_AMBIENT_CLEAR_ALL 4
static void set_ambient_cap(int cap)
{
int rc;
capng_get_caps_process();
rc = capng_update(CAPNG_ADD, CAPNG_INHERITABLE, cap);
if (rc) {
printf("Cannot add inheritable cap\n");
exit(2);
}
capng_apply(CAPNG_SELECT_CAPS);
/* Note the two 0s at the end. Kernel checks for these */
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) {
perror("Cannot set cap");
exit(1);
}
}
int main(int argc, char **argv)
{
int rc;
set_ambient_cap(CAP_NET_RAW);
set_ambient_cap(CAP_NET_ADMIN);
set_ambient_cap(CAP_SYS_NICE);
printf("Ambient_test forking shell\n");
if (execv(argv[1], argv + 1))
perror("Cannot exec");
return 0;
}
Signed-off-by: Christoph Lameter <cl@linux.com> # Original author
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
Acked-by: Kees Cook <keescook@chromium.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Aaron Jones <aaronmdjones@gmail.com>
Cc: Ted Ts'o <tytso@mit.edu>
Cc: Andrew G. Morgan <morgan@kernel.org>
Cc: Mimi Zohar <zohar@linux.vnet.ibm.com>
Cc: Austin S Hemmelgarn <ahferroin7@gmail.com>
Cc: Markku Savela <msa@moth.iki.fi>
Cc: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Cc: James Morris <james.l.morris@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-09-05 06:42:45 +08:00
|
|
|
cap_ambient = cred->cap_ambient;
|
2008-11-14 07:39:19 +08:00
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
render_cap_t(m, "CapInh:\t", &cap_inheritable);
|
|
|
|
render_cap_t(m, "CapPrm:\t", &cap_permitted);
|
|
|
|
render_cap_t(m, "CapEff:\t", &cap_effective);
|
|
|
|
render_cap_t(m, "CapBnd:\t", &cap_bset);
|
capabilities: ambient capabilities
Credit where credit is due: this idea comes from Christoph Lameter with
a lot of valuable input from Serge Hallyn. This patch is heavily based
on Christoph's patch.
===== The status quo =====
On Linux, there are a number of capabilities defined by the kernel. To
perform various privileged tasks, processes can wield capabilities that
they hold.
Each task has four capability masks: effective (pE), permitted (pP),
inheritable (pI), and a bounding set (X). When the kernel checks for a
capability, it checks pE. The other capability masks serve to modify
what capabilities can be in pE.
Any task can remove capabilities from pE, pP, or pI at any time. If a
task has a capability in pP, it can add that capability to pE and/or pI.
If a task has CAP_SETPCAP, then it can add any capability to pI, and it
can remove capabilities from X.
Tasks are not the only things that can have capabilities; files can also
have capabilities. A file can have no capabilty information at all [1].
If a file has capability information, then it has a permitted mask (fP)
and an inheritable mask (fI) as well as a single effective bit (fE) [2].
File capabilities modify the capabilities of tasks that execve(2) them.
A task that successfully calls execve has its capabilities modified for
the file ultimately being excecuted (i.e. the binary itself if that
binary is ELF or for the interpreter if the binary is a script.) [3] In
the capability evolution rules, for each mask Z, pZ represents the old
value and pZ' represents the new value. The rules are:
pP' = (X & fP) | (pI & fI)
pI' = pI
pE' = (fE ? pP' : 0)
X is unchanged
For setuid binaries, fP, fI, and fE are modified by a moderately
complicated set of rules that emulate POSIX behavior. Similarly, if
euid == 0 or ruid == 0, then fP, fI, and fE are modified differently
(primary, fP and fI usually end up being the full set). For nonroot
users executing binaries with neither setuid nor file caps, fI and fP
are empty and fE is false.
As an extra complication, if you execute a process as nonroot and fE is
set, then the "secure exec" rules are in effect: AT_SECURE gets set,
LD_PRELOAD doesn't work, etc.
This is rather messy. We've learned that making any changes is
dangerous, though: if a new kernel version allows an unprivileged
program to change its security state in a way that persists cross
execution of a setuid program or a program with file caps, this
persistent state is surprisingly likely to allow setuid or file-capped
programs to be exploited for privilege escalation.
===== The problem =====
Capability inheritance is basically useless.
If you aren't root and you execute an ordinary binary, fI is zero, so
your capabilities have no effect whatsoever on pP'. This means that you
can't usefully execute a helper process or a shell command with elevated
capabilities if you aren't root.
On current kernels, you can sort of work around this by setting fI to
the full set for most or all non-setuid executable files. This causes
pP' = pI for nonroot, and inheritance works. No one does this because
it's a PITA and it isn't even supported on most filesystems.
If you try this, you'll discover that every nonroot program ends up with
secure exec rules, breaking many things.
This is a problem that has bitten many people who have tried to use
capabilities for anything useful.
===== The proposed change =====
This patch adds a fifth capability mask called the ambient mask (pA).
pA does what most people expect pI to do.
pA obeys the invariant that no bit can ever be set in pA if it is not
set in both pP and pI. Dropping a bit from pP or pI drops that bit from
pA. This ensures that existing programs that try to drop capabilities
still do so, with a complication. Because capability inheritance is so
broken, setting KEEPCAPS, using setresuid to switch to nonroot uids, and
then calling execve effectively drops capabilities. Therefore,
setresuid from root to nonroot conditionally clears pA unless
SECBIT_NO_SETUID_FIXUP is set. Processes that don't like this can
re-add bits to pA afterwards.
The capability evolution rules are changed:
pA' = (file caps or setuid or setgid ? 0 : pA)
pP' = (X & fP) | (pI & fI) | pA'
pI' = pI
pE' = (fE ? pP' : pA')
X is unchanged
If you are nonroot but you have a capability, you can add it to pA. If
you do so, your children get that capability in pA, pP, and pE. For
example, you can set pA = CAP_NET_BIND_SERVICE, and your children can
automatically bind low-numbered ports. Hallelujah!
Unprivileged users can create user namespaces, map themselves to a
nonzero uid, and create both privileged (relative to their namespace)
and unprivileged process trees. This is currently more or less
impossible. Hallelujah!
You cannot use pA to try to subvert a setuid, setgid, or file-capped
program: if you execute any such program, pA gets cleared and the
resulting evolution rules are unchanged by this patch.
Users with nonzero pA are unlikely to unintentionally leak that
capability. If they run programs that try to drop privileges, dropping
privileges will still work.
It's worth noting that the degree of paranoia in this patch could
possibly be reduced without causing serious problems. Specifically, if
we allowed pA to persist across executing non-pA-aware setuid binaries
and across setresuid, then, naively, the only capabilities that could
leak as a result would be the capabilities in pA, and any attacker
*already* has those capabilities. This would make me nervous, though --
setuid binaries that tried to privilege-separate might fail to do so,
and putting CAP_DAC_READ_SEARCH or CAP_DAC_OVERRIDE into pA could have
unexpected side effects. (Whether these unexpected side effects would
be exploitable is an open question.) I've therefore taken the more
paranoid route. We can revisit this later.
An alternative would be to require PR_SET_NO_NEW_PRIVS before setting
ambient capabilities. I think that this would be annoying and would
make granting otherwise unprivileged users minor ambient capabilities
(CAP_NET_BIND_SERVICE or CAP_NET_RAW for example) much less useful than
it is with this patch.
===== Footnotes =====
[1] Files that are missing the "security.capability" xattr or that have
unrecognized values for that xattr end up with has_cap set to false.
The code that does that appears to be complicated for no good reason.
[2] The libcap capability mask parsers and formatters are dangerously
misleading and the documentation is flat-out wrong. fE is *not* a mask;
it's a single bit. This has probably confused every single person who
has tried to use file capabilities.
[3] Linux very confusingly processes both the script and the interpreter
if applicable, for reasons that elude me. The results from thinking
about a script's file capabilities and/or setuid bits are mostly
discarded.
Preliminary userspace code is here, but it needs updating:
https://git.kernel.org/cgit/linux/kernel/git/luto/util-linux-playground.git/commit/?h=cap_ambient&id=7f5afbd175d2
Here is a test program that can be used to verify the functionality
(from Christoph):
/*
* Test program for the ambient capabilities. This program spawns a shell
* that allows running processes with a defined set of capabilities.
*
* (C) 2015 Christoph Lameter <cl@linux.com>
* Released under: GPL v3 or later.
*
*
* Compile using:
*
* gcc -o ambient_test ambient_test.o -lcap-ng
*
* This program must have the following capabilities to run properly:
* Permissions for CAP_NET_RAW, CAP_NET_ADMIN, CAP_SYS_NICE
*
* A command to equip the binary with the right caps is:
*
* setcap cap_net_raw,cap_net_admin,cap_sys_nice+p ambient_test
*
*
* To get a shell with additional caps that can be inherited by other processes:
*
* ./ambient_test /bin/bash
*
*
* Verifying that it works:
*
* From the bash spawed by ambient_test run
*
* cat /proc/$$/status
*
* and have a look at the capabilities.
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <cap-ng.h>
#include <sys/prctl.h>
#include <linux/capability.h>
/*
* Definitions from the kernel header files. These are going to be removed
* when the /usr/include files have these defined.
*/
#define PR_CAP_AMBIENT 47
#define PR_CAP_AMBIENT_IS_SET 1
#define PR_CAP_AMBIENT_RAISE 2
#define PR_CAP_AMBIENT_LOWER 3
#define PR_CAP_AMBIENT_CLEAR_ALL 4
static void set_ambient_cap(int cap)
{
int rc;
capng_get_caps_process();
rc = capng_update(CAPNG_ADD, CAPNG_INHERITABLE, cap);
if (rc) {
printf("Cannot add inheritable cap\n");
exit(2);
}
capng_apply(CAPNG_SELECT_CAPS);
/* Note the two 0s at the end. Kernel checks for these */
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) {
perror("Cannot set cap");
exit(1);
}
}
int main(int argc, char **argv)
{
int rc;
set_ambient_cap(CAP_NET_RAW);
set_ambient_cap(CAP_NET_ADMIN);
set_ambient_cap(CAP_SYS_NICE);
printf("Ambient_test forking shell\n");
if (execv(argv[1], argv + 1))
perror("Cannot exec");
return 0;
}
Signed-off-by: Christoph Lameter <cl@linux.com> # Original author
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
Acked-by: Kees Cook <keescook@chromium.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Aaron Jones <aaronmdjones@gmail.com>
Cc: Ted Ts'o <tytso@mit.edu>
Cc: Andrew G. Morgan <morgan@kernel.org>
Cc: Mimi Zohar <zohar@linux.vnet.ibm.com>
Cc: Austin S Hemmelgarn <ahferroin7@gmail.com>
Cc: Markku Savela <msa@moth.iki.fi>
Cc: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Cc: James Morris <james.l.morris@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-09-05 06:42:45 +08:00
|
|
|
render_cap_t(m, "CapAmb:\t", &cap_ambient);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2012-12-18 08:03:14 +08:00
|
|
|
static inline void task_seccomp(struct seq_file *m, struct task_struct *p)
|
|
|
|
{
|
2016-12-13 08:45:05 +08:00
|
|
|
seq_put_decimal_ull(m, "NoNewPrivs:\t", task_no_new_privs(p));
|
2012-12-18 08:03:14 +08:00
|
|
|
#ifdef CONFIG_SECCOMP
|
2016-12-13 08:45:05 +08:00
|
|
|
seq_put_decimal_ull(m, "\nSeccomp:\t", p->seccomp.mode);
|
2012-12-18 08:03:14 +08:00
|
|
|
#endif
|
2018-05-10 03:41:38 +08:00
|
|
|
seq_printf(m, "\nSpeculation_Store_Bypass:\t");
|
2018-05-02 06:31:45 +08:00
|
|
|
switch (arch_prctl_spec_ctrl_get(p, PR_SPEC_STORE_BYPASS)) {
|
|
|
|
case -EINVAL:
|
|
|
|
seq_printf(m, "unknown");
|
|
|
|
break;
|
|
|
|
case PR_SPEC_NOT_AFFECTED:
|
|
|
|
seq_printf(m, "not vulnerable");
|
|
|
|
break;
|
2018-05-04 04:09:15 +08:00
|
|
|
case PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE:
|
|
|
|
seq_printf(m, "thread force mitigated");
|
|
|
|
break;
|
2018-05-02 06:31:45 +08:00
|
|
|
case PR_SPEC_PRCTL | PR_SPEC_DISABLE:
|
|
|
|
seq_printf(m, "thread mitigated");
|
|
|
|
break;
|
|
|
|
case PR_SPEC_PRCTL | PR_SPEC_ENABLE:
|
|
|
|
seq_printf(m, "thread vulnerable");
|
|
|
|
break;
|
|
|
|
case PR_SPEC_DISABLE:
|
|
|
|
seq_printf(m, "globally mitigated");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
seq_printf(m, "vulnerable");
|
|
|
|
break;
|
|
|
|
}
|
2016-12-13 08:45:05 +08:00
|
|
|
seq_putc(m, '\n');
|
2012-12-18 08:03:14 +08:00
|
|
|
}
|
|
|
|
|
2008-02-08 20:18:33 +08:00
|
|
|
static inline void task_context_switch_counts(struct seq_file *m,
|
|
|
|
struct task_struct *p)
|
2007-07-16 14:40:48 +08:00
|
|
|
{
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw);
|
|
|
|
seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw);
|
proc: faster /proc/*/status
top(1) opens the following files for every PID:
/proc/*/stat
/proc/*/statm
/proc/*/status
This patch switches /proc/*/status away from seq_printf().
The result is 13.5% speedup.
Benchmark is open("/proc/self/status")+read+close 1.000.000 million times.
BEFORE
$ perf stat -r 10 taskset -c 3 ./proc-self-status
Performance counter stats for 'taskset -c 3 ./proc-self-status' (10 runs):
10748.474301 task-clock (msec) # 0.954 CPUs utilized ( +- 0.91% )
12 context-switches # 0.001 K/sec ( +- 1.09% )
1 cpu-migrations # 0.000 K/sec
104 page-faults # 0.010 K/sec ( +- 0.45% )
37,424,127,876 cycles # 3.482 GHz ( +- 0.04% )
8,453,010,029 stalled-cycles-frontend # 22.59% frontend cycles idle ( +- 0.12% )
3,747,609,427 stalled-cycles-backend # 10.01% backend cycles idle ( +- 0.68% )
65,632,764,147 instructions # 1.75 insn per cycle
# 0.13 stalled cycles per insn ( +- 0.00% )
13,981,324,775 branches # 1300.773 M/sec ( +- 0.00% )
138,967,110 branch-misses # 0.99% of all branches ( +- 0.18% )
11.263885428 seconds time elapsed ( +- 0.04% )
^^^^^^^^^^^^
AFTER
$ perf stat -r 10 taskset -c 3 ./proc-self-status
Performance counter stats for 'taskset -c 3 ./proc-self-status' (10 runs):
9010.521776 task-clock (msec) # 0.925 CPUs utilized ( +- 1.54% )
11 context-switches # 0.001 K/sec ( +- 1.54% )
1 cpu-migrations # 0.000 K/sec ( +- 11.11% )
103 page-faults # 0.011 K/sec ( +- 0.60% )
32,352,310,603 cycles # 3.591 GHz ( +- 0.07% )
7,849,199,578 stalled-cycles-frontend # 24.26% frontend cycles idle ( +- 0.27% )
3,269,738,842 stalled-cycles-backend # 10.11% backend cycles idle ( +- 0.73% )
56,012,163,567 instructions # 1.73 insn per cycle
# 0.14 stalled cycles per insn ( +- 0.00% )
11,735,778,795 branches # 1302.453 M/sec ( +- 0.00% )
98,084,459 branch-misses # 0.84% of all branches ( +- 0.28% )
9.741247736 seconds time elapsed ( +- 0.07% )
^^^^^^^^^^^
Link: http://lkml.kernel.org/r/20160806125608.GB1187@p183.telecom.by
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Joe Perches <joe@perches.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-10-08 08:02:17 +08:00
|
|
|
seq_putc(m, '\n');
|
2007-07-16 14:40:48 +08:00
|
|
|
}
|
|
|
|
|
2009-09-21 17:06:27 +08:00
|
|
|
static void task_cpus_allowed(struct seq_file *m, struct task_struct *task)
|
|
|
|
{
|
2015-02-14 06:38:07 +08:00
|
|
|
seq_printf(m, "Cpus_allowed:\t%*pb\n",
|
|
|
|
cpumask_pr_args(&task->cpus_allowed));
|
|
|
|
seq_printf(m, "Cpus_allowed_list:\t%*pbl\n",
|
|
|
|
cpumask_pr_args(&task->cpus_allowed));
|
2009-09-21 17:06:27 +08:00
|
|
|
}
|
|
|
|
|
2017-11-18 07:26:45 +08:00
|
|
|
static inline void task_core_dumping(struct seq_file *m, struct mm_struct *mm)
|
|
|
|
{
|
2018-04-11 07:31:26 +08:00
|
|
|
seq_put_decimal_ull(m, "CoreDumping:\t", !!mm->core_state);
|
|
|
|
seq_putc(m, '\n');
|
2017-11-18 07:26:45 +08:00
|
|
|
}
|
|
|
|
|
2018-12-28 16:38:25 +08:00
|
|
|
static inline void task_thp_status(struct seq_file *m, struct mm_struct *mm)
|
|
|
|
{
|
|
|
|
bool thp_enabled = IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE);
|
|
|
|
|
|
|
|
if (thp_enabled)
|
|
|
|
thp_enabled = !test_bit(MMF_DISABLE_THP, &mm->flags);
|
|
|
|
seq_printf(m, "THP_enabled:\t%d\n", thp_enabled);
|
|
|
|
}
|
|
|
|
|
2008-02-08 20:18:33 +08:00
|
|
|
int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
|
|
|
|
struct pid *pid, struct task_struct *task)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct mm_struct *mm = get_task_mm(task);
|
|
|
|
|
2018-05-18 23:47:13 +08:00
|
|
|
seq_puts(m, "Name:\t");
|
|
|
|
proc_task_name(m, task, true);
|
|
|
|
seq_putc(m, '\n');
|
|
|
|
|
2008-02-08 20:18:33 +08:00
|
|
|
task_state(m, ns, pid, task);
|
2007-07-16 15:46:31 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (mm) {
|
2008-02-08 20:18:33 +08:00
|
|
|
task_mem(m, mm);
|
2017-11-18 07:26:45 +08:00
|
|
|
task_core_dumping(m, mm);
|
2018-12-28 16:38:25 +08:00
|
|
|
task_thp_status(m, mm);
|
2005-04-17 06:20:36 +08:00
|
|
|
mmput(mm);
|
|
|
|
}
|
2008-02-08 20:18:33 +08:00
|
|
|
task_sig(m, task);
|
|
|
|
task_cap(m, task);
|
2012-12-18 08:03:14 +08:00
|
|
|
task_seccomp(m, task);
|
2009-09-21 17:06:27 +08:00
|
|
|
task_cpus_allowed(m, task);
|
2008-02-08 20:18:33 +08:00
|
|
|
cpuset_task_status_allowed(m, task);
|
|
|
|
task_context_switch_counts(m, task);
|
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-02-08 20:18:31 +08:00
|
|
|
static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
|
|
|
|
struct pid *pid, struct task_struct *task, int whole)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
fs/proc, core/debug: Don't expose absolute kernel addresses via wchan
So the /proc/PID/stat 'wchan' field (the 30th field, which contains
the absolute kernel address of the kernel function a task is blocked in)
leaks absolute kernel addresses to unprivileged user-space:
seq_put_decimal_ull(m, ' ', wchan);
The absolute address might also leak via /proc/PID/wchan as well, if
KALLSYMS is turned off or if the symbol lookup fails for some reason:
static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task)
{
unsigned long wchan;
char symname[KSYM_NAME_LEN];
wchan = get_wchan(task);
if (lookup_symbol_name(wchan, symname) < 0) {
if (!ptrace_may_access(task, PTRACE_MODE_READ))
return 0;
seq_printf(m, "%lu", wchan);
} else {
seq_printf(m, "%s", symname);
}
return 0;
}
This isn't ideal, because for example it trivially leaks the KASLR offset
to any local attacker:
fomalhaut:~> printf "%016lx\n" $(cat /proc/$$/stat | cut -d' ' -f35)
ffffffff8123b380
Most real-life uses of wchan are symbolic:
ps -eo pid:10,tid:10,wchan:30,comm
and procps uses /proc/PID/wchan, not the absolute address in /proc/PID/stat:
triton:~/tip> strace -f ps -eo pid:10,tid:10,wchan:30,comm 2>&1 | grep wchan | tail -1
open("/proc/30833/wchan", O_RDONLY) = 6
There's one compatibility quirk here: procps relies on whether the
absolute value is non-zero - and we can provide that functionality
by outputing "0" or "1" depending on whether the task is blocked
(whether there's a wchan address).
These days there appears to be very little legitimate reason
user-space would be interested in the absolute address. The
absolute address is mostly historic: from the days when we
didn't have kallsyms and user-space procps had to do the
decoding itself via the System.map.
So this patch sets all numeric output to "0" or "1" and keeps only
symbolic output, in /proc/PID/wchan.
( The absolute sleep address can generally still be profiled via
perf, by tasks with sufficient privileges. )
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Kees Cook <keescook@chromium.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Cc: <stable@vger.kernel.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Alexander Potapenko <glider@google.com>
Cc: Andrey Konovalov <andreyknvl@google.com>
Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Kostya Serebryany <kcc@google.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: kasan-dev <kasan-dev@googlegroups.com>
Cc: linux-kernel@vger.kernel.org
Link: http://lkml.kernel.org/r/20150930135917.GA3285@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-09-30 21:59:17 +08:00
|
|
|
unsigned long vsize, eip, esp, wchan = 0;
|
2012-06-01 07:26:19 +08:00
|
|
|
int priority, nice;
|
2005-04-17 06:20:36 +08:00
|
|
|
int tty_pgrp = -1, tty_nr = 0;
|
|
|
|
sigset_t sigign, sigcatch;
|
|
|
|
char state;
|
2007-07-16 15:46:31 +08:00
|
|
|
pid_t ppid = 0, pgid = -1, sid = -1;
|
2005-04-17 06:20:36 +08:00
|
|
|
int num_threads = 0;
|
2009-05-05 02:51:14 +08:00
|
|
|
int permitted;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct mm_struct *mm;
|
|
|
|
unsigned long long start_time;
|
|
|
|
unsigned long cmin_flt = 0, cmaj_flt = 0;
|
|
|
|
unsigned long min_flt = 0, maj_flt = 0;
|
2017-01-31 11:09:23 +08:00
|
|
|
u64 cutime, cstime, utime, stime;
|
2017-01-31 11:09:21 +08:00
|
|
|
u64 cgtime, gtime;
|
2005-04-17 06:20:36 +08:00
|
|
|
unsigned long rsslim = 0;
|
2006-10-02 17:18:53 +08:00
|
|
|
unsigned long flags;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
state = *get_task_state(task);
|
|
|
|
vsize = eip = esp = 0;
|
ptrace: use fsuid, fsgid, effective creds for fs access checks
By checking the effective credentials instead of the real UID / permitted
capabilities, ensure that the calling process actually intended to use its
credentials.
To ensure that all ptrace checks use the correct caller credentials (e.g.
in case out-of-tree code or newly added code omits the PTRACE_MODE_*CREDS
flag), use two new flags and require one of them to be set.
The problem was that when a privileged task had temporarily dropped its
privileges, e.g. by calling setreuid(0, user_uid), with the intent to
perform following syscalls with the credentials of a user, it still passed
ptrace access checks that the user would not be able to pass.
While an attacker should not be able to convince the privileged task to
perform a ptrace() syscall, this is a problem because the ptrace access
check is reused for things in procfs.
In particular, the following somewhat interesting procfs entries only rely
on ptrace access checks:
/proc/$pid/stat - uses the check for determining whether pointers
should be visible, useful for bypassing ASLR
/proc/$pid/maps - also useful for bypassing ASLR
/proc/$pid/cwd - useful for gaining access to restricted
directories that contain files with lax permissions, e.g. in
this scenario:
lrwxrwxrwx root root /proc/13020/cwd -> /root/foobar
drwx------ root root /root
drwxr-xr-x root root /root/foobar
-rw-r--r-- root root /root/foobar/secret
Therefore, on a system where a root-owned mode 6755 binary changes its
effective credentials as described and then dumps a user-specified file,
this could be used by an attacker to reveal the memory layout of root's
processes or reveal the contents of files he is not allowed to access
(through /proc/$pid/cwd).
[akpm@linux-foundation.org: fix warning]
Signed-off-by: Jann Horn <jann@thejh.net>
Acked-by: Kees Cook <keescook@chromium.org>
Cc: Casey Schaufler <casey@schaufler-ca.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Morris <james.l.morris@oracle.com>
Cc: "Serge E. Hallyn" <serge.hallyn@ubuntu.com>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Willy Tarreau <w@1wt.eu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-01-21 07:00:04 +08:00
|
|
|
permitted = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS | PTRACE_MODE_NOAUDIT);
|
2005-04-17 06:20:36 +08:00
|
|
|
mm = get_task_mm(task);
|
|
|
|
if (mm) {
|
|
|
|
vsize = task_vsize(mm);
|
2016-10-01 01:58:56 +08:00
|
|
|
/*
|
|
|
|
* esp and eip are intentionally zeroed out. There is no
|
|
|
|
* non-racy way to read them without freezing the task.
|
|
|
|
* Programs that need reliable values can use ptrace(2).
|
2017-09-14 17:42:17 +08:00
|
|
|
*
|
|
|
|
* The only exception is if the task is core dumping because
|
|
|
|
* a program is not able to use ptrace(2) in that case. It is
|
|
|
|
* safe because the task has stopped executing permanently.
|
2016-10-01 01:58:56 +08:00
|
|
|
*/
|
2017-09-14 17:42:17 +08:00
|
|
|
if (permitted && (task->flags & PF_DUMPCORE)) {
|
proc: fix coredump vs read /proc/*/stat race
do_task_stat() accesses IP and SP of a task without bumping reference
count of a stack (which became an entity with independent lifetime at
some point).
Steps to reproduce:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
setrlimit(RLIMIT_CORE, &(struct rlimit){});
while (1) {
char buf[64];
char buf2[4096];
pid_t pid;
int fd;
pid = fork();
if (pid == 0) {
*(volatile int *)0 = 0;
}
snprintf(buf, sizeof(buf), "/proc/%u/stat", pid);
fd = open(buf, O_RDONLY);
read(fd, buf2, sizeof(buf2));
close(fd);
waitpid(pid, NULL, 0);
}
return 0;
}
BUG: unable to handle kernel paging request at 0000000000003fd8
IP: do_task_stat+0x8b4/0xaf0
PGD 800000003d73e067 P4D 800000003d73e067 PUD 3d558067 PMD 0
Oops: 0000 [#1] PREEMPT SMP PTI
CPU: 0 PID: 1417 Comm: a.out Not tainted 4.15.0-rc8-dirty #2
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1.fc27 04/01/2014
RIP: 0010:do_task_stat+0x8b4/0xaf0
Call Trace:
proc_single_show+0x43/0x70
seq_read+0xe6/0x3b0
__vfs_read+0x1e/0x120
vfs_read+0x84/0x110
SyS_read+0x3d/0xa0
entry_SYSCALL_64_fastpath+0x13/0x6c
RIP: 0033:0x7f4d7928cba0
RSP: 002b:00007ffddb245158 EFLAGS: 00000246
Code: 03 b7 a0 01 00 00 4c 8b 4c 24 70 4c 8b 44 24 78 4c 89 74 24 18 e9 91 f9 ff ff f6 45 4d 02 0f 84 fd f7 ff ff 48 8b 45 40 48 89 ef <48> 8b 80 d8 3f 00 00 48 89 44 24 20 e8 9b 97 eb ff 48 89 44 24
RIP: do_task_stat+0x8b4/0xaf0 RSP: ffffc90000607cc8
CR2: 0000000000003fd8
John Ogness said: for my tests I added an else case to verify that the
race is hit and correctly mitigated.
Link: http://lkml.kernel.org/r/20180116175054.GA11513@avx2
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Reported-by: "Kohli, Gaurav" <gkohli@codeaurora.org>
Tested-by: John Ogness <john.ogness@linutronix.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-01-19 08:34:05 +08:00
|
|
|
if (try_get_task_stack(task)) {
|
|
|
|
eip = KSTK_EIP(task);
|
|
|
|
esp = KSTK_ESP(task);
|
|
|
|
put_task_stack(task);
|
|
|
|
}
|
2017-09-14 17:42:17 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
sigemptyset(&sigign);
|
|
|
|
sigemptyset(&sigcatch);
|
2011-12-15 21:56:09 +08:00
|
|
|
cutime = cstime = utime = stime = 0;
|
|
|
|
cgtime = gtime = 0;
|
2006-09-29 17:00:41 +08:00
|
|
|
|
2006-10-02 17:18:53 +08:00
|
|
|
if (lock_task_sighand(task, &flags)) {
|
|
|
|
struct signal_struct *sig = task->signal;
|
2006-12-08 18:36:07 +08:00
|
|
|
|
|
|
|
if (sig->tty) {
|
2008-04-30 15:53:31 +08:00
|
|
|
struct pid *pgrp = tty_get_pgrp(sig->tty);
|
|
|
|
tty_pgrp = pid_nr_ns(pgrp, ns);
|
|
|
|
put_pid(pgrp);
|
2006-12-08 18:36:07 +08:00
|
|
|
tty_nr = new_encode_dev(tty_devnum(sig->tty));
|
2006-10-02 17:18:53 +08:00
|
|
|
}
|
|
|
|
|
2010-05-27 05:43:22 +08:00
|
|
|
num_threads = get_nr_threads(task);
|
2005-04-17 06:20:36 +08:00
|
|
|
collect_sigign_sigcatch(task, &sigign, &sigcatch);
|
|
|
|
|
2006-10-02 17:18:53 +08:00
|
|
|
cmin_flt = sig->cmin_flt;
|
|
|
|
cmaj_flt = sig->cmaj_flt;
|
|
|
|
cutime = sig->cutime;
|
|
|
|
cstime = sig->cstime;
|
2007-10-15 23:00:19 +08:00
|
|
|
cgtime = sig->cgtime;
|
locking/atomics: COCCINELLE/treewide: Convert trivial ACCESS_ONCE() patterns to READ_ONCE()/WRITE_ONCE()
Please do not apply this to mainline directly, instead please re-run the
coccinelle script shown below and apply its output.
For several reasons, it is desirable to use {READ,WRITE}_ONCE() in
preference to ACCESS_ONCE(), and new code is expected to use one of the
former. So far, there's been no reason to change most existing uses of
ACCESS_ONCE(), as these aren't harmful, and changing them results in
churn.
However, for some features, the read/write distinction is critical to
correct operation. To distinguish these cases, separate read/write
accessors must be used. This patch migrates (most) remaining
ACCESS_ONCE() instances to {READ,WRITE}_ONCE(), using the following
coccinelle script:
----
// Convert trivial ACCESS_ONCE() uses to equivalent READ_ONCE() and
// WRITE_ONCE()
// $ make coccicheck COCCI=/home/mark/once.cocci SPFLAGS="--include-headers" MODE=patch
virtual patch
@ depends on patch @
expression E1, E2;
@@
- ACCESS_ONCE(E1) = E2
+ WRITE_ONCE(E1, E2)
@ depends on patch @
expression E;
@@
- ACCESS_ONCE(E)
+ READ_ONCE(E)
----
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: davem@davemloft.net
Cc: linux-arch@vger.kernel.org
Cc: mpe@ellerman.id.au
Cc: shuah@kernel.org
Cc: snitzer@redhat.com
Cc: thor.thayer@linux.intel.com
Cc: tj@kernel.org
Cc: viro@zeniv.linux.org.uk
Cc: will.deacon@arm.com
Link: http://lkml.kernel.org/r/1508792849-3115-19-git-send-email-paulmck@linux.vnet.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-10-24 05:07:29 +08:00
|
|
|
rsslim = READ_ONCE(sig->rlim[RLIMIT_RSS].rlim_cur);
|
2006-10-02 17:18:53 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* add up live thread stats at the group level */
|
|
|
|
if (whole) {
|
2006-10-02 17:18:53 +08:00
|
|
|
struct task_struct *t = task;
|
2005-04-17 06:20:36 +08:00
|
|
|
do {
|
|
|
|
min_flt += t->min_flt;
|
|
|
|
maj_flt += t->maj_flt;
|
2012-11-13 21:20:55 +08:00
|
|
|
gtime += task_gtime(t);
|
2014-01-24 07:55:53 +08:00
|
|
|
} while_each_thread(task, t);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-10-02 17:18:53 +08:00
|
|
|
min_flt += sig->min_flt;
|
|
|
|
maj_flt += sig->maj_flt;
|
2012-11-21 23:26:44 +08:00
|
|
|
thread_group_cputime_adjusted(task, &utime, &stime);
|
2011-12-15 21:56:09 +08:00
|
|
|
gtime += sig->gtime;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2006-10-02 17:18:53 +08:00
|
|
|
|
2007-10-19 14:40:14 +08:00
|
|
|
sid = task_session_nr_ns(task, ns);
|
2008-01-15 05:02:37 +08:00
|
|
|
ppid = task_tgid_nr_ns(task->real_parent, ns);
|
2007-10-19 14:40:14 +08:00
|
|
|
pgid = task_pgrp_nr_ns(task, ns);
|
2006-10-02 17:18:53 +08:00
|
|
|
|
|
|
|
unlock_task_sighand(task, &flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2009-05-05 02:51:14 +08:00
|
|
|
if (permitted && (!whole || num_threads < 2))
|
2005-04-17 06:20:36 +08:00
|
|
|
wchan = get_wchan(task);
|
|
|
|
if (!whole) {
|
|
|
|
min_flt = task->min_flt;
|
|
|
|
maj_flt = task->maj_flt;
|
2012-11-21 23:26:44 +08:00
|
|
|
task_cputime_adjusted(task, &utime, &stime);
|
2012-11-13 21:20:55 +08:00
|
|
|
gtime = task_gtime(task);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* scale priority and nice values from timeslices to -20..20 */
|
|
|
|
/* to make it look like a "normal" Unix priority/nice value */
|
|
|
|
priority = task_prio(task);
|
|
|
|
nice = task_nice(task);
|
|
|
|
|
|
|
|
/* convert nsec -> ticks */
|
2014-07-17 05:04:32 +08:00
|
|
|
start_time = nsec_to_clock_t(task->real_start_time);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2018-04-11 07:31:26 +08:00
|
|
|
seq_put_decimal_ull(m, "", pid_nr_ns(pid, ns));
|
|
|
|
seq_puts(m, " (");
|
2018-05-18 23:47:13 +08:00
|
|
|
proc_task_name(m, task, false);
|
2018-04-11 07:31:26 +08:00
|
|
|
seq_puts(m, ") ");
|
|
|
|
seq_putc(m, state);
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ll(m, " ", ppid);
|
|
|
|
seq_put_decimal_ll(m, " ", pgid);
|
|
|
|
seq_put_decimal_ll(m, " ", sid);
|
|
|
|
seq_put_decimal_ll(m, " ", tty_nr);
|
|
|
|
seq_put_decimal_ll(m, " ", tty_pgrp);
|
|
|
|
seq_put_decimal_ull(m, " ", task->flags);
|
|
|
|
seq_put_decimal_ull(m, " ", min_flt);
|
|
|
|
seq_put_decimal_ull(m, " ", cmin_flt);
|
|
|
|
seq_put_decimal_ull(m, " ", maj_flt);
|
|
|
|
seq_put_decimal_ull(m, " ", cmaj_flt);
|
2017-01-31 11:09:23 +08:00
|
|
|
seq_put_decimal_ull(m, " ", nsec_to_clock_t(utime));
|
|
|
|
seq_put_decimal_ull(m, " ", nsec_to_clock_t(stime));
|
|
|
|
seq_put_decimal_ll(m, " ", nsec_to_clock_t(cutime));
|
|
|
|
seq_put_decimal_ll(m, " ", nsec_to_clock_t(cstime));
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ll(m, " ", priority);
|
|
|
|
seq_put_decimal_ll(m, " ", nice);
|
|
|
|
seq_put_decimal_ll(m, " ", num_threads);
|
|
|
|
seq_put_decimal_ull(m, " ", 0);
|
|
|
|
seq_put_decimal_ull(m, " ", start_time);
|
|
|
|
seq_put_decimal_ull(m, " ", vsize);
|
|
|
|
seq_put_decimal_ull(m, " ", mm ? get_mm_rss(mm) : 0);
|
|
|
|
seq_put_decimal_ull(m, " ", rsslim);
|
|
|
|
seq_put_decimal_ull(m, " ", mm ? (permitted ? mm->start_code : 1) : 0);
|
|
|
|
seq_put_decimal_ull(m, " ", mm ? (permitted ? mm->end_code : 1) : 0);
|
|
|
|
seq_put_decimal_ull(m, " ", (permitted && mm) ? mm->start_stack : 0);
|
|
|
|
seq_put_decimal_ull(m, " ", esp);
|
|
|
|
seq_put_decimal_ull(m, " ", eip);
|
2012-03-24 06:02:54 +08:00
|
|
|
/* The signal information here is obsolete.
|
|
|
|
* It must be decimal for Linux 2.0 compatibility.
|
|
|
|
* Use /proc/#/status for real-time signals.
|
|
|
|
*/
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ull(m, " ", task->pending.signal.sig[0] & 0x7fffffffUL);
|
|
|
|
seq_put_decimal_ull(m, " ", task->blocked.sig[0] & 0x7fffffffUL);
|
|
|
|
seq_put_decimal_ull(m, " ", sigign.sig[0] & 0x7fffffffUL);
|
|
|
|
seq_put_decimal_ull(m, " ", sigcatch.sig[0] & 0x7fffffffUL);
|
fs/proc, core/debug: Don't expose absolute kernel addresses via wchan
So the /proc/PID/stat 'wchan' field (the 30th field, which contains
the absolute kernel address of the kernel function a task is blocked in)
leaks absolute kernel addresses to unprivileged user-space:
seq_put_decimal_ull(m, ' ', wchan);
The absolute address might also leak via /proc/PID/wchan as well, if
KALLSYMS is turned off or if the symbol lookup fails for some reason:
static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task)
{
unsigned long wchan;
char symname[KSYM_NAME_LEN];
wchan = get_wchan(task);
if (lookup_symbol_name(wchan, symname) < 0) {
if (!ptrace_may_access(task, PTRACE_MODE_READ))
return 0;
seq_printf(m, "%lu", wchan);
} else {
seq_printf(m, "%s", symname);
}
return 0;
}
This isn't ideal, because for example it trivially leaks the KASLR offset
to any local attacker:
fomalhaut:~> printf "%016lx\n" $(cat /proc/$$/stat | cut -d' ' -f35)
ffffffff8123b380
Most real-life uses of wchan are symbolic:
ps -eo pid:10,tid:10,wchan:30,comm
and procps uses /proc/PID/wchan, not the absolute address in /proc/PID/stat:
triton:~/tip> strace -f ps -eo pid:10,tid:10,wchan:30,comm 2>&1 | grep wchan | tail -1
open("/proc/30833/wchan", O_RDONLY) = 6
There's one compatibility quirk here: procps relies on whether the
absolute value is non-zero - and we can provide that functionality
by outputing "0" or "1" depending on whether the task is blocked
(whether there's a wchan address).
These days there appears to be very little legitimate reason
user-space would be interested in the absolute address. The
absolute address is mostly historic: from the days when we
didn't have kallsyms and user-space procps had to do the
decoding itself via the System.map.
So this patch sets all numeric output to "0" or "1" and keeps only
symbolic output, in /proc/PID/wchan.
( The absolute sleep address can generally still be profiled via
perf, by tasks with sufficient privileges. )
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Kees Cook <keescook@chromium.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Cc: <stable@vger.kernel.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Alexander Potapenko <glider@google.com>
Cc: Andrey Konovalov <andreyknvl@google.com>
Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Kostya Serebryany <kcc@google.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: kasan-dev <kasan-dev@googlegroups.com>
Cc: linux-kernel@vger.kernel.org
Link: http://lkml.kernel.org/r/20150930135917.GA3285@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-09-30 21:59:17 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We used to output the absolute kernel address, but that's an
|
|
|
|
* information leak - so instead we show a 0/1 flag here, to signal
|
|
|
|
* to user-space whether there's a wchan field in /proc/PID/wchan.
|
|
|
|
*
|
|
|
|
* This works with older implementations of procps as well.
|
|
|
|
*/
|
|
|
|
if (wchan)
|
|
|
|
seq_puts(m, " 1");
|
|
|
|
else
|
|
|
|
seq_puts(m, " 0");
|
|
|
|
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ull(m, " ", 0);
|
|
|
|
seq_put_decimal_ull(m, " ", 0);
|
|
|
|
seq_put_decimal_ll(m, " ", task->exit_signal);
|
|
|
|
seq_put_decimal_ll(m, " ", task_cpu(task));
|
|
|
|
seq_put_decimal_ull(m, " ", task->rt_priority);
|
|
|
|
seq_put_decimal_ull(m, " ", task->policy);
|
|
|
|
seq_put_decimal_ull(m, " ", delayacct_blkio_ticks(task));
|
2017-01-31 11:09:21 +08:00
|
|
|
seq_put_decimal_ull(m, " ", nsec_to_clock_t(gtime));
|
|
|
|
seq_put_decimal_ll(m, " ", nsec_to_clock_t(cgtime));
|
2012-06-01 07:26:44 +08:00
|
|
|
|
|
|
|
if (mm && permitted) {
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ull(m, " ", mm->start_data);
|
|
|
|
seq_put_decimal_ull(m, " ", mm->end_data);
|
|
|
|
seq_put_decimal_ull(m, " ", mm->start_brk);
|
|
|
|
seq_put_decimal_ull(m, " ", mm->arg_start);
|
|
|
|
seq_put_decimal_ull(m, " ", mm->arg_end);
|
|
|
|
seq_put_decimal_ull(m, " ", mm->env_start);
|
|
|
|
seq_put_decimal_ull(m, " ", mm->env_end);
|
2012-06-01 07:26:44 +08:00
|
|
|
} else
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_puts(m, " 0 0 0 0 0 0 0");
|
2012-06-01 07:26:44 +08:00
|
|
|
|
|
|
|
if (permitted)
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ll(m, " ", task->exit_code);
|
2012-06-01 07:26:44 +08:00
|
|
|
else
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_puts(m, " 0");
|
2012-06-01 07:26:44 +08:00
|
|
|
|
2012-03-24 06:02:54 +08:00
|
|
|
seq_putc(m, '\n');
|
2007-07-16 15:46:31 +08:00
|
|
|
if (mm)
|
2005-04-17 06:20:36 +08:00
|
|
|
mmput(mm);
|
2008-02-08 20:18:31 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-02-08 20:18:31 +08:00
|
|
|
int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns,
|
|
|
|
struct pid *pid, struct task_struct *task)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-02-08 20:18:31 +08:00
|
|
|
return do_task_stat(m, ns, pid, task, 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-02-08 20:18:31 +08:00
|
|
|
int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns,
|
|
|
|
struct pid *pid, struct task_struct *task)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-02-08 20:18:31 +08:00
|
|
|
return do_task_stat(m, ns, pid, task, 1);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-02-08 20:18:32 +08:00
|
|
|
int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns,
|
|
|
|
struct pid *pid, struct task_struct *task)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2011-01-13 09:00:32 +08:00
|
|
|
unsigned long size = 0, resident = 0, shared = 0, text = 0, data = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct mm_struct *mm = get_task_mm(task);
|
2007-07-16 15:46:31 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (mm) {
|
|
|
|
size = task_statm(mm, &shared, &text, &data, &resident);
|
|
|
|
mmput(mm);
|
|
|
|
}
|
2012-03-24 06:02:54 +08:00
|
|
|
/*
|
|
|
|
* For quick read, open code by putting numbers directly
|
|
|
|
* expected format is
|
|
|
|
* seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n",
|
|
|
|
* size, resident, shared, text, data);
|
|
|
|
*/
|
2016-10-08 08:02:20 +08:00
|
|
|
seq_put_decimal_ull(m, "", size);
|
|
|
|
seq_put_decimal_ull(m, " ", resident);
|
|
|
|
seq_put_decimal_ull(m, " ", shared);
|
|
|
|
seq_put_decimal_ull(m, " ", text);
|
|
|
|
seq_put_decimal_ull(m, " ", 0);
|
|
|
|
seq_put_decimal_ull(m, " ", data);
|
|
|
|
seq_put_decimal_ull(m, " ", 0);
|
2012-03-24 06:02:54 +08:00
|
|
|
seq_putc(m, '\n');
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-02-08 20:18:32 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2012-06-01 07:26:43 +08:00
|
|
|
|
2015-06-26 06:00:57 +08:00
|
|
|
#ifdef CONFIG_PROC_CHILDREN
|
2012-06-01 07:26:43 +08:00
|
|
|
static struct pid *
|
|
|
|
get_children_pid(struct inode *inode, struct pid *pid_prev, loff_t pos)
|
|
|
|
{
|
|
|
|
struct task_struct *start, *task;
|
|
|
|
struct pid *pid = NULL;
|
|
|
|
|
|
|
|
read_lock(&tasklist_lock);
|
|
|
|
|
|
|
|
start = pid_task(proc_pid(inode), PIDTYPE_PID);
|
|
|
|
if (!start)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lets try to continue searching first, this gives
|
|
|
|
* us significant speedup on children-rich processes.
|
|
|
|
*/
|
|
|
|
if (pid_prev) {
|
|
|
|
task = pid_task(pid_prev, PIDTYPE_PID);
|
|
|
|
if (task && task->real_parent == start &&
|
|
|
|
!(list_empty(&task->sibling))) {
|
|
|
|
if (list_is_last(&task->sibling, &start->children))
|
|
|
|
goto out;
|
|
|
|
task = list_first_entry(&task->sibling,
|
|
|
|
struct task_struct, sibling);
|
|
|
|
pid = get_pid(task_pid(task));
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Slow search case.
|
|
|
|
*
|
|
|
|
* We might miss some children here if children
|
|
|
|
* are exited while we were not holding the lock,
|
|
|
|
* but it was never promised to be accurate that
|
|
|
|
* much.
|
|
|
|
*
|
|
|
|
* "Just suppose that the parent sleeps, but N children
|
|
|
|
* exit after we printed their tids. Now the slow paths
|
|
|
|
* skips N extra children, we miss N tasks." (c)
|
|
|
|
*
|
|
|
|
* So one need to stop or freeze the leader and all
|
|
|
|
* its children to get a precise result.
|
|
|
|
*/
|
|
|
|
list_for_each_entry(task, &start->children, sibling) {
|
|
|
|
if (pos-- == 0) {
|
|
|
|
pid = get_pid(task_pid(task));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
read_unlock(&tasklist_lock);
|
|
|
|
return pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int children_seq_show(struct seq_file *seq, void *v)
|
|
|
|
{
|
2018-05-16 13:21:53 +08:00
|
|
|
struct inode *inode = file_inode(seq->file);
|
2015-04-16 07:18:17 +08:00
|
|
|
|
2018-05-16 13:21:53 +08:00
|
|
|
seq_printf(seq, "%d ", pid_nr_ns(v, proc_pid_ns(inode)));
|
2015-04-16 07:18:17 +08:00
|
|
|
return 0;
|
2012-06-01 07:26:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void *children_seq_start(struct seq_file *seq, loff_t *pos)
|
|
|
|
{
|
2018-05-16 13:21:53 +08:00
|
|
|
return get_children_pid(file_inode(seq->file), NULL, *pos);
|
2012-06-01 07:26:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void *children_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
|
|
|
{
|
|
|
|
struct pid *pid;
|
|
|
|
|
2018-05-16 13:21:53 +08:00
|
|
|
pid = get_children_pid(file_inode(seq->file), v, *pos + 1);
|
2012-06-01 07:26:43 +08:00
|
|
|
put_pid(v);
|
|
|
|
|
|
|
|
++*pos;
|
|
|
|
return pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void children_seq_stop(struct seq_file *seq, void *v)
|
|
|
|
{
|
|
|
|
put_pid(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct seq_operations children_seq_ops = {
|
|
|
|
.start = children_seq_start,
|
|
|
|
.next = children_seq_next,
|
|
|
|
.stop = children_seq_stop,
|
|
|
|
.show = children_seq_show,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int children_seq_open(struct inode *inode, struct file *file)
|
|
|
|
{
|
2018-05-16 13:21:53 +08:00
|
|
|
return seq_open(file, &children_seq_ops);
|
2012-06-01 07:26:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const struct file_operations proc_tid_children_operations = {
|
|
|
|
.open = children_seq_open,
|
|
|
|
.read = seq_read,
|
|
|
|
.llseek = seq_lseek,
|
2018-02-07 07:37:10 +08:00
|
|
|
.release = seq_release,
|
2012-06-01 07:26:43 +08:00
|
|
|
};
|
2015-06-26 06:00:57 +08:00
|
|
|
#endif /* CONFIG_PROC_CHILDREN */
|