blob: a83d4cbd8f216ee706865abac67ec1ab0f474d56 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/fs/proc/base.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * proc base directory handling functions
7 *
8 * 1999, Al Viro. Rewritten. Now it covers the whole per-process part.
9 * Instead of using magical inumbers to determine the kind of object
10 * we allocate and fill in-core inodes upon lookup. They don't even
11 * go into icache. We cache the reference to task_struct upon lookup too.
12 * Eventually it should become a filesystem in its own. We don't use the
13 * rest of procfs anymore.
Mauricio Line070ad42005-09-03 15:55:10 -070014 *
15 *
16 * Changelog:
17 * 17-Jan-2005
18 * Allan Bezerra
19 * Bruna Moreira <bruna.moreira@indt.org.br>
20 * Edjard Mota <edjard.mota@indt.org.br>
21 * Ilias Biris <ilias.biris@indt.org.br>
22 * Mauricio Lin <mauricio.lin@indt.org.br>
23 *
24 * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
25 *
26 * A new process specific entry (smaps) included in /proc. It shows the
27 * size of rss for each memory area. The maps entry lacks information
28 * about physical memory size (rss) for each mapped file, i.e.,
29 * rss information for executables and library files.
30 * This additional information is useful for any tools that need to know
31 * about physical memory consumption for a process specific library.
32 *
33 * Changelog:
34 * 21-Feb-2005
35 * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
36 * Pud inclusion in the page table walking.
37 *
38 * ChangeLog:
39 * 10-Mar-2005
40 * 10LE Instituto Nokia de Tecnologia - INdT:
41 * A better way to walks through the page table as suggested by Hugh Dickins.
42 *
43 * Simo Piiroinen <simo.piiroinen@nokia.com>:
44 * Smaps information related to shared, private, clean and dirty pages.
45 *
46 * Paul Mundt <paul.mundt@nokia.com>:
47 * Overall revision about smaps.
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 */
49
50#include <asm/uaccess.h>
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <linux/errno.h>
53#include <linux/time.h>
54#include <linux/proc_fs.h>
55#include <linux/stat.h>
Andrea Righi59954772008-07-27 17:29:15 +020056#include <linux/task_io_accounting_ops.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <linux/init.h>
Randy Dunlap16f7e0f2006-01-11 12:17:46 -080058#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <linux/file.h>
Al Viro9f3acc32008-04-24 07:44:08 -040060#include <linux/fdtable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <linux/string.h>
62#include <linux/seq_file.h>
63#include <linux/namei.h>
Kirill Korotaev6b3286e2006-12-08 02:37:56 -080064#include <linux/mnt_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#include <linux/mm.h>
David Rientjesa63d83f2010-08-09 17:19:46 -070066#include <linux/swap.h>
Dipankar Sarmab8359962005-09-09 13:04:14 -070067#include <linux/rcupdate.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#include <linux/kallsyms.h>
Ken Chen2ec220e2008-11-10 11:26:08 +030069#include <linux/stacktrace.h>
Neil Hormand85f50d2007-10-18 23:40:37 -070070#include <linux/resource.h>
Kees Cook5096add2007-05-08 00:26:04 -070071#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070072#include <linux/mount.h>
73#include <linux/security.h>
74#include <linux/ptrace.h>
Roland McGrath0d094ef2008-07-25 19:45:49 -070075#include <linux/tracehook.h>
Paul Menagea4243162007-10-18 23:39:35 -070076#include <linux/cgroup.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070077#include <linux/cpuset.h>
78#include <linux/audit.h>
Al Viro5addc5d2005-11-07 17:15:49 -050079#include <linux/poll.h>
Serge E. Hallyn1651e142006-10-02 02:18:08 -070080#include <linux/nsproxy.h>
Alexey Dobriyan8ac773b2006-10-19 23:28:32 -070081#include <linux/oom.h>
Kawai, Hidehiro3cb4a0b2007-07-19 01:48:28 -070082#include <linux/elf.h>
Pavel Emelyanov60347f62007-10-18 23:40:03 -070083#include <linux/pid_namespace.h>
Al Viro5ad4e532009-03-29 19:50:06 -040084#include <linux/fs_struct.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090085#include <linux/slab.h>
Chris Metcalff133ecc2011-05-26 12:40:09 -040086#ifdef CONFIG_HARDWALL
87#include <asm/hardwall.h>
88#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#include "internal.h"
90
Eric W. Biederman0f2fe202006-06-26 00:25:46 -070091/* NOTE:
92 * Implementing inode permission operations in /proc is almost
93 * certainly an error. Permission checks need to happen during
94 * each system call not at open time. The reason is that most of
95 * what we wish to check for permissions in /proc varies at runtime.
96 *
97 * The classic example of a problem is opening file descriptors
98 * in /proc for a task before it execs a suid executable.
99 */
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101struct pid_entry {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 char *name;
Eric Dumazetc5141e62007-05-08 00:26:15 -0700103 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 mode_t mode;
Arjan van de Venc5ef1c42007-02-12 00:55:40 -0800105 const struct inode_operations *iop;
Arjan van de Ven00977a52007-02-12 00:55:34 -0800106 const struct file_operations *fop;
Eric W. Biederman20cdc892006-10-02 02:17:07 -0700107 union proc_op op;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
Eric W. Biederman61a28782006-10-02 02:18:49 -0700110#define NOD(NAME, MODE, IOP, FOP, OP) { \
Eric W. Biederman20cdc892006-10-02 02:17:07 -0700111 .name = (NAME), \
Eric Dumazetc5141e62007-05-08 00:26:15 -0700112 .len = sizeof(NAME) - 1, \
Eric W. Biederman20cdc892006-10-02 02:17:07 -0700113 .mode = MODE, \
114 .iop = IOP, \
115 .fop = FOP, \
116 .op = OP, \
117}
118
Alexey Dobriyan631f9c12008-11-10 01:32:52 +0300119#define DIR(NAME, MODE, iops, fops) \
120 NOD(NAME, (S_IFDIR|(MODE)), &iops, &fops, {} )
121#define LNK(NAME, get_link) \
Eric W. Biederman61a28782006-10-02 02:18:49 -0700122 NOD(NAME, (S_IFLNK|S_IRWXUGO), \
Eric W. Biederman20cdc892006-10-02 02:17:07 -0700123 &proc_pid_link_inode_operations, NULL, \
Alexey Dobriyan631f9c12008-11-10 01:32:52 +0300124 { .proc_get_link = get_link } )
125#define REG(NAME, MODE, fops) \
126 NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {})
127#define INF(NAME, MODE, read) \
Eric W. Biederman61a28782006-10-02 02:18:49 -0700128 NOD(NAME, (S_IFREG|(MODE)), \
Eric W. Biederman20cdc892006-10-02 02:17:07 -0700129 NULL, &proc_info_file_operations, \
Alexey Dobriyan631f9c12008-11-10 01:32:52 +0300130 { .proc_read = read } )
131#define ONE(NAME, MODE, show) \
Eric W. Biedermanbe614082008-02-08 04:18:30 -0800132 NOD(NAME, (S_IFREG|(MODE)), \
133 NULL, &proc_single_file_operations, \
Alexey Dobriyan631f9c12008-11-10 01:32:52 +0300134 { .proc_show = show } )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
Mike Chan766e9932008-04-24 10:22:26 -0700136/* ANDROID is for special files in /proc. */
137#define ANDROID(NAME, MODE, OTYPE) \
138 NOD(NAME, (S_IFREG|(MODE)), \
139 &proc_##OTYPE##_inode_operations, \
140 &proc_##OTYPE##_operations, {})
141
Vegard Nossumaed54172008-06-05 22:46:53 -0700142/*
143 * Count the number of hardlinks for the pid_entry table, excluding the .
144 * and .. links.
145 */
146static unsigned int pid_entry_count_dirs(const struct pid_entry *entries,
147 unsigned int n)
148{
149 unsigned int i;
150 unsigned int count;
151
152 count = 0;
153 for (i = 0; i < n; ++i) {
154 if (S_ISDIR(entries[i].mode))
155 ++count;
156 }
157
158 return count;
159}
160
Miklos Szeredif7ad3c62010-08-10 11:41:36 +0200161static int get_task_root(struct task_struct *task, struct path *root)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162{
Hugh Dickins7c2c7d92009-03-28 23:21:27 +0000163 int result = -ENOENT;
164
Miklos Szeredi0494f6e2005-09-06 15:18:22 -0700165 task_lock(task);
Miklos Szeredif7ad3c62010-08-10 11:41:36 +0200166 if (task->fs) {
167 get_fs_root(task->fs, root);
Hugh Dickins7c2c7d92009-03-28 23:21:27 +0000168 result = 0;
169 }
Miklos Szeredi0494f6e2005-09-06 15:18:22 -0700170 task_unlock(task);
Hugh Dickins7c2c7d92009-03-28 23:21:27 +0000171 return result;
Miklos Szeredi0494f6e2005-09-06 15:18:22 -0700172}
173
Jan Blunck3dcd25f2008-02-14 19:38:35 -0800174static int proc_cwd_link(struct inode *inode, struct path *path)
Miklos Szeredi0494f6e2005-09-06 15:18:22 -0700175{
Eric W. Biederman99f89552006-06-26 00:25:55 -0700176 struct task_struct *task = get_proc_task(inode);
Miklos Szeredi0494f6e2005-09-06 15:18:22 -0700177 int result = -ENOENT;
Eric W. Biederman99f89552006-06-26 00:25:55 -0700178
179 if (task) {
Miklos Szeredif7ad3c62010-08-10 11:41:36 +0200180 task_lock(task);
181 if (task->fs) {
182 get_fs_pwd(task->fs, path);
183 result = 0;
184 }
185 task_unlock(task);
Eric W. Biederman99f89552006-06-26 00:25:55 -0700186 put_task_struct(task);
187 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 return result;
189}
190
Jan Blunck3dcd25f2008-02-14 19:38:35 -0800191static int proc_root_link(struct inode *inode, struct path *path)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192{
Eric W. Biederman99f89552006-06-26 00:25:55 -0700193 struct task_struct *task = get_proc_task(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 int result = -ENOENT;
Eric W. Biederman99f89552006-06-26 00:25:55 -0700195
196 if (task) {
Miklos Szeredif7ad3c62010-08-10 11:41:36 +0200197 result = get_task_root(task, path);
Eric W. Biederman99f89552006-06-26 00:25:55 -0700198 put_task_struct(task);
199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 return result;
201}
202
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400203static struct mm_struct *__check_mem_permission(struct task_struct *task)
Roland McGrath638fa202008-04-29 01:01:38 -0700204{
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400205 struct mm_struct *mm;
206
207 mm = get_task_mm(task);
208 if (!mm)
209 return ERR_PTR(-EINVAL);
210
Roland McGrath638fa202008-04-29 01:01:38 -0700211 /*
212 * A task can always look at itself, in case it chooses
213 * to use system calls instead of load instructions.
214 */
215 if (task == current)
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400216 return mm;
Roland McGrath638fa202008-04-29 01:01:38 -0700217
218 /*
219 * If current is actively ptrace'ing, and would also be
220 * permitted to freshly attach with ptrace now, permit it.
221 */
Roland McGrath0d094ef2008-07-25 19:45:49 -0700222 if (task_is_stopped_or_traced(task)) {
223 int match;
224 rcu_read_lock();
225 match = (tracehook_tracer_task(task) == current);
226 rcu_read_unlock();
227 if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH))
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400228 return mm;
Roland McGrath0d094ef2008-07-25 19:45:49 -0700229 }
Roland McGrath638fa202008-04-29 01:01:38 -0700230
231 /*
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300232 * No one else is allowed.
Roland McGrath638fa202008-04-29 01:01:38 -0700233 */
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400234 mmput(mm);
235 return ERR_PTR(-EPERM);
Roland McGrath638fa202008-04-29 01:01:38 -0700236}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Stephen Wilson18f661b2011-03-13 15:49:22 -0400238/*
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400239 * If current may access user memory in @task return a reference to the
240 * corresponding mm, otherwise ERR_PTR.
Stephen Wilson18f661b2011-03-13 15:49:22 -0400241 */
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400242static struct mm_struct *check_mem_permission(struct task_struct *task)
Stephen Wilson18f661b2011-03-13 15:49:22 -0400243{
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400244 struct mm_struct *mm;
Stephen Wilson18f661b2011-03-13 15:49:22 -0400245 int err;
246
247 /*
248 * Avoid racing if task exec's as we might get a new mm but validate
249 * against old credentials.
250 */
251 err = mutex_lock_killable(&task->signal->cred_guard_mutex);
252 if (err)
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400253 return ERR_PTR(err);
Stephen Wilson18f661b2011-03-13 15:49:22 -0400254
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400255 mm = __check_mem_permission(task);
Stephen Wilson18f661b2011-03-13 15:49:22 -0400256 mutex_unlock(&task->signal->cred_guard_mutex);
257
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400258 return mm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259}
260
Al Viro831830b2008-01-02 14:09:57 +0000261struct mm_struct *mm_for_maps(struct task_struct *task)
262{
Oleg Nesterov704b8362009-07-10 03:27:40 +0200263 struct mm_struct *mm;
Al Viroec6fd8a2011-02-15 22:22:54 -0500264 int err;
Oleg Nesterov00f89d22009-07-10 03:27:38 +0200265
Al Viroec6fd8a2011-02-15 22:22:54 -0500266 err = mutex_lock_killable(&task->signal->cred_guard_mutex);
267 if (err)
268 return ERR_PTR(err);
Oleg Nesterov704b8362009-07-10 03:27:40 +0200269
270 mm = get_task_mm(task);
271 if (mm && mm != current->mm &&
272 !ptrace_may_access(task, PTRACE_MODE_READ)) {
273 mmput(mm);
Al Viroec6fd8a2011-02-15 22:22:54 -0500274 mm = ERR_PTR(-EACCES);
Oleg Nesterov13f0fea2009-06-23 21:25:32 +0200275 }
KOSAKI Motohiro9b1bf122010-10-27 15:34:08 -0700276 mutex_unlock(&task->signal->cred_guard_mutex);
Oleg Nesterov704b8362009-07-10 03:27:40 +0200277
Al Viro831830b2008-01-02 14:09:57 +0000278 return mm;
Al Viro831830b2008-01-02 14:09:57 +0000279}
280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281static int proc_pid_cmdline(struct task_struct *task, char * buffer)
282{
283 int res = 0;
284 unsigned int len;
285 struct mm_struct *mm = get_task_mm(task);
286 if (!mm)
287 goto out;
288 if (!mm->arg_end)
289 goto out_mm; /* Shh! No looking before we're done */
290
291 len = mm->arg_end - mm->arg_start;
292
293 if (len > PAGE_SIZE)
294 len = PAGE_SIZE;
295
296 res = access_process_vm(task, mm->arg_start, buffer, len, 0);
297
298 // If the nul at the end of args has been overwritten, then
299 // assume application is using setproctitle(3).
300 if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) {
301 len = strnlen(buffer, res);
302 if (len < res) {
303 res = len;
304 } else {
305 len = mm->env_end - mm->env_start;
306 if (len > PAGE_SIZE - res)
307 len = PAGE_SIZE - res;
308 res += access_process_vm(task, mm->env_start, buffer+res, len, 0);
309 res = strnlen(buffer, res);
310 }
311 }
312out_mm:
313 mmput(mm);
314out:
315 return res;
316}
317
318static int proc_pid_auxv(struct task_struct *task, char *buffer)
319{
Al Viro2fadaef2011-02-15 22:52:11 -0500320 struct mm_struct *mm = mm_for_maps(task);
321 int res = PTR_ERR(mm);
322 if (mm && !IS_ERR(mm)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 unsigned int nwords = 0;
Hannes Ederdfe6b7d2008-12-30 18:49:13 +0300324 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 nwords += 2;
Hannes Ederdfe6b7d2008-12-30 18:49:13 +0300326 } while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 res = nwords * sizeof(mm->saved_auxv[0]);
328 if (res > PAGE_SIZE)
329 res = PAGE_SIZE;
330 memcpy(buffer, mm->saved_auxv, res);
331 mmput(mm);
332 }
333 return res;
334}
335
336
337#ifdef CONFIG_KALLSYMS
338/*
339 * Provides a wchan file via kallsyms in a proper one-value-per-file format.
340 * Returns the resolved symbol. If that fails, simply return the address.
341 */
342static int proc_pid_wchan(struct task_struct *task, char *buffer)
343{
Alexey Dobriyanffb45122007-05-08 00:28:41 -0700344 unsigned long wchan;
Tejun Heo9281ace2007-07-17 04:03:51 -0700345 char symname[KSYM_NAME_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347 wchan = get_wchan(task);
348
Alexey Dobriyan9d65cb42007-05-08 00:28:43 -0700349 if (lookup_symbol_name(wchan, symname) < 0)
Jake Edgef83ce3e2009-05-04 12:51:14 -0600350 if (!ptrace_may_access(task, PTRACE_MODE_READ))
351 return 0;
352 else
353 return sprintf(buffer, "%lu", wchan);
Alexey Dobriyan9d65cb42007-05-08 00:28:43 -0700354 else
355 return sprintf(buffer, "%s", symname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356}
357#endif /* CONFIG_KALLSYMS */
358
Al Viroa9712bc2011-03-23 15:52:50 -0400359static int lock_trace(struct task_struct *task)
360{
361 int err = mutex_lock_killable(&task->signal->cred_guard_mutex);
362 if (err)
363 return err;
364 if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) {
365 mutex_unlock(&task->signal->cred_guard_mutex);
366 return -EPERM;
367 }
368 return 0;
369}
370
371static void unlock_trace(struct task_struct *task)
372{
373 mutex_unlock(&task->signal->cred_guard_mutex);
374}
375
Ken Chen2ec220e2008-11-10 11:26:08 +0300376#ifdef CONFIG_STACKTRACE
377
378#define MAX_STACK_TRACE_DEPTH 64
379
380static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns,
381 struct pid *pid, struct task_struct *task)
382{
383 struct stack_trace trace;
384 unsigned long *entries;
Al Viroa9712bc2011-03-23 15:52:50 -0400385 int err;
Ken Chen2ec220e2008-11-10 11:26:08 +0300386 int i;
387
388 entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL);
389 if (!entries)
390 return -ENOMEM;
391
392 trace.nr_entries = 0;
393 trace.max_entries = MAX_STACK_TRACE_DEPTH;
394 trace.entries = entries;
395 trace.skip = 0;
Ken Chen2ec220e2008-11-10 11:26:08 +0300396
Al Viroa9712bc2011-03-23 15:52:50 -0400397 err = lock_trace(task);
398 if (!err) {
399 save_stack_trace_tsk(task, &trace);
400
401 for (i = 0; i < trace.nr_entries; i++) {
Linus Torvaldsb81a6182011-03-23 20:51:42 -0700402 seq_printf(m, "[<%pK>] %pS\n",
Al Viroa9712bc2011-03-23 15:52:50 -0400403 (void *)entries[i], (void *)entries[i]);
404 }
405 unlock_trace(task);
Ken Chen2ec220e2008-11-10 11:26:08 +0300406 }
407 kfree(entries);
408
Al Viroa9712bc2011-03-23 15:52:50 -0400409 return err;
Ken Chen2ec220e2008-11-10 11:26:08 +0300410}
411#endif
412
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413#ifdef CONFIG_SCHEDSTATS
414/*
415 * Provides /proc/PID/schedstat
416 */
417static int proc_pid_schedstat(struct task_struct *task, char *buffer)
418{
Balbir Singh172ba842007-07-09 18:52:00 +0200419 return sprintf(buffer, "%llu %llu %lu\n",
Ingo Molnar826e08b2008-12-22 07:37:41 +0100420 (unsigned long long)task->se.sum_exec_runtime,
421 (unsigned long long)task->sched_info.run_delay,
Ingo Molnar2d723762007-10-15 17:00:12 +0200422 task->sched_info.pcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423}
424#endif
425
Arjan van de Ven97455122008-01-25 21:08:34 +0100426#ifdef CONFIG_LATENCYTOP
427static int lstats_show_proc(struct seq_file *m, void *v)
428{
429 int i;
Hiroshi Shimamoto13d77c32008-02-20 16:53:29 -0800430 struct inode *inode = m->private;
431 struct task_struct *task = get_proc_task(inode);
Arjan van de Ven97455122008-01-25 21:08:34 +0100432
Hiroshi Shimamoto13d77c32008-02-20 16:53:29 -0800433 if (!task)
434 return -ESRCH;
435 seq_puts(m, "Latency Top version : v0.1\n");
Arjan van de Ven97455122008-01-25 21:08:34 +0100436 for (i = 0; i < 32; i++) {
Joe Perches34e49d42011-01-12 17:00:30 -0800437 struct latency_record *lr = &task->latency_record[i];
438 if (lr->backtrace[0]) {
Arjan van de Ven97455122008-01-25 21:08:34 +0100439 int q;
Joe Perches34e49d42011-01-12 17:00:30 -0800440 seq_printf(m, "%i %li %li",
441 lr->count, lr->time, lr->max);
Arjan van de Ven97455122008-01-25 21:08:34 +0100442 for (q = 0; q < LT_BACKTRACEDEPTH; q++) {
Joe Perches34e49d42011-01-12 17:00:30 -0800443 unsigned long bt = lr->backtrace[q];
444 if (!bt)
Arjan van de Ven97455122008-01-25 21:08:34 +0100445 break;
Joe Perches34e49d42011-01-12 17:00:30 -0800446 if (bt == ULONG_MAX)
Arjan van de Ven97455122008-01-25 21:08:34 +0100447 break;
Joe Perches34e49d42011-01-12 17:00:30 -0800448 seq_printf(m, " %ps", (void *)bt);
Arjan van de Ven97455122008-01-25 21:08:34 +0100449 }
Alexey Dobriyan9d6de122011-01-12 17:00:32 -0800450 seq_putc(m, '\n');
Arjan van de Ven97455122008-01-25 21:08:34 +0100451 }
452
453 }
Hiroshi Shimamoto13d77c32008-02-20 16:53:29 -0800454 put_task_struct(task);
Arjan van de Ven97455122008-01-25 21:08:34 +0100455 return 0;
456}
457
458static int lstats_open(struct inode *inode, struct file *file)
459{
Hiroshi Shimamoto13d77c32008-02-20 16:53:29 -0800460 return single_open(file, lstats_show_proc, inode);
Hiroshi Shimamotod6643d12008-02-14 10:27:00 -0800461}
462
Arjan van de Ven97455122008-01-25 21:08:34 +0100463static ssize_t lstats_write(struct file *file, const char __user *buf,
464 size_t count, loff_t *offs)
465{
Hiroshi Shimamoto13d77c32008-02-20 16:53:29 -0800466 struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
Arjan van de Ven97455122008-01-25 21:08:34 +0100467
Hiroshi Shimamoto13d77c32008-02-20 16:53:29 -0800468 if (!task)
469 return -ESRCH;
Arjan van de Ven97455122008-01-25 21:08:34 +0100470 clear_all_latency_tracing(task);
Hiroshi Shimamoto13d77c32008-02-20 16:53:29 -0800471 put_task_struct(task);
Arjan van de Ven97455122008-01-25 21:08:34 +0100472
473 return count;
474}
475
476static const struct file_operations proc_lstats_operations = {
477 .open = lstats_open,
478 .read = seq_read,
479 .write = lstats_write,
480 .llseek = seq_lseek,
Hiroshi Shimamoto13d77c32008-02-20 16:53:29 -0800481 .release = single_release,
Arjan van de Ven97455122008-01-25 21:08:34 +0100482};
483
484#endif
485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486static int proc_oom_score(struct task_struct *task, char *buffer)
487{
Oleg Nesterovb95c35e2010-04-01 15:13:57 +0200488 unsigned long points = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Alexey Dobriyan19c5d452007-05-08 00:26:46 -0700490 read_lock(&tasklist_lock);
Oleg Nesterovb95c35e2010-04-01 15:13:57 +0200491 if (pid_alive(task))
David Rientjesa63d83f2010-08-09 17:19:46 -0700492 points = oom_badness(task, NULL, NULL,
493 totalram_pages + total_swap_pages);
Alexey Dobriyan19c5d452007-05-08 00:26:46 -0700494 read_unlock(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 return sprintf(buffer, "%lu\n", points);
496}
497
Neil Hormand85f50d2007-10-18 23:40:37 -0700498struct limit_names {
499 char *name;
500 char *unit;
501};
502
503static const struct limit_names lnames[RLIM_NLIMITS] = {
Kees Cookcff4edb2009-09-22 16:45:32 -0700504 [RLIMIT_CPU] = {"Max cpu time", "seconds"},
Neil Hormand85f50d2007-10-18 23:40:37 -0700505 [RLIMIT_FSIZE] = {"Max file size", "bytes"},
506 [RLIMIT_DATA] = {"Max data size", "bytes"},
507 [RLIMIT_STACK] = {"Max stack size", "bytes"},
508 [RLIMIT_CORE] = {"Max core file size", "bytes"},
509 [RLIMIT_RSS] = {"Max resident set", "bytes"},
510 [RLIMIT_NPROC] = {"Max processes", "processes"},
511 [RLIMIT_NOFILE] = {"Max open files", "files"},
512 [RLIMIT_MEMLOCK] = {"Max locked memory", "bytes"},
513 [RLIMIT_AS] = {"Max address space", "bytes"},
514 [RLIMIT_LOCKS] = {"Max file locks", "locks"},
515 [RLIMIT_SIGPENDING] = {"Max pending signals", "signals"},
516 [RLIMIT_MSGQUEUE] = {"Max msgqueue size", "bytes"},
517 [RLIMIT_NICE] = {"Max nice priority", NULL},
518 [RLIMIT_RTPRIO] = {"Max realtime priority", NULL},
Eugene Teo88081172008-02-23 15:23:52 -0800519 [RLIMIT_RTTIME] = {"Max realtime timeout", "us"},
Neil Hormand85f50d2007-10-18 23:40:37 -0700520};
521
522/* Display limits for a process */
523static int proc_pid_limits(struct task_struct *task, char *buffer)
524{
525 unsigned int i;
526 int count = 0;
527 unsigned long flags;
528 char *bufptr = buffer;
529
530 struct rlimit rlim[RLIM_NLIMITS];
531
Lai Jiangshana6bebbc2008-10-05 00:51:15 +0400532 if (!lock_task_sighand(task, &flags))
Neil Hormand85f50d2007-10-18 23:40:37 -0700533 return 0;
Neil Hormand85f50d2007-10-18 23:40:37 -0700534 memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS);
535 unlock_task_sighand(task, &flags);
Neil Hormand85f50d2007-10-18 23:40:37 -0700536
537 /*
538 * print the file header
539 */
540 count += sprintf(&bufptr[count], "%-25s %-20s %-20s %-10s\n",
541 "Limit", "Soft Limit", "Hard Limit", "Units");
542
543 for (i = 0; i < RLIM_NLIMITS; i++) {
544 if (rlim[i].rlim_cur == RLIM_INFINITY)
545 count += sprintf(&bufptr[count], "%-25s %-20s ",
546 lnames[i].name, "unlimited");
547 else
548 count += sprintf(&bufptr[count], "%-25s %-20lu ",
549 lnames[i].name, rlim[i].rlim_cur);
550
551 if (rlim[i].rlim_max == RLIM_INFINITY)
552 count += sprintf(&bufptr[count], "%-20s ", "unlimited");
553 else
554 count += sprintf(&bufptr[count], "%-20lu ",
555 rlim[i].rlim_max);
556
557 if (lnames[i].unit)
558 count += sprintf(&bufptr[count], "%-10s\n",
559 lnames[i].unit);
560 else
561 count += sprintf(&bufptr[count], "\n");
562 }
563
564 return count;
565}
566
Roland McGrathebcb6732008-07-25 19:46:00 -0700567#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
568static int proc_pid_syscall(struct task_struct *task, char *buffer)
569{
570 long nr;
571 unsigned long args[6], sp, pc;
Al Viroa9712bc2011-03-23 15:52:50 -0400572 int res = lock_trace(task);
573 if (res)
574 return res;
Roland McGrathebcb6732008-07-25 19:46:00 -0700575
576 if (task_current_syscall(task, &nr, args, 6, &sp, &pc))
Al Viroa9712bc2011-03-23 15:52:50 -0400577 res = sprintf(buffer, "running\n");
578 else if (nr < 0)
579 res = sprintf(buffer, "%ld 0x%lx 0x%lx\n", nr, sp, pc);
580 else
581 res = sprintf(buffer,
Roland McGrathebcb6732008-07-25 19:46:00 -0700582 "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
583 nr,
584 args[0], args[1], args[2], args[3], args[4], args[5],
585 sp, pc);
Al Viroa9712bc2011-03-23 15:52:50 -0400586 unlock_trace(task);
587 return res;
Roland McGrathebcb6732008-07-25 19:46:00 -0700588}
589#endif /* CONFIG_HAVE_ARCH_TRACEHOOK */
590
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591/************************************************************************/
592/* Here the fs part begins */
593/************************************************************************/
594
595/* permission checks */
Eric W. Biederman778c1142006-06-26 00:25:58 -0700596static int proc_fd_access_allowed(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
Eric W. Biederman778c1142006-06-26 00:25:58 -0700598 struct task_struct *task;
599 int allowed = 0;
Eric W. Biedermandf26c402006-06-26 00:25:59 -0700600 /* Allow access to a task's file descriptors if it is us or we
601 * may use ptrace attach to the process and find out that
602 * information.
Eric W. Biederman778c1142006-06-26 00:25:58 -0700603 */
604 task = get_proc_task(inode);
Eric W. Biedermandf26c402006-06-26 00:25:59 -0700605 if (task) {
Stephen Smalley006ebb42008-05-19 08:32:49 -0400606 allowed = ptrace_may_access(task, PTRACE_MODE_READ);
Eric W. Biederman778c1142006-06-26 00:25:58 -0700607 put_task_struct(task);
Eric W. Biedermandf26c402006-06-26 00:25:59 -0700608 }
Eric W. Biederman778c1142006-06-26 00:25:58 -0700609 return allowed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610}
611
Eric W. Biederman6b4e3062010-03-07 16:41:34 -0800612int proc_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds6d76fa52006-07-15 12:26:45 -0700613{
614 int error;
615 struct inode *inode = dentry->d_inode;
616
617 if (attr->ia_valid & ATTR_MODE)
618 return -EPERM;
619
620 error = inode_change_ok(inode, attr);
Christoph Hellwig10257742010-06-04 11:30:02 +0200621 if (error)
622 return error;
623
624 if ((attr->ia_valid & ATTR_SIZE) &&
625 attr->ia_size != i_size_read(inode)) {
626 error = vmtruncate(inode, attr->ia_size);
627 if (error)
628 return error;
629 }
630
631 setattr_copy(inode, attr);
632 mark_inode_dirty(inode);
633 return 0;
Linus Torvalds6d76fa52006-07-15 12:26:45 -0700634}
635
Arjan van de Venc5ef1c42007-02-12 00:55:40 -0800636static const struct inode_operations proc_def_inode_operations = {
Linus Torvalds6d76fa52006-07-15 12:26:45 -0700637 .setattr = proc_setattr,
638};
639
Miklos Szeredia1a2c402008-03-27 13:06:24 +0100640static int mounts_open_common(struct inode *inode, struct file *file,
641 const struct seq_operations *op)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642{
Eric W. Biederman99f89552006-06-26 00:25:55 -0700643 struct task_struct *task = get_proc_task(inode);
Pavel Emelyanovcf7b7082007-10-18 23:39:54 -0700644 struct nsproxy *nsp;
Kirill Korotaev6b3286e2006-12-08 02:37:56 -0800645 struct mnt_namespace *ns = NULL;
Miklos Szeredia1a2c402008-03-27 13:06:24 +0100646 struct path root;
Al Viro5addc5d2005-11-07 17:15:49 -0500647 struct proc_mounts *p;
648 int ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Eric W. Biederman99f89552006-06-26 00:25:55 -0700650 if (task) {
Pavel Emelyanovcf7b7082007-10-18 23:39:54 -0700651 rcu_read_lock();
652 nsp = task_nsproxy(task);
653 if (nsp) {
654 ns = nsp->mnt_ns;
Alexey Dobriyan863c4702007-01-26 00:56:53 -0800655 if (ns)
656 get_mnt_ns(ns);
657 }
Pavel Emelyanovcf7b7082007-10-18 23:39:54 -0700658 rcu_read_unlock();
Miklos Szeredif7ad3c62010-08-10 11:41:36 +0200659 if (ns && get_task_root(task, &root) == 0)
Hugh Dickins7c2c7d92009-03-28 23:21:27 +0000660 ret = 0;
Eric W. Biederman99f89552006-06-26 00:25:55 -0700661 put_task_struct(task);
662 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
Miklos Szeredia1a2c402008-03-27 13:06:24 +0100664 if (!ns)
665 goto err;
Hugh Dickins7c2c7d92009-03-28 23:21:27 +0000666 if (ret)
Miklos Szeredia1a2c402008-03-27 13:06:24 +0100667 goto err_put_ns;
668
Miklos Szeredia1a2c402008-03-27 13:06:24 +0100669 ret = -ENOMEM;
670 p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
671 if (!p)
672 goto err_put_path;
673
674 file->private_data = &p->m;
675 ret = seq_open(file, op);
676 if (ret)
677 goto err_free;
678
679 p->m.private = p;
680 p->ns = ns;
681 p->root = root;
682 p->event = ns->event;
683
684 return 0;
685
686 err_free:
687 kfree(p);
688 err_put_path:
689 path_put(&root);
690 err_put_ns:
691 put_mnt_ns(ns);
692 err:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return ret;
694}
695
696static int mounts_release(struct inode *inode, struct file *file)
697{
Miklos Szeredia1a2c402008-03-27 13:06:24 +0100698 struct proc_mounts *p = file->private_data;
699 path_put(&p->root);
700 put_mnt_ns(p->ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 return seq_release(inode, file);
702}
703
Al Viro5addc5d2005-11-07 17:15:49 -0500704static unsigned mounts_poll(struct file *file, poll_table *wait)
705{
706 struct proc_mounts *p = file->private_data;
KOSAKI Motohiro31b07092009-04-09 13:57:59 +0900707 unsigned res = POLLIN | POLLRDNORM;
Al Viro5addc5d2005-11-07 17:15:49 -0500708
Al Viro9f5596a2010-02-05 00:40:25 -0500709 poll_wait(file, &p->ns->poll, wait);
710 if (mnt_had_events(p))
KOSAKI Motohiro31b07092009-04-09 13:57:59 +0900711 res |= POLLERR | POLLPRI;
Al Viro5addc5d2005-11-07 17:15:49 -0500712
713 return res;
714}
715
Miklos Szeredia1a2c402008-03-27 13:06:24 +0100716static int mounts_open(struct inode *inode, struct file *file)
717{
718 return mounts_open_common(inode, file, &mounts_op);
719}
720
Arjan van de Ven00977a52007-02-12 00:55:34 -0800721static const struct file_operations proc_mounts_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 .open = mounts_open,
723 .read = seq_read,
724 .llseek = seq_lseek,
725 .release = mounts_release,
Al Viro5addc5d2005-11-07 17:15:49 -0500726 .poll = mounts_poll,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727};
728
Ram Pai2d4d4862008-03-27 13:06:25 +0100729static int mountinfo_open(struct inode *inode, struct file *file)
730{
731 return mounts_open_common(inode, file, &mountinfo_op);
732}
733
734static const struct file_operations proc_mountinfo_operations = {
735 .open = mountinfo_open,
736 .read = seq_read,
737 .llseek = seq_lseek,
738 .release = mounts_release,
739 .poll = mounts_poll,
740};
741
Chuck Leverb4629fe2006-03-20 13:44:12 -0500742static int mountstats_open(struct inode *inode, struct file *file)
743{
Miklos Szeredia1a2c402008-03-27 13:06:24 +0100744 return mounts_open_common(inode, file, &mountstats_op);
Chuck Leverb4629fe2006-03-20 13:44:12 -0500745}
746
Arjan van de Ven00977a52007-02-12 00:55:34 -0800747static const struct file_operations proc_mountstats_operations = {
Chuck Leverb4629fe2006-03-20 13:44:12 -0500748 .open = mountstats_open,
749 .read = seq_read,
750 .llseek = seq_lseek,
751 .release = mounts_release,
752};
753
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
755
756static ssize_t proc_info_read(struct file * file, char __user * buf,
757 size_t count, loff_t *ppos)
758{
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -0800759 struct inode * inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 unsigned long page;
761 ssize_t length;
Eric W. Biederman99f89552006-06-26 00:25:55 -0700762 struct task_struct *task = get_proc_task(inode);
763
764 length = -ESRCH;
765 if (!task)
766 goto out_no_task;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768 if (count > PROC_BLOCK_SIZE)
769 count = PROC_BLOCK_SIZE;
Eric W. Biederman99f89552006-06-26 00:25:55 -0700770
771 length = -ENOMEM;
Mel Gormane12ba742007-10-16 01:25:52 -0700772 if (!(page = __get_free_page(GFP_TEMPORARY)))
Eric W. Biederman99f89552006-06-26 00:25:55 -0700773 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
775 length = PROC_I(inode)->op.proc_read(task, (char*)page);
776
777 if (length >= 0)
778 length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
779 free_page(page);
Eric W. Biederman99f89552006-06-26 00:25:55 -0700780out:
781 put_task_struct(task);
782out_no_task:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 return length;
784}
785
Arjan van de Ven00977a52007-02-12 00:55:34 -0800786static const struct file_operations proc_info_file_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 .read = proc_info_read,
Arnd Bergmann87df8422010-03-17 23:06:02 +0100788 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789};
790
Eric W. Biedermanbe614082008-02-08 04:18:30 -0800791static int proc_single_show(struct seq_file *m, void *v)
792{
793 struct inode *inode = m->private;
794 struct pid_namespace *ns;
795 struct pid *pid;
796 struct task_struct *task;
797 int ret;
798
799 ns = inode->i_sb->s_fs_info;
800 pid = proc_pid(inode);
801 task = get_pid_task(pid, PIDTYPE_PID);
802 if (!task)
803 return -ESRCH;
804
805 ret = PROC_I(inode)->op.proc_show(m, ns, pid, task);
806
807 put_task_struct(task);
808 return ret;
809}
810
811static int proc_single_open(struct inode *inode, struct file *filp)
812{
Jovi Zhangc6a34052011-01-12 17:00:34 -0800813 return single_open(filp, proc_single_show, inode);
Eric W. Biedermanbe614082008-02-08 04:18:30 -0800814}
815
816static const struct file_operations proc_single_file_operations = {
817 .open = proc_single_open,
818 .read = seq_read,
819 .llseek = seq_lseek,
820 .release = single_release,
821};
822
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823static int mem_open(struct inode* inode, struct file* file)
824{
825 file->private_data = (void*)((long)current->self_exec_id);
KAMEZAWA Hiroyuki4a3956c2010-10-01 14:20:22 -0700826 /* OK to pass negative loff_t, we can catch out-of-range */
827 file->f_mode |= FMODE_UNSIGNED_OFFSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 return 0;
829}
830
831static ssize_t mem_read(struct file * file, char __user * buf,
832 size_t count, loff_t *ppos)
833{
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -0800834 struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 char *page;
836 unsigned long src = *ppos;
837 int ret = -ESRCH;
838 struct mm_struct *mm;
839
Eric W. Biederman99f89552006-06-26 00:25:55 -0700840 if (!task)
841 goto out_no_task;
842
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 ret = -ENOMEM;
Mel Gormane12ba742007-10-16 01:25:52 -0700844 page = (char *)__get_free_page(GFP_TEMPORARY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 if (!page)
846 goto out;
847
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400848 mm = check_mem_permission(task);
849 ret = PTR_ERR(mm);
850 if (IS_ERR(mm))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 goto out_free;
852
853 ret = -EIO;
854
855 if (file->private_data != (void*)((long)current->self_exec_id))
856 goto out_put;
857
858 ret = 0;
859
860 while (count > 0) {
861 int this_len, retval;
862
863 this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400864 retval = access_remote_vm(mm, src, page, this_len, 0);
865 if (!retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 if (!ret)
867 ret = -EIO;
868 break;
869 }
870
871 if (copy_to_user(buf, page, retval)) {
872 ret = -EFAULT;
873 break;
874 }
875
876 ret += retval;
877 src += retval;
878 buf += retval;
879 count -= retval;
880 }
881 *ppos = src;
882
883out_put:
884 mmput(mm);
885out_free:
886 free_page((unsigned long) page);
887out:
Eric W. Biederman99f89552006-06-26 00:25:55 -0700888 put_task_struct(task);
889out_no_task:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 return ret;
891}
892
Glauber de Oliveira Costa63967fa2007-02-20 13:58:12 -0800893static ssize_t mem_write(struct file * file, const char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 size_t count, loff_t *ppos)
895{
Frederik Deweerdtf7ca54f2006-09-29 02:01:02 -0700896 int copied;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 char *page;
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -0800898 struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 unsigned long dst = *ppos;
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400900 struct mm_struct *mm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
Eric W. Biederman99f89552006-06-26 00:25:55 -0700902 copied = -ESRCH;
903 if (!task)
904 goto out_no_task;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
Eric W. Biederman99f89552006-06-26 00:25:55 -0700906 copied = -ENOMEM;
Mel Gormane12ba742007-10-16 01:25:52 -0700907 page = (char *)__get_free_page(GFP_TEMPORARY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if (!page)
KOSAKI Motohiro30cd8902011-05-26 16:25:52 -0700909 goto out_task;
910
911 mm = check_mem_permission(task);
912 copied = PTR_ERR(mm);
913 if (IS_ERR(mm))
914 goto out_free;
915
916 copied = -EIO;
917 if (file->private_data != (void *)((long)current->self_exec_id))
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400918 goto out_mm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
Frederik Deweerdtf7ca54f2006-09-29 02:01:02 -0700920 copied = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 while (count > 0) {
922 int this_len, retval;
923
924 this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
925 if (copy_from_user(page, buf, this_len)) {
926 copied = -EFAULT;
927 break;
928 }
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400929 retval = access_remote_vm(mm, dst, page, this_len, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 if (!retval) {
931 if (!copied)
932 copied = -EIO;
933 break;
934 }
935 copied += retval;
936 buf += retval;
937 dst += retval;
938 count -= retval;
939 }
940 *ppos = dst;
KOSAKI Motohiro30cd8902011-05-26 16:25:52 -0700941
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400942out_mm:
943 mmput(mm);
KOSAKI Motohiro30cd8902011-05-26 16:25:52 -0700944out_free:
945 free_page((unsigned long) page);
Stephen Wilson8b0db9d2011-03-13 15:49:23 -0400946out_task:
Eric W. Biederman99f89552006-06-26 00:25:55 -0700947 put_task_struct(task);
948out_no_task:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 return copied;
950}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Matt Mackall85863e42008-02-04 22:29:04 -0800952loff_t mem_lseek(struct file *file, loff_t offset, int orig)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953{
954 switch (orig) {
955 case 0:
956 file->f_pos = offset;
957 break;
958 case 1:
959 file->f_pos += offset;
960 break;
961 default:
962 return -EINVAL;
963 }
964 force_successful_syscall_return();
965 return file->f_pos;
966}
967
Arjan van de Ven00977a52007-02-12 00:55:34 -0800968static const struct file_operations proc_mem_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 .llseek = mem_lseek,
970 .read = mem_read,
971 .write = mem_write,
972 .open = mem_open,
973};
974
James Pearson315e28c2007-10-16 23:30:17 -0700975static ssize_t environ_read(struct file *file, char __user *buf,
976 size_t count, loff_t *ppos)
977{
978 struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
979 char *page;
980 unsigned long src = *ppos;
981 int ret = -ESRCH;
982 struct mm_struct *mm;
983
984 if (!task)
985 goto out_no_task;
986
James Pearson315e28c2007-10-16 23:30:17 -0700987 ret = -ENOMEM;
988 page = (char *)__get_free_page(GFP_TEMPORARY);
989 if (!page)
990 goto out;
991
James Pearson315e28c2007-10-16 23:30:17 -0700992
Al Virod6f64b82011-02-15 22:26:01 -0500993 mm = mm_for_maps(task);
994 ret = PTR_ERR(mm);
995 if (!mm || IS_ERR(mm))
James Pearson315e28c2007-10-16 23:30:17 -0700996 goto out_free;
997
Al Virod6f64b82011-02-15 22:26:01 -0500998 ret = 0;
James Pearson315e28c2007-10-16 23:30:17 -0700999 while (count > 0) {
1000 int this_len, retval, max_len;
1001
1002 this_len = mm->env_end - (mm->env_start + src);
1003
1004 if (this_len <= 0)
1005 break;
1006
1007 max_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1008 this_len = (this_len > max_len) ? max_len : this_len;
1009
1010 retval = access_process_vm(task, (mm->env_start + src),
1011 page, this_len, 0);
1012
1013 if (retval <= 0) {
1014 ret = retval;
1015 break;
1016 }
1017
1018 if (copy_to_user(buf, page, retval)) {
1019 ret = -EFAULT;
1020 break;
1021 }
1022
1023 ret += retval;
1024 src += retval;
1025 buf += retval;
1026 count -= retval;
1027 }
1028 *ppos = src;
1029
1030 mmput(mm);
1031out_free:
1032 free_page((unsigned long) page);
1033out:
1034 put_task_struct(task);
1035out_no_task:
1036 return ret;
1037}
1038
1039static const struct file_operations proc_environ_operations = {
1040 .read = environ_read,
Arnd Bergmann87df8422010-03-17 23:06:02 +01001041 .llseek = generic_file_llseek,
James Pearson315e28c2007-10-16 23:30:17 -07001042};
1043
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044static ssize_t oom_adjust_read(struct file *file, char __user *buf,
1045 size_t count, loff_t *ppos)
1046{
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -08001047 struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
Eric W. Biederman8578cea2006-06-26 00:25:54 -07001048 char buffer[PROC_NUMBUF];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 size_t len;
KOSAKI Motohiro28b83c52009-09-21 17:03:13 -07001050 int oom_adjust = OOM_DISABLE;
1051 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
Eric W. Biederman99f89552006-06-26 00:25:55 -07001053 if (!task)
1054 return -ESRCH;
KOSAKI Motohiro28b83c52009-09-21 17:03:13 -07001055
1056 if (lock_task_sighand(task, &flags)) {
1057 oom_adjust = task->signal->oom_adj;
1058 unlock_task_sighand(task, &flags);
1059 }
1060
Eric W. Biederman99f89552006-06-26 00:25:55 -07001061 put_task_struct(task);
1062
Eric W. Biederman8578cea2006-06-26 00:25:54 -07001063 len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust);
Akinobu Mita0c28f282007-05-08 00:31:41 -07001064
1065 return simple_read_from_buffer(buf, count, ppos, buffer, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066}
1067
1068static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
1069 size_t count, loff_t *ppos)
1070{
Eric W. Biederman99f89552006-06-26 00:25:55 -07001071 struct task_struct *task;
KOSAKI Motohiro5d863b82009-09-21 17:03:16 -07001072 char buffer[PROC_NUMBUF];
Alexey Dobriyan0a8cb8e2011-05-26 16:25:50 -07001073 int oom_adjust;
KOSAKI Motohiro28b83c52009-09-21 17:03:13 -07001074 unsigned long flags;
KOSAKI Motohiro5d863b82009-09-21 17:03:16 -07001075 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
Eric W. Biederman8578cea2006-06-26 00:25:54 -07001077 memset(buffer, 0, sizeof(buffer));
1078 if (count > sizeof(buffer) - 1)
1079 count = sizeof(buffer) - 1;
David Rientjes723548b2010-10-26 14:21:25 -07001080 if (copy_from_user(buffer, buf, count)) {
1081 err = -EFAULT;
1082 goto out;
1083 }
KOSAKI Motohiro5d863b82009-09-21 17:03:16 -07001084
Alexey Dobriyan0a8cb8e2011-05-26 16:25:50 -07001085 err = kstrtoint(strstrip(buffer), 0, &oom_adjust);
KOSAKI Motohiro5d863b82009-09-21 17:03:16 -07001086 if (err)
David Rientjes723548b2010-10-26 14:21:25 -07001087 goto out;
Alexey Dobriyan8ac773b2006-10-19 23:28:32 -07001088 if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) &&
David Rientjes723548b2010-10-26 14:21:25 -07001089 oom_adjust != OOM_DISABLE) {
1090 err = -EINVAL;
1091 goto out;
1092 }
KOSAKI Motohiro5d863b82009-09-21 17:03:16 -07001093
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -08001094 task = get_proc_task(file->f_path.dentry->d_inode);
David Rientjes723548b2010-10-26 14:21:25 -07001095 if (!task) {
1096 err = -ESRCH;
1097 goto out;
1098 }
KOSAKI Motohiro28b83c52009-09-21 17:03:13 -07001099
Ying Han3d5992d2010-10-26 14:21:23 -07001100 task_lock(task);
1101 if (!task->mm) {
David Rientjes723548b2010-10-26 14:21:25 -07001102 err = -EINVAL;
1103 goto err_task_lock;
Ying Han3d5992d2010-10-26 14:21:23 -07001104 }
1105
David Rientjesd19d5472010-10-26 14:21:26 -07001106 if (!lock_task_sighand(task, &flags)) {
1107 err = -ESRCH;
1108 goto err_task_lock;
1109 }
1110
1111 if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) {
1112 err = -EACCES;
1113 goto err_sighand;
1114 }
1115
Ying Han3d5992d2010-10-26 14:21:23 -07001116 if (oom_adjust != task->signal->oom_adj) {
1117 if (oom_adjust == OOM_DISABLE)
1118 atomic_inc(&task->mm->oom_disable_count);
1119 if (task->signal->oom_adj == OOM_DISABLE)
1120 atomic_dec(&task->mm->oom_disable_count);
1121 }
1122
David Rientjes51b1bd22010-08-09 17:19:47 -07001123 /*
1124 * Warn that /proc/pid/oom_adj is deprecated, see
1125 * Documentation/feature-removal-schedule.txt.
1126 */
1127 printk_once(KERN_WARNING "%s (%d): /proc/%d/oom_adj is deprecated, "
1128 "please use /proc/%d/oom_score_adj instead.\n",
1129 current->comm, task_pid_nr(current),
1130 task_pid_nr(task), task_pid_nr(task));
KOSAKI Motohiro28b83c52009-09-21 17:03:13 -07001131 task->signal->oom_adj = oom_adjust;
David Rientjesa63d83f2010-08-09 17:19:46 -07001132 /*
1133 * Scale /proc/pid/oom_score_adj appropriately ensuring that a maximum
1134 * value is always attainable.
1135 */
1136 if (task->signal->oom_adj == OOM_ADJUST_MAX)
1137 task->signal->oom_score_adj = OOM_SCORE_ADJ_MAX;
1138 else
1139 task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) /
1140 -OOM_DISABLE;
David Rientjes723548b2010-10-26 14:21:25 -07001141err_sighand:
KOSAKI Motohiro28b83c52009-09-21 17:03:13 -07001142 unlock_task_sighand(task, &flags);
David Rientjesd19d5472010-10-26 14:21:26 -07001143err_task_lock:
1144 task_unlock(task);
Eric W. Biederman99f89552006-06-26 00:25:55 -07001145 put_task_struct(task);
David Rientjes723548b2010-10-26 14:21:25 -07001146out:
1147 return err < 0 ? err : count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148}
1149
Mike Chan766e9932008-04-24 10:22:26 -07001150static int oom_adjust_permission(struct inode *inode, int mask,
1151 unsigned int flags)
1152{
1153 uid_t uid;
1154 struct task_struct *p;
1155
1156 if (flags & IPERM_FLAG_RCU)
1157 return -ECHILD;
1158
1159 p = get_proc_task(inode);
1160 if(p) {
1161 uid = task_uid(p);
1162 put_task_struct(p);
1163 }
1164
1165 /*
1166 * System Server (uid == 1000) is granted access to oom_adj of all
1167 * android applications (uid > 10000) as and services (uid >= 1000)
1168 */
1169 if (p && (current_fsuid() == 1000) && (uid >= 1000)) {
1170 if (inode->i_mode >> 6 & mask) {
1171 return 0;
1172 }
1173 }
1174
1175 /* Fall back to default. */
1176 return generic_permission(inode, mask, flags, NULL);
1177}
1178
1179static const struct inode_operations proc_oom_adjust_inode_operations = {
1180 .permission = oom_adjust_permission,
1181};
1182
Arjan van de Ven00977a52007-02-12 00:55:34 -08001183static const struct file_operations proc_oom_adjust_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 .read = oom_adjust_read,
1185 .write = oom_adjust_write,
Arnd Bergmann87df8422010-03-17 23:06:02 +01001186 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187};
1188
David Rientjesa63d83f2010-08-09 17:19:46 -07001189static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
1190 size_t count, loff_t *ppos)
1191{
1192 struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
1193 char buffer[PROC_NUMBUF];
1194 int oom_score_adj = OOM_SCORE_ADJ_MIN;
1195 unsigned long flags;
1196 size_t len;
1197
1198 if (!task)
1199 return -ESRCH;
1200 if (lock_task_sighand(task, &flags)) {
1201 oom_score_adj = task->signal->oom_score_adj;
1202 unlock_task_sighand(task, &flags);
1203 }
1204 put_task_struct(task);
1205 len = snprintf(buffer, sizeof(buffer), "%d\n", oom_score_adj);
1206 return simple_read_from_buffer(buf, count, ppos, buffer, len);
1207}
1208
1209static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
1210 size_t count, loff_t *ppos)
1211{
1212 struct task_struct *task;
1213 char buffer[PROC_NUMBUF];
1214 unsigned long flags;
Alexey Dobriyan0a8cb8e2011-05-26 16:25:50 -07001215 int oom_score_adj;
David Rientjesa63d83f2010-08-09 17:19:46 -07001216 int err;
1217
1218 memset(buffer, 0, sizeof(buffer));
1219 if (count > sizeof(buffer) - 1)
1220 count = sizeof(buffer) - 1;
David Rientjes723548b2010-10-26 14:21:25 -07001221 if (copy_from_user(buffer, buf, count)) {
1222 err = -EFAULT;
1223 goto out;
1224 }
David Rientjesa63d83f2010-08-09 17:19:46 -07001225
Alexey Dobriyan0a8cb8e2011-05-26 16:25:50 -07001226 err = kstrtoint(strstrip(buffer), 0, &oom_score_adj);
David Rientjesa63d83f2010-08-09 17:19:46 -07001227 if (err)
David Rientjes723548b2010-10-26 14:21:25 -07001228 goto out;
David Rientjesa63d83f2010-08-09 17:19:46 -07001229 if (oom_score_adj < OOM_SCORE_ADJ_MIN ||
David Rientjes723548b2010-10-26 14:21:25 -07001230 oom_score_adj > OOM_SCORE_ADJ_MAX) {
1231 err = -EINVAL;
1232 goto out;
1233 }
David Rientjesa63d83f2010-08-09 17:19:46 -07001234
1235 task = get_proc_task(file->f_path.dentry->d_inode);
David Rientjes723548b2010-10-26 14:21:25 -07001236 if (!task) {
1237 err = -ESRCH;
1238 goto out;
1239 }
David Rientjesa63d83f2010-08-09 17:19:46 -07001240
Ying Han3d5992d2010-10-26 14:21:23 -07001241 task_lock(task);
1242 if (!task->mm) {
David Rientjes723548b2010-10-26 14:21:25 -07001243 err = -EINVAL;
1244 goto err_task_lock;
Ying Han3d5992d2010-10-26 14:21:23 -07001245 }
David Rientjesd19d5472010-10-26 14:21:26 -07001246
1247 if (!lock_task_sighand(task, &flags)) {
1248 err = -ESRCH;
1249 goto err_task_lock;
1250 }
1251
Mandeep Singh Bainesdabb16f2011-01-13 15:46:05 -08001252 if (oom_score_adj < task->signal->oom_score_adj_min &&
David Rientjesd19d5472010-10-26 14:21:26 -07001253 !capable(CAP_SYS_RESOURCE)) {
1254 err = -EACCES;
1255 goto err_sighand;
1256 }
1257
Ying Han3d5992d2010-10-26 14:21:23 -07001258 if (oom_score_adj != task->signal->oom_score_adj) {
1259 if (oom_score_adj == OOM_SCORE_ADJ_MIN)
1260 atomic_inc(&task->mm->oom_disable_count);
1261 if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
1262 atomic_dec(&task->mm->oom_disable_count);
1263 }
David Rientjesa63d83f2010-08-09 17:19:46 -07001264 task->signal->oom_score_adj = oom_score_adj;
Mandeep Singh Bainesdabb16f2011-01-13 15:46:05 -08001265 if (has_capability_noaudit(current, CAP_SYS_RESOURCE))
1266 task->signal->oom_score_adj_min = oom_score_adj;
David Rientjesa63d83f2010-08-09 17:19:46 -07001267 /*
1268 * Scale /proc/pid/oom_adj appropriately ensuring that OOM_DISABLE is
1269 * always attainable.
1270 */
1271 if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
1272 task->signal->oom_adj = OOM_DISABLE;
1273 else
1274 task->signal->oom_adj = (oom_score_adj * OOM_ADJUST_MAX) /
1275 OOM_SCORE_ADJ_MAX;
David Rientjes723548b2010-10-26 14:21:25 -07001276err_sighand:
David Rientjesa63d83f2010-08-09 17:19:46 -07001277 unlock_task_sighand(task, &flags);
David Rientjesd19d5472010-10-26 14:21:26 -07001278err_task_lock:
1279 task_unlock(task);
David Rientjesa63d83f2010-08-09 17:19:46 -07001280 put_task_struct(task);
David Rientjes723548b2010-10-26 14:21:25 -07001281out:
1282 return err < 0 ? err : count;
David Rientjesa63d83f2010-08-09 17:19:46 -07001283}
1284
1285static const struct file_operations proc_oom_score_adj_operations = {
1286 .read = oom_score_adj_read,
1287 .write = oom_score_adj_write,
Arnd Bergmann6038f372010-08-15 18:52:59 +02001288 .llseek = default_llseek,
David Rientjesa63d83f2010-08-09 17:19:46 -07001289};
1290
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291#ifdef CONFIG_AUDITSYSCALL
1292#define TMPBUFLEN 21
1293static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
1294 size_t count, loff_t *ppos)
1295{
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -08001296 struct inode * inode = file->f_path.dentry->d_inode;
Eric W. Biederman99f89552006-06-26 00:25:55 -07001297 struct task_struct *task = get_proc_task(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 ssize_t length;
1299 char tmpbuf[TMPBUFLEN];
1300
Eric W. Biederman99f89552006-06-26 00:25:55 -07001301 if (!task)
1302 return -ESRCH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
Al Viro0c11b942008-01-10 04:20:52 -05001304 audit_get_loginuid(task));
Eric W. Biederman99f89552006-06-26 00:25:55 -07001305 put_task_struct(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
1307}
1308
1309static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
1310 size_t count, loff_t *ppos)
1311{
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -08001312 struct inode * inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 char *page, *tmp;
1314 ssize_t length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 uid_t loginuid;
1316
1317 if (!capable(CAP_AUDIT_CONTROL))
1318 return -EPERM;
1319
Paul E. McKenney7dc52152010-02-22 17:04:52 -08001320 rcu_read_lock();
1321 if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) {
1322 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 return -EPERM;
Paul E. McKenney7dc52152010-02-22 17:04:52 -08001324 }
1325 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
Al Viroe0182902006-05-18 08:28:02 -04001327 if (count >= PAGE_SIZE)
1328 count = PAGE_SIZE - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329
1330 if (*ppos != 0) {
1331 /* No partial writes. */
1332 return -EINVAL;
1333 }
Mel Gormane12ba742007-10-16 01:25:52 -07001334 page = (char*)__get_free_page(GFP_TEMPORARY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 if (!page)
1336 return -ENOMEM;
1337 length = -EFAULT;
1338 if (copy_from_user(page, buf, count))
1339 goto out_free_page;
1340
Al Viroe0182902006-05-18 08:28:02 -04001341 page[count] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 loginuid = simple_strtoul(page, &tmp, 10);
1343 if (tmp == page) {
1344 length = -EINVAL;
1345 goto out_free_page;
1346
1347 }
Eric W. Biederman99f89552006-06-26 00:25:55 -07001348 length = audit_set_loginuid(current, loginuid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 if (likely(length == 0))
1350 length = count;
1351
1352out_free_page:
1353 free_page((unsigned long) page);
1354 return length;
1355}
1356
Arjan van de Ven00977a52007-02-12 00:55:34 -08001357static const struct file_operations proc_loginuid_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 .read = proc_loginuid_read,
1359 .write = proc_loginuid_write,
Arnd Bergmann87df8422010-03-17 23:06:02 +01001360 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361};
Eric Paris1e0bd752008-03-13 08:15:31 -04001362
1363static ssize_t proc_sessionid_read(struct file * file, char __user * buf,
1364 size_t count, loff_t *ppos)
1365{
1366 struct inode * inode = file->f_path.dentry->d_inode;
1367 struct task_struct *task = get_proc_task(inode);
1368 ssize_t length;
1369 char tmpbuf[TMPBUFLEN];
1370
1371 if (!task)
1372 return -ESRCH;
1373 length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
1374 audit_get_sessionid(task));
1375 put_task_struct(task);
1376 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
1377}
1378
1379static const struct file_operations proc_sessionid_operations = {
1380 .read = proc_sessionid_read,
Arnd Bergmann87df8422010-03-17 23:06:02 +01001381 .llseek = generic_file_llseek,
Eric Paris1e0bd752008-03-13 08:15:31 -04001382};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383#endif
1384
Akinobu Mitaf4f154f2006-12-08 02:39:47 -08001385#ifdef CONFIG_FAULT_INJECTION
1386static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
1387 size_t count, loff_t *ppos)
1388{
1389 struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
1390 char buffer[PROC_NUMBUF];
1391 size_t len;
1392 int make_it_fail;
Akinobu Mitaf4f154f2006-12-08 02:39:47 -08001393
1394 if (!task)
1395 return -ESRCH;
1396 make_it_fail = task->make_it_fail;
1397 put_task_struct(task);
1398
1399 len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail);
Akinobu Mita0c28f282007-05-08 00:31:41 -07001400
1401 return simple_read_from_buffer(buf, count, ppos, buffer, len);
Akinobu Mitaf4f154f2006-12-08 02:39:47 -08001402}
1403
1404static ssize_t proc_fault_inject_write(struct file * file,
1405 const char __user * buf, size_t count, loff_t *ppos)
1406{
1407 struct task_struct *task;
1408 char buffer[PROC_NUMBUF], *end;
1409 int make_it_fail;
1410
1411 if (!capable(CAP_SYS_RESOURCE))
1412 return -EPERM;
1413 memset(buffer, 0, sizeof(buffer));
1414 if (count > sizeof(buffer) - 1)
1415 count = sizeof(buffer) - 1;
1416 if (copy_from_user(buffer, buf, count))
1417 return -EFAULT;
Vincent Licba8aaf2009-09-22 16:45:38 -07001418 make_it_fail = simple_strtol(strstrip(buffer), &end, 0);
1419 if (*end)
1420 return -EINVAL;
Akinobu Mitaf4f154f2006-12-08 02:39:47 -08001421 task = get_proc_task(file->f_dentry->d_inode);
1422 if (!task)
1423 return -ESRCH;
1424 task->make_it_fail = make_it_fail;
1425 put_task_struct(task);
Vincent Licba8aaf2009-09-22 16:45:38 -07001426
1427 return count;
Akinobu Mitaf4f154f2006-12-08 02:39:47 -08001428}
1429
Arjan van de Ven00977a52007-02-12 00:55:34 -08001430static const struct file_operations proc_fault_inject_operations = {
Akinobu Mitaf4f154f2006-12-08 02:39:47 -08001431 .read = proc_fault_inject_read,
1432 .write = proc_fault_inject_write,
Arnd Bergmann87df8422010-03-17 23:06:02 +01001433 .llseek = generic_file_llseek,
Akinobu Mitaf4f154f2006-12-08 02:39:47 -08001434};
1435#endif
1436
Arjan van de Ven97455122008-01-25 21:08:34 +01001437
Ingo Molnar43ae34c2007-07-09 18:52:00 +02001438#ifdef CONFIG_SCHED_DEBUG
1439/*
1440 * Print out various scheduling related per-task fields:
1441 */
1442static int sched_show(struct seq_file *m, void *v)
1443{
1444 struct inode *inode = m->private;
1445 struct task_struct *p;
1446
Ingo Molnar43ae34c2007-07-09 18:52:00 +02001447 p = get_proc_task(inode);
1448 if (!p)
1449 return -ESRCH;
1450 proc_sched_show_task(p, m);
1451
1452 put_task_struct(p);
1453
1454 return 0;
1455}
1456
1457static ssize_t
1458sched_write(struct file *file, const char __user *buf,
1459 size_t count, loff_t *offset)
1460{
1461 struct inode *inode = file->f_path.dentry->d_inode;
1462 struct task_struct *p;
1463
Ingo Molnar43ae34c2007-07-09 18:52:00 +02001464 p = get_proc_task(inode);
1465 if (!p)
1466 return -ESRCH;
1467 proc_sched_set_task(p);
1468
1469 put_task_struct(p);
1470
1471 return count;
1472}
1473
1474static int sched_open(struct inode *inode, struct file *filp)
1475{
Jovi Zhangc6a34052011-01-12 17:00:34 -08001476 return single_open(filp, sched_show, inode);
Ingo Molnar43ae34c2007-07-09 18:52:00 +02001477}
1478
1479static const struct file_operations proc_pid_sched_operations = {
1480 .open = sched_open,
1481 .read = seq_read,
1482 .write = sched_write,
1483 .llseek = seq_lseek,
Alexey Dobriyan5ea473a2007-07-31 00:38:50 -07001484 .release = single_release,
Ingo Molnar43ae34c2007-07-09 18:52:00 +02001485};
1486
1487#endif
1488
Mike Galbraith5091faa2010-11-30 14:18:03 +01001489#ifdef CONFIG_SCHED_AUTOGROUP
1490/*
1491 * Print out autogroup related information:
1492 */
1493static int sched_autogroup_show(struct seq_file *m, void *v)
1494{
1495 struct inode *inode = m->private;
1496 struct task_struct *p;
1497
1498 p = get_proc_task(inode);
1499 if (!p)
1500 return -ESRCH;
1501 proc_sched_autogroup_show_task(p, m);
1502
1503 put_task_struct(p);
1504
1505 return 0;
1506}
1507
1508static ssize_t
1509sched_autogroup_write(struct file *file, const char __user *buf,
1510 size_t count, loff_t *offset)
1511{
1512 struct inode *inode = file->f_path.dentry->d_inode;
1513 struct task_struct *p;
1514 char buffer[PROC_NUMBUF];
Alexey Dobriyan0a8cb8e2011-05-26 16:25:50 -07001515 int nice;
Mike Galbraith5091faa2010-11-30 14:18:03 +01001516 int err;
1517
1518 memset(buffer, 0, sizeof(buffer));
1519 if (count > sizeof(buffer) - 1)
1520 count = sizeof(buffer) - 1;
1521 if (copy_from_user(buffer, buf, count))
1522 return -EFAULT;
1523
Alexey Dobriyan0a8cb8e2011-05-26 16:25:50 -07001524 err = kstrtoint(strstrip(buffer), 0, &nice);
1525 if (err < 0)
1526 return err;
Mike Galbraith5091faa2010-11-30 14:18:03 +01001527
1528 p = get_proc_task(inode);
1529 if (!p)
1530 return -ESRCH;
1531
1532 err = nice;
1533 err = proc_sched_autogroup_set_nice(p, &err);
1534 if (err)
1535 count = err;
1536
1537 put_task_struct(p);
1538
1539 return count;
1540}
1541
1542static int sched_autogroup_open(struct inode *inode, struct file *filp)
1543{
1544 int ret;
1545
1546 ret = single_open(filp, sched_autogroup_show, NULL);
1547 if (!ret) {
1548 struct seq_file *m = filp->private_data;
1549
1550 m->private = inode;
1551 }
1552 return ret;
1553}
1554
1555static const struct file_operations proc_pid_sched_autogroup_operations = {
1556 .open = sched_autogroup_open,
1557 .read = seq_read,
1558 .write = sched_autogroup_write,
1559 .llseek = seq_lseek,
1560 .release = single_release,
1561};
1562
1563#endif /* CONFIG_SCHED_AUTOGROUP */
1564
john stultz4614a696b2009-12-14 18:00:05 -08001565static ssize_t comm_write(struct file *file, const char __user *buf,
1566 size_t count, loff_t *offset)
1567{
1568 struct inode *inode = file->f_path.dentry->d_inode;
1569 struct task_struct *p;
1570 char buffer[TASK_COMM_LEN];
1571
1572 memset(buffer, 0, sizeof(buffer));
1573 if (count > sizeof(buffer) - 1)
1574 count = sizeof(buffer) - 1;
1575 if (copy_from_user(buffer, buf, count))
1576 return -EFAULT;
1577
1578 p = get_proc_task(inode);
1579 if (!p)
1580 return -ESRCH;
1581
1582 if (same_thread_group(current, p))
1583 set_task_comm(p, buffer);
1584 else
1585 count = -EINVAL;
1586
1587 put_task_struct(p);
1588
1589 return count;
1590}
1591
1592static int comm_show(struct seq_file *m, void *v)
1593{
1594 struct inode *inode = m->private;
1595 struct task_struct *p;
1596
1597 p = get_proc_task(inode);
1598 if (!p)
1599 return -ESRCH;
1600
1601 task_lock(p);
1602 seq_printf(m, "%s\n", p->comm);
1603 task_unlock(p);
1604
1605 put_task_struct(p);
1606
1607 return 0;
1608}
1609
1610static int comm_open(struct inode *inode, struct file *filp)
1611{
Jovi Zhangc6a34052011-01-12 17:00:34 -08001612 return single_open(filp, comm_show, inode);
john stultz4614a696b2009-12-14 18:00:05 -08001613}
1614
1615static const struct file_operations proc_pid_set_comm_operations = {
1616 .open = comm_open,
1617 .read = seq_read,
1618 .write = comm_write,
1619 .llseek = seq_lseek,
1620 .release = single_release,
1621};
1622
Matt Helsley925d1c42008-04-29 01:01:36 -07001623static int proc_exe_link(struct inode *inode, struct path *exe_path)
1624{
1625 struct task_struct *task;
1626 struct mm_struct *mm;
1627 struct file *exe_file;
1628
1629 task = get_proc_task(inode);
1630 if (!task)
1631 return -ENOENT;
1632 mm = get_task_mm(task);
1633 put_task_struct(task);
1634 if (!mm)
1635 return -ENOENT;
1636 exe_file = get_mm_exe_file(mm);
1637 mmput(mm);
1638 if (exe_file) {
1639 *exe_path = exe_file->f_path;
1640 path_get(&exe_file->f_path);
1641 fput(exe_file);
1642 return 0;
1643 } else
1644 return -ENOENT;
1645}
1646
Al Viro008b1502005-08-20 00:17:39 +01001647static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648{
1649 struct inode *inode = dentry->d_inode;
1650 int error = -EACCES;
1651
1652 /* We don't need a base pointer in the /proc filesystem */
Jan Blunck1d957f92008-02-14 19:34:35 -08001653 path_put(&nd->path);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
Eric W. Biederman778c1142006-06-26 00:25:58 -07001655 /* Are we allowed to snoop on the tasks file descriptors? */
1656 if (!proc_fd_access_allowed(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
Jan Blunck3dcd25f2008-02-14 19:38:35 -08001659 error = PROC_I(inode)->op.proc_get_link(inode, &nd->path);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660out:
Al Viro008b1502005-08-20 00:17:39 +01001661 return ERR_PTR(error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662}
1663
Jan Blunck3dcd25f2008-02-14 19:38:35 -08001664static int do_proc_readlink(struct path *path, char __user *buffer, int buflen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665{
Mel Gormane12ba742007-10-16 01:25:52 -07001666 char *tmp = (char*)__get_free_page(GFP_TEMPORARY);
Jan Blunck3dcd25f2008-02-14 19:38:35 -08001667 char *pathname;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 int len;
1669
1670 if (!tmp)
1671 return -ENOMEM;
Akinobu Mita0c28f282007-05-08 00:31:41 -07001672
Eric W. Biederman7b2a69b2010-12-05 15:51:21 -08001673 pathname = d_path(path, tmp, PAGE_SIZE);
Jan Blunck3dcd25f2008-02-14 19:38:35 -08001674 len = PTR_ERR(pathname);
1675 if (IS_ERR(pathname))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 goto out;
Jan Blunck3dcd25f2008-02-14 19:38:35 -08001677 len = tmp + PAGE_SIZE - 1 - pathname;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
1679 if (len > buflen)
1680 len = buflen;
Jan Blunck3dcd25f2008-02-14 19:38:35 -08001681 if (copy_to_user(buffer, pathname, len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 len = -EFAULT;
1683 out:
1684 free_page((unsigned long)tmp);
1685 return len;
1686}
1687
1688static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int buflen)
1689{
1690 int error = -EACCES;
1691 struct inode *inode = dentry->d_inode;
Jan Blunck3dcd25f2008-02-14 19:38:35 -08001692 struct path path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
Eric W. Biederman778c1142006-06-26 00:25:58 -07001694 /* Are we allowed to snoop on the tasks file descriptors? */
1695 if (!proc_fd_access_allowed(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697
Jan Blunck3dcd25f2008-02-14 19:38:35 -08001698 error = PROC_I(inode)->op.proc_get_link(inode, &path);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 if (error)
1700 goto out;
1701
Jan Blunck3dcd25f2008-02-14 19:38:35 -08001702 error = do_proc_readlink(&path, buffer, buflen);
1703 path_put(&path);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 return error;
1706}
1707
Arjan van de Venc5ef1c42007-02-12 00:55:40 -08001708static const struct inode_operations proc_pid_link_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 .readlink = proc_pid_readlink,
Linus Torvalds6d76fa52006-07-15 12:26:45 -07001710 .follow_link = proc_pid_follow_link,
1711 .setattr = proc_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712};
1713
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001714
1715/* building an inode */
1716
1717static int task_dumpable(struct task_struct *task)
1718{
1719 int dumpable = 0;
1720 struct mm_struct *mm;
1721
1722 task_lock(task);
1723 mm = task->mm;
1724 if (mm)
Kawai, Hidehiro6c5d5232007-07-19 01:48:27 -07001725 dumpable = get_dumpable(mm);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001726 task_unlock(task);
1727 if(dumpable == 1)
1728 return 1;
1729 return 0;
1730}
1731
Eric W. Biederman6b4e3062010-03-07 16:41:34 -08001732struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001733{
1734 struct inode * inode;
1735 struct proc_inode *ei;
David Howellsc69e8d92008-11-14 10:39:19 +11001736 const struct cred *cred;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001737
1738 /* We need a new inode */
1739
1740 inode = new_inode(sb);
1741 if (!inode)
1742 goto out;
1743
1744 /* Common stuff */
1745 ei = PROC_I(inode);
Christoph Hellwig85fe4022010-10-23 11:19:54 -04001746 inode->i_ino = get_next_ino();
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001747 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001748 inode->i_op = &proc_def_inode_operations;
1749
1750 /*
1751 * grab the reference to task.
1752 */
Oleg Nesterov1a657f72006-10-02 02:18:59 -07001753 ei->pid = get_task_pid(task, PIDTYPE_PID);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001754 if (!ei->pid)
1755 goto out_unlock;
1756
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001757 if (task_dumpable(task)) {
David Howellsc69e8d92008-11-14 10:39:19 +11001758 rcu_read_lock();
1759 cred = __task_cred(task);
1760 inode->i_uid = cred->euid;
1761 inode->i_gid = cred->egid;
1762 rcu_read_unlock();
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001763 }
1764 security_task_to_inode(task, inode);
1765
1766out:
1767 return inode;
1768
1769out_unlock:
1770 iput(inode);
1771 return NULL;
1772}
1773
Eric W. Biederman6b4e3062010-03-07 16:41:34 -08001774int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001775{
1776 struct inode *inode = dentry->d_inode;
1777 struct task_struct *task;
David Howellsc69e8d92008-11-14 10:39:19 +11001778 const struct cred *cred;
1779
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001780 generic_fillattr(inode, stat);
1781
1782 rcu_read_lock();
1783 stat->uid = 0;
1784 stat->gid = 0;
1785 task = pid_task(proc_pid(inode), PIDTYPE_PID);
1786 if (task) {
1787 if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
1788 task_dumpable(task)) {
David Howellsc69e8d92008-11-14 10:39:19 +11001789 cred = __task_cred(task);
1790 stat->uid = cred->euid;
1791 stat->gid = cred->egid;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001792 }
1793 }
1794 rcu_read_unlock();
1795 return 0;
1796}
1797
1798/* dentry stuff */
1799
1800/*
1801 * Exceptional case: normally we are not allowed to unhash a busy
1802 * directory. In this case, however, we can do it - no aliasing problems
1803 * due to the way we treat inodes.
1804 *
1805 * Rewrite the inode's ownerships here because the owning task may have
1806 * performed a setuid(), etc.
1807 *
1808 * Before the /proc/pid/status file was created the only way to read
1809 * the effective uid of a /process was to stat /proc/pid. Reading
1810 * /proc/pid/status is slow enough that procps and other packages
1811 * kept stating /proc/pid. To keep the rules in /proc simple I have
1812 * made this apply to all per process world readable and executable
1813 * directories.
1814 */
Eric W. Biederman6b4e3062010-03-07 16:41:34 -08001815int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001816{
Nick Piggin34286d62011-01-07 17:49:57 +11001817 struct inode *inode;
1818 struct task_struct *task;
David Howellsc69e8d92008-11-14 10:39:19 +11001819 const struct cred *cred;
1820
Nick Piggin34286d62011-01-07 17:49:57 +11001821 if (nd && nd->flags & LOOKUP_RCU)
1822 return -ECHILD;
1823
1824 inode = dentry->d_inode;
1825 task = get_proc_task(inode);
1826
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001827 if (task) {
1828 if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
1829 task_dumpable(task)) {
David Howellsc69e8d92008-11-14 10:39:19 +11001830 rcu_read_lock();
1831 cred = __task_cred(task);
1832 inode->i_uid = cred->euid;
1833 inode->i_gid = cred->egid;
1834 rcu_read_unlock();
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001835 } else {
1836 inode->i_uid = 0;
1837 inode->i_gid = 0;
1838 }
1839 inode->i_mode &= ~(S_ISUID | S_ISGID);
1840 security_task_to_inode(task, inode);
1841 put_task_struct(task);
1842 return 1;
1843 }
1844 d_drop(dentry);
1845 return 0;
1846}
1847
Nick Pigginfe15ce42011-01-07 17:49:23 +11001848static int pid_delete_dentry(const struct dentry * dentry)
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001849{
1850 /* Is the task we represent dead?
1851 * If so, then don't put the dentry on the lru list,
1852 * kill it immediately.
1853 */
1854 return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
1855}
1856
Eric W. Biederman6b4e3062010-03-07 16:41:34 -08001857const struct dentry_operations pid_dentry_operations =
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001858{
1859 .d_revalidate = pid_revalidate,
1860 .d_delete = pid_delete_dentry,
1861};
1862
1863/* Lookups */
1864
Eric W. Biederman1c0d04c2006-10-02 02:18:57 -07001865/*
1866 * Fill a directory entry.
1867 *
1868 * If possible create the dcache entry and derive our inode number and
1869 * file type from dcache entry.
1870 *
1871 * Since all of the proc inode numbers are dynamically generated, the inode
1872 * numbers do not exist until the inode is cache. This means creating the
1873 * the dcache entry in readdir is necessary to keep the inode numbers
1874 * reported by readdir in sync with the inode numbers reported
1875 * by stat.
1876 */
Eric W. Biederman6b4e3062010-03-07 16:41:34 -08001877int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
1878 const char *name, int len,
Eric Dumazetc5141e62007-05-08 00:26:15 -07001879 instantiate_t instantiate, struct task_struct *task, const void *ptr)
Eric W. Biederman61a28782006-10-02 02:18:49 -07001880{
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -08001881 struct dentry *child, *dir = filp->f_path.dentry;
Eric W. Biederman61a28782006-10-02 02:18:49 -07001882 struct inode *inode;
1883 struct qstr qname;
1884 ino_t ino = 0;
1885 unsigned type = DT_UNKNOWN;
1886
1887 qname.name = name;
1888 qname.len = len;
1889 qname.hash = full_name_hash(name, len);
1890
1891 child = d_lookup(dir, &qname);
1892 if (!child) {
1893 struct dentry *new;
1894 new = d_alloc(dir, &qname);
1895 if (new) {
1896 child = instantiate(dir->d_inode, new, task, ptr);
1897 if (child)
1898 dput(new);
1899 else
1900 child = new;
1901 }
1902 }
1903 if (!child || IS_ERR(child) || !child->d_inode)
1904 goto end_instantiate;
1905 inode = child->d_inode;
1906 if (inode) {
1907 ino = inode->i_ino;
1908 type = inode->i_mode >> 12;
1909 }
1910 dput(child);
1911end_instantiate:
1912 if (!ino)
1913 ino = find_inode_number(dir, &qname);
1914 if (!ino)
1915 ino = 1;
1916 return filldir(dirent, name, len, filp->f_pos, ino, type);
1917}
1918
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001919static unsigned name_to_int(struct dentry *dentry)
1920{
1921 const char *name = dentry->d_name.name;
1922 int len = dentry->d_name.len;
1923 unsigned n = 0;
1924
1925 if (len > 1 && *name == '0')
1926 goto out;
1927 while (len-- > 0) {
1928 unsigned c = *name++ - '0';
1929 if (c > 9)
1930 goto out;
1931 if (n >= (~0U-9)/10)
1932 goto out;
1933 n *= 10;
1934 n += c;
1935 }
1936 return n;
1937out:
1938 return ~0U;
1939}
1940
Miklos Szeredi27932742007-05-08 00:26:17 -07001941#define PROC_FDINFO_MAX 64
1942
Jan Blunck3dcd25f2008-02-14 19:38:35 -08001943static int proc_fd_info(struct inode *inode, struct path *path, char *info)
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001944{
1945 struct task_struct *task = get_proc_task(inode);
1946 struct files_struct *files = NULL;
1947 struct file *file;
1948 int fd = proc_fd(inode);
1949
1950 if (task) {
1951 files = get_files_struct(task);
1952 put_task_struct(task);
1953 }
1954 if (files) {
1955 /*
1956 * We are not taking a ref to the file structure, so we must
1957 * hold ->file_lock.
1958 */
1959 spin_lock(&files->file_lock);
1960 file = fcheck_files(files, fd);
1961 if (file) {
Jan Blunck3dcd25f2008-02-14 19:38:35 -08001962 if (path) {
1963 *path = file->f_path;
1964 path_get(&file->f_path);
1965 }
Miklos Szeredi27932742007-05-08 00:26:17 -07001966 if (info)
1967 snprintf(info, PROC_FDINFO_MAX,
1968 "pos:\t%lli\n"
1969 "flags:\t0%o\n",
1970 (long long) file->f_pos,
1971 file->f_flags);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001972 spin_unlock(&files->file_lock);
1973 put_files_struct(files);
1974 return 0;
1975 }
1976 spin_unlock(&files->file_lock);
1977 put_files_struct(files);
1978 }
1979 return -ENOENT;
1980}
1981
Jan Blunck3dcd25f2008-02-14 19:38:35 -08001982static int proc_fd_link(struct inode *inode, struct path *path)
Miklos Szeredi27932742007-05-08 00:26:17 -07001983{
Jan Blunck3dcd25f2008-02-14 19:38:35 -08001984 return proc_fd_info(inode, path, NULL);
Miklos Szeredi27932742007-05-08 00:26:17 -07001985}
1986
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001987static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
1988{
Nick Piggin34286d62011-01-07 17:49:57 +11001989 struct inode *inode;
1990 struct task_struct *task;
1991 int fd;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001992 struct files_struct *files;
David Howellsc69e8d92008-11-14 10:39:19 +11001993 const struct cred *cred;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07001994
Nick Piggin34286d62011-01-07 17:49:57 +11001995 if (nd && nd->flags & LOOKUP_RCU)
1996 return -ECHILD;
1997
1998 inode = dentry->d_inode;
1999 task = get_proc_task(inode);
2000 fd = proc_fd(inode);
2001
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002002 if (task) {
2003 files = get_files_struct(task);
2004 if (files) {
2005 rcu_read_lock();
2006 if (fcheck_files(files, fd)) {
2007 rcu_read_unlock();
2008 put_files_struct(files);
2009 if (task_dumpable(task)) {
David Howellsc69e8d92008-11-14 10:39:19 +11002010 rcu_read_lock();
2011 cred = __task_cred(task);
2012 inode->i_uid = cred->euid;
2013 inode->i_gid = cred->egid;
2014 rcu_read_unlock();
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002015 } else {
2016 inode->i_uid = 0;
2017 inode->i_gid = 0;
2018 }
2019 inode->i_mode &= ~(S_ISUID | S_ISGID);
2020 security_task_to_inode(task, inode);
2021 put_task_struct(task);
2022 return 1;
2023 }
2024 rcu_read_unlock();
2025 put_files_struct(files);
2026 }
2027 put_task_struct(task);
2028 }
2029 d_drop(dentry);
2030 return 0;
2031}
2032
Al Virod72f71e2009-02-20 05:58:47 +00002033static const struct dentry_operations tid_fd_dentry_operations =
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002034{
2035 .d_revalidate = tid_fd_revalidate,
2036 .d_delete = pid_delete_dentry,
2037};
2038
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002039static struct dentry *proc_fd_instantiate(struct inode *dir,
Eric Dumazetc5141e62007-05-08 00:26:15 -07002040 struct dentry *dentry, struct task_struct *task, const void *ptr)
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002041{
Eric Dumazetc5141e62007-05-08 00:26:15 -07002042 unsigned fd = *(const unsigned *)ptr;
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002043 struct file *file;
2044 struct files_struct *files;
2045 struct inode *inode;
2046 struct proc_inode *ei;
2047 struct dentry *error = ERR_PTR(-ENOENT);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002048
Eric W. Biederman61a28782006-10-02 02:18:49 -07002049 inode = proc_pid_make_inode(dir->i_sb, task);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002050 if (!inode)
2051 goto out;
2052 ei = PROC_I(inode);
2053 ei->fd = fd;
2054 files = get_files_struct(task);
2055 if (!files)
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002056 goto out_iput;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002057 inode->i_mode = S_IFLNK;
2058
2059 /*
2060 * We are not taking a ref to the file structure, so we must
2061 * hold ->file_lock.
2062 */
2063 spin_lock(&files->file_lock);
2064 file = fcheck_files(files, fd);
2065 if (!file)
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002066 goto out_unlock;
Al Viroaeb5d722008-09-02 15:28:45 -04002067 if (file->f_mode & FMODE_READ)
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002068 inode->i_mode |= S_IRUSR | S_IXUSR;
Al Viroaeb5d722008-09-02 15:28:45 -04002069 if (file->f_mode & FMODE_WRITE)
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002070 inode->i_mode |= S_IWUSR | S_IXUSR;
2071 spin_unlock(&files->file_lock);
2072 put_files_struct(files);
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002073
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002074 inode->i_op = &proc_pid_link_inode_operations;
2075 inode->i_size = 64;
2076 ei->op.proc_get_link = proc_fd_link;
Nick Pigginfb045ad2011-01-07 17:49:55 +11002077 d_set_d_op(dentry, &tid_fd_dentry_operations);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002078 d_add(dentry, inode);
2079 /* Close the race of the process dying before we return the dentry */
2080 if (tid_fd_revalidate(dentry, NULL))
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002081 error = NULL;
2082
2083 out:
2084 return error;
2085out_unlock:
2086 spin_unlock(&files->file_lock);
2087 put_files_struct(files);
2088out_iput:
2089 iput(inode);
2090 goto out;
2091}
2092
Miklos Szeredi27932742007-05-08 00:26:17 -07002093static struct dentry *proc_lookupfd_common(struct inode *dir,
2094 struct dentry *dentry,
2095 instantiate_t instantiate)
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002096{
2097 struct task_struct *task = get_proc_task(dir);
2098 unsigned fd = name_to_int(dentry);
2099 struct dentry *result = ERR_PTR(-ENOENT);
2100
2101 if (!task)
2102 goto out_no_task;
2103 if (fd == ~0U)
2104 goto out;
2105
Miklos Szeredi27932742007-05-08 00:26:17 -07002106 result = instantiate(dir, dentry, task, &fd);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002107out:
2108 put_task_struct(task);
2109out_no_task:
2110 return result;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002111}
2112
Miklos Szeredi27932742007-05-08 00:26:17 -07002113static int proc_readfd_common(struct file * filp, void * dirent,
2114 filldir_t filldir, instantiate_t instantiate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115{
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -08002116 struct dentry *dentry = filp->f_path.dentry;
Eric W. Biederman56347082006-06-26 00:25:40 -07002117 struct inode *inode = dentry->d_inode;
Eric W. Biederman99f89552006-06-26 00:25:55 -07002118 struct task_struct *p = get_proc_task(inode);
Pavel Emelyanov457c2512007-10-18 23:40:43 -07002119 unsigned int fd, ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 struct files_struct * files;
2122
2123 retval = -ENOENT;
Eric W. Biederman99f89552006-06-26 00:25:55 -07002124 if (!p)
2125 goto out_no_task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127
2128 fd = filp->f_pos;
2129 switch (fd) {
2130 case 0:
2131 if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
2132 goto out;
2133 filp->f_pos++;
2134 case 1:
Eric W. Biederman56347082006-06-26 00:25:40 -07002135 ino = parent_ino(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
2137 goto out;
2138 filp->f_pos++;
2139 default:
2140 files = get_files_struct(p);
2141 if (!files)
2142 goto out;
Dipankar Sarmab8359962005-09-09 13:04:14 -07002143 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 for (fd = filp->f_pos-2;
Al Viro9b4f5262008-04-22 01:32:44 -04002145 fd < files_fdtable(files)->max_fds;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 fd++, filp->f_pos++) {
Miklos Szeredi27932742007-05-08 00:26:17 -07002147 char name[PROC_NUMBUF];
2148 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149
2150 if (!fcheck_files(files, fd))
2151 continue;
Dipankar Sarmab8359962005-09-09 13:04:14 -07002152 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153
Miklos Szeredi27932742007-05-08 00:26:17 -07002154 len = snprintf(name, sizeof(name), "%d", fd);
2155 if (proc_fill_cache(filp, dirent, filldir,
2156 name, len, instantiate,
2157 p, &fd) < 0) {
Dipankar Sarmab8359962005-09-09 13:04:14 -07002158 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 break;
2160 }
Dipankar Sarmab8359962005-09-09 13:04:14 -07002161 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 }
Dipankar Sarmab8359962005-09-09 13:04:14 -07002163 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 put_files_struct(files);
2165 }
2166out:
Eric W. Biederman99f89552006-06-26 00:25:55 -07002167 put_task_struct(p);
2168out_no_task:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 return retval;
2170}
2171
Miklos Szeredi27932742007-05-08 00:26:17 -07002172static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,
2173 struct nameidata *nd)
2174{
2175 return proc_lookupfd_common(dir, dentry, proc_fd_instantiate);
2176}
2177
2178static int proc_readfd(struct file *filp, void *dirent, filldir_t filldir)
2179{
2180 return proc_readfd_common(filp, dirent, filldir, proc_fd_instantiate);
2181}
2182
2183static ssize_t proc_fdinfo_read(struct file *file, char __user *buf,
2184 size_t len, loff_t *ppos)
2185{
2186 char tmp[PROC_FDINFO_MAX];
Jan Blunck3dcd25f2008-02-14 19:38:35 -08002187 int err = proc_fd_info(file->f_path.dentry->d_inode, NULL, tmp);
Miklos Szeredi27932742007-05-08 00:26:17 -07002188 if (!err)
2189 err = simple_read_from_buffer(buf, len, ppos, tmp, strlen(tmp));
2190 return err;
2191}
2192
2193static const struct file_operations proc_fdinfo_file_operations = {
Arnd Bergmann87df8422010-03-17 23:06:02 +01002194 .open = nonseekable_open,
Miklos Szeredi27932742007-05-08 00:26:17 -07002195 .read = proc_fdinfo_read,
Arnd Bergmann6038f372010-08-15 18:52:59 +02002196 .llseek = no_llseek,
Miklos Szeredi27932742007-05-08 00:26:17 -07002197};
2198
Arjan van de Ven00977a52007-02-12 00:55:34 -08002199static const struct file_operations proc_fd_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 .read = generic_read_dir,
2201 .readdir = proc_readfd,
Arnd Bergmann6038f372010-08-15 18:52:59 +02002202 .llseek = default_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203};
2204
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205/*
Alexey Dobriyan8948e112007-05-08 00:23:35 -07002206 * /proc/pid/fd needs a special permission handler so that a process can still
2207 * access /proc/self/fd after it has executed a setuid().
2208 */
Nick Pigginb74c79e2011-01-07 17:49:58 +11002209static int proc_fd_permission(struct inode *inode, int mask, unsigned int flags)
Alexey Dobriyan8948e112007-05-08 00:23:35 -07002210{
2211 int rv;
2212
Nick Pigginb74c79e2011-01-07 17:49:58 +11002213 if (flags & IPERM_FLAG_RCU)
2214 return -ECHILD;
2215 rv = generic_permission(inode, mask, flags, NULL);
Alexey Dobriyan8948e112007-05-08 00:23:35 -07002216 if (rv == 0)
2217 return 0;
2218 if (task_pid(current) == proc_pid(inode))
2219 rv = 0;
2220 return rv;
2221}
2222
2223/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 * proc directories can do almost nothing..
2225 */
Arjan van de Venc5ef1c42007-02-12 00:55:40 -08002226static const struct inode_operations proc_fd_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 .lookup = proc_lookupfd,
Alexey Dobriyan8948e112007-05-08 00:23:35 -07002228 .permission = proc_fd_permission,
Linus Torvalds6d76fa52006-07-15 12:26:45 -07002229 .setattr = proc_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230};
2231
Miklos Szeredi27932742007-05-08 00:26:17 -07002232static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
2233 struct dentry *dentry, struct task_struct *task, const void *ptr)
2234{
2235 unsigned fd = *(unsigned *)ptr;
2236 struct inode *inode;
2237 struct proc_inode *ei;
2238 struct dentry *error = ERR_PTR(-ENOENT);
2239
2240 inode = proc_pid_make_inode(dir->i_sb, task);
2241 if (!inode)
2242 goto out;
2243 ei = PROC_I(inode);
2244 ei->fd = fd;
2245 inode->i_mode = S_IFREG | S_IRUSR;
2246 inode->i_fop = &proc_fdinfo_file_operations;
Nick Pigginfb045ad2011-01-07 17:49:55 +11002247 d_set_d_op(dentry, &tid_fd_dentry_operations);
Miklos Szeredi27932742007-05-08 00:26:17 -07002248 d_add(dentry, inode);
2249 /* Close the race of the process dying before we return the dentry */
2250 if (tid_fd_revalidate(dentry, NULL))
2251 error = NULL;
2252
2253 out:
2254 return error;
2255}
2256
2257static struct dentry *proc_lookupfdinfo(struct inode *dir,
2258 struct dentry *dentry,
2259 struct nameidata *nd)
2260{
2261 return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate);
2262}
2263
2264static int proc_readfdinfo(struct file *filp, void *dirent, filldir_t filldir)
2265{
2266 return proc_readfd_common(filp, dirent, filldir,
2267 proc_fdinfo_instantiate);
2268}
2269
2270static const struct file_operations proc_fdinfo_operations = {
2271 .read = generic_read_dir,
2272 .readdir = proc_readfdinfo,
Arnd Bergmann6038f372010-08-15 18:52:59 +02002273 .llseek = default_llseek,
Miklos Szeredi27932742007-05-08 00:26:17 -07002274};
2275
2276/*
2277 * proc directories can do almost nothing..
2278 */
2279static const struct inode_operations proc_fdinfo_inode_operations = {
2280 .lookup = proc_lookupfdinfo,
2281 .setattr = proc_setattr,
2282};
2283
2284
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002285static struct dentry *proc_pident_instantiate(struct inode *dir,
Eric Dumazetc5141e62007-05-08 00:26:15 -07002286 struct dentry *dentry, struct task_struct *task, const void *ptr)
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002287{
Eric Dumazetc5141e62007-05-08 00:26:15 -07002288 const struct pid_entry *p = ptr;
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002289 struct inode *inode;
2290 struct proc_inode *ei;
KOSAKI Motohirobd6daba2009-05-28 14:34:21 -07002291 struct dentry *error = ERR_PTR(-ENOENT);
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002292
Eric W. Biederman61a28782006-10-02 02:18:49 -07002293 inode = proc_pid_make_inode(dir->i_sb, task);
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002294 if (!inode)
2295 goto out;
2296
2297 ei = PROC_I(inode);
2298 inode->i_mode = p->mode;
2299 if (S_ISDIR(inode->i_mode))
2300 inode->i_nlink = 2; /* Use getattr to fix if necessary */
2301 if (p->iop)
2302 inode->i_op = p->iop;
2303 if (p->fop)
2304 inode->i_fop = p->fop;
2305 ei->op = p->op;
Nick Pigginfb045ad2011-01-07 17:49:55 +11002306 d_set_d_op(dentry, &pid_dentry_operations);
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002307 d_add(dentry, inode);
2308 /* Close the race of the process dying before we return the dentry */
2309 if (pid_revalidate(dentry, NULL))
2310 error = NULL;
2311out:
2312 return error;
2313}
2314
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315static struct dentry *proc_pident_lookup(struct inode *dir,
2316 struct dentry *dentry,
Eric Dumazetc5141e62007-05-08 00:26:15 -07002317 const struct pid_entry *ents,
Eric W. Biederman7bcd6b02006-10-02 02:18:56 -07002318 unsigned int nents)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319{
Eric W. Biedermancd6a3ce2006-06-26 00:25:49 -07002320 struct dentry *error;
Eric W. Biederman99f89552006-06-26 00:25:55 -07002321 struct task_struct *task = get_proc_task(dir);
Eric Dumazetc5141e62007-05-08 00:26:15 -07002322 const struct pid_entry *p, *last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
Eric W. Biedermancd6a3ce2006-06-26 00:25:49 -07002324 error = ERR_PTR(-ENOENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325
Eric W. Biederman99f89552006-06-26 00:25:55 -07002326 if (!task)
2327 goto out_no_task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328
Eric W. Biederman20cdc892006-10-02 02:17:07 -07002329 /*
2330 * Yes, it does not scale. And it should not. Don't add
2331 * new entries into /proc/<tgid>/ without very good reasons.
2332 */
Eric W. Biederman7bcd6b02006-10-02 02:18:56 -07002333 last = &ents[nents - 1];
2334 for (p = ents; p <= last; p++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 if (p->len != dentry->d_name.len)
2336 continue;
2337 if (!memcmp(dentry->d_name.name, p->name, p->len))
2338 break;
2339 }
Eric W. Biederman7bcd6b02006-10-02 02:18:56 -07002340 if (p > last)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 goto out;
2342
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002343 error = proc_pident_instantiate(dir, dentry, task, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344out:
Eric W. Biederman99f89552006-06-26 00:25:55 -07002345 put_task_struct(task);
2346out_no_task:
Eric W. Biedermancd6a3ce2006-06-26 00:25:49 -07002347 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348}
2349
Eric Dumazetc5141e62007-05-08 00:26:15 -07002350static int proc_pident_fill_cache(struct file *filp, void *dirent,
2351 filldir_t filldir, struct task_struct *task, const struct pid_entry *p)
Eric W. Biederman61a28782006-10-02 02:18:49 -07002352{
2353 return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
2354 proc_pident_instantiate, task, p);
2355}
2356
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002357static int proc_pident_readdir(struct file *filp,
2358 void *dirent, filldir_t filldir,
Eric Dumazetc5141e62007-05-08 00:26:15 -07002359 const struct pid_entry *ents, unsigned int nents)
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002360{
2361 int i;
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -08002362 struct dentry *dentry = filp->f_path.dentry;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002363 struct inode *inode = dentry->d_inode;
2364 struct task_struct *task = get_proc_task(inode);
Eric Dumazetc5141e62007-05-08 00:26:15 -07002365 const struct pid_entry *p, *last;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002366 ino_t ino;
2367 int ret;
2368
2369 ret = -ENOENT;
2370 if (!task)
Eric W. Biederman61a28782006-10-02 02:18:49 -07002371 goto out_no_task;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002372
2373 ret = 0;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002374 i = filp->f_pos;
2375 switch (i) {
2376 case 0:
2377 ino = inode->i_ino;
2378 if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
2379 goto out;
2380 i++;
2381 filp->f_pos++;
2382 /* fall through */
2383 case 1:
2384 ino = parent_ino(dentry);
2385 if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
2386 goto out;
2387 i++;
2388 filp->f_pos++;
2389 /* fall through */
2390 default:
2391 i -= 2;
2392 if (i >= nents) {
2393 ret = 1;
2394 goto out;
2395 }
2396 p = ents + i;
Eric W. Biederman7bcd6b02006-10-02 02:18:56 -07002397 last = &ents[nents - 1];
2398 while (p <= last) {
Eric W. Biederman61a28782006-10-02 02:18:49 -07002399 if (proc_pident_fill_cache(filp, dirent, filldir, task, p) < 0)
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002400 goto out;
2401 filp->f_pos++;
2402 p++;
2403 }
2404 }
2405
2406 ret = 1;
2407out:
Eric W. Biederman61a28782006-10-02 02:18:49 -07002408 put_task_struct(task);
2409out_no_task:
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002410 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411}
2412
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413#ifdef CONFIG_SECURITY
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002414static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
2415 size_t count, loff_t *ppos)
2416{
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -08002417 struct inode * inode = file->f_path.dentry->d_inode;
Al Viro04ff9702007-03-12 16:17:58 +00002418 char *p = NULL;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002419 ssize_t length;
2420 struct task_struct *task = get_proc_task(inode);
2421
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002422 if (!task)
Al Viro04ff9702007-03-12 16:17:58 +00002423 return -ESRCH;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002424
2425 length = security_getprocattr(task,
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -08002426 (char*)file->f_path.dentry->d_name.name,
Al Viro04ff9702007-03-12 16:17:58 +00002427 &p);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002428 put_task_struct(task);
Al Viro04ff9702007-03-12 16:17:58 +00002429 if (length > 0)
2430 length = simple_read_from_buffer(buf, count, ppos, p, length);
2431 kfree(p);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002432 return length;
2433}
2434
2435static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
2436 size_t count, loff_t *ppos)
2437{
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -08002438 struct inode * inode = file->f_path.dentry->d_inode;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002439 char *page;
2440 ssize_t length;
2441 struct task_struct *task = get_proc_task(inode);
2442
2443 length = -ESRCH;
2444 if (!task)
2445 goto out_no_task;
2446 if (count > PAGE_SIZE)
2447 count = PAGE_SIZE;
2448
2449 /* No partial writes. */
2450 length = -EINVAL;
2451 if (*ppos != 0)
2452 goto out;
2453
2454 length = -ENOMEM;
Mel Gormane12ba742007-10-16 01:25:52 -07002455 page = (char*)__get_free_page(GFP_TEMPORARY);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002456 if (!page)
2457 goto out;
2458
2459 length = -EFAULT;
2460 if (copy_from_user(page, buf, count))
2461 goto out_free;
2462
David Howells107db7c2009-05-08 13:55:27 +01002463 /* Guard against adverse ptrace interaction */
KOSAKI Motohiro9b1bf122010-10-27 15:34:08 -07002464 length = mutex_lock_interruptible(&task->signal->cred_guard_mutex);
David Howells107db7c2009-05-08 13:55:27 +01002465 if (length < 0)
2466 goto out_free;
2467
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002468 length = security_setprocattr(task,
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -08002469 (char*)file->f_path.dentry->d_name.name,
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002470 (void*)page, count);
KOSAKI Motohiro9b1bf122010-10-27 15:34:08 -07002471 mutex_unlock(&task->signal->cred_guard_mutex);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002472out_free:
2473 free_page((unsigned long) page);
2474out:
2475 put_task_struct(task);
2476out_no_task:
2477 return length;
2478}
2479
Arjan van de Ven00977a52007-02-12 00:55:34 -08002480static const struct file_operations proc_pid_attr_operations = {
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002481 .read = proc_pid_attr_read,
2482 .write = proc_pid_attr_write,
Arnd Bergmann87df8422010-03-17 23:06:02 +01002483 .llseek = generic_file_llseek,
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002484};
2485
Eric Dumazetc5141e62007-05-08 00:26:15 -07002486static const struct pid_entry attr_dir_stuff[] = {
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002487 REG("current", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
2488 REG("prev", S_IRUGO, proc_pid_attr_operations),
2489 REG("exec", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
2490 REG("fscreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
2491 REG("keycreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
2492 REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002493};
2494
Eric W. Biederman72d9dcf2006-10-02 02:18:50 -07002495static int proc_attr_dir_readdir(struct file * filp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 void * dirent, filldir_t filldir)
2497{
2498 return proc_pident_readdir(filp,dirent,filldir,
Eric W. Biederman72d9dcf2006-10-02 02:18:50 -07002499 attr_dir_stuff,ARRAY_SIZE(attr_dir_stuff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500}
2501
Arjan van de Ven00977a52007-02-12 00:55:34 -08002502static const struct file_operations proc_attr_dir_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 .read = generic_read_dir,
Eric W. Biederman72d9dcf2006-10-02 02:18:50 -07002504 .readdir = proc_attr_dir_readdir,
Arnd Bergmann6038f372010-08-15 18:52:59 +02002505 .llseek = default_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506};
2507
Eric W. Biederman72d9dcf2006-10-02 02:18:50 -07002508static struct dentry *proc_attr_dir_lookup(struct inode *dir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 struct dentry *dentry, struct nameidata *nd)
2510{
Eric W. Biederman7bcd6b02006-10-02 02:18:56 -07002511 return proc_pident_lookup(dir, dentry,
2512 attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513}
2514
Arjan van de Venc5ef1c42007-02-12 00:55:40 -08002515static const struct inode_operations proc_attr_dir_inode_operations = {
Eric W. Biederman72d9dcf2006-10-02 02:18:50 -07002516 .lookup = proc_attr_dir_lookup,
Eric W. Biederman99f89552006-06-26 00:25:55 -07002517 .getattr = pid_getattr,
Linus Torvalds6d76fa52006-07-15 12:26:45 -07002518 .setattr = proc_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519};
2520
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521#endif
2522
Christoph Hellwig698ba7b2009-12-15 16:47:37 -08002523#ifdef CONFIG_ELF_CORE
Kawai, Hidehiro3cb4a0b2007-07-19 01:48:28 -07002524static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf,
2525 size_t count, loff_t *ppos)
2526{
2527 struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
2528 struct mm_struct *mm;
2529 char buffer[PROC_NUMBUF];
2530 size_t len;
2531 int ret;
2532
2533 if (!task)
2534 return -ESRCH;
2535
2536 ret = 0;
2537 mm = get_task_mm(task);
2538 if (mm) {
2539 len = snprintf(buffer, sizeof(buffer), "%08lx\n",
2540 ((mm->flags & MMF_DUMP_FILTER_MASK) >>
2541 MMF_DUMP_FILTER_SHIFT));
2542 mmput(mm);
2543 ret = simple_read_from_buffer(buf, count, ppos, buffer, len);
2544 }
2545
2546 put_task_struct(task);
2547
2548 return ret;
2549}
2550
2551static ssize_t proc_coredump_filter_write(struct file *file,
2552 const char __user *buf,
2553 size_t count,
2554 loff_t *ppos)
2555{
2556 struct task_struct *task;
2557 struct mm_struct *mm;
2558 char buffer[PROC_NUMBUF], *end;
2559 unsigned int val;
2560 int ret;
2561 int i;
2562 unsigned long mask;
2563
2564 ret = -EFAULT;
2565 memset(buffer, 0, sizeof(buffer));
2566 if (count > sizeof(buffer) - 1)
2567 count = sizeof(buffer) - 1;
2568 if (copy_from_user(buffer, buf, count))
2569 goto out_no_task;
2570
2571 ret = -EINVAL;
2572 val = (unsigned int)simple_strtoul(buffer, &end, 0);
2573 if (*end == '\n')
2574 end++;
2575 if (end - buffer == 0)
2576 goto out_no_task;
2577
2578 ret = -ESRCH;
2579 task = get_proc_task(file->f_dentry->d_inode);
2580 if (!task)
2581 goto out_no_task;
2582
2583 ret = end - buffer;
2584 mm = get_task_mm(task);
2585 if (!mm)
2586 goto out_no_mm;
2587
2588 for (i = 0, mask = 1; i < MMF_DUMP_FILTER_BITS; i++, mask <<= 1) {
2589 if (val & mask)
2590 set_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags);
2591 else
2592 clear_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags);
2593 }
2594
2595 mmput(mm);
2596 out_no_mm:
2597 put_task_struct(task);
2598 out_no_task:
2599 return ret;
2600}
2601
2602static const struct file_operations proc_coredump_filter_operations = {
2603 .read = proc_coredump_filter_read,
2604 .write = proc_coredump_filter_write,
Arnd Bergmann87df8422010-03-17 23:06:02 +01002605 .llseek = generic_file_llseek,
Kawai, Hidehiro3cb4a0b2007-07-19 01:48:28 -07002606};
2607#endif
2608
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609/*
2610 * /proc/self:
2611 */
2612static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
2613 int buflen)
2614{
Eric W. Biederman488e5bc2008-02-08 04:18:34 -08002615 struct pid_namespace *ns = dentry->d_sb->s_fs_info;
Andrew Mortonb55fcb22008-02-08 15:00:43 -08002616 pid_t tgid = task_tgid_nr_ns(current, ns);
Eric W. Biederman8578cea2006-06-26 00:25:54 -07002617 char tmp[PROC_NUMBUF];
Andrew Mortonb55fcb22008-02-08 15:00:43 -08002618 if (!tgid)
Eric W. Biederman488e5bc2008-02-08 04:18:34 -08002619 return -ENOENT;
Andrew Mortonb55fcb22008-02-08 15:00:43 -08002620 sprintf(tmp, "%d", tgid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 return vfs_readlink(dentry,buffer,buflen,tmp);
2622}
2623
Al Viro008b1502005-08-20 00:17:39 +01002624static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625{
Eric W. Biederman488e5bc2008-02-08 04:18:34 -08002626 struct pid_namespace *ns = dentry->d_sb->s_fs_info;
Andrew Mortonb55fcb22008-02-08 15:00:43 -08002627 pid_t tgid = task_tgid_nr_ns(current, ns);
Al Viro7fee4862010-01-14 01:03:28 -05002628 char *name = ERR_PTR(-ENOENT);
2629 if (tgid) {
2630 name = __getname();
2631 if (!name)
2632 name = ERR_PTR(-ENOMEM);
2633 else
2634 sprintf(name, "%d", tgid);
2635 }
2636 nd_set_link(nd, name);
2637 return NULL;
2638}
2639
2640static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd,
2641 void *cookie)
2642{
2643 char *s = nd_get_link(nd);
2644 if (!IS_ERR(s))
2645 __putname(s);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002646}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647
Arjan van de Venc5ef1c42007-02-12 00:55:40 -08002648static const struct inode_operations proc_self_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 .readlink = proc_self_readlink,
2650 .follow_link = proc_self_follow_link,
Al Viro7fee4862010-01-14 01:03:28 -05002651 .put_link = proc_self_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652};
2653
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002654/*
Eric W. Biederman801199c2006-10-02 02:18:48 -07002655 * proc base
2656 *
2657 * These are the directory entries in the root directory of /proc
2658 * that properly belong to the /proc filesystem, as they describe
2659 * describe something that is process related.
2660 */
Eric Dumazetc5141e62007-05-08 00:26:15 -07002661static const struct pid_entry proc_base_stuff[] = {
Eric W. Biederman61a28782006-10-02 02:18:49 -07002662 NOD("self", S_IFLNK|S_IRWXUGO,
Eric W. Biederman801199c2006-10-02 02:18:48 -07002663 &proc_self_inode_operations, NULL, {}),
Eric W. Biederman801199c2006-10-02 02:18:48 -07002664};
2665
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002666static struct dentry *proc_base_instantiate(struct inode *dir,
Eric Dumazetc5141e62007-05-08 00:26:15 -07002667 struct dentry *dentry, struct task_struct *task, const void *ptr)
Eric W. Biederman801199c2006-10-02 02:18:48 -07002668{
Eric Dumazetc5141e62007-05-08 00:26:15 -07002669 const struct pid_entry *p = ptr;
Eric W. Biederman801199c2006-10-02 02:18:48 -07002670 struct inode *inode;
Eric W. Biederman801199c2006-10-02 02:18:48 -07002671 struct proc_inode *ei;
Dan Carpenter73d36462010-05-26 14:43:25 -07002672 struct dentry *error;
Eric W. Biederman801199c2006-10-02 02:18:48 -07002673
2674 /* Allocate the inode */
2675 error = ERR_PTR(-ENOMEM);
2676 inode = new_inode(dir->i_sb);
2677 if (!inode)
2678 goto out;
2679
2680 /* Initialize the inode */
2681 ei = PROC_I(inode);
Christoph Hellwig85fe4022010-10-23 11:19:54 -04002682 inode->i_ino = get_next_ino();
Eric W. Biederman801199c2006-10-02 02:18:48 -07002683 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
Eric W. Biederman801199c2006-10-02 02:18:48 -07002684
2685 /*
2686 * grab the reference to the task.
2687 */
Oleg Nesterov1a657f72006-10-02 02:18:59 -07002688 ei->pid = get_task_pid(task, PIDTYPE_PID);
Eric W. Biederman801199c2006-10-02 02:18:48 -07002689 if (!ei->pid)
2690 goto out_iput;
2691
Eric W. Biederman801199c2006-10-02 02:18:48 -07002692 inode->i_mode = p->mode;
2693 if (S_ISDIR(inode->i_mode))
2694 inode->i_nlink = 2;
2695 if (S_ISLNK(inode->i_mode))
2696 inode->i_size = 64;
2697 if (p->iop)
2698 inode->i_op = p->iop;
2699 if (p->fop)
2700 inode->i_fop = p->fop;
2701 ei->op = p->op;
Eric W. Biederman801199c2006-10-02 02:18:48 -07002702 d_add(dentry, inode);
2703 error = NULL;
2704out:
Eric W. Biederman801199c2006-10-02 02:18:48 -07002705 return error;
2706out_iput:
2707 iput(inode);
2708 goto out;
2709}
2710
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002711static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
2712{
2713 struct dentry *error;
2714 struct task_struct *task = get_proc_task(dir);
Eric Dumazetc5141e62007-05-08 00:26:15 -07002715 const struct pid_entry *p, *last;
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002716
2717 error = ERR_PTR(-ENOENT);
2718
2719 if (!task)
2720 goto out_no_task;
2721
2722 /* Lookup the directory entry */
Eric W. Biederman7bcd6b02006-10-02 02:18:56 -07002723 last = &proc_base_stuff[ARRAY_SIZE(proc_base_stuff) - 1];
2724 for (p = proc_base_stuff; p <= last; p++) {
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002725 if (p->len != dentry->d_name.len)
2726 continue;
2727 if (!memcmp(dentry->d_name.name, p->name, p->len))
2728 break;
2729 }
Eric W. Biederman7bcd6b02006-10-02 02:18:56 -07002730 if (p > last)
Eric W. Biederman444ceed2006-10-02 02:18:49 -07002731 goto out;
2732
2733 error = proc_base_instantiate(dir, dentry, task, p);
2734
2735out:
2736 put_task_struct(task);
2737out_no_task:
2738 return error;
2739}
2740
Eric Dumazetc5141e62007-05-08 00:26:15 -07002741static int proc_base_fill_cache(struct file *filp, void *dirent,
2742 filldir_t filldir, struct task_struct *task, const struct pid_entry *p)
Eric W. Biederman61a28782006-10-02 02:18:49 -07002743{
2744 return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
2745 proc_base_instantiate, task, p);
2746}
2747
Andrew Mortonaba76fd2006-12-10 02:19:48 -08002748#ifdef CONFIG_TASK_IO_ACCOUNTING
Andrea Righi297c5d92008-07-25 01:48:49 -07002749static int do_io_accounting(struct task_struct *task, char *buffer, int whole)
Andrew Mortonaba76fd2006-12-10 02:19:48 -08002750{
Andrea Righi940389b2008-07-28 00:48:12 +02002751 struct task_io_accounting acct = task->ioac;
Andrea Righi59954772008-07-27 17:29:15 +02002752 unsigned long flags;
Andrea Righi297c5d92008-07-25 01:48:49 -07002753
Andrea Righi59954772008-07-27 17:29:15 +02002754 if (whole && lock_task_sighand(task, &flags)) {
2755 struct task_struct *t = task;
Andrea Righib2d002d2008-07-26 15:22:27 -07002756
Andrea Righi59954772008-07-27 17:29:15 +02002757 task_io_accounting_add(&acct, &task->signal->ioac);
2758 while_each_thread(task, t)
2759 task_io_accounting_add(&acct, &t->ioac);
Andrea Righi297c5d92008-07-25 01:48:49 -07002760
Andrea Righi59954772008-07-27 17:29:15 +02002761 unlock_task_sighand(task, &flags);
Andrea Righi297c5d92008-07-25 01:48:49 -07002762 }
Andrew Mortonaba76fd2006-12-10 02:19:48 -08002763 return sprintf(buffer,
2764 "rchar: %llu\n"
2765 "wchar: %llu\n"
2766 "syscr: %llu\n"
2767 "syscw: %llu\n"
2768 "read_bytes: %llu\n"
2769 "write_bytes: %llu\n"
2770 "cancelled_write_bytes: %llu\n",
Alexander Beregalov7c443192008-08-05 13:01:34 -07002771 (unsigned long long)acct.rchar,
2772 (unsigned long long)acct.wchar,
2773 (unsigned long long)acct.syscr,
2774 (unsigned long long)acct.syscw,
2775 (unsigned long long)acct.read_bytes,
2776 (unsigned long long)acct.write_bytes,
2777 (unsigned long long)acct.cancelled_write_bytes);
Andrew Mortonaba76fd2006-12-10 02:19:48 -08002778}
Andrea Righi297c5d92008-07-25 01:48:49 -07002779
2780static int proc_tid_io_accounting(struct task_struct *task, char *buffer)
2781{
2782 return do_io_accounting(task, buffer, 0);
2783}
2784
2785static int proc_tgid_io_accounting(struct task_struct *task, char *buffer)
2786{
2787 return do_io_accounting(task, buffer, 1);
2788}
2789#endif /* CONFIG_TASK_IO_ACCOUNTING */
Andrew Mortonaba76fd2006-12-10 02:19:48 -08002790
Kees Cook47830722008-10-06 03:11:58 +04002791static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
2792 struct pid *pid, struct task_struct *task)
2793{
Al Viroa9712bc2011-03-23 15:52:50 -04002794 int err = lock_trace(task);
2795 if (!err) {
2796 seq_printf(m, "%08x\n", task->personality);
2797 unlock_trace(task);
2798 }
2799 return err;
Kees Cook47830722008-10-06 03:11:58 +04002800}
2801
Eric W. Biederman801199c2006-10-02 02:18:48 -07002802/*
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002803 * Thread groups
2804 */
Arjan van de Ven00977a52007-02-12 00:55:34 -08002805static const struct file_operations proc_task_operations;
Arjan van de Venc5ef1c42007-02-12 00:55:40 -08002806static const struct inode_operations proc_task_inode_operations;
Eric W. Biederman20cdc892006-10-02 02:17:07 -07002807
Eric Dumazetc5141e62007-05-08 00:26:15 -07002808static const struct pid_entry tgid_base_stuff[] = {
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002809 DIR("task", S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations),
2810 DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
2811 DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations),
Eric W. Biederman6b4e3062010-03-07 16:41:34 -08002812 DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations),
Andrew Mortonb2211a32008-03-11 18:03:35 -07002813#ifdef CONFIG_NET
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002814 DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations),
Andrew Mortonb2211a32008-03-11 18:03:35 -07002815#endif
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002816 REG("environ", S_IRUSR, proc_environ_operations),
2817 INF("auxv", S_IRUSR, proc_pid_auxv),
2818 ONE("status", S_IRUGO, proc_pid_status),
Al Viroa9712bc2011-03-23 15:52:50 -04002819 ONE("personality", S_IRUGO, proc_pid_personality),
Jiri Olsa3036e7b2010-09-30 15:15:33 -07002820 INF("limits", S_IRUGO, proc_pid_limits),
Ingo Molnar43ae34c2007-07-09 18:52:00 +02002821#ifdef CONFIG_SCHED_DEBUG
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002822 REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
Ingo Molnar43ae34c2007-07-09 18:52:00 +02002823#endif
Mike Galbraith5091faa2010-11-30 14:18:03 +01002824#ifdef CONFIG_SCHED_AUTOGROUP
2825 REG("autogroup", S_IRUGO|S_IWUSR, proc_pid_sched_autogroup_operations),
2826#endif
john stultz4614a696b2009-12-14 18:00:05 -08002827 REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
Roland McGrathebcb6732008-07-25 19:46:00 -07002828#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
Al Viroa9712bc2011-03-23 15:52:50 -04002829 INF("syscall", S_IRUGO, proc_pid_syscall),
Roland McGrathebcb6732008-07-25 19:46:00 -07002830#endif
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002831 INF("cmdline", S_IRUGO, proc_pid_cmdline),
2832 ONE("stat", S_IRUGO, proc_tgid_stat),
2833 ONE("statm", S_IRUGO, proc_pid_statm),
2834 REG("maps", S_IRUGO, proc_maps_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002835#ifdef CONFIG_NUMA
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002836 REG("numa_maps", S_IRUGO, proc_numa_maps_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002837#endif
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002838 REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations),
2839 LNK("cwd", proc_cwd_link),
2840 LNK("root", proc_root_link),
2841 LNK("exe", proc_exe_link),
2842 REG("mounts", S_IRUGO, proc_mounts_operations),
2843 REG("mountinfo", S_IRUGO, proc_mountinfo_operations),
2844 REG("mountstats", S_IRUSR, proc_mountstats_operations),
Matt Mackall1e883282008-02-04 22:29:07 -08002845#ifdef CONFIG_PROC_PAGE_MONITOR
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002846 REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
2847 REG("smaps", S_IRUGO, proc_smaps_operations),
Al Viroca6b0bf2011-02-15 22:04:37 -05002848 REG("pagemap", S_IRUGO, proc_pagemap_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002849#endif
2850#ifdef CONFIG_SECURITY
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002851 DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002852#endif
2853#ifdef CONFIG_KALLSYMS
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002854 INF("wchan", S_IRUGO, proc_pid_wchan),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002855#endif
Ken Chen2ec220e2008-11-10 11:26:08 +03002856#ifdef CONFIG_STACKTRACE
Al Viroa9712bc2011-03-23 15:52:50 -04002857 ONE("stack", S_IRUGO, proc_pid_stack),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002858#endif
2859#ifdef CONFIG_SCHEDSTATS
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002860 INF("schedstat", S_IRUGO, proc_pid_schedstat),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002861#endif
Arjan van de Ven97455122008-01-25 21:08:34 +01002862#ifdef CONFIG_LATENCYTOP
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002863 REG("latency", S_IRUGO, proc_lstats_operations),
Arjan van de Ven97455122008-01-25 21:08:34 +01002864#endif
Paul Menage8793d852007-10-18 23:39:39 -07002865#ifdef CONFIG_PROC_PID_CPUSET
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002866 REG("cpuset", S_IRUGO, proc_cpuset_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002867#endif
Paul Menagea4243162007-10-18 23:39:35 -07002868#ifdef CONFIG_CGROUPS
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002869 REG("cgroup", S_IRUGO, proc_cgroup_operations),
Paul Menagea4243162007-10-18 23:39:35 -07002870#endif
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002871 INF("oom_score", S_IRUGO, proc_oom_score),
Mike Chan766e9932008-04-24 10:22:26 -07002872 ANDROID("oom_adj",S_IRUGO|S_IWUSR, oom_adjust),
David Rientjesa63d83f2010-08-09 17:19:46 -07002873 REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002874#ifdef CONFIG_AUDITSYSCALL
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002875 REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
2876 REG("sessionid", S_IRUGO, proc_sessionid_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002877#endif
Akinobu Mitaf4f154f2006-12-08 02:39:47 -08002878#ifdef CONFIG_FAULT_INJECTION
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002879 REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations),
Akinobu Mitaf4f154f2006-12-08 02:39:47 -08002880#endif
Christoph Hellwig698ba7b2009-12-15 16:47:37 -08002881#ifdef CONFIG_ELF_CORE
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002882 REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations),
Kawai, Hidehiro3cb4a0b2007-07-19 01:48:28 -07002883#endif
Andrew Mortonaba76fd2006-12-10 02:19:48 -08002884#ifdef CONFIG_TASK_IO_ACCOUNTING
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03002885 INF("io", S_IRUGO, proc_tgid_io_accounting),
Andrew Mortonaba76fd2006-12-10 02:19:48 -08002886#endif
Chris Metcalff133ecc2011-05-26 12:40:09 -04002887#ifdef CONFIG_HARDWALL
2888 INF("hardwall", S_IRUGO, proc_pid_hardwall),
2889#endif
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002890};
2891
2892static int proc_tgid_base_readdir(struct file * filp,
2893 void * dirent, filldir_t filldir)
2894{
2895 return proc_pident_readdir(filp,dirent,filldir,
2896 tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff));
2897}
2898
Arjan van de Ven00977a52007-02-12 00:55:34 -08002899static const struct file_operations proc_tgid_base_operations = {
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002900 .read = generic_read_dir,
2901 .readdir = proc_tgid_base_readdir,
Arnd Bergmann6038f372010-08-15 18:52:59 +02002902 .llseek = default_llseek,
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002903};
2904
2905static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
Eric W. Biederman7bcd6b02006-10-02 02:18:56 -07002906 return proc_pident_lookup(dir, dentry,
2907 tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff));
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002908}
2909
Arjan van de Venc5ef1c42007-02-12 00:55:40 -08002910static const struct inode_operations proc_tgid_base_inode_operations = {
Eric W. Biederman28a6d672006-10-02 02:17:05 -07002911 .lookup = proc_tgid_base_lookup,
2912 .getattr = pid_getattr,
2913 .setattr = proc_setattr,
2914};
2915
Pavel Emelyanov60347f62007-10-18 23:40:03 -07002916static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917{
Eric W. Biederman48e64842006-06-26 00:25:48 -07002918 struct dentry *dentry, *leader, *dir;
Eric W. Biederman8578cea2006-06-26 00:25:54 -07002919 char buf[PROC_NUMBUF];
Eric W. Biederman48e64842006-06-26 00:25:48 -07002920 struct qstr name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921
Eric W. Biederman48e64842006-06-26 00:25:48 -07002922 name.name = buf;
Pavel Emelyanov60347f62007-10-18 23:40:03 -07002923 name.len = snprintf(buf, sizeof(buf), "%d", pid);
2924 dentry = d_hash_and_lookup(mnt->mnt_root, &name);
Eric W. Biederman48e64842006-06-26 00:25:48 -07002925 if (dentry) {
Sukadev Bhattiprolu29f12ca2009-11-11 14:26:32 -08002926 shrink_dcache_parent(dentry);
Eric W. Biederman48e64842006-06-26 00:25:48 -07002927 d_drop(dentry);
2928 dput(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930
Eric W. Biederman48e64842006-06-26 00:25:48 -07002931 name.name = buf;
Pavel Emelyanov60347f62007-10-18 23:40:03 -07002932 name.len = snprintf(buf, sizeof(buf), "%d", tgid);
2933 leader = d_hash_and_lookup(mnt->mnt_root, &name);
Eric W. Biederman48e64842006-06-26 00:25:48 -07002934 if (!leader)
2935 goto out;
2936
2937 name.name = "task";
2938 name.len = strlen(name.name);
2939 dir = d_hash_and_lookup(leader, &name);
2940 if (!dir)
2941 goto out_put_leader;
2942
2943 name.name = buf;
Pavel Emelyanov60347f62007-10-18 23:40:03 -07002944 name.len = snprintf(buf, sizeof(buf), "%d", pid);
Eric W. Biederman48e64842006-06-26 00:25:48 -07002945 dentry = d_hash_and_lookup(dir, &name);
2946 if (dentry) {
2947 shrink_dcache_parent(dentry);
2948 d_drop(dentry);
2949 dput(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 }
Eric W. Biederman48e64842006-06-26 00:25:48 -07002951
2952 dput(dir);
2953out_put_leader:
2954 dput(leader);
2955out:
2956 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957}
2958
Randy Dunlap0895e912007-10-21 21:00:10 -07002959/**
2960 * proc_flush_task - Remove dcache entries for @task from the /proc dcache.
2961 * @task: task that should be flushed.
2962 *
2963 * When flushing dentries from proc, one needs to flush them from global
Pavel Emelyanov60347f62007-10-18 23:40:03 -07002964 * proc (proc_mnt) and from all the namespaces' procs this task was seen
Randy Dunlap0895e912007-10-21 21:00:10 -07002965 * in. This call is supposed to do all of this job.
2966 *
2967 * Looks in the dcache for
2968 * /proc/@pid
2969 * /proc/@tgid/task/@pid
2970 * if either directory is present flushes it and all of it'ts children
2971 * from the dcache.
2972 *
2973 * It is safe and reasonable to cache /proc entries for a task until
2974 * that task exits. After that they just clog up the dcache with
2975 * useless entries, possibly causing useful dcache entries to be
2976 * flushed instead. This routine is proved to flush those useless
2977 * dcache entries at process exit time.
2978 *
2979 * NOTE: This routine is just an optimization so it does not guarantee
2980 * that no dcache entries will exist at process exit time it
2981 * just makes it very unlikely that any will persist.
Pavel Emelyanov60347f62007-10-18 23:40:03 -07002982 */
2983
2984void proc_flush_task(struct task_struct *task)
2985{
Eric W. Biederman9fcc2d12007-11-14 17:00:07 -08002986 int i;
Oleg Nesterov9b4d1cbe2009-09-22 16:45:34 -07002987 struct pid *pid, *tgid;
Pavel Emelyanov130f77e2007-10-18 23:40:11 -07002988 struct upid *upid;
2989
Pavel Emelyanov130f77e2007-10-18 23:40:11 -07002990 pid = task_pid(task);
Oleg Nesterov9b4d1cbe2009-09-22 16:45:34 -07002991 tgid = task_tgid(task);
Pavel Emelyanov130f77e2007-10-18 23:40:11 -07002992
Eric W. Biederman9fcc2d12007-11-14 17:00:07 -08002993 for (i = 0; i <= pid->level; i++) {
Pavel Emelyanov130f77e2007-10-18 23:40:11 -07002994 upid = &pid->numbers[i];
2995 proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr,
Oleg Nesterov9b4d1cbe2009-09-22 16:45:34 -07002996 tgid->numbers[i].nr);
Pavel Emelyanov130f77e2007-10-18 23:40:11 -07002997 }
Pavel Emelyanov6f4e6432007-10-18 23:40:11 -07002998
2999 upid = &pid->numbers[pid->level];
3000 if (upid->nr == 1)
3001 pid_ns_release_proc(upid->ns);
Pavel Emelyanov60347f62007-10-18 23:40:03 -07003002}
3003
Adrian Bunk9711ef92006-12-06 20:38:31 -08003004static struct dentry *proc_pid_instantiate(struct inode *dir,
3005 struct dentry * dentry,
Eric Dumazetc5141e62007-05-08 00:26:15 -07003006 struct task_struct *task, const void *ptr)
Eric W. Biederman444ceed2006-10-02 02:18:49 -07003007{
3008 struct dentry *error = ERR_PTR(-ENOENT);
3009 struct inode *inode;
3010
Eric W. Biederman61a28782006-10-02 02:18:49 -07003011 inode = proc_pid_make_inode(dir->i_sb, task);
Eric W. Biederman444ceed2006-10-02 02:18:49 -07003012 if (!inode)
3013 goto out;
3014
3015 inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
3016 inode->i_op = &proc_tgid_base_inode_operations;
3017 inode->i_fop = &proc_tgid_base_operations;
3018 inode->i_flags|=S_IMMUTABLE;
Vegard Nossumaed54172008-06-05 22:46:53 -07003019
3020 inode->i_nlink = 2 + pid_entry_count_dirs(tgid_base_stuff,
3021 ARRAY_SIZE(tgid_base_stuff));
Eric W. Biederman444ceed2006-10-02 02:18:49 -07003022
Nick Pigginfb045ad2011-01-07 17:49:55 +11003023 d_set_d_op(dentry, &pid_dentry_operations);
Eric W. Biederman444ceed2006-10-02 02:18:49 -07003024
3025 d_add(dentry, inode);
3026 /* Close the race of the process dying before we return the dentry */
3027 if (pid_revalidate(dentry, NULL))
3028 error = NULL;
3029out:
3030 return error;
3031}
3032
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
3034{
Dan Carpenter73d36462010-05-26 14:43:25 -07003035 struct dentry *result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 struct task_struct *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 unsigned tgid;
Pavel Emelyanovb4888932007-10-18 23:40:14 -07003038 struct pid_namespace *ns;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039
Eric W. Biederman801199c2006-10-02 02:18:48 -07003040 result = proc_base_lookup(dir, dentry);
3041 if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT)
3042 goto out;
3043
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 tgid = name_to_int(dentry);
3045 if (tgid == ~0U)
3046 goto out;
3047
Pavel Emelyanovb4888932007-10-18 23:40:14 -07003048 ns = dentry->d_sb->s_fs_info;
Eric W. Biedermande758732006-06-26 00:25:51 -07003049 rcu_read_lock();
Pavel Emelyanovb4888932007-10-18 23:40:14 -07003050 task = find_task_by_pid_ns(tgid, ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 if (task)
3052 get_task_struct(task);
Eric W. Biedermande758732006-06-26 00:25:51 -07003053 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 if (!task)
3055 goto out;
3056
Eric W. Biederman444ceed2006-10-02 02:18:49 -07003057 result = proc_pid_instantiate(dir, dentry, task, NULL);
Eric W. Biederman48e64842006-06-26 00:25:48 -07003058 put_task_struct(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059out:
Eric W. Biedermancd6a3ce2006-06-26 00:25:49 -07003060 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061}
3062
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063/*
Eric W. Biederman0804ef42006-10-02 02:17:04 -07003064 * Find the first task with tgid >= tgid
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003065 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 */
Eric W. Biederman19fd4bb2007-11-28 16:21:26 -08003067struct tgid_iter {
3068 unsigned int tgid;
Eric W. Biederman0804ef42006-10-02 02:17:04 -07003069 struct task_struct *task;
Eric W. Biederman19fd4bb2007-11-28 16:21:26 -08003070};
3071static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter iter)
3072{
Eric W. Biederman0804ef42006-10-02 02:17:04 -07003073 struct pid *pid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074
Eric W. Biederman19fd4bb2007-11-28 16:21:26 -08003075 if (iter.task)
3076 put_task_struct(iter.task);
Eric W. Biederman0804ef42006-10-02 02:17:04 -07003077 rcu_read_lock();
3078retry:
Eric W. Biederman19fd4bb2007-11-28 16:21:26 -08003079 iter.task = NULL;
3080 pid = find_ge_pid(iter.tgid, ns);
Eric W. Biederman0804ef42006-10-02 02:17:04 -07003081 if (pid) {
Eric W. Biederman19fd4bb2007-11-28 16:21:26 -08003082 iter.tgid = pid_nr_ns(pid, ns);
3083 iter.task = pid_task(pid, PIDTYPE_PID);
Eric W. Biederman0804ef42006-10-02 02:17:04 -07003084 /* What we to know is if the pid we have find is the
3085 * pid of a thread_group_leader. Testing for task
3086 * being a thread_group_leader is the obvious thing
3087 * todo but there is a window when it fails, due to
3088 * the pid transfer logic in de_thread.
3089 *
3090 * So we perform the straight forward test of seeing
3091 * if the pid we have found is the pid of a thread
3092 * group leader, and don't worry if the task we have
3093 * found doesn't happen to be a thread group leader.
3094 * As we don't care in the case of readdir.
3095 */
Eric W. Biederman19fd4bb2007-11-28 16:21:26 -08003096 if (!iter.task || !has_group_leader_pid(iter.task)) {
3097 iter.tgid += 1;
Eric W. Biederman0804ef42006-10-02 02:17:04 -07003098 goto retry;
Eric W. Biederman19fd4bb2007-11-28 16:21:26 -08003099 }
3100 get_task_struct(iter.task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 }
Eric W. Biederman454cc102006-06-26 00:25:51 -07003102 rcu_read_unlock();
Eric W. Biederman19fd4bb2007-11-28 16:21:26 -08003103 return iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104}
3105
Eric W. Biederman7bcd6b02006-10-02 02:18:56 -07003106#define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107
Eric W. Biederman61a28782006-10-02 02:18:49 -07003108static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
Eric W. Biederman19fd4bb2007-11-28 16:21:26 -08003109 struct tgid_iter iter)
Eric W. Biederman61a28782006-10-02 02:18:49 -07003110{
3111 char name[PROC_NUMBUF];
Eric W. Biederman19fd4bb2007-11-28 16:21:26 -08003112 int len = snprintf(name, sizeof(name), "%d", iter.tgid);
Eric W. Biederman61a28782006-10-02 02:18:49 -07003113 return proc_fill_cache(filp, dirent, filldir, name, len,
Eric W. Biederman19fd4bb2007-11-28 16:21:26 -08003114 proc_pid_instantiate, iter.task, NULL);
Eric W. Biederman61a28782006-10-02 02:18:49 -07003115}
3116
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117/* for the /proc/ directory itself, after non-process stuff has been done */
3118int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
3119{
Linus Torvaldsd8bdc592011-04-18 10:36:54 -07003120 unsigned int nr;
3121 struct task_struct *reaper;
Eric W. Biederman19fd4bb2007-11-28 16:21:26 -08003122 struct tgid_iter iter;
Pavel Emelyanovb4888932007-10-18 23:40:14 -07003123 struct pid_namespace *ns;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124
Linus Torvaldsd8bdc592011-04-18 10:36:54 -07003125 if (filp->f_pos >= PID_MAX_LIMIT + TGID_OFFSET)
3126 goto out_no_task;
3127 nr = filp->f_pos - FIRST_PROCESS_ENTRY;
3128
3129 reaper = get_proc_task(filp->f_path.dentry->d_inode);
Eric W. Biederman61a28782006-10-02 02:18:49 -07003130 if (!reaper)
3131 goto out_no_task;
3132
Eric W. Biederman7bcd6b02006-10-02 02:18:56 -07003133 for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) {
Eric Dumazetc5141e62007-05-08 00:26:15 -07003134 const struct pid_entry *p = &proc_base_stuff[nr];
Eric W. Biederman61a28782006-10-02 02:18:49 -07003135 if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0)
Eric W. Biederman801199c2006-10-02 02:18:48 -07003136 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 }
3138
Pavel Emelyanovb4888932007-10-18 23:40:14 -07003139 ns = filp->f_dentry->d_sb->s_fs_info;
Eric W. Biederman19fd4bb2007-11-28 16:21:26 -08003140 iter.task = NULL;
3141 iter.tgid = filp->f_pos - TGID_OFFSET;
3142 for (iter = next_tgid(ns, iter);
3143 iter.task;
3144 iter.tgid += 1, iter = next_tgid(ns, iter)) {
3145 filp->f_pos = iter.tgid + TGID_OFFSET;
3146 if (proc_pid_fill_cache(filp, dirent, filldir, iter) < 0) {
3147 put_task_struct(iter.task);
Eric W. Biederman0804ef42006-10-02 02:17:04 -07003148 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 }
Eric W. Biederman0804ef42006-10-02 02:17:04 -07003151 filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET;
3152out:
Eric W. Biederman61a28782006-10-02 02:18:49 -07003153 put_task_struct(reaper);
3154out_no_task:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 return 0;
3156}
3157
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003158/*
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003159 * Tasks
3160 */
Eric Dumazetc5141e62007-05-08 00:26:15 -07003161static const struct pid_entry tid_base_stuff[] = {
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003162 DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
Jerome Marchand38355412010-04-27 13:13:06 -07003163 DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations),
Eric W. Biederman6b4e3062010-03-07 16:41:34 -08003164 DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations),
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003165 REG("environ", S_IRUSR, proc_environ_operations),
3166 INF("auxv", S_IRUSR, proc_pid_auxv),
3167 ONE("status", S_IRUGO, proc_pid_status),
Al Viroa9712bc2011-03-23 15:52:50 -04003168 ONE("personality", S_IRUGO, proc_pid_personality),
Jiri Olsa3036e7b2010-09-30 15:15:33 -07003169 INF("limits", S_IRUGO, proc_pid_limits),
Ingo Molnar43ae34c2007-07-09 18:52:00 +02003170#ifdef CONFIG_SCHED_DEBUG
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003171 REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
Ingo Molnar43ae34c2007-07-09 18:52:00 +02003172#endif
john stultz4614a696b2009-12-14 18:00:05 -08003173 REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
Roland McGrathebcb6732008-07-25 19:46:00 -07003174#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
Al Viroa9712bc2011-03-23 15:52:50 -04003175 INF("syscall", S_IRUGO, proc_pid_syscall),
Roland McGrathebcb6732008-07-25 19:46:00 -07003176#endif
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003177 INF("cmdline", S_IRUGO, proc_pid_cmdline),
3178 ONE("stat", S_IRUGO, proc_tid_stat),
3179 ONE("statm", S_IRUGO, proc_pid_statm),
3180 REG("maps", S_IRUGO, proc_maps_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003181#ifdef CONFIG_NUMA
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003182 REG("numa_maps", S_IRUGO, proc_numa_maps_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003183#endif
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003184 REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations),
3185 LNK("cwd", proc_cwd_link),
3186 LNK("root", proc_root_link),
3187 LNK("exe", proc_exe_link),
3188 REG("mounts", S_IRUGO, proc_mounts_operations),
3189 REG("mountinfo", S_IRUGO, proc_mountinfo_operations),
Matt Mackall1e883282008-02-04 22:29:07 -08003190#ifdef CONFIG_PROC_PAGE_MONITOR
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003191 REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
3192 REG("smaps", S_IRUGO, proc_smaps_operations),
Al Viroca6b0bf2011-02-15 22:04:37 -05003193 REG("pagemap", S_IRUGO, proc_pagemap_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003194#endif
3195#ifdef CONFIG_SECURITY
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003196 DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003197#endif
3198#ifdef CONFIG_KALLSYMS
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003199 INF("wchan", S_IRUGO, proc_pid_wchan),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003200#endif
Ken Chen2ec220e2008-11-10 11:26:08 +03003201#ifdef CONFIG_STACKTRACE
Al Viroa9712bc2011-03-23 15:52:50 -04003202 ONE("stack", S_IRUGO, proc_pid_stack),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003203#endif
3204#ifdef CONFIG_SCHEDSTATS
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003205 INF("schedstat", S_IRUGO, proc_pid_schedstat),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003206#endif
Arjan van de Ven97455122008-01-25 21:08:34 +01003207#ifdef CONFIG_LATENCYTOP
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003208 REG("latency", S_IRUGO, proc_lstats_operations),
Arjan van de Ven97455122008-01-25 21:08:34 +01003209#endif
Paul Menage8793d852007-10-18 23:39:39 -07003210#ifdef CONFIG_PROC_PID_CPUSET
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003211 REG("cpuset", S_IRUGO, proc_cpuset_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003212#endif
Paul Menagea4243162007-10-18 23:39:35 -07003213#ifdef CONFIG_CGROUPS
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003214 REG("cgroup", S_IRUGO, proc_cgroup_operations),
Paul Menagea4243162007-10-18 23:39:35 -07003215#endif
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003216 INF("oom_score", S_IRUGO, proc_oom_score),
3217 REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_operations),
David Rientjesa63d83f2010-08-09 17:19:46 -07003218 REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003219#ifdef CONFIG_AUDITSYSCALL
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003220 REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
Al Viro26ec3c62011-02-15 21:24:05 -05003221 REG("sessionid", S_IRUGO, proc_sessionid_operations),
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003222#endif
Akinobu Mitaf4f154f2006-12-08 02:39:47 -08003223#ifdef CONFIG_FAULT_INJECTION
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003224 REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations),
Akinobu Mitaf4f154f2006-12-08 02:39:47 -08003225#endif
Andrea Righi297c5d92008-07-25 01:48:49 -07003226#ifdef CONFIG_TASK_IO_ACCOUNTING
Alexey Dobriyan631f9c12008-11-10 01:32:52 +03003227 INF("io", S_IRUGO, proc_tid_io_accounting),
Andrea Righi297c5d92008-07-25 01:48:49 -07003228#endif
Chris Metcalff133ecc2011-05-26 12:40:09 -04003229#ifdef CONFIG_HARDWALL
3230 INF("hardwall", S_IRUGO, proc_pid_hardwall),
3231#endif
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003232};
3233
3234static int proc_tid_base_readdir(struct file * filp,
3235 void * dirent, filldir_t filldir)
3236{
3237 return proc_pident_readdir(filp,dirent,filldir,
3238 tid_base_stuff,ARRAY_SIZE(tid_base_stuff));
3239}
3240
3241static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
Eric W. Biederman7bcd6b02006-10-02 02:18:56 -07003242 return proc_pident_lookup(dir, dentry,
3243 tid_base_stuff, ARRAY_SIZE(tid_base_stuff));
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003244}
3245
Arjan van de Ven00977a52007-02-12 00:55:34 -08003246static const struct file_operations proc_tid_base_operations = {
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003247 .read = generic_read_dir,
3248 .readdir = proc_tid_base_readdir,
Arnd Bergmann6038f372010-08-15 18:52:59 +02003249 .llseek = default_llseek,
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003250};
3251
Arjan van de Venc5ef1c42007-02-12 00:55:40 -08003252static const struct inode_operations proc_tid_base_inode_operations = {
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003253 .lookup = proc_tid_base_lookup,
3254 .getattr = pid_getattr,
3255 .setattr = proc_setattr,
3256};
3257
Eric W. Biederman444ceed2006-10-02 02:18:49 -07003258static struct dentry *proc_task_instantiate(struct inode *dir,
Eric Dumazetc5141e62007-05-08 00:26:15 -07003259 struct dentry *dentry, struct task_struct *task, const void *ptr)
Eric W. Biederman444ceed2006-10-02 02:18:49 -07003260{
3261 struct dentry *error = ERR_PTR(-ENOENT);
3262 struct inode *inode;
Eric W. Biederman61a28782006-10-02 02:18:49 -07003263 inode = proc_pid_make_inode(dir->i_sb, task);
Eric W. Biederman444ceed2006-10-02 02:18:49 -07003264
3265 if (!inode)
3266 goto out;
3267 inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
3268 inode->i_op = &proc_tid_base_inode_operations;
3269 inode->i_fop = &proc_tid_base_operations;
3270 inode->i_flags|=S_IMMUTABLE;
Vegard Nossumaed54172008-06-05 22:46:53 -07003271
3272 inode->i_nlink = 2 + pid_entry_count_dirs(tid_base_stuff,
3273 ARRAY_SIZE(tid_base_stuff));
Eric W. Biederman444ceed2006-10-02 02:18:49 -07003274
Nick Pigginfb045ad2011-01-07 17:49:55 +11003275 d_set_d_op(dentry, &pid_dentry_operations);
Eric W. Biederman444ceed2006-10-02 02:18:49 -07003276
3277 d_add(dentry, inode);
3278 /* Close the race of the process dying before we return the dentry */
3279 if (pid_revalidate(dentry, NULL))
3280 error = NULL;
3281out:
3282 return error;
3283}
3284
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003285static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
3286{
3287 struct dentry *result = ERR_PTR(-ENOENT);
3288 struct task_struct *task;
3289 struct task_struct *leader = get_proc_task(dir);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003290 unsigned tid;
Pavel Emelyanovb4888932007-10-18 23:40:14 -07003291 struct pid_namespace *ns;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003292
3293 if (!leader)
3294 goto out_no_task;
3295
3296 tid = name_to_int(dentry);
3297 if (tid == ~0U)
3298 goto out;
3299
Pavel Emelyanovb4888932007-10-18 23:40:14 -07003300 ns = dentry->d_sb->s_fs_info;
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003301 rcu_read_lock();
Pavel Emelyanovb4888932007-10-18 23:40:14 -07003302 task = find_task_by_pid_ns(tid, ns);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003303 if (task)
3304 get_task_struct(task);
3305 rcu_read_unlock();
3306 if (!task)
3307 goto out;
Pavel Emelyanovbac0abd2007-10-18 23:40:18 -07003308 if (!same_thread_group(leader, task))
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003309 goto out_drop_task;
3310
Eric W. Biederman444ceed2006-10-02 02:18:49 -07003311 result = proc_task_instantiate(dir, dentry, task, NULL);
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003312out_drop_task:
3313 put_task_struct(task);
3314out:
3315 put_task_struct(leader);
3316out_no_task:
3317 return result;
3318}
3319
3320/*
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003321 * Find the first tid of a thread group to return to user space.
3322 *
3323 * Usually this is just the thread group leader, but if the users
3324 * buffer was too small or there was a seek into the middle of the
3325 * directory we have more work todo.
3326 *
3327 * In the case of a short read we start with find_task_by_pid.
3328 *
3329 * In the case of a seek we start with the leader and walk nr
3330 * threads past it.
3331 */
Eric W. Biedermancc288732006-06-26 00:26:01 -07003332static struct task_struct *first_tid(struct task_struct *leader,
Pavel Emelyanovb4888932007-10-18 23:40:14 -07003333 int tid, int nr, struct pid_namespace *ns)
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003334{
Oleg Nesterova872ff02006-06-26 00:26:01 -07003335 struct task_struct *pos;
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003336
Eric W. Biedermancc288732006-06-26 00:26:01 -07003337 rcu_read_lock();
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003338 /* Attempt to start with the pid of a thread */
3339 if (tid && (nr > 0)) {
Pavel Emelyanovb4888932007-10-18 23:40:14 -07003340 pos = find_task_by_pid_ns(tid, ns);
Oleg Nesterova872ff02006-06-26 00:26:01 -07003341 if (pos && (pos->group_leader == leader))
3342 goto found;
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003343 }
3344
3345 /* If nr exceeds the number of threads there is nothing todo */
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003346 pos = NULL;
Oleg Nesterova872ff02006-06-26 00:26:01 -07003347 if (nr && nr >= get_nr_threads(leader))
3348 goto out;
3349
3350 /* If we haven't found our starting place yet start
3351 * with the leader and walk nr threads forward.
3352 */
3353 for (pos = leader; nr > 0; --nr) {
3354 pos = next_thread(pos);
3355 if (pos == leader) {
3356 pos = NULL;
3357 goto out;
3358 }
3359 }
3360found:
3361 get_task_struct(pos);
3362out:
Eric W. Biedermancc288732006-06-26 00:26:01 -07003363 rcu_read_unlock();
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003364 return pos;
3365}
3366
3367/*
3368 * Find the next thread in the thread list.
3369 * Return NULL if there is an error or no next thread.
3370 *
3371 * The reference to the input task_struct is released.
3372 */
3373static struct task_struct *next_tid(struct task_struct *start)
3374{
Oleg Nesterovc1df7fb2006-06-26 00:26:02 -07003375 struct task_struct *pos = NULL;
Eric W. Biedermancc288732006-06-26 00:26:01 -07003376 rcu_read_lock();
Oleg Nesterovc1df7fb2006-06-26 00:26:02 -07003377 if (pid_alive(start)) {
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003378 pos = next_thread(start);
Oleg Nesterovc1df7fb2006-06-26 00:26:02 -07003379 if (thread_group_leader(pos))
3380 pos = NULL;
3381 else
3382 get_task_struct(pos);
3383 }
Eric W. Biedermancc288732006-06-26 00:26:01 -07003384 rcu_read_unlock();
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003385 put_task_struct(start);
3386 return pos;
3387}
3388
Eric W. Biederman61a28782006-10-02 02:18:49 -07003389static int proc_task_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
3390 struct task_struct *task, int tid)
3391{
3392 char name[PROC_NUMBUF];
3393 int len = snprintf(name, sizeof(name), "%d", tid);
3394 return proc_fill_cache(filp, dirent, filldir, name, len,
3395 proc_task_instantiate, task, NULL);
3396}
3397
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398/* for the /proc/TGID/task/ directories */
3399static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir)
3400{
Josef "Jeff" Sipek2fddfee2006-12-08 02:36:36 -08003401 struct dentry *dentry = filp->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 struct inode *inode = dentry->d_inode;
Guillaume Chazarain7d895242007-01-31 23:48:14 -08003403 struct task_struct *leader = NULL;
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003404 struct task_struct *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 int retval = -ENOENT;
3406 ino_t ino;
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003407 int tid;
Pavel Emelyanovb4888932007-10-18 23:40:14 -07003408 struct pid_namespace *ns;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409
Guillaume Chazarain7d895242007-01-31 23:48:14 -08003410 task = get_proc_task(inode);
3411 if (!task)
3412 goto out_no_task;
3413 rcu_read_lock();
3414 if (pid_alive(task)) {
3415 leader = task->group_leader;
3416 get_task_struct(leader);
3417 }
3418 rcu_read_unlock();
3419 put_task_struct(task);
Eric W. Biederman99f89552006-06-26 00:25:55 -07003420 if (!leader)
3421 goto out_no_task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 retval = 0;
3423
Linus Torvaldsee568b22009-03-17 10:02:35 -07003424 switch ((unsigned long)filp->f_pos) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 case 0:
3426 ino = inode->i_ino;
Zhang Leee6f7792009-03-16 14:44:31 +08003427 if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 goto out;
Zhang Leee6f7792009-03-16 14:44:31 +08003429 filp->f_pos++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 /* fall through */
3431 case 1:
3432 ino = parent_ino(dentry);
Zhang Leee6f7792009-03-16 14:44:31 +08003433 if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 goto out;
Zhang Leee6f7792009-03-16 14:44:31 +08003435 filp->f_pos++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 /* fall through */
3437 }
3438
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003439 /* f_version caches the tgid value that the last readdir call couldn't
3440 * return. lseek aka telldir automagically resets f_version to 0.
3441 */
Pavel Emelyanovb4888932007-10-18 23:40:14 -07003442 ns = filp->f_dentry->d_sb->s_fs_info;
Mathieu Desnoyers2b47c362007-10-16 23:27:21 -07003443 tid = (int)filp->f_version;
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003444 filp->f_version = 0;
Zhang Leee6f7792009-03-16 14:44:31 +08003445 for (task = first_tid(leader, tid, filp->f_pos - 2, ns);
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003446 task;
Zhang Leee6f7792009-03-16 14:44:31 +08003447 task = next_tid(task), filp->f_pos++) {
Pavel Emelyanovb4888932007-10-18 23:40:14 -07003448 tid = task_pid_nr_ns(task, ns);
Eric W. Biederman61a28782006-10-02 02:18:49 -07003449 if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) {
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003450 /* returning this tgid failed, save it as the first
3451 * pid for the next readir call */
Mathieu Desnoyers2b47c362007-10-16 23:27:21 -07003452 filp->f_version = (u64)tid;
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003453 put_task_struct(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 break;
Eric W. Biederman0bc58a92006-06-26 00:25:50 -07003455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 }
3457out:
Eric W. Biederman99f89552006-06-26 00:25:55 -07003458 put_task_struct(leader);
3459out_no_task:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 return retval;
3461}
Eric W. Biederman6e66b522006-06-26 00:25:47 -07003462
3463static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
3464{
3465 struct inode *inode = dentry->d_inode;
Eric W. Biederman99f89552006-06-26 00:25:55 -07003466 struct task_struct *p = get_proc_task(inode);
Eric W. Biederman6e66b522006-06-26 00:25:47 -07003467 generic_fillattr(inode, stat);
3468
Eric W. Biederman99f89552006-06-26 00:25:55 -07003469 if (p) {
Eric W. Biederman99f89552006-06-26 00:25:55 -07003470 stat->nlink += get_nr_threads(p);
Eric W. Biederman99f89552006-06-26 00:25:55 -07003471 put_task_struct(p);
Eric W. Biederman6e66b522006-06-26 00:25:47 -07003472 }
3473
3474 return 0;
3475}
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003476
Arjan van de Venc5ef1c42007-02-12 00:55:40 -08003477static const struct inode_operations proc_task_inode_operations = {
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003478 .lookup = proc_task_lookup,
3479 .getattr = proc_task_getattr,
3480 .setattr = proc_setattr,
3481};
3482
Arjan van de Ven00977a52007-02-12 00:55:34 -08003483static const struct file_operations proc_task_operations = {
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003484 .read = generic_read_dir,
3485 .readdir = proc_task_readdir,
Arnd Bergmann6038f372010-08-15 18:52:59 +02003486 .llseek = default_llseek,
Eric W. Biederman28a6d672006-10-02 02:17:05 -07003487};