1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * linux/fs/proc/array.c |
4 | * |
5 | * Copyright (C) 1992 by Linus Torvalds |
6 | * based on ideas by Darren Senn |
7 | * |
8 | * Fixes: |
9 | * Michael. K. Johnson: stat,statm extensions. |
10 | * <johnsonm@stolaf.edu> |
11 | * |
12 | * Pauline Middelink : Made cmdline,envline only break at '\0's, to |
13 | * make sure SET_PROCTITLE works. Also removed |
14 | * bad '!' which forced address recalculation for |
15 | * EVERY character on the current page. |
16 | * <middelin@polyware.iaf.nl> |
17 | * |
18 | * Danny ter Haar : added cpuinfo |
19 | * <dth@cistron.nl> |
20 | * |
21 | * Alessandro Rubini : profile extension. |
22 | * <rubini@ipvvis.unipv.it> |
23 | * |
24 | * Jeff Tranter : added BogoMips field to cpuinfo |
25 | * <Jeff_Tranter@Mitel.COM> |
26 | * |
27 | * Bruno Haible : remove 4K limit for the maps file |
28 | * <haible@ma2s2.mathematik.uni-karlsruhe.de> |
29 | * |
30 | * Yves Arrouye : remove removal of trailing spaces in get_array. |
31 | * <Yves.Arrouye@marin.fdn.fr> |
32 | * |
33 | * Jerome Forissier : added per-CPU time information to /proc/stat |
34 | * and /proc/<pid>/cpu extension |
35 | * <forissier@isia.cma.fr> |
36 | * - Incorporation and non-SMP safe operation |
37 | * of forissier patch in 2.1.78 by |
38 | * Hans Marcus <crowbar@concepts.nl> |
39 | * |
40 | * aeb@cwi.nl : /proc/partitions |
41 | * |
42 | * |
43 | * Alan Cox : security fixes. |
44 | * <alan@lxorguk.ukuu.org.uk> |
45 | * |
46 | * Al Viro : safe handling of mm_struct |
47 | * |
48 | * Gerhard Wichert : added BIGMEM support |
49 | * Siemens AG <Gerhard.Wichert@pdb.siemens.de> |
50 | * |
51 | * Al Viro & Jeff Garzik : moved most of the thing into base.c and |
52 | * : proc_misc.c. The rest may eventually go into |
53 | * : base.c too. |
54 | */ |
55 | |
56 | #include <linux/types.h> |
57 | #include <linux/errno.h> |
58 | #include <linux/time.h> |
59 | #include <linux/time_namespace.h> |
60 | #include <linux/kernel.h> |
61 | #include <linux/kernel_stat.h> |
62 | #include <linux/tty.h> |
63 | #include <linux/string.h> |
64 | #include <linux/mman.h> |
65 | #include <linux/sched/mm.h> |
66 | #include <linux/sched/numa_balancing.h> |
67 | #include <linux/sched/task_stack.h> |
68 | #include <linux/sched/task.h> |
69 | #include <linux/sched/cputime.h> |
70 | #include <linux/proc_fs.h> |
71 | #include <linux/ioport.h> |
72 | #include <linux/io.h> |
73 | #include <linux/mm.h> |
74 | #include <linux/hugetlb.h> |
75 | #include <linux/pagemap.h> |
76 | #include <linux/swap.h> |
77 | #include <linux/smp.h> |
78 | #include <linux/signal.h> |
79 | #include <linux/highmem.h> |
80 | #include <linux/file.h> |
81 | #include <linux/fdtable.h> |
82 | #include <linux/times.h> |
83 | #include <linux/cpuset.h> |
84 | #include <linux/rcupdate.h> |
85 | #include <linux/delayacct.h> |
86 | #include <linux/seq_file.h> |
87 | #include <linux/pid_namespace.h> |
88 | #include <linux/prctl.h> |
89 | #include <linux/ptrace.h> |
90 | #include <linux/string_helpers.h> |
91 | #include <linux/user_namespace.h> |
92 | #include <linux/fs_struct.h> |
93 | #include <linux/kthread.h> |
94 | #include <linux/mmu_context.h> |
95 | |
96 | #include <asm/processor.h> |
97 | #include "internal.h" |
98 | |
99 | void proc_task_name(struct seq_file *m, struct task_struct *p, bool escape) |
100 | { |
101 | char tcomm[64]; |
102 | |
103 | /* |
104 | * Test before PF_KTHREAD because all workqueue worker threads are |
105 | * kernel threads. |
106 | */ |
107 | if (p->flags & PF_WQ_WORKER) |
108 | wq_worker_comm(buf: tcomm, size: sizeof(tcomm), task: p); |
109 | else if (p->flags & PF_KTHREAD) |
110 | get_kthread_comm(buf: tcomm, buf_size: sizeof(tcomm), tsk: p); |
111 | else |
112 | __get_task_comm(to: tcomm, len: sizeof(tcomm), tsk: p); |
113 | |
114 | if (escape) |
115 | seq_escape_str(m, src: tcomm, ESCAPE_SPACE | ESCAPE_SPECIAL, esc: "\n\\" ); |
116 | else |
117 | seq_printf(m, fmt: "%.64s" , tcomm); |
118 | } |
119 | |
120 | /* |
121 | * The task state array is a strange "bitmap" of |
122 | * reasons to sleep. Thus "running" is zero, and |
123 | * you can test for combinations of others with |
124 | * simple bit tests. |
125 | */ |
126 | static const char * const task_state_array[] = { |
127 | |
128 | /* states in TASK_REPORT: */ |
129 | "R (running)" , /* 0x00 */ |
130 | "S (sleeping)" , /* 0x01 */ |
131 | "D (disk sleep)" , /* 0x02 */ |
132 | "T (stopped)" , /* 0x04 */ |
133 | "t (tracing stop)" , /* 0x08 */ |
134 | "X (dead)" , /* 0x10 */ |
135 | "Z (zombie)" , /* 0x20 */ |
136 | "P (parked)" , /* 0x40 */ |
137 | |
138 | /* states beyond TASK_REPORT: */ |
139 | "I (idle)" , /* 0x80 */ |
140 | }; |
141 | |
142 | static inline const char *get_task_state(struct task_struct *tsk) |
143 | { |
144 | BUILD_BUG_ON(1 + ilog2(TASK_REPORT_MAX) != ARRAY_SIZE(task_state_array)); |
145 | return task_state_array[task_state_index(tsk)]; |
146 | } |
147 | |
148 | static inline void task_state(struct seq_file *m, struct pid_namespace *ns, |
149 | struct pid *pid, struct task_struct *p) |
150 | { |
151 | struct user_namespace *user_ns = seq_user_ns(seq: m); |
152 | struct group_info *group_info; |
153 | int g, umask = -1; |
154 | struct task_struct *tracer; |
155 | const struct cred *cred; |
156 | pid_t ppid, tpid = 0, tgid, ngid; |
157 | unsigned int max_fds = 0; |
158 | |
159 | rcu_read_lock(); |
160 | ppid = pid_alive(p) ? |
161 | task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; |
162 | |
163 | tracer = ptrace_parent(task: p); |
164 | if (tracer) |
165 | tpid = task_pid_nr_ns(tsk: tracer, ns); |
166 | |
167 | tgid = task_tgid_nr_ns(tsk: p, ns); |
168 | ngid = task_numa_group_id(p); |
169 | cred = get_task_cred(p); |
170 | |
171 | task_lock(p); |
172 | if (p->fs) |
173 | umask = p->fs->umask; |
174 | if (p->files) |
175 | max_fds = files_fdtable(p->files)->max_fds; |
176 | task_unlock(p); |
177 | rcu_read_unlock(); |
178 | |
179 | if (umask >= 0) |
180 | seq_printf(m, fmt: "Umask:\t%#04o\n" , umask); |
181 | seq_puts(m, s: "State:\t" ); |
182 | seq_puts(m, s: get_task_state(tsk: p)); |
183 | |
184 | seq_put_decimal_ull(m, delimiter: "\nTgid:\t" , num: tgid); |
185 | seq_put_decimal_ull(m, delimiter: "\nNgid:\t" , num: ngid); |
186 | seq_put_decimal_ull(m, delimiter: "\nPid:\t" , num: pid_nr_ns(pid, ns)); |
187 | seq_put_decimal_ull(m, delimiter: "\nPPid:\t" , num: ppid); |
188 | seq_put_decimal_ull(m, delimiter: "\nTracerPid:\t" , num: tpid); |
189 | seq_put_decimal_ull(m, delimiter: "\nUid:\t" , num: from_kuid_munged(to: user_ns, uid: cred->uid)); |
190 | seq_put_decimal_ull(m, delimiter: "\t" , num: from_kuid_munged(to: user_ns, uid: cred->euid)); |
191 | seq_put_decimal_ull(m, delimiter: "\t" , num: from_kuid_munged(to: user_ns, uid: cred->suid)); |
192 | seq_put_decimal_ull(m, delimiter: "\t" , num: from_kuid_munged(to: user_ns, uid: cred->fsuid)); |
193 | seq_put_decimal_ull(m, delimiter: "\nGid:\t" , num: from_kgid_munged(to: user_ns, gid: cred->gid)); |
194 | seq_put_decimal_ull(m, delimiter: "\t" , num: from_kgid_munged(to: user_ns, gid: cred->egid)); |
195 | seq_put_decimal_ull(m, delimiter: "\t" , num: from_kgid_munged(to: user_ns, gid: cred->sgid)); |
196 | seq_put_decimal_ull(m, delimiter: "\t" , num: from_kgid_munged(to: user_ns, gid: cred->fsgid)); |
197 | seq_put_decimal_ull(m, delimiter: "\nFDSize:\t" , num: max_fds); |
198 | |
199 | seq_puts(m, s: "\nGroups:\t" ); |
200 | group_info = cred->group_info; |
201 | for (g = 0; g < group_info->ngroups; g++) |
202 | seq_put_decimal_ull(m, delimiter: g ? " " : "" , |
203 | num: from_kgid_munged(to: user_ns, gid: group_info->gid[g])); |
204 | put_cred(cred); |
205 | /* Trailing space shouldn't have been added in the first place. */ |
206 | seq_putc(m, c: ' '); |
207 | |
208 | #ifdef CONFIG_PID_NS |
209 | seq_puts(m, s: "\nNStgid:" ); |
210 | for (g = ns->level; g <= pid->level; g++) |
211 | seq_put_decimal_ull(m, delimiter: "\t" , num: task_tgid_nr_ns(tsk: p, ns: pid->numbers[g].ns)); |
212 | seq_puts(m, s: "\nNSpid:" ); |
213 | for (g = ns->level; g <= pid->level; g++) |
214 | seq_put_decimal_ull(m, delimiter: "\t" , num: task_pid_nr_ns(tsk: p, ns: pid->numbers[g].ns)); |
215 | seq_puts(m, s: "\nNSpgid:" ); |
216 | for (g = ns->level; g <= pid->level; g++) |
217 | seq_put_decimal_ull(m, delimiter: "\t" , num: task_pgrp_nr_ns(tsk: p, ns: pid->numbers[g].ns)); |
218 | seq_puts(m, s: "\nNSsid:" ); |
219 | for (g = ns->level; g <= pid->level; g++) |
220 | seq_put_decimal_ull(m, delimiter: "\t" , num: task_session_nr_ns(tsk: p, ns: pid->numbers[g].ns)); |
221 | #endif |
222 | seq_putc(m, c: '\n'); |
223 | |
224 | seq_printf(m, fmt: "Kthread:\t%c\n" , p->flags & PF_KTHREAD ? '1' : '0'); |
225 | } |
226 | |
227 | void render_sigset_t(struct seq_file *m, const char *, |
228 | sigset_t *set) |
229 | { |
230 | int i; |
231 | |
232 | seq_puts(m, s: header); |
233 | |
234 | i = _NSIG; |
235 | do { |
236 | int x = 0; |
237 | |
238 | i -= 4; |
239 | if (sigismember(set, sig: i+1)) x |= 1; |
240 | if (sigismember(set, sig: i+2)) x |= 2; |
241 | if (sigismember(set, sig: i+3)) x |= 4; |
242 | if (sigismember(set, sig: i+4)) x |= 8; |
243 | seq_putc(m, c: hex_asc[x]); |
244 | } while (i >= 4); |
245 | |
246 | seq_putc(m, c: '\n'); |
247 | } |
248 | |
249 | static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *sigign, |
250 | sigset_t *sigcatch) |
251 | { |
252 | struct k_sigaction *k; |
253 | int i; |
254 | |
255 | k = p->sighand->action; |
256 | for (i = 1; i <= _NSIG; ++i, ++k) { |
257 | if (k->sa.sa_handler == SIG_IGN) |
258 | sigaddset(set: sigign, sig: i); |
259 | else if (k->sa.sa_handler != SIG_DFL) |
260 | sigaddset(set: sigcatch, sig: i); |
261 | } |
262 | } |
263 | |
264 | static inline void task_sig(struct seq_file *m, struct task_struct *p) |
265 | { |
266 | unsigned long flags; |
267 | sigset_t pending, shpending, blocked, ignored, caught; |
268 | int num_threads = 0; |
269 | unsigned int qsize = 0; |
270 | unsigned long qlim = 0; |
271 | |
272 | sigemptyset(set: &pending); |
273 | sigemptyset(set: &shpending); |
274 | sigemptyset(set: &blocked); |
275 | sigemptyset(set: &ignored); |
276 | sigemptyset(set: &caught); |
277 | |
278 | if (lock_task_sighand(task: p, flags: &flags)) { |
279 | pending = p->pending.signal; |
280 | shpending = p->signal->shared_pending.signal; |
281 | blocked = p->blocked; |
282 | collect_sigign_sigcatch(p, sigign: &ignored, sigcatch: &caught); |
283 | num_threads = get_nr_threads(task: p); |
284 | rcu_read_lock(); /* FIXME: is this correct? */ |
285 | qsize = get_rlimit_value(task_ucounts(p), type: UCOUNT_RLIMIT_SIGPENDING); |
286 | rcu_read_unlock(); |
287 | qlim = task_rlimit(task: p, RLIMIT_SIGPENDING); |
288 | unlock_task_sighand(task: p, flags: &flags); |
289 | } |
290 | |
291 | seq_put_decimal_ull(m, delimiter: "Threads:\t" , num: num_threads); |
292 | seq_put_decimal_ull(m, delimiter: "\nSigQ:\t" , num: qsize); |
293 | seq_put_decimal_ull(m, delimiter: "/" , num: qlim); |
294 | |
295 | /* render them all */ |
296 | render_sigset_t(m, header: "\nSigPnd:\t" , set: &pending); |
297 | render_sigset_t(m, header: "ShdPnd:\t" , set: &shpending); |
298 | render_sigset_t(m, header: "SigBlk:\t" , set: &blocked); |
299 | render_sigset_t(m, header: "SigIgn:\t" , set: &ignored); |
300 | render_sigset_t(m, header: "SigCgt:\t" , set: &caught); |
301 | } |
302 | |
303 | static void render_cap_t(struct seq_file *m, const char *, |
304 | kernel_cap_t *a) |
305 | { |
306 | seq_puts(m, s: header); |
307 | seq_put_hex_ll(m, NULL, v: a->val, width: 16); |
308 | seq_putc(m, c: '\n'); |
309 | } |
310 | |
311 | static inline void task_cap(struct seq_file *m, struct task_struct *p) |
312 | { |
313 | const struct cred *cred; |
314 | kernel_cap_t cap_inheritable, cap_permitted, cap_effective, |
315 | cap_bset, cap_ambient; |
316 | |
317 | rcu_read_lock(); |
318 | cred = __task_cred(p); |
319 | cap_inheritable = cred->cap_inheritable; |
320 | cap_permitted = cred->cap_permitted; |
321 | cap_effective = cred->cap_effective; |
322 | cap_bset = cred->cap_bset; |
323 | cap_ambient = cred->cap_ambient; |
324 | rcu_read_unlock(); |
325 | |
326 | render_cap_t(m, header: "CapInh:\t" , a: &cap_inheritable); |
327 | render_cap_t(m, header: "CapPrm:\t" , a: &cap_permitted); |
328 | render_cap_t(m, header: "CapEff:\t" , a: &cap_effective); |
329 | render_cap_t(m, header: "CapBnd:\t" , a: &cap_bset); |
330 | render_cap_t(m, header: "CapAmb:\t" , a: &cap_ambient); |
331 | } |
332 | |
333 | static inline void task_seccomp(struct seq_file *m, struct task_struct *p) |
334 | { |
335 | seq_put_decimal_ull(m, delimiter: "NoNewPrivs:\t" , num: task_no_new_privs(p)); |
336 | #ifdef CONFIG_SECCOMP |
337 | seq_put_decimal_ull(m, delimiter: "\nSeccomp:\t" , num: p->seccomp.mode); |
338 | #ifdef CONFIG_SECCOMP_FILTER |
339 | seq_put_decimal_ull(m, delimiter: "\nSeccomp_filters:\t" , |
340 | num: atomic_read(v: &p->seccomp.filter_count)); |
341 | #endif |
342 | #endif |
343 | seq_puts(m, s: "\nSpeculation_Store_Bypass:\t" ); |
344 | switch (arch_prctl_spec_ctrl_get(task: p, PR_SPEC_STORE_BYPASS)) { |
345 | case -EINVAL: |
346 | seq_puts(m, s: "unknown" ); |
347 | break; |
348 | case PR_SPEC_NOT_AFFECTED: |
349 | seq_puts(m, s: "not vulnerable" ); |
350 | break; |
351 | case PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE: |
352 | seq_puts(m, s: "thread force mitigated" ); |
353 | break; |
354 | case PR_SPEC_PRCTL | PR_SPEC_DISABLE: |
355 | seq_puts(m, s: "thread mitigated" ); |
356 | break; |
357 | case PR_SPEC_PRCTL | PR_SPEC_ENABLE: |
358 | seq_puts(m, s: "thread vulnerable" ); |
359 | break; |
360 | case PR_SPEC_DISABLE: |
361 | seq_puts(m, s: "globally mitigated" ); |
362 | break; |
363 | default: |
364 | seq_puts(m, s: "vulnerable" ); |
365 | break; |
366 | } |
367 | |
368 | seq_puts(m, s: "\nSpeculationIndirectBranch:\t" ); |
369 | switch (arch_prctl_spec_ctrl_get(task: p, PR_SPEC_INDIRECT_BRANCH)) { |
370 | case -EINVAL: |
371 | seq_puts(m, s: "unsupported" ); |
372 | break; |
373 | case PR_SPEC_NOT_AFFECTED: |
374 | seq_puts(m, s: "not affected" ); |
375 | break; |
376 | case PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE: |
377 | seq_puts(m, s: "conditional force disabled" ); |
378 | break; |
379 | case PR_SPEC_PRCTL | PR_SPEC_DISABLE: |
380 | seq_puts(m, s: "conditional disabled" ); |
381 | break; |
382 | case PR_SPEC_PRCTL | PR_SPEC_ENABLE: |
383 | seq_puts(m, s: "conditional enabled" ); |
384 | break; |
385 | case PR_SPEC_ENABLE: |
386 | seq_puts(m, s: "always enabled" ); |
387 | break; |
388 | case PR_SPEC_DISABLE: |
389 | seq_puts(m, s: "always disabled" ); |
390 | break; |
391 | default: |
392 | seq_puts(m, s: "unknown" ); |
393 | break; |
394 | } |
395 | seq_putc(m, c: '\n'); |
396 | } |
397 | |
398 | static inline void task_context_switch_counts(struct seq_file *m, |
399 | struct task_struct *p) |
400 | { |
401 | seq_put_decimal_ull(m, delimiter: "voluntary_ctxt_switches:\t" , num: p->nvcsw); |
402 | seq_put_decimal_ull(m, delimiter: "\nnonvoluntary_ctxt_switches:\t" , num: p->nivcsw); |
403 | seq_putc(m, c: '\n'); |
404 | } |
405 | |
406 | static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) |
407 | { |
408 | seq_printf(m, fmt: "Cpus_allowed:\t%*pb\n" , |
409 | cpumask_pr_args(&task->cpus_mask)); |
410 | seq_printf(m, fmt: "Cpus_allowed_list:\t%*pbl\n" , |
411 | cpumask_pr_args(&task->cpus_mask)); |
412 | } |
413 | |
414 | static inline void task_core_dumping(struct seq_file *m, struct task_struct *task) |
415 | { |
416 | seq_put_decimal_ull(m, delimiter: "CoreDumping:\t" , num: !!task->signal->core_state); |
417 | seq_putc(m, c: '\n'); |
418 | } |
419 | |
420 | static inline void task_thp_status(struct seq_file *m, struct mm_struct *mm) |
421 | { |
422 | bool thp_enabled = IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE); |
423 | |
424 | if (thp_enabled) |
425 | thp_enabled = !test_bit(MMF_DISABLE_THP, &mm->flags); |
426 | seq_printf(m, fmt: "THP_enabled:\t%d\n" , thp_enabled); |
427 | } |
428 | |
429 | static inline void task_untag_mask(struct seq_file *m, struct mm_struct *mm) |
430 | { |
431 | seq_printf(m, fmt: "untag_mask:\t%#lx\n" , mm_untag_mask(mm)); |
432 | } |
433 | |
434 | __weak void arch_proc_pid_thread_features(struct seq_file *m, |
435 | struct task_struct *task) |
436 | { |
437 | } |
438 | |
439 | int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, |
440 | struct pid *pid, struct task_struct *task) |
441 | { |
442 | struct mm_struct *mm = get_task_mm(task); |
443 | |
444 | seq_puts(m, s: "Name:\t" ); |
445 | proc_task_name(m, p: task, escape: true); |
446 | seq_putc(m, c: '\n'); |
447 | |
448 | task_state(m, ns, pid, p: task); |
449 | |
450 | if (mm) { |
451 | task_mem(m, mm); |
452 | task_core_dumping(m, task); |
453 | task_thp_status(m, mm); |
454 | task_untag_mask(m, mm); |
455 | mmput(mm); |
456 | } |
457 | task_sig(m, p: task); |
458 | task_cap(m, p: task); |
459 | task_seccomp(m, p: task); |
460 | task_cpus_allowed(m, task); |
461 | cpuset_task_status_allowed(m, task); |
462 | task_context_switch_counts(m, p: task); |
463 | arch_proc_pid_thread_features(m, task); |
464 | return 0; |
465 | } |
466 | |
467 | static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, |
468 | struct pid *pid, struct task_struct *task, int whole) |
469 | { |
470 | unsigned long vsize, eip, esp, wchan = 0; |
471 | int priority, nice; |
472 | int tty_pgrp = -1, tty_nr = 0; |
473 | sigset_t sigign, sigcatch; |
474 | char state; |
475 | pid_t ppid = 0, pgid = -1, sid = -1; |
476 | int num_threads = 0; |
477 | int permitted; |
478 | struct mm_struct *mm; |
479 | unsigned long long start_time; |
480 | unsigned long cmin_flt, cmaj_flt, min_flt, maj_flt; |
481 | u64 cutime, cstime, cgtime, utime, stime, gtime; |
482 | unsigned long = 0; |
483 | unsigned long flags; |
484 | int exit_code = task->exit_code; |
485 | struct signal_struct *sig = task->signal; |
486 | unsigned int seq = 1; |
487 | |
488 | state = *get_task_state(tsk: task); |
489 | vsize = eip = esp = 0; |
490 | permitted = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS | PTRACE_MODE_NOAUDIT); |
491 | mm = get_task_mm(task); |
492 | if (mm) { |
493 | vsize = task_vsize(mm); |
494 | /* |
495 | * esp and eip are intentionally zeroed out. There is no |
496 | * non-racy way to read them without freezing the task. |
497 | * Programs that need reliable values can use ptrace(2). |
498 | * |
499 | * The only exception is if the task is core dumping because |
500 | * a program is not able to use ptrace(2) in that case. It is |
501 | * safe because the task has stopped executing permanently. |
502 | */ |
503 | if (permitted && (task->flags & (PF_EXITING|PF_DUMPCORE))) { |
504 | if (try_get_task_stack(tsk: task)) { |
505 | eip = KSTK_EIP(task); |
506 | esp = KSTK_ESP(task); |
507 | put_task_stack(tsk: task); |
508 | } |
509 | } |
510 | } |
511 | |
512 | sigemptyset(set: &sigign); |
513 | sigemptyset(set: &sigcatch); |
514 | |
515 | if (lock_task_sighand(task, flags: &flags)) { |
516 | if (sig->tty) { |
517 | struct pid *pgrp = tty_get_pgrp(tty: sig->tty); |
518 | tty_pgrp = pid_nr_ns(pid: pgrp, ns); |
519 | put_pid(pid: pgrp); |
520 | tty_nr = new_encode_dev(dev: tty_devnum(tty: sig->tty)); |
521 | } |
522 | |
523 | num_threads = get_nr_threads(task); |
524 | collect_sigign_sigcatch(p: task, sigign: &sigign, sigcatch: &sigcatch); |
525 | |
526 | rsslim = READ_ONCE(sig->rlim[RLIMIT_RSS].rlim_cur); |
527 | |
528 | if (whole) { |
529 | if (sig->flags & (SIGNAL_GROUP_EXIT | SIGNAL_STOP_STOPPED)) |
530 | exit_code = sig->group_exit_code; |
531 | } |
532 | |
533 | sid = task_session_nr_ns(tsk: task, ns); |
534 | ppid = task_tgid_nr_ns(tsk: task->real_parent, ns); |
535 | pgid = task_pgrp_nr_ns(tsk: task, ns); |
536 | |
537 | unlock_task_sighand(task, flags: &flags); |
538 | } |
539 | |
540 | if (permitted && (!whole || num_threads < 2)) |
541 | wchan = !task_is_running(task); |
542 | |
543 | do { |
544 | seq++; /* 2 on the 1st/lockless path, otherwise odd */ |
545 | flags = read_seqbegin_or_lock_irqsave(lock: &sig->stats_lock, seq: &seq); |
546 | |
547 | cmin_flt = sig->cmin_flt; |
548 | cmaj_flt = sig->cmaj_flt; |
549 | cutime = sig->cutime; |
550 | cstime = sig->cstime; |
551 | cgtime = sig->cgtime; |
552 | |
553 | if (whole) { |
554 | struct task_struct *t; |
555 | |
556 | min_flt = sig->min_flt; |
557 | maj_flt = sig->maj_flt; |
558 | gtime = sig->gtime; |
559 | |
560 | rcu_read_lock(); |
561 | __for_each_thread(sig, t) { |
562 | min_flt += t->min_flt; |
563 | maj_flt += t->maj_flt; |
564 | gtime += task_gtime(t); |
565 | } |
566 | rcu_read_unlock(); |
567 | } |
568 | } while (need_seqretry(lock: &sig->stats_lock, seq)); |
569 | done_seqretry_irqrestore(lock: &sig->stats_lock, seq, flags); |
570 | |
571 | if (whole) { |
572 | thread_group_cputime_adjusted(p: task, ut: &utime, st: &stime); |
573 | } else { |
574 | task_cputime_adjusted(p: task, ut: &utime, st: &stime); |
575 | min_flt = task->min_flt; |
576 | maj_flt = task->maj_flt; |
577 | gtime = task_gtime(t: task); |
578 | } |
579 | |
580 | /* scale priority and nice values from timeslices to -20..20 */ |
581 | /* to make it look like a "normal" Unix priority/nice value */ |
582 | priority = task_prio(p: task); |
583 | nice = task_nice(p: task); |
584 | |
585 | /* apply timens offset for boottime and convert nsec -> ticks */ |
586 | start_time = |
587 | nsec_to_clock_t(x: timens_add_boottime_ns(nsec: task->start_boottime)); |
588 | |
589 | seq_put_decimal_ull(m, delimiter: "" , num: pid_nr_ns(pid, ns)); |
590 | seq_puts(m, s: " (" ); |
591 | proc_task_name(m, p: task, escape: false); |
592 | seq_puts(m, s: ") " ); |
593 | seq_putc(m, c: state); |
594 | seq_put_decimal_ll(m, delimiter: " " , num: ppid); |
595 | seq_put_decimal_ll(m, delimiter: " " , num: pgid); |
596 | seq_put_decimal_ll(m, delimiter: " " , num: sid); |
597 | seq_put_decimal_ll(m, delimiter: " " , num: tty_nr); |
598 | seq_put_decimal_ll(m, delimiter: " " , num: tty_pgrp); |
599 | seq_put_decimal_ull(m, delimiter: " " , num: task->flags); |
600 | seq_put_decimal_ull(m, delimiter: " " , num: min_flt); |
601 | seq_put_decimal_ull(m, delimiter: " " , num: cmin_flt); |
602 | seq_put_decimal_ull(m, delimiter: " " , num: maj_flt); |
603 | seq_put_decimal_ull(m, delimiter: " " , num: cmaj_flt); |
604 | seq_put_decimal_ull(m, delimiter: " " , num: nsec_to_clock_t(x: utime)); |
605 | seq_put_decimal_ull(m, delimiter: " " , num: nsec_to_clock_t(x: stime)); |
606 | seq_put_decimal_ll(m, delimiter: " " , num: nsec_to_clock_t(x: cutime)); |
607 | seq_put_decimal_ll(m, delimiter: " " , num: nsec_to_clock_t(x: cstime)); |
608 | seq_put_decimal_ll(m, delimiter: " " , num: priority); |
609 | seq_put_decimal_ll(m, delimiter: " " , num: nice); |
610 | seq_put_decimal_ll(m, delimiter: " " , num: num_threads); |
611 | seq_put_decimal_ull(m, delimiter: " " , num: 0); |
612 | seq_put_decimal_ull(m, delimiter: " " , num: start_time); |
613 | seq_put_decimal_ull(m, delimiter: " " , num: vsize); |
614 | seq_put_decimal_ull(m, delimiter: " " , num: mm ? get_mm_rss(mm) : 0); |
615 | seq_put_decimal_ull(m, delimiter: " " , num: rsslim); |
616 | seq_put_decimal_ull(m, delimiter: " " , num: mm ? (permitted ? mm->start_code : 1) : 0); |
617 | seq_put_decimal_ull(m, delimiter: " " , num: mm ? (permitted ? mm->end_code : 1) : 0); |
618 | seq_put_decimal_ull(m, delimiter: " " , num: (permitted && mm) ? mm->start_stack : 0); |
619 | seq_put_decimal_ull(m, delimiter: " " , num: esp); |
620 | seq_put_decimal_ull(m, delimiter: " " , num: eip); |
621 | /* The signal information here is obsolete. |
622 | * It must be decimal for Linux 2.0 compatibility. |
623 | * Use /proc/#/status for real-time signals. |
624 | */ |
625 | seq_put_decimal_ull(m, delimiter: " " , num: task->pending.signal.sig[0] & 0x7fffffffUL); |
626 | seq_put_decimal_ull(m, delimiter: " " , num: task->blocked.sig[0] & 0x7fffffffUL); |
627 | seq_put_decimal_ull(m, delimiter: " " , num: sigign.sig[0] & 0x7fffffffUL); |
628 | seq_put_decimal_ull(m, delimiter: " " , num: sigcatch.sig[0] & 0x7fffffffUL); |
629 | |
630 | /* |
631 | * We used to output the absolute kernel address, but that's an |
632 | * information leak - so instead we show a 0/1 flag here, to signal |
633 | * to user-space whether there's a wchan field in /proc/PID/wchan. |
634 | * |
635 | * This works with older implementations of procps as well. |
636 | */ |
637 | seq_put_decimal_ull(m, delimiter: " " , num: wchan); |
638 | |
639 | seq_put_decimal_ull(m, delimiter: " " , num: 0); |
640 | seq_put_decimal_ull(m, delimiter: " " , num: 0); |
641 | seq_put_decimal_ll(m, delimiter: " " , num: task->exit_signal); |
642 | seq_put_decimal_ll(m, delimiter: " " , num: task_cpu(p: task)); |
643 | seq_put_decimal_ull(m, delimiter: " " , num: task->rt_priority); |
644 | seq_put_decimal_ull(m, delimiter: " " , num: task->policy); |
645 | seq_put_decimal_ull(m, delimiter: " " , num: delayacct_blkio_ticks(tsk: task)); |
646 | seq_put_decimal_ull(m, delimiter: " " , num: nsec_to_clock_t(x: gtime)); |
647 | seq_put_decimal_ll(m, delimiter: " " , num: nsec_to_clock_t(x: cgtime)); |
648 | |
649 | if (mm && permitted) { |
650 | seq_put_decimal_ull(m, delimiter: " " , num: mm->start_data); |
651 | seq_put_decimal_ull(m, delimiter: " " , num: mm->end_data); |
652 | seq_put_decimal_ull(m, delimiter: " " , num: mm->start_brk); |
653 | seq_put_decimal_ull(m, delimiter: " " , num: mm->arg_start); |
654 | seq_put_decimal_ull(m, delimiter: " " , num: mm->arg_end); |
655 | seq_put_decimal_ull(m, delimiter: " " , num: mm->env_start); |
656 | seq_put_decimal_ull(m, delimiter: " " , num: mm->env_end); |
657 | } else |
658 | seq_puts(m, s: " 0 0 0 0 0 0 0" ); |
659 | |
660 | if (permitted) |
661 | seq_put_decimal_ll(m, delimiter: " " , num: exit_code); |
662 | else |
663 | seq_puts(m, s: " 0" ); |
664 | |
665 | seq_putc(m, c: '\n'); |
666 | if (mm) |
667 | mmput(mm); |
668 | return 0; |
669 | } |
670 | |
671 | int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns, |
672 | struct pid *pid, struct task_struct *task) |
673 | { |
674 | return do_task_stat(m, ns, pid, task, whole: 0); |
675 | } |
676 | |
677 | int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns, |
678 | struct pid *pid, struct task_struct *task) |
679 | { |
680 | return do_task_stat(m, ns, pid, task, whole: 1); |
681 | } |
682 | |
683 | int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns, |
684 | struct pid *pid, struct task_struct *task) |
685 | { |
686 | struct mm_struct *mm = get_task_mm(task); |
687 | |
688 | if (mm) { |
689 | unsigned long size; |
690 | unsigned long resident = 0; |
691 | unsigned long shared = 0; |
692 | unsigned long text = 0; |
693 | unsigned long data = 0; |
694 | |
695 | size = task_statm(mm, &shared, &text, &data, &resident); |
696 | mmput(mm); |
697 | |
698 | /* |
699 | * For quick read, open code by putting numbers directly |
700 | * expected format is |
701 | * seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n", |
702 | * size, resident, shared, text, data); |
703 | */ |
704 | seq_put_decimal_ull(m, delimiter: "" , num: size); |
705 | seq_put_decimal_ull(m, delimiter: " " , num: resident); |
706 | seq_put_decimal_ull(m, delimiter: " " , num: shared); |
707 | seq_put_decimal_ull(m, delimiter: " " , num: text); |
708 | seq_put_decimal_ull(m, delimiter: " " , num: 0); |
709 | seq_put_decimal_ull(m, delimiter: " " , num: data); |
710 | seq_put_decimal_ull(m, delimiter: " " , num: 0); |
711 | seq_putc(m, c: '\n'); |
712 | } else { |
713 | seq_write(seq: m, data: "0 0 0 0 0 0 0\n" , len: 14); |
714 | } |
715 | return 0; |
716 | } |
717 | |
718 | #ifdef CONFIG_PROC_CHILDREN |
719 | static struct pid * |
720 | get_children_pid(struct inode *inode, struct pid *pid_prev, loff_t pos) |
721 | { |
722 | struct task_struct *start, *task; |
723 | struct pid *pid = NULL; |
724 | |
725 | read_lock(&tasklist_lock); |
726 | |
727 | start = pid_task(pid: proc_pid(inode), PIDTYPE_PID); |
728 | if (!start) |
729 | goto out; |
730 | |
731 | /* |
732 | * Lets try to continue searching first, this gives |
733 | * us significant speedup on children-rich processes. |
734 | */ |
735 | if (pid_prev) { |
736 | task = pid_task(pid: pid_prev, PIDTYPE_PID); |
737 | if (task && task->real_parent == start && |
738 | !(list_empty(head: &task->sibling))) { |
739 | if (list_is_last(list: &task->sibling, head: &start->children)) |
740 | goto out; |
741 | task = list_first_entry(&task->sibling, |
742 | struct task_struct, sibling); |
743 | pid = get_pid(pid: task_pid(task)); |
744 | goto out; |
745 | } |
746 | } |
747 | |
748 | /* |
749 | * Slow search case. |
750 | * |
751 | * We might miss some children here if children |
752 | * are exited while we were not holding the lock, |
753 | * but it was never promised to be accurate that |
754 | * much. |
755 | * |
756 | * "Just suppose that the parent sleeps, but N children |
757 | * exit after we printed their tids. Now the slow paths |
758 | * skips N extra children, we miss N tasks." (c) |
759 | * |
760 | * So one need to stop or freeze the leader and all |
761 | * its children to get a precise result. |
762 | */ |
763 | list_for_each_entry(task, &start->children, sibling) { |
764 | if (pos-- == 0) { |
765 | pid = get_pid(pid: task_pid(task)); |
766 | break; |
767 | } |
768 | } |
769 | |
770 | out: |
771 | read_unlock(&tasklist_lock); |
772 | return pid; |
773 | } |
774 | |
775 | static int children_seq_show(struct seq_file *seq, void *v) |
776 | { |
777 | struct inode *inode = file_inode(f: seq->file); |
778 | |
779 | seq_printf(m: seq, fmt: "%d " , pid_nr_ns(pid: v, ns: proc_pid_ns(sb: inode->i_sb))); |
780 | return 0; |
781 | } |
782 | |
783 | static void *children_seq_start(struct seq_file *seq, loff_t *pos) |
784 | { |
785 | return get_children_pid(inode: file_inode(f: seq->file), NULL, pos: *pos); |
786 | } |
787 | |
788 | static void *children_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
789 | { |
790 | struct pid *pid; |
791 | |
792 | pid = get_children_pid(inode: file_inode(f: seq->file), pid_prev: v, pos: *pos + 1); |
793 | put_pid(pid: v); |
794 | |
795 | ++*pos; |
796 | return pid; |
797 | } |
798 | |
799 | static void children_seq_stop(struct seq_file *seq, void *v) |
800 | { |
801 | put_pid(pid: v); |
802 | } |
803 | |
804 | static const struct seq_operations children_seq_ops = { |
805 | .start = children_seq_start, |
806 | .next = children_seq_next, |
807 | .stop = children_seq_stop, |
808 | .show = children_seq_show, |
809 | }; |
810 | |
811 | static int children_seq_open(struct inode *inode, struct file *file) |
812 | { |
813 | return seq_open(file, &children_seq_ops); |
814 | } |
815 | |
816 | const struct file_operations proc_tid_children_operations = { |
817 | .open = children_seq_open, |
818 | .read = seq_read, |
819 | .llseek = seq_lseek, |
820 | .release = seq_release, |
821 | }; |
822 | #endif /* CONFIG_PROC_CHILDREN */ |
823 | |