18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/proc/base.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * proc base directory handling functions 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * 1999, Al Viro. Rewritten. Now it covers the whole per-process part. 108c2ecf20Sopenharmony_ci * Instead of using magical inumbers to determine the kind of object 118c2ecf20Sopenharmony_ci * we allocate and fill in-core inodes upon lookup. They don't even 128c2ecf20Sopenharmony_ci * go into icache. We cache the reference to task_struct upon lookup too. 138c2ecf20Sopenharmony_ci * Eventually it should become a filesystem in its own. We don't use the 148c2ecf20Sopenharmony_ci * rest of procfs anymore. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Changelog: 188c2ecf20Sopenharmony_ci * 17-Jan-2005 198c2ecf20Sopenharmony_ci * Allan Bezerra 208c2ecf20Sopenharmony_ci * Bruna Moreira <bruna.moreira@indt.org.br> 218c2ecf20Sopenharmony_ci * Edjard Mota <edjard.mota@indt.org.br> 228c2ecf20Sopenharmony_ci * Ilias Biris <ilias.biris@indt.org.br> 238c2ecf20Sopenharmony_ci * Mauricio Lin <mauricio.lin@indt.org.br> 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * A new process specific entry (smaps) included in /proc. It shows the 288c2ecf20Sopenharmony_ci * size of rss for each memory area. The maps entry lacks information 298c2ecf20Sopenharmony_ci * about physical memory size (rss) for each mapped file, i.e., 308c2ecf20Sopenharmony_ci * rss information for executables and library files. 318c2ecf20Sopenharmony_ci * This additional information is useful for any tools that need to know 328c2ecf20Sopenharmony_ci * about physical memory consumption for a process specific library. 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * Changelog: 358c2ecf20Sopenharmony_ci * 21-Feb-2005 368c2ecf20Sopenharmony_ci * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT 378c2ecf20Sopenharmony_ci * Pud inclusion in the page table walking. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * ChangeLog: 408c2ecf20Sopenharmony_ci * 10-Mar-2005 418c2ecf20Sopenharmony_ci * 10LE Instituto Nokia de Tecnologia - INdT: 428c2ecf20Sopenharmony_ci * A better way to walks through the page table as suggested by Hugh Dickins. 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * Simo Piiroinen <simo.piiroinen@nokia.com>: 458c2ecf20Sopenharmony_ci * Smaps information related to shared, private, clean and dirty pages. 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * Paul Mundt <paul.mundt@nokia.com>: 488c2ecf20Sopenharmony_ci * Overall revision about smaps. 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#include <linux/errno.h> 548c2ecf20Sopenharmony_ci#include <linux/time.h> 558c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 568c2ecf20Sopenharmony_ci#include <linux/stat.h> 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#ifdef CONFIG_QOS_CTRL 598c2ecf20Sopenharmony_ci#include <linux/sched/qos_ctrl.h> 608c2ecf20Sopenharmony_ci#endif 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#include <linux/task_io_accounting_ops.h> 638c2ecf20Sopenharmony_ci#include <linux/init.h> 648c2ecf20Sopenharmony_ci#include <linux/capability.h> 658c2ecf20Sopenharmony_ci#include <linux/file.h> 668c2ecf20Sopenharmony_ci#include <linux/fdtable.h> 678c2ecf20Sopenharmony_ci#include <linux/generic-radix-tree.h> 688c2ecf20Sopenharmony_ci#include <linux/string.h> 698c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 708c2ecf20Sopenharmony_ci#include <linux/namei.h> 718c2ecf20Sopenharmony_ci#include <linux/mnt_namespace.h> 728c2ecf20Sopenharmony_ci#include <linux/mm.h> 738c2ecf20Sopenharmony_ci#include <linux/swap.h> 748c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 758c2ecf20Sopenharmony_ci#include <linux/kallsyms.h> 768c2ecf20Sopenharmony_ci#include <linux/stacktrace.h> 778c2ecf20Sopenharmony_ci#include <linux/resource.h> 788c2ecf20Sopenharmony_ci#include <linux/module.h> 798c2ecf20Sopenharmony_ci#include <linux/mount.h> 808c2ecf20Sopenharmony_ci#include <linux/security.h> 818c2ecf20Sopenharmony_ci#include <linux/ptrace.h> 828c2ecf20Sopenharmony_ci#include <linux/tracehook.h> 838c2ecf20Sopenharmony_ci#include <linux/printk.h> 848c2ecf20Sopenharmony_ci#include <linux/cache.h> 858c2ecf20Sopenharmony_ci#include <linux/cgroup.h> 868c2ecf20Sopenharmony_ci#include <linux/cpuset.h> 878c2ecf20Sopenharmony_ci#include <linux/audit.h> 888c2ecf20Sopenharmony_ci#include <linux/poll.h> 898c2ecf20Sopenharmony_ci#include <linux/nsproxy.h> 908c2ecf20Sopenharmony_ci#include <linux/oom.h> 918c2ecf20Sopenharmony_ci#include <linux/elf.h> 928c2ecf20Sopenharmony_ci#include <linux/pid_namespace.h> 938c2ecf20Sopenharmony_ci#include <linux/user_namespace.h> 948c2ecf20Sopenharmony_ci#include <linux/fs_struct.h> 958c2ecf20Sopenharmony_ci#include <linux/slab.h> 968c2ecf20Sopenharmony_ci#include <linux/sched.h> 978c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_RTG 988c2ecf20Sopenharmony_ci#include <linux/sched/rtg_ctrl.h> 998c2ecf20Sopenharmony_ci#endif 1008c2ecf20Sopenharmony_ci#include <linux/sched/autogroup.h> 1018c2ecf20Sopenharmony_ci#include <linux/sched/mm.h> 1028c2ecf20Sopenharmony_ci#include <linux/sched/coredump.h> 1038c2ecf20Sopenharmony_ci#include <linux/sched/debug.h> 1048c2ecf20Sopenharmony_ci#include <linux/sched/stat.h> 1058c2ecf20Sopenharmony_ci#include <linux/posix-timers.h> 1068c2ecf20Sopenharmony_ci#include <linux/time_namespace.h> 1078c2ecf20Sopenharmony_ci#include <linux/resctrl.h> 1088c2ecf20Sopenharmony_ci#include <trace/events/oom.h> 1098c2ecf20Sopenharmony_ci#include "internal.h" 1108c2ecf20Sopenharmony_ci#include "fd.h" 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#include "../../lib/kstrtox.h" 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* NOTE: 1158c2ecf20Sopenharmony_ci * Implementing inode permission operations in /proc is almost 1168c2ecf20Sopenharmony_ci * certainly an error. Permission checks need to happen during 1178c2ecf20Sopenharmony_ci * each system call not at open time. The reason is that most of 1188c2ecf20Sopenharmony_ci * what we wish to check for permissions in /proc varies at runtime. 1198c2ecf20Sopenharmony_ci * 1208c2ecf20Sopenharmony_ci * The classic example of a problem is opening file descriptors 1218c2ecf20Sopenharmony_ci * in /proc for a task before it execs a suid executable. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic u8 nlink_tid __ro_after_init; 1258c2ecf20Sopenharmony_cistatic u8 nlink_tgid __ro_after_init; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistruct pid_entry { 1288c2ecf20Sopenharmony_ci const char *name; 1298c2ecf20Sopenharmony_ci unsigned int len; 1308c2ecf20Sopenharmony_ci umode_t mode; 1318c2ecf20Sopenharmony_ci const struct inode_operations *iop; 1328c2ecf20Sopenharmony_ci const struct file_operations *fop; 1338c2ecf20Sopenharmony_ci union proc_op op; 1348c2ecf20Sopenharmony_ci}; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci#define NOD(NAME, MODE, IOP, FOP, OP) { \ 1378c2ecf20Sopenharmony_ci .name = (NAME), \ 1388c2ecf20Sopenharmony_ci .len = sizeof(NAME) - 1, \ 1398c2ecf20Sopenharmony_ci .mode = MODE, \ 1408c2ecf20Sopenharmony_ci .iop = IOP, \ 1418c2ecf20Sopenharmony_ci .fop = FOP, \ 1428c2ecf20Sopenharmony_ci .op = OP, \ 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci#define DIR(NAME, MODE, iops, fops) \ 1468c2ecf20Sopenharmony_ci NOD(NAME, (S_IFDIR|(MODE)), &iops, &fops, {} ) 1478c2ecf20Sopenharmony_ci#define LNK(NAME, get_link) \ 1488c2ecf20Sopenharmony_ci NOD(NAME, (S_IFLNK|S_IRWXUGO), \ 1498c2ecf20Sopenharmony_ci &proc_pid_link_inode_operations, NULL, \ 1508c2ecf20Sopenharmony_ci { .proc_get_link = get_link } ) 1518c2ecf20Sopenharmony_ci#define REG(NAME, MODE, fops) \ 1528c2ecf20Sopenharmony_ci NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {}) 1538c2ecf20Sopenharmony_ci#define ONE(NAME, MODE, show) \ 1548c2ecf20Sopenharmony_ci NOD(NAME, (S_IFREG|(MODE)), \ 1558c2ecf20Sopenharmony_ci NULL, &proc_single_file_operations, \ 1568c2ecf20Sopenharmony_ci { .proc_show = show } ) 1578c2ecf20Sopenharmony_ci#define ATTR(LSM, NAME, MODE) \ 1588c2ecf20Sopenharmony_ci NOD(NAME, (S_IFREG|(MODE)), \ 1598c2ecf20Sopenharmony_ci NULL, &proc_pid_attr_operations, \ 1608c2ecf20Sopenharmony_ci { .lsm = LSM }) 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* 1638c2ecf20Sopenharmony_ci * Count the number of hardlinks for the pid_entry table, excluding the . 1648c2ecf20Sopenharmony_ci * and .. links. 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_cistatic unsigned int __init pid_entry_nlink(const struct pid_entry *entries, 1678c2ecf20Sopenharmony_ci unsigned int n) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci unsigned int i; 1708c2ecf20Sopenharmony_ci unsigned int count; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci count = 2; 1738c2ecf20Sopenharmony_ci for (i = 0; i < n; ++i) { 1748c2ecf20Sopenharmony_ci if (S_ISDIR(entries[i].mode)) 1758c2ecf20Sopenharmony_ci ++count; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return count; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int get_task_root(struct task_struct *task, struct path *root) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci int result = -ENOENT; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci task_lock(task); 1868c2ecf20Sopenharmony_ci if (task->fs) { 1878c2ecf20Sopenharmony_ci get_fs_root(task->fs, root); 1888c2ecf20Sopenharmony_ci result = 0; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci task_unlock(task); 1918c2ecf20Sopenharmony_ci return result; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int proc_cwd_link(struct dentry *dentry, struct path *path) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(d_inode(dentry)); 1978c2ecf20Sopenharmony_ci int result = -ENOENT; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (task) { 2008c2ecf20Sopenharmony_ci task_lock(task); 2018c2ecf20Sopenharmony_ci if (task->fs) { 2028c2ecf20Sopenharmony_ci get_fs_pwd(task->fs, path); 2038c2ecf20Sopenharmony_ci result = 0; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci task_unlock(task); 2068c2ecf20Sopenharmony_ci put_task_struct(task); 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci return result; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int proc_root_link(struct dentry *dentry, struct path *path) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(d_inode(dentry)); 2148c2ecf20Sopenharmony_ci int result = -ENOENT; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (task) { 2178c2ecf20Sopenharmony_ci result = get_task_root(task, path); 2188c2ecf20Sopenharmony_ci put_task_struct(task); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci return result; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* 2248c2ecf20Sopenharmony_ci * If the user used setproctitle(), we just get the string from 2258c2ecf20Sopenharmony_ci * user space at arg_start, and limit it to a maximum of one page. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_cistatic ssize_t get_mm_proctitle(struct mm_struct *mm, char __user *buf, 2288c2ecf20Sopenharmony_ci size_t count, unsigned long pos, 2298c2ecf20Sopenharmony_ci unsigned long arg_start) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci char *page; 2328c2ecf20Sopenharmony_ci int ret, got; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (pos >= PAGE_SIZE) 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci page = (char *)__get_free_page(GFP_KERNEL); 2388c2ecf20Sopenharmony_ci if (!page) 2398c2ecf20Sopenharmony_ci return -ENOMEM; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci ret = 0; 2428c2ecf20Sopenharmony_ci got = access_remote_vm(mm, arg_start, page, PAGE_SIZE, FOLL_ANON); 2438c2ecf20Sopenharmony_ci if (got > 0) { 2448c2ecf20Sopenharmony_ci int len = strnlen(page, got); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* Include the NUL character if it was found */ 2478c2ecf20Sopenharmony_ci if (len < got) 2488c2ecf20Sopenharmony_ci len++; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (len > pos) { 2518c2ecf20Sopenharmony_ci len -= pos; 2528c2ecf20Sopenharmony_ci if (len > count) 2538c2ecf20Sopenharmony_ci len = count; 2548c2ecf20Sopenharmony_ci len -= copy_to_user(buf, page+pos, len); 2558c2ecf20Sopenharmony_ci if (!len) 2568c2ecf20Sopenharmony_ci len = -EFAULT; 2578c2ecf20Sopenharmony_ci ret = len; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci free_page((unsigned long)page); 2618c2ecf20Sopenharmony_ci return ret; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf, 2658c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci unsigned long arg_start, arg_end, env_start, env_end; 2688c2ecf20Sopenharmony_ci unsigned long pos, len; 2698c2ecf20Sopenharmony_ci char *page, c; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Check if process spawned far enough to have cmdline. */ 2728c2ecf20Sopenharmony_ci if (!mm->env_end) 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci spin_lock(&mm->arg_lock); 2768c2ecf20Sopenharmony_ci arg_start = mm->arg_start; 2778c2ecf20Sopenharmony_ci arg_end = mm->arg_end; 2788c2ecf20Sopenharmony_ci env_start = mm->env_start; 2798c2ecf20Sopenharmony_ci env_end = mm->env_end; 2808c2ecf20Sopenharmony_ci spin_unlock(&mm->arg_lock); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (arg_start >= arg_end) 2838c2ecf20Sopenharmony_ci return 0; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* 2868c2ecf20Sopenharmony_ci * We allow setproctitle() to overwrite the argument 2878c2ecf20Sopenharmony_ci * strings, and overflow past the original end. But 2888c2ecf20Sopenharmony_ci * only when it overflows into the environment area. 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci if (env_start != arg_end || env_end < env_start) 2918c2ecf20Sopenharmony_ci env_start = env_end = arg_end; 2928c2ecf20Sopenharmony_ci len = env_end - arg_start; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* We're not going to care if "*ppos" has high bits set */ 2958c2ecf20Sopenharmony_ci pos = *ppos; 2968c2ecf20Sopenharmony_ci if (pos >= len) 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci if (count > len - pos) 2998c2ecf20Sopenharmony_ci count = len - pos; 3008c2ecf20Sopenharmony_ci if (!count) 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* 3048c2ecf20Sopenharmony_ci * Magical special case: if the argv[] end byte is not 3058c2ecf20Sopenharmony_ci * zero, the user has overwritten it with setproctitle(3). 3068c2ecf20Sopenharmony_ci * 3078c2ecf20Sopenharmony_ci * Possible future enhancement: do this only once when 3088c2ecf20Sopenharmony_ci * pos is 0, and set a flag in the 'struct file'. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci if (access_remote_vm(mm, arg_end-1, &c, 1, FOLL_ANON) == 1 && c) 3118c2ecf20Sopenharmony_ci return get_mm_proctitle(mm, buf, count, pos, arg_start); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* 3148c2ecf20Sopenharmony_ci * For the non-setproctitle() case we limit things strictly 3158c2ecf20Sopenharmony_ci * to the [arg_start, arg_end[ range. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci pos += arg_start; 3188c2ecf20Sopenharmony_ci if (pos < arg_start || pos >= arg_end) 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci if (count > arg_end - pos) 3218c2ecf20Sopenharmony_ci count = arg_end - pos; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci page = (char *)__get_free_page(GFP_KERNEL); 3248c2ecf20Sopenharmony_ci if (!page) 3258c2ecf20Sopenharmony_ci return -ENOMEM; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci len = 0; 3288c2ecf20Sopenharmony_ci while (count) { 3298c2ecf20Sopenharmony_ci int got; 3308c2ecf20Sopenharmony_ci size_t size = min_t(size_t, PAGE_SIZE, count); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci got = access_remote_vm(mm, pos, page, size, FOLL_ANON); 3338c2ecf20Sopenharmony_ci if (got <= 0) 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci got -= copy_to_user(buf, page, got); 3368c2ecf20Sopenharmony_ci if (unlikely(!got)) { 3378c2ecf20Sopenharmony_ci if (!len) 3388c2ecf20Sopenharmony_ci len = -EFAULT; 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci pos += got; 3428c2ecf20Sopenharmony_ci buf += got; 3438c2ecf20Sopenharmony_ci len += got; 3448c2ecf20Sopenharmony_ci count -= got; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci free_page((unsigned long)page); 3488c2ecf20Sopenharmony_ci return len; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic ssize_t get_task_cmdline(struct task_struct *tsk, char __user *buf, 3528c2ecf20Sopenharmony_ci size_t count, loff_t *pos) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct mm_struct *mm; 3558c2ecf20Sopenharmony_ci ssize_t ret; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci mm = get_task_mm(tsk); 3588c2ecf20Sopenharmony_ci if (!mm) 3598c2ecf20Sopenharmony_ci return 0; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci ret = get_mm_cmdline(mm, buf, count, pos); 3628c2ecf20Sopenharmony_ci mmput(mm); 3638c2ecf20Sopenharmony_ci return ret; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, 3678c2ecf20Sopenharmony_ci size_t count, loff_t *pos) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct task_struct *tsk; 3708c2ecf20Sopenharmony_ci ssize_t ret; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci BUG_ON(*pos < 0); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci tsk = get_proc_task(file_inode(file)); 3758c2ecf20Sopenharmony_ci if (!tsk) 3768c2ecf20Sopenharmony_ci return -ESRCH; 3778c2ecf20Sopenharmony_ci ret = get_task_cmdline(tsk, buf, count, pos); 3788c2ecf20Sopenharmony_ci put_task_struct(tsk); 3798c2ecf20Sopenharmony_ci if (ret > 0) 3808c2ecf20Sopenharmony_ci *pos += ret; 3818c2ecf20Sopenharmony_ci return ret; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic const struct file_operations proc_pid_cmdline_ops = { 3858c2ecf20Sopenharmony_ci .read = proc_pid_cmdline_read, 3868c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 3878c2ecf20Sopenharmony_ci}; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci#ifdef CONFIG_KALLSYMS 3908c2ecf20Sopenharmony_ci/* 3918c2ecf20Sopenharmony_ci * Provides a wchan file via kallsyms in a proper one-value-per-file format. 3928c2ecf20Sopenharmony_ci * Returns the resolved symbol. If that fails, simply return the address. 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_cistatic int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns, 3958c2ecf20Sopenharmony_ci struct pid *pid, struct task_struct *task) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci unsigned long wchan; 3988c2ecf20Sopenharmony_ci char symname[KSYM_NAME_LEN]; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) 4018c2ecf20Sopenharmony_ci goto print0; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci wchan = get_wchan(task); 4048c2ecf20Sopenharmony_ci if (wchan && !lookup_symbol_name(wchan, symname)) { 4058c2ecf20Sopenharmony_ci seq_puts(m, symname); 4068c2ecf20Sopenharmony_ci return 0; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ciprint0: 4108c2ecf20Sopenharmony_ci seq_putc(m, '0'); 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci#endif /* CONFIG_KALLSYMS */ 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic int lock_trace(struct task_struct *task) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci int err = down_read_killable(&task->signal->exec_update_lock); 4188c2ecf20Sopenharmony_ci if (err) 4198c2ecf20Sopenharmony_ci return err; 4208c2ecf20Sopenharmony_ci if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) { 4218c2ecf20Sopenharmony_ci up_read(&task->signal->exec_update_lock); 4228c2ecf20Sopenharmony_ci return -EPERM; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic void unlock_trace(struct task_struct *task) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci up_read(&task->signal->exec_update_lock); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci#ifdef CONFIG_STACKTRACE 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci#define MAX_STACK_TRACE_DEPTH 64 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, 4378c2ecf20Sopenharmony_ci struct pid *pid, struct task_struct *task) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci unsigned long *entries; 4408c2ecf20Sopenharmony_ci int err; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* 4438c2ecf20Sopenharmony_ci * The ability to racily run the kernel stack unwinder on a running task 4448c2ecf20Sopenharmony_ci * and then observe the unwinder output is scary; while it is useful for 4458c2ecf20Sopenharmony_ci * debugging kernel issues, it can also allow an attacker to leak kernel 4468c2ecf20Sopenharmony_ci * stack contents. 4478c2ecf20Sopenharmony_ci * Doing this in a manner that is at least safe from races would require 4488c2ecf20Sopenharmony_ci * some work to ensure that the remote task can not be scheduled; and 4498c2ecf20Sopenharmony_ci * even then, this would still expose the unwinder as local attack 4508c2ecf20Sopenharmony_ci * surface. 4518c2ecf20Sopenharmony_ci * Therefore, this interface is restricted to root. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_ci if (!file_ns_capable(m->file, &init_user_ns, CAP_SYS_ADMIN)) 4548c2ecf20Sopenharmony_ci return -EACCES; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci entries = kmalloc_array(MAX_STACK_TRACE_DEPTH, sizeof(*entries), 4578c2ecf20Sopenharmony_ci GFP_KERNEL); 4588c2ecf20Sopenharmony_ci if (!entries) 4598c2ecf20Sopenharmony_ci return -ENOMEM; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci err = lock_trace(task); 4628c2ecf20Sopenharmony_ci if (!err) { 4638c2ecf20Sopenharmony_ci unsigned int i, nr_entries; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci nr_entries = stack_trace_save_tsk(task, entries, 4668c2ecf20Sopenharmony_ci MAX_STACK_TRACE_DEPTH, 0); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci for (i = 0; i < nr_entries; i++) { 4698c2ecf20Sopenharmony_ci seq_printf(m, "[<0>] %pB\n", (void *)entries[i]); 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci unlock_trace(task); 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci kfree(entries); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return err; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci#endif 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_INFO 4818c2ecf20Sopenharmony_ci/* 4828c2ecf20Sopenharmony_ci * Provides /proc/PID/schedstat 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_cistatic int proc_pid_schedstat(struct seq_file *m, struct pid_namespace *ns, 4858c2ecf20Sopenharmony_ci struct pid *pid, struct task_struct *task) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci if (unlikely(!sched_info_on())) 4888c2ecf20Sopenharmony_ci seq_puts(m, "0 0 0\n"); 4898c2ecf20Sopenharmony_ci else 4908c2ecf20Sopenharmony_ci seq_printf(m, "%llu %llu %lu\n", 4918c2ecf20Sopenharmony_ci (unsigned long long)task->se.sum_exec_runtime, 4928c2ecf20Sopenharmony_ci (unsigned long long)task->sched_info.run_delay, 4938c2ecf20Sopenharmony_ci task->sched_info.pcount); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci#endif 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci#ifdef CONFIG_LATENCYTOP 5008c2ecf20Sopenharmony_cistatic int lstats_show_proc(struct seq_file *m, void *v) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci int i; 5038c2ecf20Sopenharmony_ci struct inode *inode = m->private; 5048c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(inode); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (!task) 5078c2ecf20Sopenharmony_ci return -ESRCH; 5088c2ecf20Sopenharmony_ci seq_puts(m, "Latency Top version : v0.1\n"); 5098c2ecf20Sopenharmony_ci for (i = 0; i < LT_SAVECOUNT; i++) { 5108c2ecf20Sopenharmony_ci struct latency_record *lr = &task->latency_record[i]; 5118c2ecf20Sopenharmony_ci if (lr->backtrace[0]) { 5128c2ecf20Sopenharmony_ci int q; 5138c2ecf20Sopenharmony_ci seq_printf(m, "%i %li %li", 5148c2ecf20Sopenharmony_ci lr->count, lr->time, lr->max); 5158c2ecf20Sopenharmony_ci for (q = 0; q < LT_BACKTRACEDEPTH; q++) { 5168c2ecf20Sopenharmony_ci unsigned long bt = lr->backtrace[q]; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (!bt) 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci seq_printf(m, " %ps", (void *)bt); 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci put_task_struct(task); 5278c2ecf20Sopenharmony_ci return 0; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic int lstats_open(struct inode *inode, struct file *file) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci return single_open(file, lstats_show_proc, inode); 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic ssize_t lstats_write(struct file *file, const char __user *buf, 5368c2ecf20Sopenharmony_ci size_t count, loff_t *offs) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(file_inode(file)); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (!task) 5418c2ecf20Sopenharmony_ci return -ESRCH; 5428c2ecf20Sopenharmony_ci clear_tsk_latency_tracing(task); 5438c2ecf20Sopenharmony_ci put_task_struct(task); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci return count; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic const struct file_operations proc_lstats_operations = { 5498c2ecf20Sopenharmony_ci .open = lstats_open, 5508c2ecf20Sopenharmony_ci .read = seq_read, 5518c2ecf20Sopenharmony_ci .write = lstats_write, 5528c2ecf20Sopenharmony_ci .llseek = seq_lseek, 5538c2ecf20Sopenharmony_ci .release = single_release, 5548c2ecf20Sopenharmony_ci}; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci#endif 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cistatic int proc_oom_score(struct seq_file *m, struct pid_namespace *ns, 5598c2ecf20Sopenharmony_ci struct pid *pid, struct task_struct *task) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci unsigned long totalpages = totalram_pages() + total_swap_pages; 5628c2ecf20Sopenharmony_ci unsigned long points = 0; 5638c2ecf20Sopenharmony_ci long badness; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci badness = oom_badness(task, totalpages); 5668c2ecf20Sopenharmony_ci /* 5678c2ecf20Sopenharmony_ci * Special case OOM_SCORE_ADJ_MIN for all others scale the 5688c2ecf20Sopenharmony_ci * badness value into [0, 2000] range which we have been 5698c2ecf20Sopenharmony_ci * exporting for a long time so userspace might depend on it. 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_ci if (badness != LONG_MIN) 5728c2ecf20Sopenharmony_ci points = (1000 + badness * 1000 / (long)totalpages) * 2 / 3; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci seq_printf(m, "%lu\n", points); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci return 0; 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistruct limit_names { 5808c2ecf20Sopenharmony_ci const char *name; 5818c2ecf20Sopenharmony_ci const char *unit; 5828c2ecf20Sopenharmony_ci}; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_cistatic const struct limit_names lnames[RLIM_NLIMITS] = { 5858c2ecf20Sopenharmony_ci [RLIMIT_CPU] = {"Max cpu time", "seconds"}, 5868c2ecf20Sopenharmony_ci [RLIMIT_FSIZE] = {"Max file size", "bytes"}, 5878c2ecf20Sopenharmony_ci [RLIMIT_DATA] = {"Max data size", "bytes"}, 5888c2ecf20Sopenharmony_ci [RLIMIT_STACK] = {"Max stack size", "bytes"}, 5898c2ecf20Sopenharmony_ci [RLIMIT_CORE] = {"Max core file size", "bytes"}, 5908c2ecf20Sopenharmony_ci [RLIMIT_RSS] = {"Max resident set", "bytes"}, 5918c2ecf20Sopenharmony_ci [RLIMIT_NPROC] = {"Max processes", "processes"}, 5928c2ecf20Sopenharmony_ci [RLIMIT_NOFILE] = {"Max open files", "files"}, 5938c2ecf20Sopenharmony_ci [RLIMIT_MEMLOCK] = {"Max locked memory", "bytes"}, 5948c2ecf20Sopenharmony_ci [RLIMIT_AS] = {"Max address space", "bytes"}, 5958c2ecf20Sopenharmony_ci [RLIMIT_LOCKS] = {"Max file locks", "locks"}, 5968c2ecf20Sopenharmony_ci [RLIMIT_SIGPENDING] = {"Max pending signals", "signals"}, 5978c2ecf20Sopenharmony_ci [RLIMIT_MSGQUEUE] = {"Max msgqueue size", "bytes"}, 5988c2ecf20Sopenharmony_ci [RLIMIT_NICE] = {"Max nice priority", NULL}, 5998c2ecf20Sopenharmony_ci [RLIMIT_RTPRIO] = {"Max realtime priority", NULL}, 6008c2ecf20Sopenharmony_ci [RLIMIT_RTTIME] = {"Max realtime timeout", "us"}, 6018c2ecf20Sopenharmony_ci}; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci/* Display limits for a process */ 6048c2ecf20Sopenharmony_cistatic int proc_pid_limits(struct seq_file *m, struct pid_namespace *ns, 6058c2ecf20Sopenharmony_ci struct pid *pid, struct task_struct *task) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci unsigned int i; 6088c2ecf20Sopenharmony_ci unsigned long flags; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci struct rlimit rlim[RLIM_NLIMITS]; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (!lock_task_sighand(task, &flags)) 6138c2ecf20Sopenharmony_ci return 0; 6148c2ecf20Sopenharmony_ci memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS); 6158c2ecf20Sopenharmony_ci unlock_task_sighand(task, &flags); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* 6188c2ecf20Sopenharmony_ci * print the file header 6198c2ecf20Sopenharmony_ci */ 6208c2ecf20Sopenharmony_ci seq_puts(m, "Limit " 6218c2ecf20Sopenharmony_ci "Soft Limit " 6228c2ecf20Sopenharmony_ci "Hard Limit " 6238c2ecf20Sopenharmony_ci "Units \n"); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci for (i = 0; i < RLIM_NLIMITS; i++) { 6268c2ecf20Sopenharmony_ci if (rlim[i].rlim_cur == RLIM_INFINITY) 6278c2ecf20Sopenharmony_ci seq_printf(m, "%-25s %-20s ", 6288c2ecf20Sopenharmony_ci lnames[i].name, "unlimited"); 6298c2ecf20Sopenharmony_ci else 6308c2ecf20Sopenharmony_ci seq_printf(m, "%-25s %-20lu ", 6318c2ecf20Sopenharmony_ci lnames[i].name, rlim[i].rlim_cur); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (rlim[i].rlim_max == RLIM_INFINITY) 6348c2ecf20Sopenharmony_ci seq_printf(m, "%-20s ", "unlimited"); 6358c2ecf20Sopenharmony_ci else 6368c2ecf20Sopenharmony_ci seq_printf(m, "%-20lu ", rlim[i].rlim_max); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (lnames[i].unit) 6398c2ecf20Sopenharmony_ci seq_printf(m, "%-10s\n", lnames[i].unit); 6408c2ecf20Sopenharmony_ci else 6418c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return 0; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_TRACEHOOK 6488c2ecf20Sopenharmony_cistatic int proc_pid_syscall(struct seq_file *m, struct pid_namespace *ns, 6498c2ecf20Sopenharmony_ci struct pid *pid, struct task_struct *task) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci struct syscall_info info; 6528c2ecf20Sopenharmony_ci u64 *args = &info.data.args[0]; 6538c2ecf20Sopenharmony_ci int res; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci res = lock_trace(task); 6568c2ecf20Sopenharmony_ci if (res) 6578c2ecf20Sopenharmony_ci return res; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (task_current_syscall(task, &info)) 6608c2ecf20Sopenharmony_ci seq_puts(m, "running\n"); 6618c2ecf20Sopenharmony_ci else if (info.data.nr < 0) 6628c2ecf20Sopenharmony_ci seq_printf(m, "%d 0x%llx 0x%llx\n", 6638c2ecf20Sopenharmony_ci info.data.nr, info.sp, info.data.instruction_pointer); 6648c2ecf20Sopenharmony_ci else 6658c2ecf20Sopenharmony_ci seq_printf(m, 6668c2ecf20Sopenharmony_ci "%d 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx\n", 6678c2ecf20Sopenharmony_ci info.data.nr, 6688c2ecf20Sopenharmony_ci args[0], args[1], args[2], args[3], args[4], args[5], 6698c2ecf20Sopenharmony_ci info.sp, info.data.instruction_pointer); 6708c2ecf20Sopenharmony_ci unlock_trace(task); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci return 0; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci#endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci/************************************************************************/ 6778c2ecf20Sopenharmony_ci/* Here the fs part begins */ 6788c2ecf20Sopenharmony_ci/************************************************************************/ 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci/* permission checks */ 6818c2ecf20Sopenharmony_cistatic int proc_fd_access_allowed(struct inode *inode) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci struct task_struct *task; 6848c2ecf20Sopenharmony_ci int allowed = 0; 6858c2ecf20Sopenharmony_ci /* Allow access to a task's file descriptors if it is us or we 6868c2ecf20Sopenharmony_ci * may use ptrace attach to the process and find out that 6878c2ecf20Sopenharmony_ci * information. 6888c2ecf20Sopenharmony_ci */ 6898c2ecf20Sopenharmony_ci task = get_proc_task(inode); 6908c2ecf20Sopenharmony_ci if (task) { 6918c2ecf20Sopenharmony_ci allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); 6928c2ecf20Sopenharmony_ci put_task_struct(task); 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci return allowed; 6958c2ecf20Sopenharmony_ci} 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ciint proc_setattr(struct dentry *dentry, struct iattr *attr) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci int error; 7008c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (attr->ia_valid & ATTR_MODE) 7038c2ecf20Sopenharmony_ci return -EPERM; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci error = setattr_prepare(dentry, attr); 7068c2ecf20Sopenharmony_ci if (error) 7078c2ecf20Sopenharmony_ci return error; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci setattr_copy(inode, attr); 7108c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 7118c2ecf20Sopenharmony_ci return 0; 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci/* 7158c2ecf20Sopenharmony_ci * May current process learn task's sched/cmdline info (for hide_pid_min=1) 7168c2ecf20Sopenharmony_ci * or euid/egid (for hide_pid_min=2)? 7178c2ecf20Sopenharmony_ci */ 7188c2ecf20Sopenharmony_cistatic bool has_pid_permissions(struct proc_fs_info *fs_info, 7198c2ecf20Sopenharmony_ci struct task_struct *task, 7208c2ecf20Sopenharmony_ci enum proc_hidepid hide_pid_min) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci /* 7238c2ecf20Sopenharmony_ci * If 'hidpid' mount option is set force a ptrace check, 7248c2ecf20Sopenharmony_ci * we indicate that we are using a filesystem syscall 7258c2ecf20Sopenharmony_ci * by passing PTRACE_MODE_READ_FSCREDS 7268c2ecf20Sopenharmony_ci */ 7278c2ecf20Sopenharmony_ci if (fs_info->hide_pid == HIDEPID_NOT_PTRACEABLE) 7288c2ecf20Sopenharmony_ci return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (fs_info->hide_pid < hide_pid_min) 7318c2ecf20Sopenharmony_ci return true; 7328c2ecf20Sopenharmony_ci if (in_group_p(fs_info->pid_gid)) 7338c2ecf20Sopenharmony_ci return true; 7348c2ecf20Sopenharmony_ci return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_cistatic int proc_pid_permission(struct inode *inode, int mask) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); 7418c2ecf20Sopenharmony_ci struct task_struct *task; 7428c2ecf20Sopenharmony_ci bool has_perms; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci task = get_proc_task(inode); 7458c2ecf20Sopenharmony_ci if (!task) 7468c2ecf20Sopenharmony_ci return -ESRCH; 7478c2ecf20Sopenharmony_ci has_perms = has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS); 7488c2ecf20Sopenharmony_ci put_task_struct(task); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci if (!has_perms) { 7518c2ecf20Sopenharmony_ci if (fs_info->hide_pid == HIDEPID_INVISIBLE) { 7528c2ecf20Sopenharmony_ci /* 7538c2ecf20Sopenharmony_ci * Let's make getdents(), stat(), and open() 7548c2ecf20Sopenharmony_ci * consistent with each other. If a process 7558c2ecf20Sopenharmony_ci * may not stat() a file, it shouldn't be seen 7568c2ecf20Sopenharmony_ci * in procfs at all. 7578c2ecf20Sopenharmony_ci */ 7588c2ecf20Sopenharmony_ci return -ENOENT; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci return -EPERM; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci return generic_permission(inode, mask); 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistatic const struct inode_operations proc_def_inode_operations = { 7698c2ecf20Sopenharmony_ci .setattr = proc_setattr, 7708c2ecf20Sopenharmony_ci}; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic int proc_single_show(struct seq_file *m, void *v) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci struct inode *inode = m->private; 7758c2ecf20Sopenharmony_ci struct pid_namespace *ns = proc_pid_ns(inode->i_sb); 7768c2ecf20Sopenharmony_ci struct pid *pid = proc_pid(inode); 7778c2ecf20Sopenharmony_ci struct task_struct *task; 7788c2ecf20Sopenharmony_ci int ret; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci task = get_pid_task(pid, PIDTYPE_PID); 7818c2ecf20Sopenharmony_ci if (!task) 7828c2ecf20Sopenharmony_ci return -ESRCH; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci ret = PROC_I(inode)->op.proc_show(m, ns, pid, task); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci put_task_struct(task); 7878c2ecf20Sopenharmony_ci return ret; 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic int proc_single_open(struct inode *inode, struct file *filp) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci return single_open(filp, proc_single_show, inode); 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_cistatic const struct file_operations proc_single_file_operations = { 7968c2ecf20Sopenharmony_ci .open = proc_single_open, 7978c2ecf20Sopenharmony_ci .read = seq_read, 7988c2ecf20Sopenharmony_ci .llseek = seq_lseek, 7998c2ecf20Sopenharmony_ci .release = single_release, 8008c2ecf20Sopenharmony_ci}; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistruct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(inode); 8068c2ecf20Sopenharmony_ci struct mm_struct *mm = ERR_PTR(-ESRCH); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if (task) { 8098c2ecf20Sopenharmony_ci mm = mm_access(task, mode | PTRACE_MODE_FSCREDS); 8108c2ecf20Sopenharmony_ci put_task_struct(task); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(mm)) { 8138c2ecf20Sopenharmony_ci /* ensure this mm_struct can't be freed */ 8148c2ecf20Sopenharmony_ci mmgrab(mm); 8158c2ecf20Sopenharmony_ci /* but do not pin its memory */ 8168c2ecf20Sopenharmony_ci mmput(mm); 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci return mm; 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_cistatic int __mem_open(struct inode *inode, struct file *file, unsigned int mode) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci struct mm_struct *mm = proc_mem_open(inode, mode); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (IS_ERR(mm)) 8288c2ecf20Sopenharmony_ci return PTR_ERR(mm); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci file->private_data = mm; 8318c2ecf20Sopenharmony_ci return 0; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistatic int mem_open(struct inode *inode, struct file *file) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci int ret = __mem_open(inode, file, PTRACE_MODE_ATTACH); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci /* OK to pass negative loff_t, we can catch out-of-range */ 8398c2ecf20Sopenharmony_ci file->f_mode |= FMODE_UNSIGNED_OFFSET; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci return ret; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistatic ssize_t mem_rw(struct file *file, char __user *buf, 8458c2ecf20Sopenharmony_ci size_t count, loff_t *ppos, int write) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct mm_struct *mm = file->private_data; 8488c2ecf20Sopenharmony_ci unsigned long addr = *ppos; 8498c2ecf20Sopenharmony_ci ssize_t copied; 8508c2ecf20Sopenharmony_ci char *page; 8518c2ecf20Sopenharmony_ci unsigned int flags; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (!mm) 8548c2ecf20Sopenharmony_ci return 0; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci page = (char *)__get_free_page(GFP_KERNEL); 8578c2ecf20Sopenharmony_ci if (!page) 8588c2ecf20Sopenharmony_ci return -ENOMEM; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci copied = 0; 8618c2ecf20Sopenharmony_ci if (!mmget_not_zero(mm)) 8628c2ecf20Sopenharmony_ci goto free; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci flags = FOLL_FORCE | (write ? FOLL_WRITE : 0); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci while (count > 0) { 8678c2ecf20Sopenharmony_ci size_t this_len = min_t(size_t, count, PAGE_SIZE); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci if (write && copy_from_user(page, buf, this_len)) { 8708c2ecf20Sopenharmony_ci copied = -EFAULT; 8718c2ecf20Sopenharmony_ci break; 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci this_len = access_remote_vm(mm, addr, page, this_len, flags); 8758c2ecf20Sopenharmony_ci if (!this_len) { 8768c2ecf20Sopenharmony_ci if (!copied) 8778c2ecf20Sopenharmony_ci copied = -EIO; 8788c2ecf20Sopenharmony_ci break; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if (!write && copy_to_user(buf, page, this_len)) { 8828c2ecf20Sopenharmony_ci copied = -EFAULT; 8838c2ecf20Sopenharmony_ci break; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci buf += this_len; 8878c2ecf20Sopenharmony_ci addr += this_len; 8888c2ecf20Sopenharmony_ci copied += this_len; 8898c2ecf20Sopenharmony_ci count -= this_len; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci *ppos = addr; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci mmput(mm); 8948c2ecf20Sopenharmony_cifree: 8958c2ecf20Sopenharmony_ci free_page((unsigned long) page); 8968c2ecf20Sopenharmony_ci return copied; 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cistatic ssize_t mem_read(struct file *file, char __user *buf, 9008c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci return mem_rw(file, buf, count, ppos, 0); 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic ssize_t mem_write(struct file *file, const char __user *buf, 9068c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci return mem_rw(file, (char __user*)buf, count, ppos, 1); 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ciloff_t mem_lseek(struct file *file, loff_t offset, int orig) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci loff_t ret = 0; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci spin_lock(&file->f_lock); 9168c2ecf20Sopenharmony_ci switch (orig) { 9178c2ecf20Sopenharmony_ci case SEEK_CUR: 9188c2ecf20Sopenharmony_ci offset += file->f_pos; 9198c2ecf20Sopenharmony_ci /* fall through */ 9208c2ecf20Sopenharmony_ci case SEEK_SET: 9218c2ecf20Sopenharmony_ci /* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */ 9228c2ecf20Sopenharmony_ci if ((unsigned long long)offset >= -MAX_ERRNO) 9238c2ecf20Sopenharmony_ci ret = -EOVERFLOW; 9248c2ecf20Sopenharmony_ci break; 9258c2ecf20Sopenharmony_ci default: 9268c2ecf20Sopenharmony_ci ret = -EINVAL; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci if (!ret) { 9308c2ecf20Sopenharmony_ci if (offset < 0 && !(unsigned_offsets(file))) { 9318c2ecf20Sopenharmony_ci ret = -EINVAL; 9328c2ecf20Sopenharmony_ci } else { 9338c2ecf20Sopenharmony_ci file->f_pos = offset; 9348c2ecf20Sopenharmony_ci ret = file->f_pos; 9358c2ecf20Sopenharmony_ci force_successful_syscall_return(); 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci spin_unlock(&file->f_lock); 9408c2ecf20Sopenharmony_ci return ret; 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_cistatic int mem_release(struct inode *inode, struct file *file) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci struct mm_struct *mm = file->private_data; 9468c2ecf20Sopenharmony_ci if (mm) 9478c2ecf20Sopenharmony_ci mmdrop(mm); 9488c2ecf20Sopenharmony_ci return 0; 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_cistatic const struct file_operations proc_mem_operations = { 9528c2ecf20Sopenharmony_ci .llseek = mem_lseek, 9538c2ecf20Sopenharmony_ci .read = mem_read, 9548c2ecf20Sopenharmony_ci .write = mem_write, 9558c2ecf20Sopenharmony_ci .open = mem_open, 9568c2ecf20Sopenharmony_ci .release = mem_release, 9578c2ecf20Sopenharmony_ci}; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic int environ_open(struct inode *inode, struct file *file) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci return __mem_open(inode, file, PTRACE_MODE_READ); 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_cistatic ssize_t environ_read(struct file *file, char __user *buf, 9658c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci char *page; 9688c2ecf20Sopenharmony_ci unsigned long src = *ppos; 9698c2ecf20Sopenharmony_ci int ret = 0; 9708c2ecf20Sopenharmony_ci struct mm_struct *mm = file->private_data; 9718c2ecf20Sopenharmony_ci unsigned long env_start, env_end; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci /* Ensure the process spawned far enough to have an environment. */ 9748c2ecf20Sopenharmony_ci if (!mm || !mm->env_end) 9758c2ecf20Sopenharmony_ci return 0; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci page = (char *)__get_free_page(GFP_KERNEL); 9788c2ecf20Sopenharmony_ci if (!page) 9798c2ecf20Sopenharmony_ci return -ENOMEM; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci ret = 0; 9828c2ecf20Sopenharmony_ci if (!mmget_not_zero(mm)) 9838c2ecf20Sopenharmony_ci goto free; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci spin_lock(&mm->arg_lock); 9868c2ecf20Sopenharmony_ci env_start = mm->env_start; 9878c2ecf20Sopenharmony_ci env_end = mm->env_end; 9888c2ecf20Sopenharmony_ci spin_unlock(&mm->arg_lock); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci while (count > 0) { 9918c2ecf20Sopenharmony_ci size_t this_len, max_len; 9928c2ecf20Sopenharmony_ci int retval; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (src >= (env_end - env_start)) 9958c2ecf20Sopenharmony_ci break; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci this_len = env_end - (env_start + src); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci max_len = min_t(size_t, PAGE_SIZE, count); 10008c2ecf20Sopenharmony_ci this_len = min(max_len, this_len); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci retval = access_remote_vm(mm, (env_start + src), page, this_len, FOLL_ANON); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (retval <= 0) { 10058c2ecf20Sopenharmony_ci ret = retval; 10068c2ecf20Sopenharmony_ci break; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (copy_to_user(buf, page, retval)) { 10108c2ecf20Sopenharmony_ci ret = -EFAULT; 10118c2ecf20Sopenharmony_ci break; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci ret += retval; 10158c2ecf20Sopenharmony_ci src += retval; 10168c2ecf20Sopenharmony_ci buf += retval; 10178c2ecf20Sopenharmony_ci count -= retval; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci *ppos = src; 10208c2ecf20Sopenharmony_ci mmput(mm); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cifree: 10238c2ecf20Sopenharmony_ci free_page((unsigned long) page); 10248c2ecf20Sopenharmony_ci return ret; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic const struct file_operations proc_environ_operations = { 10288c2ecf20Sopenharmony_ci .open = environ_open, 10298c2ecf20Sopenharmony_ci .read = environ_read, 10308c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 10318c2ecf20Sopenharmony_ci .release = mem_release, 10328c2ecf20Sopenharmony_ci}; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_cistatic int auxv_open(struct inode *inode, struct file *file) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci return __mem_open(inode, file, PTRACE_MODE_READ_FSCREDS); 10378c2ecf20Sopenharmony_ci} 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cistatic ssize_t auxv_read(struct file *file, char __user *buf, 10408c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci struct mm_struct *mm = file->private_data; 10438c2ecf20Sopenharmony_ci unsigned int nwords = 0; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (!mm) 10468c2ecf20Sopenharmony_ci return 0; 10478c2ecf20Sopenharmony_ci do { 10488c2ecf20Sopenharmony_ci nwords += 2; 10498c2ecf20Sopenharmony_ci } while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */ 10508c2ecf20Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, mm->saved_auxv, 10518c2ecf20Sopenharmony_ci nwords * sizeof(mm->saved_auxv[0])); 10528c2ecf20Sopenharmony_ci} 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_cistatic const struct file_operations proc_auxv_operations = { 10558c2ecf20Sopenharmony_ci .open = auxv_open, 10568c2ecf20Sopenharmony_ci .read = auxv_read, 10578c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 10588c2ecf20Sopenharmony_ci .release = mem_release, 10598c2ecf20Sopenharmony_ci}; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_cistatic ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count, 10628c2ecf20Sopenharmony_ci loff_t *ppos) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(file_inode(file)); 10658c2ecf20Sopenharmony_ci char buffer[PROC_NUMBUF]; 10668c2ecf20Sopenharmony_ci int oom_adj = OOM_ADJUST_MIN; 10678c2ecf20Sopenharmony_ci size_t len; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci if (!task) 10708c2ecf20Sopenharmony_ci return -ESRCH; 10718c2ecf20Sopenharmony_ci if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX) 10728c2ecf20Sopenharmony_ci oom_adj = OOM_ADJUST_MAX; 10738c2ecf20Sopenharmony_ci else 10748c2ecf20Sopenharmony_ci oom_adj = (task->signal->oom_score_adj * -OOM_DISABLE) / 10758c2ecf20Sopenharmony_ci OOM_SCORE_ADJ_MAX; 10768c2ecf20Sopenharmony_ci put_task_struct(task); 10778c2ecf20Sopenharmony_ci if (oom_adj > OOM_ADJUST_MAX) 10788c2ecf20Sopenharmony_ci oom_adj = OOM_ADJUST_MAX; 10798c2ecf20Sopenharmony_ci len = snprintf(buffer, sizeof(buffer), "%d\n", oom_adj); 10808c2ecf20Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, buffer, len); 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic int __set_oom_adj(struct file *file, int oom_adj, bool legacy) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci struct mm_struct *mm = NULL; 10868c2ecf20Sopenharmony_ci struct task_struct *task; 10878c2ecf20Sopenharmony_ci int err = 0; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci task = get_proc_task(file_inode(file)); 10908c2ecf20Sopenharmony_ci if (!task) 10918c2ecf20Sopenharmony_ci return -ESRCH; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci mutex_lock(&oom_adj_mutex); 10948c2ecf20Sopenharmony_ci if (legacy) { 10958c2ecf20Sopenharmony_ci if (oom_adj < task->signal->oom_score_adj && 10968c2ecf20Sopenharmony_ci !capable(CAP_SYS_RESOURCE)) { 10978c2ecf20Sopenharmony_ci err = -EACCES; 10988c2ecf20Sopenharmony_ci goto err_unlock; 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci /* 11018c2ecf20Sopenharmony_ci * /proc/pid/oom_adj is provided for legacy purposes, ask users to use 11028c2ecf20Sopenharmony_ci * /proc/pid/oom_score_adj instead. 11038c2ecf20Sopenharmony_ci */ 11048c2ecf20Sopenharmony_ci pr_warn_once("%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n", 11058c2ecf20Sopenharmony_ci current->comm, task_pid_nr(current), task_pid_nr(task), 11068c2ecf20Sopenharmony_ci task_pid_nr(task)); 11078c2ecf20Sopenharmony_ci } else { 11088c2ecf20Sopenharmony_ci if ((short)oom_adj < task->signal->oom_score_adj_min && 11098c2ecf20Sopenharmony_ci !capable(CAP_SYS_RESOURCE)) { 11108c2ecf20Sopenharmony_ci err = -EACCES; 11118c2ecf20Sopenharmony_ci goto err_unlock; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci /* 11168c2ecf20Sopenharmony_ci * Make sure we will check other processes sharing the mm if this is 11178c2ecf20Sopenharmony_ci * not vfrok which wants its own oom_score_adj. 11188c2ecf20Sopenharmony_ci * pin the mm so it doesn't go away and get reused after task_unlock 11198c2ecf20Sopenharmony_ci */ 11208c2ecf20Sopenharmony_ci if (!task->vfork_done) { 11218c2ecf20Sopenharmony_ci struct task_struct *p = find_lock_task_mm(task); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci if (p) { 11248c2ecf20Sopenharmony_ci if (test_bit(MMF_MULTIPROCESS, &p->mm->flags)) { 11258c2ecf20Sopenharmony_ci mm = p->mm; 11268c2ecf20Sopenharmony_ci mmgrab(mm); 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci task_unlock(p); 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci task->signal->oom_score_adj = oom_adj; 11338c2ecf20Sopenharmony_ci if (!legacy && has_capability_noaudit(current, CAP_SYS_RESOURCE)) 11348c2ecf20Sopenharmony_ci task->signal->oom_score_adj_min = (short)oom_adj; 11358c2ecf20Sopenharmony_ci trace_oom_score_adj_update(task); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if (mm) { 11388c2ecf20Sopenharmony_ci struct task_struct *p; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci rcu_read_lock(); 11418c2ecf20Sopenharmony_ci for_each_process(p) { 11428c2ecf20Sopenharmony_ci if (same_thread_group(task, p)) 11438c2ecf20Sopenharmony_ci continue; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci /* do not touch kernel threads or the global init */ 11468c2ecf20Sopenharmony_ci if (p->flags & PF_KTHREAD || is_global_init(p)) 11478c2ecf20Sopenharmony_ci continue; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci task_lock(p); 11508c2ecf20Sopenharmony_ci if (!p->vfork_done && process_shares_mm(p, mm)) { 11518c2ecf20Sopenharmony_ci p->signal->oom_score_adj = oom_adj; 11528c2ecf20Sopenharmony_ci if (!legacy && has_capability_noaudit(current, CAP_SYS_RESOURCE)) 11538c2ecf20Sopenharmony_ci p->signal->oom_score_adj_min = (short)oom_adj; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci task_unlock(p); 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci rcu_read_unlock(); 11588c2ecf20Sopenharmony_ci mmdrop(mm); 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_cierr_unlock: 11618c2ecf20Sopenharmony_ci mutex_unlock(&oom_adj_mutex); 11628c2ecf20Sopenharmony_ci put_task_struct(task); 11638c2ecf20Sopenharmony_ci return err; 11648c2ecf20Sopenharmony_ci} 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci/* 11678c2ecf20Sopenharmony_ci * /proc/pid/oom_adj exists solely for backwards compatibility with previous 11688c2ecf20Sopenharmony_ci * kernels. The effective policy is defined by oom_score_adj, which has a 11698c2ecf20Sopenharmony_ci * different scale: oom_adj grew exponentially and oom_score_adj grows linearly. 11708c2ecf20Sopenharmony_ci * Values written to oom_adj are simply mapped linearly to oom_score_adj. 11718c2ecf20Sopenharmony_ci * Processes that become oom disabled via oom_adj will still be oom disabled 11728c2ecf20Sopenharmony_ci * with this implementation. 11738c2ecf20Sopenharmony_ci * 11748c2ecf20Sopenharmony_ci * oom_adj cannot be removed since existing userspace binaries use it. 11758c2ecf20Sopenharmony_ci */ 11768c2ecf20Sopenharmony_cistatic ssize_t oom_adj_write(struct file *file, const char __user *buf, 11778c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci char buffer[PROC_NUMBUF]; 11808c2ecf20Sopenharmony_ci int oom_adj; 11818c2ecf20Sopenharmony_ci int err; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci memset(buffer, 0, sizeof(buffer)); 11848c2ecf20Sopenharmony_ci if (count > sizeof(buffer) - 1) 11858c2ecf20Sopenharmony_ci count = sizeof(buffer) - 1; 11868c2ecf20Sopenharmony_ci if (copy_from_user(buffer, buf, count)) { 11878c2ecf20Sopenharmony_ci err = -EFAULT; 11888c2ecf20Sopenharmony_ci goto out; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci err = kstrtoint(strstrip(buffer), 0, &oom_adj); 11928c2ecf20Sopenharmony_ci if (err) 11938c2ecf20Sopenharmony_ci goto out; 11948c2ecf20Sopenharmony_ci if ((oom_adj < OOM_ADJUST_MIN || oom_adj > OOM_ADJUST_MAX) && 11958c2ecf20Sopenharmony_ci oom_adj != OOM_DISABLE) { 11968c2ecf20Sopenharmony_ci err = -EINVAL; 11978c2ecf20Sopenharmony_ci goto out; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci /* 12018c2ecf20Sopenharmony_ci * Scale /proc/pid/oom_score_adj appropriately ensuring that a maximum 12028c2ecf20Sopenharmony_ci * value is always attainable. 12038c2ecf20Sopenharmony_ci */ 12048c2ecf20Sopenharmony_ci if (oom_adj == OOM_ADJUST_MAX) 12058c2ecf20Sopenharmony_ci oom_adj = OOM_SCORE_ADJ_MAX; 12068c2ecf20Sopenharmony_ci else 12078c2ecf20Sopenharmony_ci oom_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci err = __set_oom_adj(file, oom_adj, true); 12108c2ecf20Sopenharmony_ciout: 12118c2ecf20Sopenharmony_ci return err < 0 ? err : count; 12128c2ecf20Sopenharmony_ci} 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_cistatic const struct file_operations proc_oom_adj_operations = { 12158c2ecf20Sopenharmony_ci .read = oom_adj_read, 12168c2ecf20Sopenharmony_ci .write = oom_adj_write, 12178c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 12188c2ecf20Sopenharmony_ci}; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_cistatic ssize_t oom_score_adj_read(struct file *file, char __user *buf, 12218c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(file_inode(file)); 12248c2ecf20Sopenharmony_ci char buffer[PROC_NUMBUF]; 12258c2ecf20Sopenharmony_ci short oom_score_adj = OOM_SCORE_ADJ_MIN; 12268c2ecf20Sopenharmony_ci size_t len; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci if (!task) 12298c2ecf20Sopenharmony_ci return -ESRCH; 12308c2ecf20Sopenharmony_ci oom_score_adj = task->signal->oom_score_adj; 12318c2ecf20Sopenharmony_ci put_task_struct(task); 12328c2ecf20Sopenharmony_ci len = snprintf(buffer, sizeof(buffer), "%hd\n", oom_score_adj); 12338c2ecf20Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, buffer, len); 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic ssize_t oom_score_adj_write(struct file *file, const char __user *buf, 12378c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci char buffer[PROC_NUMBUF]; 12408c2ecf20Sopenharmony_ci int oom_score_adj; 12418c2ecf20Sopenharmony_ci int err; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci memset(buffer, 0, sizeof(buffer)); 12448c2ecf20Sopenharmony_ci if (count > sizeof(buffer) - 1) 12458c2ecf20Sopenharmony_ci count = sizeof(buffer) - 1; 12468c2ecf20Sopenharmony_ci if (copy_from_user(buffer, buf, count)) { 12478c2ecf20Sopenharmony_ci err = -EFAULT; 12488c2ecf20Sopenharmony_ci goto out; 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci err = kstrtoint(strstrip(buffer), 0, &oom_score_adj); 12528c2ecf20Sopenharmony_ci if (err) 12538c2ecf20Sopenharmony_ci goto out; 12548c2ecf20Sopenharmony_ci if (oom_score_adj < OOM_SCORE_ADJ_MIN || 12558c2ecf20Sopenharmony_ci oom_score_adj > OOM_SCORE_ADJ_MAX) { 12568c2ecf20Sopenharmony_ci err = -EINVAL; 12578c2ecf20Sopenharmony_ci goto out; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci err = __set_oom_adj(file, oom_score_adj, false); 12618c2ecf20Sopenharmony_ciout: 12628c2ecf20Sopenharmony_ci return err < 0 ? err : count; 12638c2ecf20Sopenharmony_ci} 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_cistatic const struct file_operations proc_oom_score_adj_operations = { 12668c2ecf20Sopenharmony_ci .read = oom_score_adj_read, 12678c2ecf20Sopenharmony_ci .write = oom_score_adj_write, 12688c2ecf20Sopenharmony_ci .llseek = default_llseek, 12698c2ecf20Sopenharmony_ci}; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 12728c2ecf20Sopenharmony_ci#define TMPBUFLEN 11 12738c2ecf20Sopenharmony_cistatic ssize_t proc_loginuid_read(struct file * file, char __user * buf, 12748c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 12758c2ecf20Sopenharmony_ci{ 12768c2ecf20Sopenharmony_ci struct inode * inode = file_inode(file); 12778c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(inode); 12788c2ecf20Sopenharmony_ci ssize_t length; 12798c2ecf20Sopenharmony_ci char tmpbuf[TMPBUFLEN]; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (!task) 12828c2ecf20Sopenharmony_ci return -ESRCH; 12838c2ecf20Sopenharmony_ci length = scnprintf(tmpbuf, TMPBUFLEN, "%u", 12848c2ecf20Sopenharmony_ci from_kuid(file->f_cred->user_ns, 12858c2ecf20Sopenharmony_ci audit_get_loginuid(task))); 12868c2ecf20Sopenharmony_ci put_task_struct(task); 12878c2ecf20Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_cistatic ssize_t proc_loginuid_write(struct file * file, const char __user * buf, 12918c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci struct inode * inode = file_inode(file); 12948c2ecf20Sopenharmony_ci uid_t loginuid; 12958c2ecf20Sopenharmony_ci kuid_t kloginuid; 12968c2ecf20Sopenharmony_ci int rv; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci /* Don't let kthreads write their own loginuid */ 12998c2ecf20Sopenharmony_ci if (current->flags & PF_KTHREAD) 13008c2ecf20Sopenharmony_ci return -EPERM; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci rcu_read_lock(); 13038c2ecf20Sopenharmony_ci if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) { 13048c2ecf20Sopenharmony_ci rcu_read_unlock(); 13058c2ecf20Sopenharmony_ci return -EPERM; 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci rcu_read_unlock(); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (*ppos != 0) { 13108c2ecf20Sopenharmony_ci /* No partial writes. */ 13118c2ecf20Sopenharmony_ci return -EINVAL; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci rv = kstrtou32_from_user(buf, count, 10, &loginuid); 13158c2ecf20Sopenharmony_ci if (rv < 0) 13168c2ecf20Sopenharmony_ci return rv; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci /* is userspace tring to explicitly UNSET the loginuid? */ 13198c2ecf20Sopenharmony_ci if (loginuid == AUDIT_UID_UNSET) { 13208c2ecf20Sopenharmony_ci kloginuid = INVALID_UID; 13218c2ecf20Sopenharmony_ci } else { 13228c2ecf20Sopenharmony_ci kloginuid = make_kuid(file->f_cred->user_ns, loginuid); 13238c2ecf20Sopenharmony_ci if (!uid_valid(kloginuid)) 13248c2ecf20Sopenharmony_ci return -EINVAL; 13258c2ecf20Sopenharmony_ci } 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci rv = audit_set_loginuid(kloginuid); 13288c2ecf20Sopenharmony_ci if (rv < 0) 13298c2ecf20Sopenharmony_ci return rv; 13308c2ecf20Sopenharmony_ci return count; 13318c2ecf20Sopenharmony_ci} 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_cistatic const struct file_operations proc_loginuid_operations = { 13348c2ecf20Sopenharmony_ci .read = proc_loginuid_read, 13358c2ecf20Sopenharmony_ci .write = proc_loginuid_write, 13368c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 13378c2ecf20Sopenharmony_ci}; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_cistatic ssize_t proc_sessionid_read(struct file * file, char __user * buf, 13408c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci struct inode * inode = file_inode(file); 13438c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(inode); 13448c2ecf20Sopenharmony_ci ssize_t length; 13458c2ecf20Sopenharmony_ci char tmpbuf[TMPBUFLEN]; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci if (!task) 13488c2ecf20Sopenharmony_ci return -ESRCH; 13498c2ecf20Sopenharmony_ci length = scnprintf(tmpbuf, TMPBUFLEN, "%u", 13508c2ecf20Sopenharmony_ci audit_get_sessionid(task)); 13518c2ecf20Sopenharmony_ci put_task_struct(task); 13528c2ecf20Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); 13538c2ecf20Sopenharmony_ci} 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_cistatic const struct file_operations proc_sessionid_operations = { 13568c2ecf20Sopenharmony_ci .read = proc_sessionid_read, 13578c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 13588c2ecf20Sopenharmony_ci}; 13598c2ecf20Sopenharmony_ci#endif 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION 13628c2ecf20Sopenharmony_cistatic ssize_t proc_fault_inject_read(struct file * file, char __user * buf, 13638c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 13648c2ecf20Sopenharmony_ci{ 13658c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(file_inode(file)); 13668c2ecf20Sopenharmony_ci char buffer[PROC_NUMBUF]; 13678c2ecf20Sopenharmony_ci size_t len; 13688c2ecf20Sopenharmony_ci int make_it_fail; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci if (!task) 13718c2ecf20Sopenharmony_ci return -ESRCH; 13728c2ecf20Sopenharmony_ci make_it_fail = task->make_it_fail; 13738c2ecf20Sopenharmony_ci put_task_struct(task); 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, buffer, len); 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_cistatic ssize_t proc_fault_inject_write(struct file * file, 13818c2ecf20Sopenharmony_ci const char __user * buf, size_t count, loff_t *ppos) 13828c2ecf20Sopenharmony_ci{ 13838c2ecf20Sopenharmony_ci struct task_struct *task; 13848c2ecf20Sopenharmony_ci char buffer[PROC_NUMBUF]; 13858c2ecf20Sopenharmony_ci int make_it_fail; 13868c2ecf20Sopenharmony_ci int rv; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_RESOURCE)) 13898c2ecf20Sopenharmony_ci return -EPERM; 13908c2ecf20Sopenharmony_ci memset(buffer, 0, sizeof(buffer)); 13918c2ecf20Sopenharmony_ci if (count > sizeof(buffer) - 1) 13928c2ecf20Sopenharmony_ci count = sizeof(buffer) - 1; 13938c2ecf20Sopenharmony_ci if (copy_from_user(buffer, buf, count)) 13948c2ecf20Sopenharmony_ci return -EFAULT; 13958c2ecf20Sopenharmony_ci rv = kstrtoint(strstrip(buffer), 0, &make_it_fail); 13968c2ecf20Sopenharmony_ci if (rv < 0) 13978c2ecf20Sopenharmony_ci return rv; 13988c2ecf20Sopenharmony_ci if (make_it_fail < 0 || make_it_fail > 1) 13998c2ecf20Sopenharmony_ci return -EINVAL; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci task = get_proc_task(file_inode(file)); 14028c2ecf20Sopenharmony_ci if (!task) 14038c2ecf20Sopenharmony_ci return -ESRCH; 14048c2ecf20Sopenharmony_ci task->make_it_fail = make_it_fail; 14058c2ecf20Sopenharmony_ci put_task_struct(task); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci return count; 14088c2ecf20Sopenharmony_ci} 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_cistatic const struct file_operations proc_fault_inject_operations = { 14118c2ecf20Sopenharmony_ci .read = proc_fault_inject_read, 14128c2ecf20Sopenharmony_ci .write = proc_fault_inject_write, 14138c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 14148c2ecf20Sopenharmony_ci}; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_cistatic ssize_t proc_fail_nth_write(struct file *file, const char __user *buf, 14178c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 14188c2ecf20Sopenharmony_ci{ 14198c2ecf20Sopenharmony_ci struct task_struct *task; 14208c2ecf20Sopenharmony_ci int err; 14218c2ecf20Sopenharmony_ci unsigned int n; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci err = kstrtouint_from_user(buf, count, 0, &n); 14248c2ecf20Sopenharmony_ci if (err) 14258c2ecf20Sopenharmony_ci return err; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci task = get_proc_task(file_inode(file)); 14288c2ecf20Sopenharmony_ci if (!task) 14298c2ecf20Sopenharmony_ci return -ESRCH; 14308c2ecf20Sopenharmony_ci task->fail_nth = n; 14318c2ecf20Sopenharmony_ci put_task_struct(task); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci return count; 14348c2ecf20Sopenharmony_ci} 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_cistatic ssize_t proc_fail_nth_read(struct file *file, char __user *buf, 14378c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 14388c2ecf20Sopenharmony_ci{ 14398c2ecf20Sopenharmony_ci struct task_struct *task; 14408c2ecf20Sopenharmony_ci char numbuf[PROC_NUMBUF]; 14418c2ecf20Sopenharmony_ci ssize_t len; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci task = get_proc_task(file_inode(file)); 14448c2ecf20Sopenharmony_ci if (!task) 14458c2ecf20Sopenharmony_ci return -ESRCH; 14468c2ecf20Sopenharmony_ci len = snprintf(numbuf, sizeof(numbuf), "%u\n", task->fail_nth); 14478c2ecf20Sopenharmony_ci put_task_struct(task); 14488c2ecf20Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, numbuf, len); 14498c2ecf20Sopenharmony_ci} 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_cistatic const struct file_operations proc_fail_nth_operations = { 14528c2ecf20Sopenharmony_ci .read = proc_fail_nth_read, 14538c2ecf20Sopenharmony_ci .write = proc_fail_nth_write, 14548c2ecf20Sopenharmony_ci}; 14558c2ecf20Sopenharmony_ci#endif 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_DEBUG 14598c2ecf20Sopenharmony_ci/* 14608c2ecf20Sopenharmony_ci * Print out various scheduling related per-task fields: 14618c2ecf20Sopenharmony_ci */ 14628c2ecf20Sopenharmony_cistatic int sched_show(struct seq_file *m, void *v) 14638c2ecf20Sopenharmony_ci{ 14648c2ecf20Sopenharmony_ci struct inode *inode = m->private; 14658c2ecf20Sopenharmony_ci struct pid_namespace *ns = proc_pid_ns(inode->i_sb); 14668c2ecf20Sopenharmony_ci struct task_struct *p; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci p = get_proc_task(inode); 14698c2ecf20Sopenharmony_ci if (!p) 14708c2ecf20Sopenharmony_ci return -ESRCH; 14718c2ecf20Sopenharmony_ci proc_sched_show_task(p, ns, m); 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci put_task_struct(p); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci return 0; 14768c2ecf20Sopenharmony_ci} 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_cistatic ssize_t 14798c2ecf20Sopenharmony_cisched_write(struct file *file, const char __user *buf, 14808c2ecf20Sopenharmony_ci size_t count, loff_t *offset) 14818c2ecf20Sopenharmony_ci{ 14828c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 14838c2ecf20Sopenharmony_ci struct task_struct *p; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci p = get_proc_task(inode); 14868c2ecf20Sopenharmony_ci if (!p) 14878c2ecf20Sopenharmony_ci return -ESRCH; 14888c2ecf20Sopenharmony_ci proc_sched_set_task(p); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci put_task_struct(p); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci return count; 14938c2ecf20Sopenharmony_ci} 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_cistatic int sched_open(struct inode *inode, struct file *filp) 14968c2ecf20Sopenharmony_ci{ 14978c2ecf20Sopenharmony_ci return single_open(filp, sched_show, inode); 14988c2ecf20Sopenharmony_ci} 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_cistatic const struct file_operations proc_pid_sched_operations = { 15018c2ecf20Sopenharmony_ci .open = sched_open, 15028c2ecf20Sopenharmony_ci .read = seq_read, 15038c2ecf20Sopenharmony_ci .write = sched_write, 15048c2ecf20Sopenharmony_ci .llseek = seq_lseek, 15058c2ecf20Sopenharmony_ci .release = single_release, 15068c2ecf20Sopenharmony_ci}; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci#endif 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci#ifdef CONFIG_QOS_CTRL 15118c2ecf20Sopenharmony_cilong proc_qos_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 15128c2ecf20Sopenharmony_ci{ 15138c2ecf20Sopenharmony_ci return do_qos_ctrl_ioctl(QOS_IOCTL_ABI_AARCH64, file, cmd, arg); 15148c2ecf20Sopenharmony_ci} 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 15178c2ecf20Sopenharmony_cilong proc_qos_ctrl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 15188c2ecf20Sopenharmony_ci{ 15198c2ecf20Sopenharmony_ci return do_qos_ctrl_ioctl(QOS_IOCTL_ABI_ARM32, file, cmd, 15208c2ecf20Sopenharmony_ci (unsigned long)(compat_ptr((compat_uptr_t)arg))); 15218c2ecf20Sopenharmony_ci} 15228c2ecf20Sopenharmony_ci#endif 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ciint proc_qos_ctrl_open(struct inode *inode, struct file *filp) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci return 0; 15278c2ecf20Sopenharmony_ci} 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_cistatic const struct file_operations proc_qos_ctrl_operations = { 15308c2ecf20Sopenharmony_ci .open = proc_qos_ctrl_open, 15318c2ecf20Sopenharmony_ci .unlocked_ioctl = proc_qos_ctrl_ioctl, 15328c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 15338c2ecf20Sopenharmony_ci .compat_ioctl = proc_qos_ctrl_compat_ioctl, 15348c2ecf20Sopenharmony_ci#endif 15358c2ecf20Sopenharmony_ci}; 15368c2ecf20Sopenharmony_ci#endif 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_RTG 15398c2ecf20Sopenharmony_cistatic const struct file_operations proc_rtg_operations = { 15408c2ecf20Sopenharmony_ci .open = proc_rtg_open, 15418c2ecf20Sopenharmony_ci .unlocked_ioctl = proc_rtg_ioctl, 15428c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 15438c2ecf20Sopenharmony_ci .compat_ioctl = proc_rtg_compat_ioctl, 15448c2ecf20Sopenharmony_ci#endif 15458c2ecf20Sopenharmony_ci}; 15468c2ecf20Sopenharmony_ci#endif 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_RTG_DEBUG 15498c2ecf20Sopenharmony_cistatic int sched_group_id_show(struct seq_file *m, void *v) 15508c2ecf20Sopenharmony_ci{ 15518c2ecf20Sopenharmony_ci struct inode *inode = m->private; 15528c2ecf20Sopenharmony_ci struct task_struct *p; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci p = get_proc_task(inode); 15558c2ecf20Sopenharmony_ci if (!p) 15568c2ecf20Sopenharmony_ci return -ESRCH; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci seq_printf(m, "%d\n", sched_get_group_id(p)); 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci put_task_struct(p); 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci return 0; 15638c2ecf20Sopenharmony_ci} 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_cistatic ssize_t 15668c2ecf20Sopenharmony_cisched_group_id_write(struct file *file, const char __user *buf, 15678c2ecf20Sopenharmony_ci size_t count, loff_t *offset) 15688c2ecf20Sopenharmony_ci{ 15698c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 15708c2ecf20Sopenharmony_ci struct task_struct *p; 15718c2ecf20Sopenharmony_ci char buffer[PROC_NUMBUF]; 15728c2ecf20Sopenharmony_ci int group_id, err; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci memset(buffer, 0, sizeof(buffer)); 15758c2ecf20Sopenharmony_ci if (count > sizeof(buffer) - 1) 15768c2ecf20Sopenharmony_ci count = sizeof(buffer) - 1; 15778c2ecf20Sopenharmony_ci if (copy_from_user(buffer, buf, count)) { 15788c2ecf20Sopenharmony_ci err = -EFAULT; 15798c2ecf20Sopenharmony_ci goto out; 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci err = kstrtoint(strstrip(buffer), 0, &group_id); 15838c2ecf20Sopenharmony_ci if (err) 15848c2ecf20Sopenharmony_ci goto out; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci p = get_proc_task(inode); 15878c2ecf20Sopenharmony_ci if (!p) 15888c2ecf20Sopenharmony_ci return -ESRCH; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci err = sched_set_group_id(p, group_id); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci put_task_struct(p); 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ciout: 15958c2ecf20Sopenharmony_ci return err < 0 ? err : count; 15968c2ecf20Sopenharmony_ci} 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_cistatic int sched_group_id_open(struct inode *inode, struct file *filp) 15998c2ecf20Sopenharmony_ci{ 16008c2ecf20Sopenharmony_ci return single_open(filp, sched_group_id_show, inode); 16018c2ecf20Sopenharmony_ci} 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_cistatic const struct file_operations proc_pid_sched_group_id_operations = { 16048c2ecf20Sopenharmony_ci .open = sched_group_id_open, 16058c2ecf20Sopenharmony_ci .read = seq_read, 16068c2ecf20Sopenharmony_ci .write = sched_group_id_write, 16078c2ecf20Sopenharmony_ci .llseek = seq_lseek, 16088c2ecf20Sopenharmony_ci .release = single_release, 16098c2ecf20Sopenharmony_ci}; 16108c2ecf20Sopenharmony_ci#endif /* CONFIG_SCHED_RTG_DEBUG */ 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_AUTOGROUP 16138c2ecf20Sopenharmony_ci/* 16148c2ecf20Sopenharmony_ci * Print out autogroup related information: 16158c2ecf20Sopenharmony_ci */ 16168c2ecf20Sopenharmony_cistatic int sched_autogroup_show(struct seq_file *m, void *v) 16178c2ecf20Sopenharmony_ci{ 16188c2ecf20Sopenharmony_ci struct inode *inode = m->private; 16198c2ecf20Sopenharmony_ci struct task_struct *p; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci p = get_proc_task(inode); 16228c2ecf20Sopenharmony_ci if (!p) 16238c2ecf20Sopenharmony_ci return -ESRCH; 16248c2ecf20Sopenharmony_ci proc_sched_autogroup_show_task(p, m); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci put_task_struct(p); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci return 0; 16298c2ecf20Sopenharmony_ci} 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_cistatic ssize_t 16328c2ecf20Sopenharmony_cisched_autogroup_write(struct file *file, const char __user *buf, 16338c2ecf20Sopenharmony_ci size_t count, loff_t *offset) 16348c2ecf20Sopenharmony_ci{ 16358c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 16368c2ecf20Sopenharmony_ci struct task_struct *p; 16378c2ecf20Sopenharmony_ci char buffer[PROC_NUMBUF]; 16388c2ecf20Sopenharmony_ci int nice; 16398c2ecf20Sopenharmony_ci int err; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci memset(buffer, 0, sizeof(buffer)); 16428c2ecf20Sopenharmony_ci if (count > sizeof(buffer) - 1) 16438c2ecf20Sopenharmony_ci count = sizeof(buffer) - 1; 16448c2ecf20Sopenharmony_ci if (copy_from_user(buffer, buf, count)) 16458c2ecf20Sopenharmony_ci return -EFAULT; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci err = kstrtoint(strstrip(buffer), 0, &nice); 16488c2ecf20Sopenharmony_ci if (err < 0) 16498c2ecf20Sopenharmony_ci return err; 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci p = get_proc_task(inode); 16528c2ecf20Sopenharmony_ci if (!p) 16538c2ecf20Sopenharmony_ci return -ESRCH; 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci err = proc_sched_autogroup_set_nice(p, nice); 16568c2ecf20Sopenharmony_ci if (err) 16578c2ecf20Sopenharmony_ci count = err; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci put_task_struct(p); 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci return count; 16628c2ecf20Sopenharmony_ci} 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_cistatic int sched_autogroup_open(struct inode *inode, struct file *filp) 16658c2ecf20Sopenharmony_ci{ 16668c2ecf20Sopenharmony_ci int ret; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci ret = single_open(filp, sched_autogroup_show, NULL); 16698c2ecf20Sopenharmony_ci if (!ret) { 16708c2ecf20Sopenharmony_ci struct seq_file *m = filp->private_data; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci m->private = inode; 16738c2ecf20Sopenharmony_ci } 16748c2ecf20Sopenharmony_ci return ret; 16758c2ecf20Sopenharmony_ci} 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_cistatic const struct file_operations proc_pid_sched_autogroup_operations = { 16788c2ecf20Sopenharmony_ci .open = sched_autogroup_open, 16798c2ecf20Sopenharmony_ci .read = seq_read, 16808c2ecf20Sopenharmony_ci .write = sched_autogroup_write, 16818c2ecf20Sopenharmony_ci .llseek = seq_lseek, 16828c2ecf20Sopenharmony_ci .release = single_release, 16838c2ecf20Sopenharmony_ci}; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci#endif /* CONFIG_SCHED_AUTOGROUP */ 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_WALT 16888c2ecf20Sopenharmony_cistatic int sched_init_task_load_show(struct seq_file *m, void *v) 16898c2ecf20Sopenharmony_ci{ 16908c2ecf20Sopenharmony_ci struct inode *inode = m->private; 16918c2ecf20Sopenharmony_ci struct task_struct *p; 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci p = get_proc_task(inode); 16948c2ecf20Sopenharmony_ci if (!p) 16958c2ecf20Sopenharmony_ci return -ESRCH; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci seq_printf(m, "%d\n", sched_get_init_task_load(p)); 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci put_task_struct(p); 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci return 0; 17028c2ecf20Sopenharmony_ci} 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_cistatic ssize_t 17058c2ecf20Sopenharmony_cisched_init_task_load_write(struct file *file, const char __user *buf, 17068c2ecf20Sopenharmony_ci size_t count, loff_t *offset) 17078c2ecf20Sopenharmony_ci{ 17088c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 17098c2ecf20Sopenharmony_ci struct task_struct *p; 17108c2ecf20Sopenharmony_ci char buffer[PROC_NUMBUF]; 17118c2ecf20Sopenharmony_ci int init_task_load, err; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci memset(buffer, 0, sizeof(buffer)); 17148c2ecf20Sopenharmony_ci if (count > sizeof(buffer) - 1) 17158c2ecf20Sopenharmony_ci count = sizeof(buffer) - 1; 17168c2ecf20Sopenharmony_ci if (copy_from_user(buffer, buf, count)) { 17178c2ecf20Sopenharmony_ci err = -EFAULT; 17188c2ecf20Sopenharmony_ci goto out; 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci err = kstrtoint(strstrip(buffer), 0, &init_task_load); 17228c2ecf20Sopenharmony_ci if (err) 17238c2ecf20Sopenharmony_ci goto out; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci p = get_proc_task(inode); 17268c2ecf20Sopenharmony_ci if (!p) 17278c2ecf20Sopenharmony_ci return -ESRCH; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci err = sched_set_init_task_load(p, init_task_load); 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci put_task_struct(p); 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ciout: 17348c2ecf20Sopenharmony_ci return err < 0 ? err : count; 17358c2ecf20Sopenharmony_ci} 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_cistatic int sched_init_task_load_open(struct inode *inode, struct file *filp) 17388c2ecf20Sopenharmony_ci{ 17398c2ecf20Sopenharmony_ci return single_open(filp, sched_init_task_load_show, inode); 17408c2ecf20Sopenharmony_ci} 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_cistatic const struct file_operations proc_pid_sched_init_task_load_operations = { 17438c2ecf20Sopenharmony_ci .open = sched_init_task_load_open, 17448c2ecf20Sopenharmony_ci .read = seq_read, 17458c2ecf20Sopenharmony_ci .write = sched_init_task_load_write, 17468c2ecf20Sopenharmony_ci .llseek = seq_lseek, 17478c2ecf20Sopenharmony_ci .release = single_release, 17488c2ecf20Sopenharmony_ci}; 17498c2ecf20Sopenharmony_ci#endif /* CONFIG_SCHED_WALT */ 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci#ifdef CONFIG_TIME_NS 17528c2ecf20Sopenharmony_cistatic int timens_offsets_show(struct seq_file *m, void *v) 17538c2ecf20Sopenharmony_ci{ 17548c2ecf20Sopenharmony_ci struct task_struct *p; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci p = get_proc_task(file_inode(m->file)); 17578c2ecf20Sopenharmony_ci if (!p) 17588c2ecf20Sopenharmony_ci return -ESRCH; 17598c2ecf20Sopenharmony_ci proc_timens_show_offsets(p, m); 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci put_task_struct(p); 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci return 0; 17648c2ecf20Sopenharmony_ci} 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_cistatic ssize_t timens_offsets_write(struct file *file, const char __user *buf, 17678c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 17688c2ecf20Sopenharmony_ci{ 17698c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 17708c2ecf20Sopenharmony_ci struct proc_timens_offset offsets[2]; 17718c2ecf20Sopenharmony_ci char *kbuf = NULL, *pos, *next_line; 17728c2ecf20Sopenharmony_ci struct task_struct *p; 17738c2ecf20Sopenharmony_ci int ret, noffsets; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci /* Only allow < page size writes at the beginning of the file */ 17768c2ecf20Sopenharmony_ci if ((*ppos != 0) || (count >= PAGE_SIZE)) 17778c2ecf20Sopenharmony_ci return -EINVAL; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci /* Slurp in the user data */ 17808c2ecf20Sopenharmony_ci kbuf = memdup_user_nul(buf, count); 17818c2ecf20Sopenharmony_ci if (IS_ERR(kbuf)) 17828c2ecf20Sopenharmony_ci return PTR_ERR(kbuf); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci /* Parse the user data */ 17858c2ecf20Sopenharmony_ci ret = -EINVAL; 17868c2ecf20Sopenharmony_ci noffsets = 0; 17878c2ecf20Sopenharmony_ci for (pos = kbuf; pos; pos = next_line) { 17888c2ecf20Sopenharmony_ci struct proc_timens_offset *off = &offsets[noffsets]; 17898c2ecf20Sopenharmony_ci char clock[10]; 17908c2ecf20Sopenharmony_ci int err; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci /* Find the end of line and ensure we don't look past it */ 17938c2ecf20Sopenharmony_ci next_line = strchr(pos, '\n'); 17948c2ecf20Sopenharmony_ci if (next_line) { 17958c2ecf20Sopenharmony_ci *next_line = '\0'; 17968c2ecf20Sopenharmony_ci next_line++; 17978c2ecf20Sopenharmony_ci if (*next_line == '\0') 17988c2ecf20Sopenharmony_ci next_line = NULL; 17998c2ecf20Sopenharmony_ci } 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci err = sscanf(pos, "%9s %lld %lu", clock, 18028c2ecf20Sopenharmony_ci &off->val.tv_sec, &off->val.tv_nsec); 18038c2ecf20Sopenharmony_ci if (err != 3 || off->val.tv_nsec >= NSEC_PER_SEC) 18048c2ecf20Sopenharmony_ci goto out; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci clock[sizeof(clock) - 1] = 0; 18078c2ecf20Sopenharmony_ci if (strcmp(clock, "monotonic") == 0 || 18088c2ecf20Sopenharmony_ci strcmp(clock, __stringify(CLOCK_MONOTONIC)) == 0) 18098c2ecf20Sopenharmony_ci off->clockid = CLOCK_MONOTONIC; 18108c2ecf20Sopenharmony_ci else if (strcmp(clock, "boottime") == 0 || 18118c2ecf20Sopenharmony_ci strcmp(clock, __stringify(CLOCK_BOOTTIME)) == 0) 18128c2ecf20Sopenharmony_ci off->clockid = CLOCK_BOOTTIME; 18138c2ecf20Sopenharmony_ci else 18148c2ecf20Sopenharmony_ci goto out; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci noffsets++; 18178c2ecf20Sopenharmony_ci if (noffsets == ARRAY_SIZE(offsets)) { 18188c2ecf20Sopenharmony_ci if (next_line) 18198c2ecf20Sopenharmony_ci count = next_line - kbuf; 18208c2ecf20Sopenharmony_ci break; 18218c2ecf20Sopenharmony_ci } 18228c2ecf20Sopenharmony_ci } 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci ret = -ESRCH; 18258c2ecf20Sopenharmony_ci p = get_proc_task(inode); 18268c2ecf20Sopenharmony_ci if (!p) 18278c2ecf20Sopenharmony_ci goto out; 18288c2ecf20Sopenharmony_ci ret = proc_timens_set_offset(file, p, offsets, noffsets); 18298c2ecf20Sopenharmony_ci put_task_struct(p); 18308c2ecf20Sopenharmony_ci if (ret) 18318c2ecf20Sopenharmony_ci goto out; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci ret = count; 18348c2ecf20Sopenharmony_ciout: 18358c2ecf20Sopenharmony_ci kfree(kbuf); 18368c2ecf20Sopenharmony_ci return ret; 18378c2ecf20Sopenharmony_ci} 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_cistatic int timens_offsets_open(struct inode *inode, struct file *filp) 18408c2ecf20Sopenharmony_ci{ 18418c2ecf20Sopenharmony_ci return single_open(filp, timens_offsets_show, inode); 18428c2ecf20Sopenharmony_ci} 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_cistatic const struct file_operations proc_timens_offsets_operations = { 18458c2ecf20Sopenharmony_ci .open = timens_offsets_open, 18468c2ecf20Sopenharmony_ci .read = seq_read, 18478c2ecf20Sopenharmony_ci .write = timens_offsets_write, 18488c2ecf20Sopenharmony_ci .llseek = seq_lseek, 18498c2ecf20Sopenharmony_ci .release = single_release, 18508c2ecf20Sopenharmony_ci}; 18518c2ecf20Sopenharmony_ci#endif /* CONFIG_TIME_NS */ 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_cistatic ssize_t comm_write(struct file *file, const char __user *buf, 18548c2ecf20Sopenharmony_ci size_t count, loff_t *offset) 18558c2ecf20Sopenharmony_ci{ 18568c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 18578c2ecf20Sopenharmony_ci struct task_struct *p; 18588c2ecf20Sopenharmony_ci char buffer[TASK_COMM_LEN]; 18598c2ecf20Sopenharmony_ci const size_t maxlen = sizeof(buffer) - 1; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci memset(buffer, 0, sizeof(buffer)); 18628c2ecf20Sopenharmony_ci if (copy_from_user(buffer, buf, count > maxlen ? maxlen : count)) 18638c2ecf20Sopenharmony_ci return -EFAULT; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci p = get_proc_task(inode); 18668c2ecf20Sopenharmony_ci if (!p) 18678c2ecf20Sopenharmony_ci return -ESRCH; 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci if (same_thread_group(current, p)) 18708c2ecf20Sopenharmony_ci set_task_comm(p, buffer); 18718c2ecf20Sopenharmony_ci else 18728c2ecf20Sopenharmony_ci count = -EINVAL; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci put_task_struct(p); 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci return count; 18778c2ecf20Sopenharmony_ci} 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_cistatic int comm_show(struct seq_file *m, void *v) 18808c2ecf20Sopenharmony_ci{ 18818c2ecf20Sopenharmony_ci struct inode *inode = m->private; 18828c2ecf20Sopenharmony_ci struct task_struct *p; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci p = get_proc_task(inode); 18858c2ecf20Sopenharmony_ci if (!p) 18868c2ecf20Sopenharmony_ci return -ESRCH; 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci proc_task_name(m, p, false); 18898c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci put_task_struct(p); 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci return 0; 18948c2ecf20Sopenharmony_ci} 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_cistatic int comm_open(struct inode *inode, struct file *filp) 18978c2ecf20Sopenharmony_ci{ 18988c2ecf20Sopenharmony_ci return single_open(filp, comm_show, inode); 18998c2ecf20Sopenharmony_ci} 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_cistatic const struct file_operations proc_pid_set_comm_operations = { 19028c2ecf20Sopenharmony_ci .open = comm_open, 19038c2ecf20Sopenharmony_ci .read = seq_read, 19048c2ecf20Sopenharmony_ci .write = comm_write, 19058c2ecf20Sopenharmony_ci .llseek = seq_lseek, 19068c2ecf20Sopenharmony_ci .release = single_release, 19078c2ecf20Sopenharmony_ci}; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_cistatic int proc_exe_link(struct dentry *dentry, struct path *exe_path) 19108c2ecf20Sopenharmony_ci{ 19118c2ecf20Sopenharmony_ci struct task_struct *task; 19128c2ecf20Sopenharmony_ci struct file *exe_file; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci task = get_proc_task(d_inode(dentry)); 19158c2ecf20Sopenharmony_ci if (!task) 19168c2ecf20Sopenharmony_ci return -ENOENT; 19178c2ecf20Sopenharmony_ci exe_file = get_task_exe_file(task); 19188c2ecf20Sopenharmony_ci put_task_struct(task); 19198c2ecf20Sopenharmony_ci if (exe_file) { 19208c2ecf20Sopenharmony_ci *exe_path = exe_file->f_path; 19218c2ecf20Sopenharmony_ci path_get(&exe_file->f_path); 19228c2ecf20Sopenharmony_ci fput(exe_file); 19238c2ecf20Sopenharmony_ci return 0; 19248c2ecf20Sopenharmony_ci } else 19258c2ecf20Sopenharmony_ci return -ENOENT; 19268c2ecf20Sopenharmony_ci} 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_cistatic const char *proc_pid_get_link(struct dentry *dentry, 19298c2ecf20Sopenharmony_ci struct inode *inode, 19308c2ecf20Sopenharmony_ci struct delayed_call *done) 19318c2ecf20Sopenharmony_ci{ 19328c2ecf20Sopenharmony_ci struct path path; 19338c2ecf20Sopenharmony_ci int error = -EACCES; 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci if (!dentry) 19368c2ecf20Sopenharmony_ci return ERR_PTR(-ECHILD); 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci /* Are we allowed to snoop on the tasks file descriptors? */ 19398c2ecf20Sopenharmony_ci if (!proc_fd_access_allowed(inode)) 19408c2ecf20Sopenharmony_ci goto out; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci error = PROC_I(inode)->op.proc_get_link(dentry, &path); 19438c2ecf20Sopenharmony_ci if (error) 19448c2ecf20Sopenharmony_ci goto out; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci error = nd_jump_link(&path); 19478c2ecf20Sopenharmony_ciout: 19488c2ecf20Sopenharmony_ci return ERR_PTR(error); 19498c2ecf20Sopenharmony_ci} 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_cistatic int do_proc_readlink(struct path *path, char __user *buffer, int buflen) 19528c2ecf20Sopenharmony_ci{ 19538c2ecf20Sopenharmony_ci char *tmp = (char *)__get_free_page(GFP_KERNEL); 19548c2ecf20Sopenharmony_ci char *pathname; 19558c2ecf20Sopenharmony_ci int len; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci if (!tmp) 19588c2ecf20Sopenharmony_ci return -ENOMEM; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci pathname = d_path(path, tmp, PAGE_SIZE); 19618c2ecf20Sopenharmony_ci len = PTR_ERR(pathname); 19628c2ecf20Sopenharmony_ci if (IS_ERR(pathname)) 19638c2ecf20Sopenharmony_ci goto out; 19648c2ecf20Sopenharmony_ci len = tmp + PAGE_SIZE - 1 - pathname; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci if (len > buflen) 19678c2ecf20Sopenharmony_ci len = buflen; 19688c2ecf20Sopenharmony_ci if (copy_to_user(buffer, pathname, len)) 19698c2ecf20Sopenharmony_ci len = -EFAULT; 19708c2ecf20Sopenharmony_ci out: 19718c2ecf20Sopenharmony_ci free_page((unsigned long)tmp); 19728c2ecf20Sopenharmony_ci return len; 19738c2ecf20Sopenharmony_ci} 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_cistatic int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int buflen) 19768c2ecf20Sopenharmony_ci{ 19778c2ecf20Sopenharmony_ci int error = -EACCES; 19788c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 19798c2ecf20Sopenharmony_ci struct path path; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci /* Are we allowed to snoop on the tasks file descriptors? */ 19828c2ecf20Sopenharmony_ci if (!proc_fd_access_allowed(inode)) 19838c2ecf20Sopenharmony_ci goto out; 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci error = PROC_I(inode)->op.proc_get_link(dentry, &path); 19868c2ecf20Sopenharmony_ci if (error) 19878c2ecf20Sopenharmony_ci goto out; 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci error = do_proc_readlink(&path, buffer, buflen); 19908c2ecf20Sopenharmony_ci path_put(&path); 19918c2ecf20Sopenharmony_ciout: 19928c2ecf20Sopenharmony_ci return error; 19938c2ecf20Sopenharmony_ci} 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ciconst struct inode_operations proc_pid_link_inode_operations = { 19968c2ecf20Sopenharmony_ci .readlink = proc_pid_readlink, 19978c2ecf20Sopenharmony_ci .get_link = proc_pid_get_link, 19988c2ecf20Sopenharmony_ci .setattr = proc_setattr, 19998c2ecf20Sopenharmony_ci}; 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci/* building an inode */ 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_civoid task_dump_owner(struct task_struct *task, umode_t mode, 20058c2ecf20Sopenharmony_ci kuid_t *ruid, kgid_t *rgid) 20068c2ecf20Sopenharmony_ci{ 20078c2ecf20Sopenharmony_ci /* Depending on the state of dumpable compute who should own a 20088c2ecf20Sopenharmony_ci * proc file for a task. 20098c2ecf20Sopenharmony_ci */ 20108c2ecf20Sopenharmony_ci const struct cred *cred; 20118c2ecf20Sopenharmony_ci kuid_t uid; 20128c2ecf20Sopenharmony_ci kgid_t gid; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci if (unlikely(task->flags & PF_KTHREAD)) { 20158c2ecf20Sopenharmony_ci *ruid = GLOBAL_ROOT_UID; 20168c2ecf20Sopenharmony_ci *rgid = GLOBAL_ROOT_GID; 20178c2ecf20Sopenharmony_ci return; 20188c2ecf20Sopenharmony_ci } 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci /* Default to the tasks effective ownership */ 20218c2ecf20Sopenharmony_ci rcu_read_lock(); 20228c2ecf20Sopenharmony_ci cred = __task_cred(task); 20238c2ecf20Sopenharmony_ci uid = cred->euid; 20248c2ecf20Sopenharmony_ci gid = cred->egid; 20258c2ecf20Sopenharmony_ci rcu_read_unlock(); 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci /* 20288c2ecf20Sopenharmony_ci * Before the /proc/pid/status file was created the only way to read 20298c2ecf20Sopenharmony_ci * the effective uid of a /process was to stat /proc/pid. Reading 20308c2ecf20Sopenharmony_ci * /proc/pid/status is slow enough that procps and other packages 20318c2ecf20Sopenharmony_ci * kept stating /proc/pid. To keep the rules in /proc simple I have 20328c2ecf20Sopenharmony_ci * made this apply to all per process world readable and executable 20338c2ecf20Sopenharmony_ci * directories. 20348c2ecf20Sopenharmony_ci */ 20358c2ecf20Sopenharmony_ci if (mode != (S_IFDIR|S_IRUGO|S_IXUGO)) { 20368c2ecf20Sopenharmony_ci struct mm_struct *mm; 20378c2ecf20Sopenharmony_ci task_lock(task); 20388c2ecf20Sopenharmony_ci mm = task->mm; 20398c2ecf20Sopenharmony_ci /* Make non-dumpable tasks owned by some root */ 20408c2ecf20Sopenharmony_ci if (mm) { 20418c2ecf20Sopenharmony_ci if (get_dumpable(mm) != SUID_DUMP_USER) { 20428c2ecf20Sopenharmony_ci struct user_namespace *user_ns = mm->user_ns; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci uid = make_kuid(user_ns, 0); 20458c2ecf20Sopenharmony_ci if (!uid_valid(uid)) 20468c2ecf20Sopenharmony_ci uid = GLOBAL_ROOT_UID; 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci gid = make_kgid(user_ns, 0); 20498c2ecf20Sopenharmony_ci if (!gid_valid(gid)) 20508c2ecf20Sopenharmony_ci gid = GLOBAL_ROOT_GID; 20518c2ecf20Sopenharmony_ci } 20528c2ecf20Sopenharmony_ci } else { 20538c2ecf20Sopenharmony_ci uid = GLOBAL_ROOT_UID; 20548c2ecf20Sopenharmony_ci gid = GLOBAL_ROOT_GID; 20558c2ecf20Sopenharmony_ci } 20568c2ecf20Sopenharmony_ci task_unlock(task); 20578c2ecf20Sopenharmony_ci } 20588c2ecf20Sopenharmony_ci *ruid = uid; 20598c2ecf20Sopenharmony_ci *rgid = gid; 20608c2ecf20Sopenharmony_ci} 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_civoid proc_pid_evict_inode(struct proc_inode *ei) 20638c2ecf20Sopenharmony_ci{ 20648c2ecf20Sopenharmony_ci struct pid *pid = ei->pid; 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci if (S_ISDIR(ei->vfs_inode.i_mode)) { 20678c2ecf20Sopenharmony_ci spin_lock(&pid->lock); 20688c2ecf20Sopenharmony_ci hlist_del_init_rcu(&ei->sibling_inodes); 20698c2ecf20Sopenharmony_ci spin_unlock(&pid->lock); 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci put_pid(pid); 20738c2ecf20Sopenharmony_ci} 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_cistruct inode *proc_pid_make_inode(struct super_block *sb, 20768c2ecf20Sopenharmony_ci struct task_struct *task, umode_t mode) 20778c2ecf20Sopenharmony_ci{ 20788c2ecf20Sopenharmony_ci struct inode * inode; 20798c2ecf20Sopenharmony_ci struct proc_inode *ei; 20808c2ecf20Sopenharmony_ci struct pid *pid; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci /* We need a new inode */ 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci inode = new_inode(sb); 20858c2ecf20Sopenharmony_ci if (!inode) 20868c2ecf20Sopenharmony_ci goto out; 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci /* Common stuff */ 20898c2ecf20Sopenharmony_ci ei = PROC_I(inode); 20908c2ecf20Sopenharmony_ci inode->i_mode = mode; 20918c2ecf20Sopenharmony_ci inode->i_ino = get_next_ino(); 20928c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 20938c2ecf20Sopenharmony_ci inode->i_op = &proc_def_inode_operations; 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci /* 20968c2ecf20Sopenharmony_ci * grab the reference to task. 20978c2ecf20Sopenharmony_ci */ 20988c2ecf20Sopenharmony_ci pid = get_task_pid(task, PIDTYPE_PID); 20998c2ecf20Sopenharmony_ci if (!pid) 21008c2ecf20Sopenharmony_ci goto out_unlock; 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci /* Let the pid remember us for quick removal */ 21038c2ecf20Sopenharmony_ci ei->pid = pid; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid); 21068c2ecf20Sopenharmony_ci security_task_to_inode(task, inode); 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ciout: 21098c2ecf20Sopenharmony_ci return inode; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ciout_unlock: 21128c2ecf20Sopenharmony_ci iput(inode); 21138c2ecf20Sopenharmony_ci return NULL; 21148c2ecf20Sopenharmony_ci} 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci/* 21178c2ecf20Sopenharmony_ci * Generating an inode and adding it into @pid->inodes, so that task will 21188c2ecf20Sopenharmony_ci * invalidate inode's dentry before being released. 21198c2ecf20Sopenharmony_ci * 21208c2ecf20Sopenharmony_ci * This helper is used for creating dir-type entries under '/proc' and 21218c2ecf20Sopenharmony_ci * '/proc/<tgid>/task'. Other entries(eg. fd, stat) under '/proc/<tgid>' 21228c2ecf20Sopenharmony_ci * can be released by invalidating '/proc/<tgid>' dentry. 21238c2ecf20Sopenharmony_ci * In theory, dentries under '/proc/<tgid>/task' can also be released by 21248c2ecf20Sopenharmony_ci * invalidating '/proc/<tgid>' dentry, we reserve it to handle single 21258c2ecf20Sopenharmony_ci * thread exiting situation: Any one of threads should invalidate its 21268c2ecf20Sopenharmony_ci * '/proc/<tgid>/task/<pid>' dentry before released. 21278c2ecf20Sopenharmony_ci */ 21288c2ecf20Sopenharmony_cistatic struct inode *proc_pid_make_base_inode(struct super_block *sb, 21298c2ecf20Sopenharmony_ci struct task_struct *task, umode_t mode) 21308c2ecf20Sopenharmony_ci{ 21318c2ecf20Sopenharmony_ci struct inode *inode; 21328c2ecf20Sopenharmony_ci struct proc_inode *ei; 21338c2ecf20Sopenharmony_ci struct pid *pid; 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci inode = proc_pid_make_inode(sb, task, mode); 21368c2ecf20Sopenharmony_ci if (!inode) 21378c2ecf20Sopenharmony_ci return NULL; 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci /* Let proc_flush_pid find this directory inode */ 21408c2ecf20Sopenharmony_ci ei = PROC_I(inode); 21418c2ecf20Sopenharmony_ci pid = ei->pid; 21428c2ecf20Sopenharmony_ci spin_lock(&pid->lock); 21438c2ecf20Sopenharmony_ci hlist_add_head_rcu(&ei->sibling_inodes, &pid->inodes); 21448c2ecf20Sopenharmony_ci spin_unlock(&pid->lock); 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci return inode; 21478c2ecf20Sopenharmony_ci} 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ciint pid_getattr(const struct path *path, struct kstat *stat, 21508c2ecf20Sopenharmony_ci u32 request_mask, unsigned int query_flags) 21518c2ecf20Sopenharmony_ci{ 21528c2ecf20Sopenharmony_ci struct inode *inode = d_inode(path->dentry); 21538c2ecf20Sopenharmony_ci struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); 21548c2ecf20Sopenharmony_ci struct task_struct *task; 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci generic_fillattr(inode, stat); 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci stat->uid = GLOBAL_ROOT_UID; 21598c2ecf20Sopenharmony_ci stat->gid = GLOBAL_ROOT_GID; 21608c2ecf20Sopenharmony_ci rcu_read_lock(); 21618c2ecf20Sopenharmony_ci task = pid_task(proc_pid(inode), PIDTYPE_PID); 21628c2ecf20Sopenharmony_ci if (task) { 21638c2ecf20Sopenharmony_ci if (!has_pid_permissions(fs_info, task, HIDEPID_INVISIBLE)) { 21648c2ecf20Sopenharmony_ci rcu_read_unlock(); 21658c2ecf20Sopenharmony_ci /* 21668c2ecf20Sopenharmony_ci * This doesn't prevent learning whether PID exists, 21678c2ecf20Sopenharmony_ci * it only makes getattr() consistent with readdir(). 21688c2ecf20Sopenharmony_ci */ 21698c2ecf20Sopenharmony_ci return -ENOENT; 21708c2ecf20Sopenharmony_ci } 21718c2ecf20Sopenharmony_ci task_dump_owner(task, inode->i_mode, &stat->uid, &stat->gid); 21728c2ecf20Sopenharmony_ci } 21738c2ecf20Sopenharmony_ci rcu_read_unlock(); 21748c2ecf20Sopenharmony_ci return 0; 21758c2ecf20Sopenharmony_ci} 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci/* dentry stuff */ 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci/* 21808c2ecf20Sopenharmony_ci * Set <pid>/... inode ownership (can change due to setuid(), etc.) 21818c2ecf20Sopenharmony_ci */ 21828c2ecf20Sopenharmony_civoid pid_update_inode(struct task_struct *task, struct inode *inode) 21838c2ecf20Sopenharmony_ci{ 21848c2ecf20Sopenharmony_ci task_dump_owner(task, inode->i_mode, &inode->i_uid, &inode->i_gid); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci inode->i_mode &= ~(S_ISUID | S_ISGID); 21878c2ecf20Sopenharmony_ci security_task_to_inode(task, inode); 21888c2ecf20Sopenharmony_ci} 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci/* 21918c2ecf20Sopenharmony_ci * Rewrite the inode's ownerships here because the owning task may have 21928c2ecf20Sopenharmony_ci * performed a setuid(), etc. 21938c2ecf20Sopenharmony_ci * 21948c2ecf20Sopenharmony_ci */ 21958c2ecf20Sopenharmony_cistatic int pid_revalidate(struct dentry *dentry, unsigned int flags) 21968c2ecf20Sopenharmony_ci{ 21978c2ecf20Sopenharmony_ci struct inode *inode; 21988c2ecf20Sopenharmony_ci struct task_struct *task; 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci if (flags & LOOKUP_RCU) 22018c2ecf20Sopenharmony_ci return -ECHILD; 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci inode = d_inode(dentry); 22048c2ecf20Sopenharmony_ci task = get_proc_task(inode); 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci if (task) { 22078c2ecf20Sopenharmony_ci pid_update_inode(task, inode); 22088c2ecf20Sopenharmony_ci put_task_struct(task); 22098c2ecf20Sopenharmony_ci return 1; 22108c2ecf20Sopenharmony_ci } 22118c2ecf20Sopenharmony_ci return 0; 22128c2ecf20Sopenharmony_ci} 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_cistatic inline bool proc_inode_is_dead(struct inode *inode) 22158c2ecf20Sopenharmony_ci{ 22168c2ecf20Sopenharmony_ci return !proc_pid(inode)->tasks[PIDTYPE_PID].first; 22178c2ecf20Sopenharmony_ci} 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ciint pid_delete_dentry(const struct dentry *dentry) 22208c2ecf20Sopenharmony_ci{ 22218c2ecf20Sopenharmony_ci /* Is the task we represent dead? 22228c2ecf20Sopenharmony_ci * If so, then don't put the dentry on the lru list, 22238c2ecf20Sopenharmony_ci * kill it immediately. 22248c2ecf20Sopenharmony_ci */ 22258c2ecf20Sopenharmony_ci return proc_inode_is_dead(d_inode(dentry)); 22268c2ecf20Sopenharmony_ci} 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ciconst struct dentry_operations pid_dentry_operations = 22298c2ecf20Sopenharmony_ci{ 22308c2ecf20Sopenharmony_ci .d_revalidate = pid_revalidate, 22318c2ecf20Sopenharmony_ci .d_delete = pid_delete_dentry, 22328c2ecf20Sopenharmony_ci}; 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci/* Lookups */ 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci/* 22378c2ecf20Sopenharmony_ci * Fill a directory entry. 22388c2ecf20Sopenharmony_ci * 22398c2ecf20Sopenharmony_ci * If possible create the dcache entry and derive our inode number and 22408c2ecf20Sopenharmony_ci * file type from dcache entry. 22418c2ecf20Sopenharmony_ci * 22428c2ecf20Sopenharmony_ci * Since all of the proc inode numbers are dynamically generated, the inode 22438c2ecf20Sopenharmony_ci * numbers do not exist until the inode is cache. This means creating the 22448c2ecf20Sopenharmony_ci * the dcache entry in readdir is necessary to keep the inode numbers 22458c2ecf20Sopenharmony_ci * reported by readdir in sync with the inode numbers reported 22468c2ecf20Sopenharmony_ci * by stat. 22478c2ecf20Sopenharmony_ci */ 22488c2ecf20Sopenharmony_cibool proc_fill_cache(struct file *file, struct dir_context *ctx, 22498c2ecf20Sopenharmony_ci const char *name, unsigned int len, 22508c2ecf20Sopenharmony_ci instantiate_t instantiate, struct task_struct *task, const void *ptr) 22518c2ecf20Sopenharmony_ci{ 22528c2ecf20Sopenharmony_ci struct dentry *child, *dir = file->f_path.dentry; 22538c2ecf20Sopenharmony_ci struct qstr qname = QSTR_INIT(name, len); 22548c2ecf20Sopenharmony_ci struct inode *inode; 22558c2ecf20Sopenharmony_ci unsigned type = DT_UNKNOWN; 22568c2ecf20Sopenharmony_ci ino_t ino = 1; 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci child = d_hash_and_lookup(dir, &qname); 22598c2ecf20Sopenharmony_ci if (!child) { 22608c2ecf20Sopenharmony_ci DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); 22618c2ecf20Sopenharmony_ci child = d_alloc_parallel(dir, &qname, &wq); 22628c2ecf20Sopenharmony_ci if (IS_ERR(child)) 22638c2ecf20Sopenharmony_ci goto end_instantiate; 22648c2ecf20Sopenharmony_ci if (d_in_lookup(child)) { 22658c2ecf20Sopenharmony_ci struct dentry *res; 22668c2ecf20Sopenharmony_ci res = instantiate(child, task, ptr); 22678c2ecf20Sopenharmony_ci d_lookup_done(child); 22688c2ecf20Sopenharmony_ci if (unlikely(res)) { 22698c2ecf20Sopenharmony_ci dput(child); 22708c2ecf20Sopenharmony_ci child = res; 22718c2ecf20Sopenharmony_ci if (IS_ERR(child)) 22728c2ecf20Sopenharmony_ci goto end_instantiate; 22738c2ecf20Sopenharmony_ci } 22748c2ecf20Sopenharmony_ci } 22758c2ecf20Sopenharmony_ci } 22768c2ecf20Sopenharmony_ci inode = d_inode(child); 22778c2ecf20Sopenharmony_ci ino = inode->i_ino; 22788c2ecf20Sopenharmony_ci type = inode->i_mode >> 12; 22798c2ecf20Sopenharmony_ci dput(child); 22808c2ecf20Sopenharmony_ciend_instantiate: 22818c2ecf20Sopenharmony_ci return dir_emit(ctx, name, len, ino, type); 22828c2ecf20Sopenharmony_ci} 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci/* 22858c2ecf20Sopenharmony_ci * dname_to_vma_addr - maps a dentry name into two unsigned longs 22868c2ecf20Sopenharmony_ci * which represent vma start and end addresses. 22878c2ecf20Sopenharmony_ci */ 22888c2ecf20Sopenharmony_cistatic int dname_to_vma_addr(struct dentry *dentry, 22898c2ecf20Sopenharmony_ci unsigned long *start, unsigned long *end) 22908c2ecf20Sopenharmony_ci{ 22918c2ecf20Sopenharmony_ci const char *str = dentry->d_name.name; 22928c2ecf20Sopenharmony_ci unsigned long long sval, eval; 22938c2ecf20Sopenharmony_ci unsigned int len; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci if (str[0] == '0' && str[1] != '-') 22968c2ecf20Sopenharmony_ci return -EINVAL; 22978c2ecf20Sopenharmony_ci len = _parse_integer(str, 16, &sval); 22988c2ecf20Sopenharmony_ci if (len & KSTRTOX_OVERFLOW) 22998c2ecf20Sopenharmony_ci return -EINVAL; 23008c2ecf20Sopenharmony_ci if (sval != (unsigned long)sval) 23018c2ecf20Sopenharmony_ci return -EINVAL; 23028c2ecf20Sopenharmony_ci str += len; 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci if (*str != '-') 23058c2ecf20Sopenharmony_ci return -EINVAL; 23068c2ecf20Sopenharmony_ci str++; 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci if (str[0] == '0' && str[1]) 23098c2ecf20Sopenharmony_ci return -EINVAL; 23108c2ecf20Sopenharmony_ci len = _parse_integer(str, 16, &eval); 23118c2ecf20Sopenharmony_ci if (len & KSTRTOX_OVERFLOW) 23128c2ecf20Sopenharmony_ci return -EINVAL; 23138c2ecf20Sopenharmony_ci if (eval != (unsigned long)eval) 23148c2ecf20Sopenharmony_ci return -EINVAL; 23158c2ecf20Sopenharmony_ci str += len; 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci if (*str != '\0') 23188c2ecf20Sopenharmony_ci return -EINVAL; 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci *start = sval; 23218c2ecf20Sopenharmony_ci *end = eval; 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci return 0; 23248c2ecf20Sopenharmony_ci} 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_cistatic int map_files_d_revalidate(struct dentry *dentry, unsigned int flags) 23278c2ecf20Sopenharmony_ci{ 23288c2ecf20Sopenharmony_ci unsigned long vm_start, vm_end; 23298c2ecf20Sopenharmony_ci bool exact_vma_exists = false; 23308c2ecf20Sopenharmony_ci struct mm_struct *mm = NULL; 23318c2ecf20Sopenharmony_ci struct task_struct *task; 23328c2ecf20Sopenharmony_ci struct inode *inode; 23338c2ecf20Sopenharmony_ci int status = 0; 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci if (flags & LOOKUP_RCU) 23368c2ecf20Sopenharmony_ci return -ECHILD; 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci inode = d_inode(dentry); 23398c2ecf20Sopenharmony_ci task = get_proc_task(inode); 23408c2ecf20Sopenharmony_ci if (!task) 23418c2ecf20Sopenharmony_ci goto out_notask; 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci mm = mm_access(task, PTRACE_MODE_READ_FSCREDS); 23448c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(mm)) 23458c2ecf20Sopenharmony_ci goto out; 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci if (!dname_to_vma_addr(dentry, &vm_start, &vm_end)) { 23488c2ecf20Sopenharmony_ci status = mmap_read_lock_killable(mm); 23498c2ecf20Sopenharmony_ci if (!status) { 23508c2ecf20Sopenharmony_ci exact_vma_exists = !!find_exact_vma(mm, vm_start, 23518c2ecf20Sopenharmony_ci vm_end); 23528c2ecf20Sopenharmony_ci mmap_read_unlock(mm); 23538c2ecf20Sopenharmony_ci } 23548c2ecf20Sopenharmony_ci } 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci mmput(mm); 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci if (exact_vma_exists) { 23598c2ecf20Sopenharmony_ci task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid); 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci security_task_to_inode(task, inode); 23628c2ecf20Sopenharmony_ci status = 1; 23638c2ecf20Sopenharmony_ci } 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ciout: 23668c2ecf20Sopenharmony_ci put_task_struct(task); 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ciout_notask: 23698c2ecf20Sopenharmony_ci return status; 23708c2ecf20Sopenharmony_ci} 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_cistatic const struct dentry_operations tid_map_files_dentry_operations = { 23738c2ecf20Sopenharmony_ci .d_revalidate = map_files_d_revalidate, 23748c2ecf20Sopenharmony_ci .d_delete = pid_delete_dentry, 23758c2ecf20Sopenharmony_ci}; 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_cistatic int map_files_get_link(struct dentry *dentry, struct path *path) 23788c2ecf20Sopenharmony_ci{ 23798c2ecf20Sopenharmony_ci unsigned long vm_start, vm_end; 23808c2ecf20Sopenharmony_ci struct vm_area_struct *vma; 23818c2ecf20Sopenharmony_ci struct task_struct *task; 23828c2ecf20Sopenharmony_ci struct mm_struct *mm; 23838c2ecf20Sopenharmony_ci int rc; 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci rc = -ENOENT; 23868c2ecf20Sopenharmony_ci task = get_proc_task(d_inode(dentry)); 23878c2ecf20Sopenharmony_ci if (!task) 23888c2ecf20Sopenharmony_ci goto out; 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci mm = get_task_mm(task); 23918c2ecf20Sopenharmony_ci put_task_struct(task); 23928c2ecf20Sopenharmony_ci if (!mm) 23938c2ecf20Sopenharmony_ci goto out; 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ci rc = dname_to_vma_addr(dentry, &vm_start, &vm_end); 23968c2ecf20Sopenharmony_ci if (rc) 23978c2ecf20Sopenharmony_ci goto out_mmput; 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci rc = mmap_read_lock_killable(mm); 24008c2ecf20Sopenharmony_ci if (rc) 24018c2ecf20Sopenharmony_ci goto out_mmput; 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci rc = -ENOENT; 24048c2ecf20Sopenharmony_ci vma = find_exact_vma(mm, vm_start, vm_end); 24058c2ecf20Sopenharmony_ci if (vma && vma->vm_file) { 24068c2ecf20Sopenharmony_ci *path = vma->vm_file->f_path; 24078c2ecf20Sopenharmony_ci path_get(path); 24088c2ecf20Sopenharmony_ci rc = 0; 24098c2ecf20Sopenharmony_ci } 24108c2ecf20Sopenharmony_ci mmap_read_unlock(mm); 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ciout_mmput: 24138c2ecf20Sopenharmony_ci mmput(mm); 24148c2ecf20Sopenharmony_ciout: 24158c2ecf20Sopenharmony_ci return rc; 24168c2ecf20Sopenharmony_ci} 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_cistruct map_files_info { 24198c2ecf20Sopenharmony_ci unsigned long start; 24208c2ecf20Sopenharmony_ci unsigned long end; 24218c2ecf20Sopenharmony_ci fmode_t mode; 24228c2ecf20Sopenharmony_ci}; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci/* 24258c2ecf20Sopenharmony_ci * Only allow CAP_SYS_ADMIN and CAP_CHECKPOINT_RESTORE to follow the links, due 24268c2ecf20Sopenharmony_ci * to concerns about how the symlinks may be used to bypass permissions on 24278c2ecf20Sopenharmony_ci * ancestor directories in the path to the file in question. 24288c2ecf20Sopenharmony_ci */ 24298c2ecf20Sopenharmony_cistatic const char * 24308c2ecf20Sopenharmony_ciproc_map_files_get_link(struct dentry *dentry, 24318c2ecf20Sopenharmony_ci struct inode *inode, 24328c2ecf20Sopenharmony_ci struct delayed_call *done) 24338c2ecf20Sopenharmony_ci{ 24348c2ecf20Sopenharmony_ci if (!checkpoint_restore_ns_capable(&init_user_ns)) 24358c2ecf20Sopenharmony_ci return ERR_PTR(-EPERM); 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci return proc_pid_get_link(dentry, inode, done); 24388c2ecf20Sopenharmony_ci} 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci/* 24418c2ecf20Sopenharmony_ci * Identical to proc_pid_link_inode_operations except for get_link() 24428c2ecf20Sopenharmony_ci */ 24438c2ecf20Sopenharmony_cistatic const struct inode_operations proc_map_files_link_inode_operations = { 24448c2ecf20Sopenharmony_ci .readlink = proc_pid_readlink, 24458c2ecf20Sopenharmony_ci .get_link = proc_map_files_get_link, 24468c2ecf20Sopenharmony_ci .setattr = proc_setattr, 24478c2ecf20Sopenharmony_ci}; 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_cistatic struct dentry * 24508c2ecf20Sopenharmony_ciproc_map_files_instantiate(struct dentry *dentry, 24518c2ecf20Sopenharmony_ci struct task_struct *task, const void *ptr) 24528c2ecf20Sopenharmony_ci{ 24538c2ecf20Sopenharmony_ci fmode_t mode = (fmode_t)(unsigned long)ptr; 24548c2ecf20Sopenharmony_ci struct proc_inode *ei; 24558c2ecf20Sopenharmony_ci struct inode *inode; 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK | 24588c2ecf20Sopenharmony_ci ((mode & FMODE_READ ) ? S_IRUSR : 0) | 24598c2ecf20Sopenharmony_ci ((mode & FMODE_WRITE) ? S_IWUSR : 0)); 24608c2ecf20Sopenharmony_ci if (!inode) 24618c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci ei = PROC_I(inode); 24648c2ecf20Sopenharmony_ci ei->op.proc_get_link = map_files_get_link; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci inode->i_op = &proc_map_files_link_inode_operations; 24678c2ecf20Sopenharmony_ci inode->i_size = 64; 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci d_set_d_op(dentry, &tid_map_files_dentry_operations); 24708c2ecf20Sopenharmony_ci return d_splice_alias(inode, dentry); 24718c2ecf20Sopenharmony_ci} 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_cistatic struct dentry *proc_map_files_lookup(struct inode *dir, 24748c2ecf20Sopenharmony_ci struct dentry *dentry, unsigned int flags) 24758c2ecf20Sopenharmony_ci{ 24768c2ecf20Sopenharmony_ci unsigned long vm_start, vm_end; 24778c2ecf20Sopenharmony_ci struct vm_area_struct *vma; 24788c2ecf20Sopenharmony_ci struct task_struct *task; 24798c2ecf20Sopenharmony_ci struct dentry *result; 24808c2ecf20Sopenharmony_ci struct mm_struct *mm; 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci result = ERR_PTR(-ENOENT); 24838c2ecf20Sopenharmony_ci task = get_proc_task(dir); 24848c2ecf20Sopenharmony_ci if (!task) 24858c2ecf20Sopenharmony_ci goto out; 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci result = ERR_PTR(-EACCES); 24888c2ecf20Sopenharmony_ci if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) 24898c2ecf20Sopenharmony_ci goto out_put_task; 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci result = ERR_PTR(-ENOENT); 24928c2ecf20Sopenharmony_ci if (dname_to_vma_addr(dentry, &vm_start, &vm_end)) 24938c2ecf20Sopenharmony_ci goto out_put_task; 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_ci mm = get_task_mm(task); 24968c2ecf20Sopenharmony_ci if (!mm) 24978c2ecf20Sopenharmony_ci goto out_put_task; 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci result = ERR_PTR(-EINTR); 25008c2ecf20Sopenharmony_ci if (mmap_read_lock_killable(mm)) 25018c2ecf20Sopenharmony_ci goto out_put_mm; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci result = ERR_PTR(-ENOENT); 25048c2ecf20Sopenharmony_ci vma = find_exact_vma(mm, vm_start, vm_end); 25058c2ecf20Sopenharmony_ci if (!vma) 25068c2ecf20Sopenharmony_ci goto out_no_vma; 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci if (vma->vm_file) 25098c2ecf20Sopenharmony_ci result = proc_map_files_instantiate(dentry, task, 25108c2ecf20Sopenharmony_ci (void *)(unsigned long)vma->vm_file->f_mode); 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ciout_no_vma: 25138c2ecf20Sopenharmony_ci mmap_read_unlock(mm); 25148c2ecf20Sopenharmony_ciout_put_mm: 25158c2ecf20Sopenharmony_ci mmput(mm); 25168c2ecf20Sopenharmony_ciout_put_task: 25178c2ecf20Sopenharmony_ci put_task_struct(task); 25188c2ecf20Sopenharmony_ciout: 25198c2ecf20Sopenharmony_ci return result; 25208c2ecf20Sopenharmony_ci} 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_cistatic const struct inode_operations proc_map_files_inode_operations = { 25238c2ecf20Sopenharmony_ci .lookup = proc_map_files_lookup, 25248c2ecf20Sopenharmony_ci .permission = proc_fd_permission, 25258c2ecf20Sopenharmony_ci .setattr = proc_setattr, 25268c2ecf20Sopenharmony_ci}; 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_cistatic int 25298c2ecf20Sopenharmony_ciproc_map_files_readdir(struct file *file, struct dir_context *ctx) 25308c2ecf20Sopenharmony_ci{ 25318c2ecf20Sopenharmony_ci struct vm_area_struct *vma; 25328c2ecf20Sopenharmony_ci struct task_struct *task; 25338c2ecf20Sopenharmony_ci struct mm_struct *mm; 25348c2ecf20Sopenharmony_ci unsigned long nr_files, pos, i; 25358c2ecf20Sopenharmony_ci GENRADIX(struct map_files_info) fa; 25368c2ecf20Sopenharmony_ci struct map_files_info *p; 25378c2ecf20Sopenharmony_ci int ret; 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci genradix_init(&fa); 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci ret = -ENOENT; 25428c2ecf20Sopenharmony_ci task = get_proc_task(file_inode(file)); 25438c2ecf20Sopenharmony_ci if (!task) 25448c2ecf20Sopenharmony_ci goto out; 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci ret = -EACCES; 25478c2ecf20Sopenharmony_ci if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) 25488c2ecf20Sopenharmony_ci goto out_put_task; 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci ret = 0; 25518c2ecf20Sopenharmony_ci if (!dir_emit_dots(file, ctx)) 25528c2ecf20Sopenharmony_ci goto out_put_task; 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci mm = get_task_mm(task); 25558c2ecf20Sopenharmony_ci if (!mm) 25568c2ecf20Sopenharmony_ci goto out_put_task; 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci ret = mmap_read_lock_killable(mm); 25598c2ecf20Sopenharmony_ci if (ret) { 25608c2ecf20Sopenharmony_ci mmput(mm); 25618c2ecf20Sopenharmony_ci goto out_put_task; 25628c2ecf20Sopenharmony_ci } 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci nr_files = 0; 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci /* 25678c2ecf20Sopenharmony_ci * We need two passes here: 25688c2ecf20Sopenharmony_ci * 25698c2ecf20Sopenharmony_ci * 1) Collect vmas of mapped files with mmap_lock taken 25708c2ecf20Sopenharmony_ci * 2) Release mmap_lock and instantiate entries 25718c2ecf20Sopenharmony_ci * 25728c2ecf20Sopenharmony_ci * otherwise we get lockdep complained, since filldir() 25738c2ecf20Sopenharmony_ci * routine might require mmap_lock taken in might_fault(). 25748c2ecf20Sopenharmony_ci */ 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci for (vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) { 25778c2ecf20Sopenharmony_ci if (!vma->vm_file) 25788c2ecf20Sopenharmony_ci continue; 25798c2ecf20Sopenharmony_ci if (++pos <= ctx->pos) 25808c2ecf20Sopenharmony_ci continue; 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci p = genradix_ptr_alloc(&fa, nr_files++, GFP_KERNEL); 25838c2ecf20Sopenharmony_ci if (!p) { 25848c2ecf20Sopenharmony_ci ret = -ENOMEM; 25858c2ecf20Sopenharmony_ci mmap_read_unlock(mm); 25868c2ecf20Sopenharmony_ci mmput(mm); 25878c2ecf20Sopenharmony_ci goto out_put_task; 25888c2ecf20Sopenharmony_ci } 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci p->start = vma->vm_start; 25918c2ecf20Sopenharmony_ci p->end = vma->vm_end; 25928c2ecf20Sopenharmony_ci p->mode = vma->vm_file->f_mode; 25938c2ecf20Sopenharmony_ci } 25948c2ecf20Sopenharmony_ci mmap_read_unlock(mm); 25958c2ecf20Sopenharmony_ci mmput(mm); 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci for (i = 0; i < nr_files; i++) { 25988c2ecf20Sopenharmony_ci char buf[4 * sizeof(long) + 2]; /* max: %lx-%lx\0 */ 25998c2ecf20Sopenharmony_ci unsigned int len; 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci p = genradix_ptr(&fa, i); 26028c2ecf20Sopenharmony_ci len = snprintf(buf, sizeof(buf), "%lx-%lx", p->start, p->end); 26038c2ecf20Sopenharmony_ci if (!proc_fill_cache(file, ctx, 26048c2ecf20Sopenharmony_ci buf, len, 26058c2ecf20Sopenharmony_ci proc_map_files_instantiate, 26068c2ecf20Sopenharmony_ci task, 26078c2ecf20Sopenharmony_ci (void *)(unsigned long)p->mode)) 26088c2ecf20Sopenharmony_ci break; 26098c2ecf20Sopenharmony_ci ctx->pos++; 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ciout_put_task: 26138c2ecf20Sopenharmony_ci put_task_struct(task); 26148c2ecf20Sopenharmony_ciout: 26158c2ecf20Sopenharmony_ci genradix_free(&fa); 26168c2ecf20Sopenharmony_ci return ret; 26178c2ecf20Sopenharmony_ci} 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_cistatic const struct file_operations proc_map_files_operations = { 26208c2ecf20Sopenharmony_ci .read = generic_read_dir, 26218c2ecf20Sopenharmony_ci .iterate_shared = proc_map_files_readdir, 26228c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 26238c2ecf20Sopenharmony_ci}; 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci#if defined(CONFIG_CHECKPOINT_RESTORE) && defined(CONFIG_POSIX_TIMERS) 26268c2ecf20Sopenharmony_cistruct timers_private { 26278c2ecf20Sopenharmony_ci struct pid *pid; 26288c2ecf20Sopenharmony_ci struct task_struct *task; 26298c2ecf20Sopenharmony_ci struct sighand_struct *sighand; 26308c2ecf20Sopenharmony_ci struct pid_namespace *ns; 26318c2ecf20Sopenharmony_ci unsigned long flags; 26328c2ecf20Sopenharmony_ci}; 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_cistatic void *timers_start(struct seq_file *m, loff_t *pos) 26358c2ecf20Sopenharmony_ci{ 26368c2ecf20Sopenharmony_ci struct timers_private *tp = m->private; 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci tp->task = get_pid_task(tp->pid, PIDTYPE_PID); 26398c2ecf20Sopenharmony_ci if (!tp->task) 26408c2ecf20Sopenharmony_ci return ERR_PTR(-ESRCH); 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci tp->sighand = lock_task_sighand(tp->task, &tp->flags); 26438c2ecf20Sopenharmony_ci if (!tp->sighand) 26448c2ecf20Sopenharmony_ci return ERR_PTR(-ESRCH); 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ci return seq_list_start(&tp->task->signal->posix_timers, *pos); 26478c2ecf20Sopenharmony_ci} 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_cistatic void *timers_next(struct seq_file *m, void *v, loff_t *pos) 26508c2ecf20Sopenharmony_ci{ 26518c2ecf20Sopenharmony_ci struct timers_private *tp = m->private; 26528c2ecf20Sopenharmony_ci return seq_list_next(v, &tp->task->signal->posix_timers, pos); 26538c2ecf20Sopenharmony_ci} 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_cistatic void timers_stop(struct seq_file *m, void *v) 26568c2ecf20Sopenharmony_ci{ 26578c2ecf20Sopenharmony_ci struct timers_private *tp = m->private; 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci if (tp->sighand) { 26608c2ecf20Sopenharmony_ci unlock_task_sighand(tp->task, &tp->flags); 26618c2ecf20Sopenharmony_ci tp->sighand = NULL; 26628c2ecf20Sopenharmony_ci } 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci if (tp->task) { 26658c2ecf20Sopenharmony_ci put_task_struct(tp->task); 26668c2ecf20Sopenharmony_ci tp->task = NULL; 26678c2ecf20Sopenharmony_ci } 26688c2ecf20Sopenharmony_ci} 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_cistatic int show_timer(struct seq_file *m, void *v) 26718c2ecf20Sopenharmony_ci{ 26728c2ecf20Sopenharmony_ci struct k_itimer *timer; 26738c2ecf20Sopenharmony_ci struct timers_private *tp = m->private; 26748c2ecf20Sopenharmony_ci int notify; 26758c2ecf20Sopenharmony_ci static const char * const nstr[] = { 26768c2ecf20Sopenharmony_ci [SIGEV_SIGNAL] = "signal", 26778c2ecf20Sopenharmony_ci [SIGEV_NONE] = "none", 26788c2ecf20Sopenharmony_ci [SIGEV_THREAD] = "thread", 26798c2ecf20Sopenharmony_ci }; 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci timer = list_entry((struct list_head *)v, struct k_itimer, list); 26828c2ecf20Sopenharmony_ci notify = timer->it_sigev_notify; 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci seq_printf(m, "ID: %d\n", timer->it_id); 26858c2ecf20Sopenharmony_ci seq_printf(m, "signal: %d/%px\n", 26868c2ecf20Sopenharmony_ci timer->sigq->info.si_signo, 26878c2ecf20Sopenharmony_ci timer->sigq->info.si_value.sival_ptr); 26888c2ecf20Sopenharmony_ci seq_printf(m, "notify: %s/%s.%d\n", 26898c2ecf20Sopenharmony_ci nstr[notify & ~SIGEV_THREAD_ID], 26908c2ecf20Sopenharmony_ci (notify & SIGEV_THREAD_ID) ? "tid" : "pid", 26918c2ecf20Sopenharmony_ci pid_nr_ns(timer->it_pid, tp->ns)); 26928c2ecf20Sopenharmony_ci seq_printf(m, "ClockID: %d\n", timer->it_clock); 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci return 0; 26958c2ecf20Sopenharmony_ci} 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_cistatic const struct seq_operations proc_timers_seq_ops = { 26988c2ecf20Sopenharmony_ci .start = timers_start, 26998c2ecf20Sopenharmony_ci .next = timers_next, 27008c2ecf20Sopenharmony_ci .stop = timers_stop, 27018c2ecf20Sopenharmony_ci .show = show_timer, 27028c2ecf20Sopenharmony_ci}; 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_cistatic int proc_timers_open(struct inode *inode, struct file *file) 27058c2ecf20Sopenharmony_ci{ 27068c2ecf20Sopenharmony_ci struct timers_private *tp; 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci tp = __seq_open_private(file, &proc_timers_seq_ops, 27098c2ecf20Sopenharmony_ci sizeof(struct timers_private)); 27108c2ecf20Sopenharmony_ci if (!tp) 27118c2ecf20Sopenharmony_ci return -ENOMEM; 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci tp->pid = proc_pid(inode); 27148c2ecf20Sopenharmony_ci tp->ns = proc_pid_ns(inode->i_sb); 27158c2ecf20Sopenharmony_ci return 0; 27168c2ecf20Sopenharmony_ci} 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_cistatic const struct file_operations proc_timers_operations = { 27198c2ecf20Sopenharmony_ci .open = proc_timers_open, 27208c2ecf20Sopenharmony_ci .read = seq_read, 27218c2ecf20Sopenharmony_ci .llseek = seq_lseek, 27228c2ecf20Sopenharmony_ci .release = seq_release_private, 27238c2ecf20Sopenharmony_ci}; 27248c2ecf20Sopenharmony_ci#endif 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_cistatic ssize_t timerslack_ns_write(struct file *file, const char __user *buf, 27278c2ecf20Sopenharmony_ci size_t count, loff_t *offset) 27288c2ecf20Sopenharmony_ci{ 27298c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 27308c2ecf20Sopenharmony_ci struct task_struct *p; 27318c2ecf20Sopenharmony_ci u64 slack_ns; 27328c2ecf20Sopenharmony_ci int err; 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci err = kstrtoull_from_user(buf, count, 10, &slack_ns); 27358c2ecf20Sopenharmony_ci if (err < 0) 27368c2ecf20Sopenharmony_ci return err; 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_ci p = get_proc_task(inode); 27398c2ecf20Sopenharmony_ci if (!p) 27408c2ecf20Sopenharmony_ci return -ESRCH; 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci if (p != current) { 27438c2ecf20Sopenharmony_ci rcu_read_lock(); 27448c2ecf20Sopenharmony_ci if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) { 27458c2ecf20Sopenharmony_ci rcu_read_unlock(); 27468c2ecf20Sopenharmony_ci count = -EPERM; 27478c2ecf20Sopenharmony_ci goto out; 27488c2ecf20Sopenharmony_ci } 27498c2ecf20Sopenharmony_ci rcu_read_unlock(); 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_ci err = security_task_setscheduler(p); 27528c2ecf20Sopenharmony_ci if (err) { 27538c2ecf20Sopenharmony_ci count = err; 27548c2ecf20Sopenharmony_ci goto out; 27558c2ecf20Sopenharmony_ci } 27568c2ecf20Sopenharmony_ci } 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci task_lock(p); 27598c2ecf20Sopenharmony_ci if (slack_ns == 0) 27608c2ecf20Sopenharmony_ci p->timer_slack_ns = p->default_timer_slack_ns; 27618c2ecf20Sopenharmony_ci else 27628c2ecf20Sopenharmony_ci p->timer_slack_ns = slack_ns; 27638c2ecf20Sopenharmony_ci task_unlock(p); 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_ciout: 27668c2ecf20Sopenharmony_ci put_task_struct(p); 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci return count; 27698c2ecf20Sopenharmony_ci} 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_cistatic int timerslack_ns_show(struct seq_file *m, void *v) 27728c2ecf20Sopenharmony_ci{ 27738c2ecf20Sopenharmony_ci struct inode *inode = m->private; 27748c2ecf20Sopenharmony_ci struct task_struct *p; 27758c2ecf20Sopenharmony_ci int err = 0; 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_ci p = get_proc_task(inode); 27788c2ecf20Sopenharmony_ci if (!p) 27798c2ecf20Sopenharmony_ci return -ESRCH; 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci if (p != current) { 27828c2ecf20Sopenharmony_ci rcu_read_lock(); 27838c2ecf20Sopenharmony_ci if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) { 27848c2ecf20Sopenharmony_ci rcu_read_unlock(); 27858c2ecf20Sopenharmony_ci err = -EPERM; 27868c2ecf20Sopenharmony_ci goto out; 27878c2ecf20Sopenharmony_ci } 27888c2ecf20Sopenharmony_ci rcu_read_unlock(); 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci err = security_task_getscheduler(p); 27918c2ecf20Sopenharmony_ci if (err) 27928c2ecf20Sopenharmony_ci goto out; 27938c2ecf20Sopenharmony_ci } 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci task_lock(p); 27968c2ecf20Sopenharmony_ci seq_printf(m, "%llu\n", p->timer_slack_ns); 27978c2ecf20Sopenharmony_ci task_unlock(p); 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ciout: 28008c2ecf20Sopenharmony_ci put_task_struct(p); 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci return err; 28038c2ecf20Sopenharmony_ci} 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_cistatic int timerslack_ns_open(struct inode *inode, struct file *filp) 28068c2ecf20Sopenharmony_ci{ 28078c2ecf20Sopenharmony_ci return single_open(filp, timerslack_ns_show, inode); 28088c2ecf20Sopenharmony_ci} 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_cistatic const struct file_operations proc_pid_set_timerslack_ns_operations = { 28118c2ecf20Sopenharmony_ci .open = timerslack_ns_open, 28128c2ecf20Sopenharmony_ci .read = seq_read, 28138c2ecf20Sopenharmony_ci .write = timerslack_ns_write, 28148c2ecf20Sopenharmony_ci .llseek = seq_lseek, 28158c2ecf20Sopenharmony_ci .release = single_release, 28168c2ecf20Sopenharmony_ci}; 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_cistatic struct dentry *proc_pident_instantiate(struct dentry *dentry, 28198c2ecf20Sopenharmony_ci struct task_struct *task, const void *ptr) 28208c2ecf20Sopenharmony_ci{ 28218c2ecf20Sopenharmony_ci const struct pid_entry *p = ptr; 28228c2ecf20Sopenharmony_ci struct inode *inode; 28238c2ecf20Sopenharmony_ci struct proc_inode *ei; 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci inode = proc_pid_make_inode(dentry->d_sb, task, p->mode); 28268c2ecf20Sopenharmony_ci if (!inode) 28278c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci ei = PROC_I(inode); 28308c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 28318c2ecf20Sopenharmony_ci set_nlink(inode, 2); /* Use getattr to fix if necessary */ 28328c2ecf20Sopenharmony_ci if (p->iop) 28338c2ecf20Sopenharmony_ci inode->i_op = p->iop; 28348c2ecf20Sopenharmony_ci if (p->fop) 28358c2ecf20Sopenharmony_ci inode->i_fop = p->fop; 28368c2ecf20Sopenharmony_ci ei->op = p->op; 28378c2ecf20Sopenharmony_ci pid_update_inode(task, inode); 28388c2ecf20Sopenharmony_ci d_set_d_op(dentry, &pid_dentry_operations); 28398c2ecf20Sopenharmony_ci return d_splice_alias(inode, dentry); 28408c2ecf20Sopenharmony_ci} 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_cistatic struct dentry *proc_pident_lookup(struct inode *dir, 28438c2ecf20Sopenharmony_ci struct dentry *dentry, 28448c2ecf20Sopenharmony_ci const struct pid_entry *p, 28458c2ecf20Sopenharmony_ci const struct pid_entry *end) 28468c2ecf20Sopenharmony_ci{ 28478c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(dir); 28488c2ecf20Sopenharmony_ci struct dentry *res = ERR_PTR(-ENOENT); 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci if (!task) 28518c2ecf20Sopenharmony_ci goto out_no_task; 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci /* 28548c2ecf20Sopenharmony_ci * Yes, it does not scale. And it should not. Don't add 28558c2ecf20Sopenharmony_ci * new entries into /proc/<tgid>/ without very good reasons. 28568c2ecf20Sopenharmony_ci */ 28578c2ecf20Sopenharmony_ci for (; p < end; p++) { 28588c2ecf20Sopenharmony_ci if (p->len != dentry->d_name.len) 28598c2ecf20Sopenharmony_ci continue; 28608c2ecf20Sopenharmony_ci if (!memcmp(dentry->d_name.name, p->name, p->len)) { 28618c2ecf20Sopenharmony_ci res = proc_pident_instantiate(dentry, task, p); 28628c2ecf20Sopenharmony_ci break; 28638c2ecf20Sopenharmony_ci } 28648c2ecf20Sopenharmony_ci } 28658c2ecf20Sopenharmony_ci put_task_struct(task); 28668c2ecf20Sopenharmony_ciout_no_task: 28678c2ecf20Sopenharmony_ci return res; 28688c2ecf20Sopenharmony_ci} 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_cistatic int proc_pident_readdir(struct file *file, struct dir_context *ctx, 28718c2ecf20Sopenharmony_ci const struct pid_entry *ents, unsigned int nents) 28728c2ecf20Sopenharmony_ci{ 28738c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(file_inode(file)); 28748c2ecf20Sopenharmony_ci const struct pid_entry *p; 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_ci if (!task) 28778c2ecf20Sopenharmony_ci return -ENOENT; 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci if (!dir_emit_dots(file, ctx)) 28808c2ecf20Sopenharmony_ci goto out; 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci if (ctx->pos >= nents + 2) 28838c2ecf20Sopenharmony_ci goto out; 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci for (p = ents + (ctx->pos - 2); p < ents + nents; p++) { 28868c2ecf20Sopenharmony_ci if (!proc_fill_cache(file, ctx, p->name, p->len, 28878c2ecf20Sopenharmony_ci proc_pident_instantiate, task, p)) 28888c2ecf20Sopenharmony_ci break; 28898c2ecf20Sopenharmony_ci ctx->pos++; 28908c2ecf20Sopenharmony_ci } 28918c2ecf20Sopenharmony_ciout: 28928c2ecf20Sopenharmony_ci put_task_struct(task); 28938c2ecf20Sopenharmony_ci return 0; 28948c2ecf20Sopenharmony_ci} 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY 28978c2ecf20Sopenharmony_cistatic int proc_pid_attr_open(struct inode *inode, struct file *file) 28988c2ecf20Sopenharmony_ci{ 28998c2ecf20Sopenharmony_ci file->private_data = NULL; 29008c2ecf20Sopenharmony_ci __mem_open(inode, file, PTRACE_MODE_READ_FSCREDS); 29018c2ecf20Sopenharmony_ci return 0; 29028c2ecf20Sopenharmony_ci} 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_cistatic ssize_t proc_pid_attr_read(struct file * file, char __user * buf, 29058c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 29068c2ecf20Sopenharmony_ci{ 29078c2ecf20Sopenharmony_ci struct inode * inode = file_inode(file); 29088c2ecf20Sopenharmony_ci char *p = NULL; 29098c2ecf20Sopenharmony_ci ssize_t length; 29108c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(inode); 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ci if (!task) 29138c2ecf20Sopenharmony_ci return -ESRCH; 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci length = security_getprocattr(task, PROC_I(inode)->op.lsm, 29168c2ecf20Sopenharmony_ci (char*)file->f_path.dentry->d_name.name, 29178c2ecf20Sopenharmony_ci &p); 29188c2ecf20Sopenharmony_ci put_task_struct(task); 29198c2ecf20Sopenharmony_ci if (length > 0) 29208c2ecf20Sopenharmony_ci length = simple_read_from_buffer(buf, count, ppos, p, length); 29218c2ecf20Sopenharmony_ci kfree(p); 29228c2ecf20Sopenharmony_ci return length; 29238c2ecf20Sopenharmony_ci} 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_cistatic ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, 29268c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 29278c2ecf20Sopenharmony_ci{ 29288c2ecf20Sopenharmony_ci struct inode * inode = file_inode(file); 29298c2ecf20Sopenharmony_ci struct task_struct *task; 29308c2ecf20Sopenharmony_ci void *page; 29318c2ecf20Sopenharmony_ci int rv; 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci /* A task may only write when it was the opener. */ 29348c2ecf20Sopenharmony_ci if (file->private_data != current->mm) 29358c2ecf20Sopenharmony_ci return -EPERM; 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci rcu_read_lock(); 29388c2ecf20Sopenharmony_ci task = pid_task(proc_pid(inode), PIDTYPE_PID); 29398c2ecf20Sopenharmony_ci if (!task) { 29408c2ecf20Sopenharmony_ci rcu_read_unlock(); 29418c2ecf20Sopenharmony_ci return -ESRCH; 29428c2ecf20Sopenharmony_ci } 29438c2ecf20Sopenharmony_ci /* A task may only write its own attributes. */ 29448c2ecf20Sopenharmony_ci if (current != task) { 29458c2ecf20Sopenharmony_ci rcu_read_unlock(); 29468c2ecf20Sopenharmony_ci return -EACCES; 29478c2ecf20Sopenharmony_ci } 29488c2ecf20Sopenharmony_ci /* Prevent changes to overridden credentials. */ 29498c2ecf20Sopenharmony_ci if (current_cred() != current_real_cred()) { 29508c2ecf20Sopenharmony_ci rcu_read_unlock(); 29518c2ecf20Sopenharmony_ci return -EBUSY; 29528c2ecf20Sopenharmony_ci } 29538c2ecf20Sopenharmony_ci rcu_read_unlock(); 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ci if (count > PAGE_SIZE) 29568c2ecf20Sopenharmony_ci count = PAGE_SIZE; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci /* No partial writes. */ 29598c2ecf20Sopenharmony_ci if (*ppos != 0) 29608c2ecf20Sopenharmony_ci return -EINVAL; 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci page = memdup_user(buf, count); 29638c2ecf20Sopenharmony_ci if (IS_ERR(page)) { 29648c2ecf20Sopenharmony_ci rv = PTR_ERR(page); 29658c2ecf20Sopenharmony_ci goto out; 29668c2ecf20Sopenharmony_ci } 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci /* Guard against adverse ptrace interaction */ 29698c2ecf20Sopenharmony_ci rv = mutex_lock_interruptible(¤t->signal->cred_guard_mutex); 29708c2ecf20Sopenharmony_ci if (rv < 0) 29718c2ecf20Sopenharmony_ci goto out_free; 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci rv = security_setprocattr(PROC_I(inode)->op.lsm, 29748c2ecf20Sopenharmony_ci file->f_path.dentry->d_name.name, page, 29758c2ecf20Sopenharmony_ci count); 29768c2ecf20Sopenharmony_ci mutex_unlock(¤t->signal->cred_guard_mutex); 29778c2ecf20Sopenharmony_ciout_free: 29788c2ecf20Sopenharmony_ci kfree(page); 29798c2ecf20Sopenharmony_ciout: 29808c2ecf20Sopenharmony_ci return rv; 29818c2ecf20Sopenharmony_ci} 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_cistatic const struct file_operations proc_pid_attr_operations = { 29848c2ecf20Sopenharmony_ci .open = proc_pid_attr_open, 29858c2ecf20Sopenharmony_ci .read = proc_pid_attr_read, 29868c2ecf20Sopenharmony_ci .write = proc_pid_attr_write, 29878c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 29888c2ecf20Sopenharmony_ci .release = mem_release, 29898c2ecf20Sopenharmony_ci}; 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci#define LSM_DIR_OPS(LSM) \ 29928c2ecf20Sopenharmony_cistatic int proc_##LSM##_attr_dir_iterate(struct file *filp, \ 29938c2ecf20Sopenharmony_ci struct dir_context *ctx) \ 29948c2ecf20Sopenharmony_ci{ \ 29958c2ecf20Sopenharmony_ci return proc_pident_readdir(filp, ctx, \ 29968c2ecf20Sopenharmony_ci LSM##_attr_dir_stuff, \ 29978c2ecf20Sopenharmony_ci ARRAY_SIZE(LSM##_attr_dir_stuff)); \ 29988c2ecf20Sopenharmony_ci} \ 29998c2ecf20Sopenharmony_ci\ 30008c2ecf20Sopenharmony_cistatic const struct file_operations proc_##LSM##_attr_dir_ops = { \ 30018c2ecf20Sopenharmony_ci .read = generic_read_dir, \ 30028c2ecf20Sopenharmony_ci .iterate = proc_##LSM##_attr_dir_iterate, \ 30038c2ecf20Sopenharmony_ci .llseek = default_llseek, \ 30048c2ecf20Sopenharmony_ci}; \ 30058c2ecf20Sopenharmony_ci\ 30068c2ecf20Sopenharmony_cistatic struct dentry *proc_##LSM##_attr_dir_lookup(struct inode *dir, \ 30078c2ecf20Sopenharmony_ci struct dentry *dentry, unsigned int flags) \ 30088c2ecf20Sopenharmony_ci{ \ 30098c2ecf20Sopenharmony_ci return proc_pident_lookup(dir, dentry, \ 30108c2ecf20Sopenharmony_ci LSM##_attr_dir_stuff, \ 30118c2ecf20Sopenharmony_ci LSM##_attr_dir_stuff + ARRAY_SIZE(LSM##_attr_dir_stuff)); \ 30128c2ecf20Sopenharmony_ci} \ 30138c2ecf20Sopenharmony_ci\ 30148c2ecf20Sopenharmony_cistatic const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \ 30158c2ecf20Sopenharmony_ci .lookup = proc_##LSM##_attr_dir_lookup, \ 30168c2ecf20Sopenharmony_ci .getattr = pid_getattr, \ 30178c2ecf20Sopenharmony_ci .setattr = proc_setattr, \ 30188c2ecf20Sopenharmony_ci} 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK 30218c2ecf20Sopenharmony_cistatic const struct pid_entry smack_attr_dir_stuff[] = { 30228c2ecf20Sopenharmony_ci ATTR("smack", "current", 0666), 30238c2ecf20Sopenharmony_ci}; 30248c2ecf20Sopenharmony_ciLSM_DIR_OPS(smack); 30258c2ecf20Sopenharmony_ci#endif 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_APPARMOR 30288c2ecf20Sopenharmony_cistatic const struct pid_entry apparmor_attr_dir_stuff[] = { 30298c2ecf20Sopenharmony_ci ATTR("apparmor", "current", 0666), 30308c2ecf20Sopenharmony_ci ATTR("apparmor", "prev", 0444), 30318c2ecf20Sopenharmony_ci ATTR("apparmor", "exec", 0666), 30328c2ecf20Sopenharmony_ci}; 30338c2ecf20Sopenharmony_ciLSM_DIR_OPS(apparmor); 30348c2ecf20Sopenharmony_ci#endif 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_cistatic const struct pid_entry attr_dir_stuff[] = { 30378c2ecf20Sopenharmony_ci ATTR(NULL, "current", 0666), 30388c2ecf20Sopenharmony_ci ATTR(NULL, "prev", 0444), 30398c2ecf20Sopenharmony_ci ATTR(NULL, "exec", 0666), 30408c2ecf20Sopenharmony_ci ATTR(NULL, "fscreate", 0666), 30418c2ecf20Sopenharmony_ci ATTR(NULL, "keycreate", 0666), 30428c2ecf20Sopenharmony_ci ATTR(NULL, "sockcreate", 0666), 30438c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK 30448c2ecf20Sopenharmony_ci DIR("smack", 0555, 30458c2ecf20Sopenharmony_ci proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops), 30468c2ecf20Sopenharmony_ci#endif 30478c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_APPARMOR 30488c2ecf20Sopenharmony_ci DIR("apparmor", 0555, 30498c2ecf20Sopenharmony_ci proc_apparmor_attr_dir_inode_ops, proc_apparmor_attr_dir_ops), 30508c2ecf20Sopenharmony_ci#endif 30518c2ecf20Sopenharmony_ci}; 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_cistatic int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx) 30548c2ecf20Sopenharmony_ci{ 30558c2ecf20Sopenharmony_ci return proc_pident_readdir(file, ctx, 30568c2ecf20Sopenharmony_ci attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff)); 30578c2ecf20Sopenharmony_ci} 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_cistatic const struct file_operations proc_attr_dir_operations = { 30608c2ecf20Sopenharmony_ci .read = generic_read_dir, 30618c2ecf20Sopenharmony_ci .iterate_shared = proc_attr_dir_readdir, 30628c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 30638c2ecf20Sopenharmony_ci}; 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_cistatic struct dentry *proc_attr_dir_lookup(struct inode *dir, 30668c2ecf20Sopenharmony_ci struct dentry *dentry, unsigned int flags) 30678c2ecf20Sopenharmony_ci{ 30688c2ecf20Sopenharmony_ci return proc_pident_lookup(dir, dentry, 30698c2ecf20Sopenharmony_ci attr_dir_stuff, 30708c2ecf20Sopenharmony_ci attr_dir_stuff + ARRAY_SIZE(attr_dir_stuff)); 30718c2ecf20Sopenharmony_ci} 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_cistatic const struct inode_operations proc_attr_dir_inode_operations = { 30748c2ecf20Sopenharmony_ci .lookup = proc_attr_dir_lookup, 30758c2ecf20Sopenharmony_ci .getattr = pid_getattr, 30768c2ecf20Sopenharmony_ci .setattr = proc_setattr, 30778c2ecf20Sopenharmony_ci}; 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci#endif 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci#ifdef CONFIG_ELF_CORE 30828c2ecf20Sopenharmony_cistatic ssize_t proc_coredump_filter_read(struct file *file, char __user *buf, 30838c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 30848c2ecf20Sopenharmony_ci{ 30858c2ecf20Sopenharmony_ci struct task_struct *task = get_proc_task(file_inode(file)); 30868c2ecf20Sopenharmony_ci struct mm_struct *mm; 30878c2ecf20Sopenharmony_ci char buffer[PROC_NUMBUF]; 30888c2ecf20Sopenharmony_ci size_t len; 30898c2ecf20Sopenharmony_ci int ret; 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci if (!task) 30928c2ecf20Sopenharmony_ci return -ESRCH; 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci ret = 0; 30958c2ecf20Sopenharmony_ci mm = get_task_mm(task); 30968c2ecf20Sopenharmony_ci if (mm) { 30978c2ecf20Sopenharmony_ci len = snprintf(buffer, sizeof(buffer), "%08lx\n", 30988c2ecf20Sopenharmony_ci ((mm->flags & MMF_DUMP_FILTER_MASK) >> 30998c2ecf20Sopenharmony_ci MMF_DUMP_FILTER_SHIFT)); 31008c2ecf20Sopenharmony_ci mmput(mm); 31018c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(buf, count, ppos, buffer, len); 31028c2ecf20Sopenharmony_ci } 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_ci put_task_struct(task); 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci return ret; 31078c2ecf20Sopenharmony_ci} 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_cistatic ssize_t proc_coredump_filter_write(struct file *file, 31108c2ecf20Sopenharmony_ci const char __user *buf, 31118c2ecf20Sopenharmony_ci size_t count, 31128c2ecf20Sopenharmony_ci loff_t *ppos) 31138c2ecf20Sopenharmony_ci{ 31148c2ecf20Sopenharmony_ci struct task_struct *task; 31158c2ecf20Sopenharmony_ci struct mm_struct *mm; 31168c2ecf20Sopenharmony_ci unsigned int val; 31178c2ecf20Sopenharmony_ci int ret; 31188c2ecf20Sopenharmony_ci int i; 31198c2ecf20Sopenharmony_ci unsigned long mask; 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci ret = kstrtouint_from_user(buf, count, 0, &val); 31228c2ecf20Sopenharmony_ci if (ret < 0) 31238c2ecf20Sopenharmony_ci return ret; 31248c2ecf20Sopenharmony_ci 31258c2ecf20Sopenharmony_ci ret = -ESRCH; 31268c2ecf20Sopenharmony_ci task = get_proc_task(file_inode(file)); 31278c2ecf20Sopenharmony_ci if (!task) 31288c2ecf20Sopenharmony_ci goto out_no_task; 31298c2ecf20Sopenharmony_ci 31308c2ecf20Sopenharmony_ci mm = get_task_mm(task); 31318c2ecf20Sopenharmony_ci if (!mm) 31328c2ecf20Sopenharmony_ci goto out_no_mm; 31338c2ecf20Sopenharmony_ci ret = 0; 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci for (i = 0, mask = 1; i < MMF_DUMP_FILTER_BITS; i++, mask <<= 1) { 31368c2ecf20Sopenharmony_ci if (val & mask) 31378c2ecf20Sopenharmony_ci set_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags); 31388c2ecf20Sopenharmony_ci else 31398c2ecf20Sopenharmony_ci clear_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags); 31408c2ecf20Sopenharmony_ci } 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci mmput(mm); 31438c2ecf20Sopenharmony_ci out_no_mm: 31448c2ecf20Sopenharmony_ci put_task_struct(task); 31458c2ecf20Sopenharmony_ci out_no_task: 31468c2ecf20Sopenharmony_ci if (ret < 0) 31478c2ecf20Sopenharmony_ci return ret; 31488c2ecf20Sopenharmony_ci return count; 31498c2ecf20Sopenharmony_ci} 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_cistatic const struct file_operations proc_coredump_filter_operations = { 31528c2ecf20Sopenharmony_ci .read = proc_coredump_filter_read, 31538c2ecf20Sopenharmony_ci .write = proc_coredump_filter_write, 31548c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 31558c2ecf20Sopenharmony_ci}; 31568c2ecf20Sopenharmony_ci#endif 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci#ifdef CONFIG_TASK_IO_ACCOUNTING 31598c2ecf20Sopenharmony_cistatic int do_io_accounting(struct task_struct *task, struct seq_file *m, int whole) 31608c2ecf20Sopenharmony_ci{ 31618c2ecf20Sopenharmony_ci struct task_io_accounting acct = task->ioac; 31628c2ecf20Sopenharmony_ci unsigned long flags; 31638c2ecf20Sopenharmony_ci int result; 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci result = down_read_killable(&task->signal->exec_update_lock); 31668c2ecf20Sopenharmony_ci if (result) 31678c2ecf20Sopenharmony_ci return result; 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_ci if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) { 31708c2ecf20Sopenharmony_ci result = -EACCES; 31718c2ecf20Sopenharmony_ci goto out_unlock; 31728c2ecf20Sopenharmony_ci } 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci if (whole && lock_task_sighand(task, &flags)) { 31758c2ecf20Sopenharmony_ci struct task_struct *t = task; 31768c2ecf20Sopenharmony_ci 31778c2ecf20Sopenharmony_ci task_io_accounting_add(&acct, &task->signal->ioac); 31788c2ecf20Sopenharmony_ci while_each_thread(task, t) 31798c2ecf20Sopenharmony_ci task_io_accounting_add(&acct, &t->ioac); 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci unlock_task_sighand(task, &flags); 31828c2ecf20Sopenharmony_ci } 31838c2ecf20Sopenharmony_ci seq_printf(m, 31848c2ecf20Sopenharmony_ci "rchar: %llu\n" 31858c2ecf20Sopenharmony_ci "wchar: %llu\n" 31868c2ecf20Sopenharmony_ci "syscr: %llu\n" 31878c2ecf20Sopenharmony_ci "syscw: %llu\n" 31888c2ecf20Sopenharmony_ci "read_bytes: %llu\n" 31898c2ecf20Sopenharmony_ci "write_bytes: %llu\n" 31908c2ecf20Sopenharmony_ci "cancelled_write_bytes: %llu\n", 31918c2ecf20Sopenharmony_ci (unsigned long long)acct.rchar, 31928c2ecf20Sopenharmony_ci (unsigned long long)acct.wchar, 31938c2ecf20Sopenharmony_ci (unsigned long long)acct.syscr, 31948c2ecf20Sopenharmony_ci (unsigned long long)acct.syscw, 31958c2ecf20Sopenharmony_ci (unsigned long long)acct.read_bytes, 31968c2ecf20Sopenharmony_ci (unsigned long long)acct.write_bytes, 31978c2ecf20Sopenharmony_ci (unsigned long long)acct.cancelled_write_bytes); 31988c2ecf20Sopenharmony_ci result = 0; 31998c2ecf20Sopenharmony_ci 32008c2ecf20Sopenharmony_ciout_unlock: 32018c2ecf20Sopenharmony_ci up_read(&task->signal->exec_update_lock); 32028c2ecf20Sopenharmony_ci return result; 32038c2ecf20Sopenharmony_ci} 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_cistatic int proc_tid_io_accounting(struct seq_file *m, struct pid_namespace *ns, 32068c2ecf20Sopenharmony_ci struct pid *pid, struct task_struct *task) 32078c2ecf20Sopenharmony_ci{ 32088c2ecf20Sopenharmony_ci return do_io_accounting(task, m, 0); 32098c2ecf20Sopenharmony_ci} 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_cistatic int proc_tgid_io_accounting(struct seq_file *m, struct pid_namespace *ns, 32128c2ecf20Sopenharmony_ci struct pid *pid, struct task_struct *task) 32138c2ecf20Sopenharmony_ci{ 32148c2ecf20Sopenharmony_ci return do_io_accounting(task, m, 1); 32158c2ecf20Sopenharmony_ci} 32168c2ecf20Sopenharmony_ci#endif /* CONFIG_TASK_IO_ACCOUNTING */ 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci#ifdef CONFIG_USER_NS 32198c2ecf20Sopenharmony_cistatic int proc_id_map_open(struct inode *inode, struct file *file, 32208c2ecf20Sopenharmony_ci const struct seq_operations *seq_ops) 32218c2ecf20Sopenharmony_ci{ 32228c2ecf20Sopenharmony_ci struct user_namespace *ns = NULL; 32238c2ecf20Sopenharmony_ci struct task_struct *task; 32248c2ecf20Sopenharmony_ci struct seq_file *seq; 32258c2ecf20Sopenharmony_ci int ret = -EINVAL; 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci task = get_proc_task(inode); 32288c2ecf20Sopenharmony_ci if (task) { 32298c2ecf20Sopenharmony_ci rcu_read_lock(); 32308c2ecf20Sopenharmony_ci ns = get_user_ns(task_cred_xxx(task, user_ns)); 32318c2ecf20Sopenharmony_ci rcu_read_unlock(); 32328c2ecf20Sopenharmony_ci put_task_struct(task); 32338c2ecf20Sopenharmony_ci } 32348c2ecf20Sopenharmony_ci if (!ns) 32358c2ecf20Sopenharmony_ci goto err; 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_ci ret = seq_open(file, seq_ops); 32388c2ecf20Sopenharmony_ci if (ret) 32398c2ecf20Sopenharmony_ci goto err_put_ns; 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci seq = file->private_data; 32428c2ecf20Sopenharmony_ci seq->private = ns; 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_ci return 0; 32458c2ecf20Sopenharmony_cierr_put_ns: 32468c2ecf20Sopenharmony_ci put_user_ns(ns); 32478c2ecf20Sopenharmony_cierr: 32488c2ecf20Sopenharmony_ci return ret; 32498c2ecf20Sopenharmony_ci} 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_cistatic int proc_id_map_release(struct inode *inode, struct file *file) 32528c2ecf20Sopenharmony_ci{ 32538c2ecf20Sopenharmony_ci struct seq_file *seq = file->private_data; 32548c2ecf20Sopenharmony_ci struct user_namespace *ns = seq->private; 32558c2ecf20Sopenharmony_ci put_user_ns(ns); 32568c2ecf20Sopenharmony_ci return seq_release(inode, file); 32578c2ecf20Sopenharmony_ci} 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_cistatic int proc_uid_map_open(struct inode *inode, struct file *file) 32608c2ecf20Sopenharmony_ci{ 32618c2ecf20Sopenharmony_ci return proc_id_map_open(inode, file, &proc_uid_seq_operations); 32628c2ecf20Sopenharmony_ci} 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_cistatic int proc_gid_map_open(struct inode *inode, struct file *file) 32658c2ecf20Sopenharmony_ci{ 32668c2ecf20Sopenharmony_ci return proc_id_map_open(inode, file, &proc_gid_seq_operations); 32678c2ecf20Sopenharmony_ci} 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_cistatic int proc_projid_map_open(struct inode *inode, struct file *file) 32708c2ecf20Sopenharmony_ci{ 32718c2ecf20Sopenharmony_ci return proc_id_map_open(inode, file, &proc_projid_seq_operations); 32728c2ecf20Sopenharmony_ci} 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_cistatic const struct file_operations proc_uid_map_operations = { 32758c2ecf20Sopenharmony_ci .open = proc_uid_map_open, 32768c2ecf20Sopenharmony_ci .write = proc_uid_map_write, 32778c2ecf20Sopenharmony_ci .read = seq_read, 32788c2ecf20Sopenharmony_ci .llseek = seq_lseek, 32798c2ecf20Sopenharmony_ci .release = proc_id_map_release, 32808c2ecf20Sopenharmony_ci}; 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_cistatic const struct file_operations proc_gid_map_operations = { 32838c2ecf20Sopenharmony_ci .open = proc_gid_map_open, 32848c2ecf20Sopenharmony_ci .write = proc_gid_map_write, 32858c2ecf20Sopenharmony_ci .read = seq_read, 32868c2ecf20Sopenharmony_ci .llseek = seq_lseek, 32878c2ecf20Sopenharmony_ci .release = proc_id_map_release, 32888c2ecf20Sopenharmony_ci}; 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_cistatic const struct file_operations proc_projid_map_operations = { 32918c2ecf20Sopenharmony_ci .open = proc_projid_map_open, 32928c2ecf20Sopenharmony_ci .write = proc_projid_map_write, 32938c2ecf20Sopenharmony_ci .read = seq_read, 32948c2ecf20Sopenharmony_ci .llseek = seq_lseek, 32958c2ecf20Sopenharmony_ci .release = proc_id_map_release, 32968c2ecf20Sopenharmony_ci}; 32978c2ecf20Sopenharmony_ci 32988c2ecf20Sopenharmony_cistatic int proc_setgroups_open(struct inode *inode, struct file *file) 32998c2ecf20Sopenharmony_ci{ 33008c2ecf20Sopenharmony_ci struct user_namespace *ns = NULL; 33018c2ecf20Sopenharmony_ci struct task_struct *task; 33028c2ecf20Sopenharmony_ci int ret; 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci ret = -ESRCH; 33058c2ecf20Sopenharmony_ci task = get_proc_task(inode); 33068c2ecf20Sopenharmony_ci if (task) { 33078c2ecf20Sopenharmony_ci rcu_read_lock(); 33088c2ecf20Sopenharmony_ci ns = get_user_ns(task_cred_xxx(task, user_ns)); 33098c2ecf20Sopenharmony_ci rcu_read_unlock(); 33108c2ecf20Sopenharmony_ci put_task_struct(task); 33118c2ecf20Sopenharmony_ci } 33128c2ecf20Sopenharmony_ci if (!ns) 33138c2ecf20Sopenharmony_ci goto err; 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci if (file->f_mode & FMODE_WRITE) { 33168c2ecf20Sopenharmony_ci ret = -EACCES; 33178c2ecf20Sopenharmony_ci if (!ns_capable(ns, CAP_SYS_ADMIN)) 33188c2ecf20Sopenharmony_ci goto err_put_ns; 33198c2ecf20Sopenharmony_ci } 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_ci ret = single_open(file, &proc_setgroups_show, ns); 33228c2ecf20Sopenharmony_ci if (ret) 33238c2ecf20Sopenharmony_ci goto err_put_ns; 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci return 0; 33268c2ecf20Sopenharmony_cierr_put_ns: 33278c2ecf20Sopenharmony_ci put_user_ns(ns); 33288c2ecf20Sopenharmony_cierr: 33298c2ecf20Sopenharmony_ci return ret; 33308c2ecf20Sopenharmony_ci} 33318c2ecf20Sopenharmony_ci 33328c2ecf20Sopenharmony_cistatic int proc_setgroups_release(struct inode *inode, struct file *file) 33338c2ecf20Sopenharmony_ci{ 33348c2ecf20Sopenharmony_ci struct seq_file *seq = file->private_data; 33358c2ecf20Sopenharmony_ci struct user_namespace *ns = seq->private; 33368c2ecf20Sopenharmony_ci int ret = single_release(inode, file); 33378c2ecf20Sopenharmony_ci put_user_ns(ns); 33388c2ecf20Sopenharmony_ci return ret; 33398c2ecf20Sopenharmony_ci} 33408c2ecf20Sopenharmony_ci 33418c2ecf20Sopenharmony_cistatic const struct file_operations proc_setgroups_operations = { 33428c2ecf20Sopenharmony_ci .open = proc_setgroups_open, 33438c2ecf20Sopenharmony_ci .write = proc_setgroups_write, 33448c2ecf20Sopenharmony_ci .read = seq_read, 33458c2ecf20Sopenharmony_ci .llseek = seq_lseek, 33468c2ecf20Sopenharmony_ci .release = proc_setgroups_release, 33478c2ecf20Sopenharmony_ci}; 33488c2ecf20Sopenharmony_ci#endif /* CONFIG_USER_NS */ 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_cistatic int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, 33518c2ecf20Sopenharmony_ci struct pid *pid, struct task_struct *task) 33528c2ecf20Sopenharmony_ci{ 33538c2ecf20Sopenharmony_ci int err = lock_trace(task); 33548c2ecf20Sopenharmony_ci if (!err) { 33558c2ecf20Sopenharmony_ci seq_printf(m, "%08x\n", task->personality); 33568c2ecf20Sopenharmony_ci unlock_trace(task); 33578c2ecf20Sopenharmony_ci } 33588c2ecf20Sopenharmony_ci return err; 33598c2ecf20Sopenharmony_ci} 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ci#ifdef CONFIG_LIVEPATCH 33628c2ecf20Sopenharmony_cistatic int proc_pid_patch_state(struct seq_file *m, struct pid_namespace *ns, 33638c2ecf20Sopenharmony_ci struct pid *pid, struct task_struct *task) 33648c2ecf20Sopenharmony_ci{ 33658c2ecf20Sopenharmony_ci seq_printf(m, "%d\n", task->patch_state); 33668c2ecf20Sopenharmony_ci return 0; 33678c2ecf20Sopenharmony_ci} 33688c2ecf20Sopenharmony_ci#endif /* CONFIG_LIVEPATCH */ 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_ci#ifdef CONFIG_STACKLEAK_METRICS 33718c2ecf20Sopenharmony_cistatic int proc_stack_depth(struct seq_file *m, struct pid_namespace *ns, 33728c2ecf20Sopenharmony_ci struct pid *pid, struct task_struct *task) 33738c2ecf20Sopenharmony_ci{ 33748c2ecf20Sopenharmony_ci unsigned long prev_depth = THREAD_SIZE - 33758c2ecf20Sopenharmony_ci (task->prev_lowest_stack & (THREAD_SIZE - 1)); 33768c2ecf20Sopenharmony_ci unsigned long depth = THREAD_SIZE - 33778c2ecf20Sopenharmony_ci (task->lowest_stack & (THREAD_SIZE - 1)); 33788c2ecf20Sopenharmony_ci 33798c2ecf20Sopenharmony_ci seq_printf(m, "previous stack depth: %lu\nstack depth: %lu\n", 33808c2ecf20Sopenharmony_ci prev_depth, depth); 33818c2ecf20Sopenharmony_ci return 0; 33828c2ecf20Sopenharmony_ci} 33838c2ecf20Sopenharmony_ci#endif /* CONFIG_STACKLEAK_METRICS */ 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_ci#ifdef CONFIG_ACCESS_TOKENID 33868c2ecf20Sopenharmony_cistatic int proc_token_operations(struct seq_file *m, struct pid_namespace *ns, 33878c2ecf20Sopenharmony_ci struct pid *pid, struct task_struct *task) 33888c2ecf20Sopenharmony_ci{ 33898c2ecf20Sopenharmony_ci seq_printf(m, "%#llx %#llx\n", task->token, task->ftoken); 33908c2ecf20Sopenharmony_ci return 0; 33918c2ecf20Sopenharmony_ci} 33928c2ecf20Sopenharmony_ci#endif /* CONFIG_ACCESS_TOKENID */ 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci/* 33958c2ecf20Sopenharmony_ci * Thread groups 33968c2ecf20Sopenharmony_ci */ 33978c2ecf20Sopenharmony_cistatic const struct file_operations proc_task_operations; 33988c2ecf20Sopenharmony_cistatic const struct inode_operations proc_task_inode_operations; 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_cistatic const struct pid_entry tgid_base_stuff[] = { 34018c2ecf20Sopenharmony_ci DIR("task", S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations), 34028c2ecf20Sopenharmony_ci DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), 34038c2ecf20Sopenharmony_ci DIR("map_files", S_IRUSR|S_IXUSR, proc_map_files_inode_operations, proc_map_files_operations), 34048c2ecf20Sopenharmony_ci DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), 34058c2ecf20Sopenharmony_ci DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), 34068c2ecf20Sopenharmony_ci#ifdef CONFIG_NET 34078c2ecf20Sopenharmony_ci DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), 34088c2ecf20Sopenharmony_ci#endif 34098c2ecf20Sopenharmony_ci REG("environ", S_IRUSR, proc_environ_operations), 34108c2ecf20Sopenharmony_ci REG("auxv", S_IRUSR, proc_auxv_operations), 34118c2ecf20Sopenharmony_ci ONE("status", S_IRUGO, proc_pid_status), 34128c2ecf20Sopenharmony_ci ONE("personality", S_IRUSR, proc_pid_personality), 34138c2ecf20Sopenharmony_ci ONE("limits", S_IRUGO, proc_pid_limits), 34148c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_WALT 34158c2ecf20Sopenharmony_ci REG("sched_init_task_load", 00644, proc_pid_sched_init_task_load_operations), 34168c2ecf20Sopenharmony_ci#endif 34178c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_DEBUG 34188c2ecf20Sopenharmony_ci REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), 34198c2ecf20Sopenharmony_ci#endif 34208c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_AUTOGROUP 34218c2ecf20Sopenharmony_ci REG("autogroup", S_IRUGO|S_IWUSR, proc_pid_sched_autogroup_operations), 34228c2ecf20Sopenharmony_ci#endif 34238c2ecf20Sopenharmony_ci#ifdef CONFIG_TIME_NS 34248c2ecf20Sopenharmony_ci REG("timens_offsets", S_IRUGO|S_IWUSR, proc_timens_offsets_operations), 34258c2ecf20Sopenharmony_ci#endif 34268c2ecf20Sopenharmony_ci#ifdef CONFIG_RSS_THRESHOLD 34278c2ecf20Sopenharmony_ci ONE("rss", S_IRUGO, proc_pid_rss), 34288c2ecf20Sopenharmony_ci REG("rss_threshold", S_IRUGO|S_IWUSR, proc_pid_rss_threshold_operations), 34298c2ecf20Sopenharmony_ci#endif 34308c2ecf20Sopenharmony_ci REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), 34318c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_TRACEHOOK 34328c2ecf20Sopenharmony_ci ONE("syscall", S_IRUSR, proc_pid_syscall), 34338c2ecf20Sopenharmony_ci#endif 34348c2ecf20Sopenharmony_ci REG("cmdline", S_IRUGO, proc_pid_cmdline_ops), 34358c2ecf20Sopenharmony_ci ONE("stat", S_IRUGO, proc_tgid_stat), 34368c2ecf20Sopenharmony_ci ONE("statm", S_IRUGO, proc_pid_statm), 34378c2ecf20Sopenharmony_ci REG("maps", S_IRUGO, proc_pid_maps_operations), 34388c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA 34398c2ecf20Sopenharmony_ci REG("numa_maps", S_IRUGO, proc_pid_numa_maps_operations), 34408c2ecf20Sopenharmony_ci#endif 34418c2ecf20Sopenharmony_ci REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations), 34428c2ecf20Sopenharmony_ci LNK("cwd", proc_cwd_link), 34438c2ecf20Sopenharmony_ci LNK("root", proc_root_link), 34448c2ecf20Sopenharmony_ci LNK("exe", proc_exe_link), 34458c2ecf20Sopenharmony_ci REG("mounts", S_IRUGO, proc_mounts_operations), 34468c2ecf20Sopenharmony_ci REG("mountinfo", S_IRUGO, proc_mountinfo_operations), 34478c2ecf20Sopenharmony_ci REG("mountstats", S_IRUSR, proc_mountstats_operations), 34488c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_PAGE_MONITOR 34498c2ecf20Sopenharmony_ci REG("clear_refs", S_IWUSR, proc_clear_refs_operations), 34508c2ecf20Sopenharmony_ci REG("smaps", S_IRUGO, proc_pid_smaps_operations), 34518c2ecf20Sopenharmony_ci REG("smaps_rollup", S_IRUGO, proc_pid_smaps_rollup_operations), 34528c2ecf20Sopenharmony_ci REG("pagemap", S_IRUSR, proc_pagemap_operations), 34538c2ecf20Sopenharmony_ci#endif 34548c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY 34558c2ecf20Sopenharmony_ci DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), 34568c2ecf20Sopenharmony_ci#endif 34578c2ecf20Sopenharmony_ci#ifdef CONFIG_KALLSYMS 34588c2ecf20Sopenharmony_ci ONE("wchan", S_IRUGO, proc_pid_wchan), 34598c2ecf20Sopenharmony_ci#endif 34608c2ecf20Sopenharmony_ci#ifdef CONFIG_STACKTRACE 34618c2ecf20Sopenharmony_ci ONE("stack", S_IRUSR, proc_pid_stack), 34628c2ecf20Sopenharmony_ci#endif 34638c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_INFO 34648c2ecf20Sopenharmony_ci ONE("schedstat", S_IRUGO, proc_pid_schedstat), 34658c2ecf20Sopenharmony_ci#endif 34668c2ecf20Sopenharmony_ci#ifdef CONFIG_LATENCYTOP 34678c2ecf20Sopenharmony_ci REG("latency", S_IRUGO, proc_lstats_operations), 34688c2ecf20Sopenharmony_ci#endif 34698c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_PID_CPUSET 34708c2ecf20Sopenharmony_ci ONE("cpuset", S_IRUGO, proc_cpuset_show), 34718c2ecf20Sopenharmony_ci#endif 34728c2ecf20Sopenharmony_ci#ifdef CONFIG_CGROUPS 34738c2ecf20Sopenharmony_ci ONE("cgroup", S_IRUGO, proc_cgroup_show), 34748c2ecf20Sopenharmony_ci#endif 34758c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_CPU_RESCTRL 34768c2ecf20Sopenharmony_ci ONE("cpu_resctrl_groups", S_IRUGO, proc_resctrl_show), 34778c2ecf20Sopenharmony_ci#endif 34788c2ecf20Sopenharmony_ci ONE("oom_score", S_IRUGO, proc_oom_score), 34798c2ecf20Sopenharmony_ci REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations), 34808c2ecf20Sopenharmony_ci REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), 34818c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 34828c2ecf20Sopenharmony_ci REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), 34838c2ecf20Sopenharmony_ci REG("sessionid", S_IRUGO, proc_sessionid_operations), 34848c2ecf20Sopenharmony_ci#endif 34858c2ecf20Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION 34868c2ecf20Sopenharmony_ci REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), 34878c2ecf20Sopenharmony_ci REG("fail-nth", 0644, proc_fail_nth_operations), 34888c2ecf20Sopenharmony_ci#endif 34898c2ecf20Sopenharmony_ci#ifdef CONFIG_ELF_CORE 34908c2ecf20Sopenharmony_ci REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations), 34918c2ecf20Sopenharmony_ci#endif 34928c2ecf20Sopenharmony_ci#ifdef CONFIG_TASK_IO_ACCOUNTING 34938c2ecf20Sopenharmony_ci ONE("io", S_IRUSR, proc_tgid_io_accounting), 34948c2ecf20Sopenharmony_ci#endif 34958c2ecf20Sopenharmony_ci#ifdef CONFIG_USER_NS 34968c2ecf20Sopenharmony_ci REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), 34978c2ecf20Sopenharmony_ci REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), 34988c2ecf20Sopenharmony_ci REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), 34998c2ecf20Sopenharmony_ci REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations), 35008c2ecf20Sopenharmony_ci#endif 35018c2ecf20Sopenharmony_ci#if defined(CONFIG_CHECKPOINT_RESTORE) && defined(CONFIG_POSIX_TIMERS) 35028c2ecf20Sopenharmony_ci REG("timers", S_IRUGO, proc_timers_operations), 35038c2ecf20Sopenharmony_ci#endif 35048c2ecf20Sopenharmony_ci REG("timerslack_ns", S_IRUGO|S_IWUGO, proc_pid_set_timerslack_ns_operations), 35058c2ecf20Sopenharmony_ci#ifdef CONFIG_LIVEPATCH 35068c2ecf20Sopenharmony_ci ONE("patch_state", S_IRUSR, proc_pid_patch_state), 35078c2ecf20Sopenharmony_ci#endif 35088c2ecf20Sopenharmony_ci#ifdef CONFIG_STACKLEAK_METRICS 35098c2ecf20Sopenharmony_ci ONE("stack_depth", S_IRUGO, proc_stack_depth), 35108c2ecf20Sopenharmony_ci#endif 35118c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_PID_ARCH_STATUS 35128c2ecf20Sopenharmony_ci ONE("arch_status", S_IRUGO, proc_pid_arch_status), 35138c2ecf20Sopenharmony_ci#endif 35148c2ecf20Sopenharmony_ci#ifdef CONFIG_ACCESS_TOKENID 35158c2ecf20Sopenharmony_ci ONE("tokenid", S_IRUSR, proc_token_operations), 35168c2ecf20Sopenharmony_ci#endif 35178c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_RTG 35188c2ecf20Sopenharmony_ci REG("sched_rtg_ctrl", S_IRUGO|S_IWUGO, proc_rtg_operations), 35198c2ecf20Sopenharmony_ci#endif 35208c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_RTG_DEBUG 35218c2ecf20Sopenharmony_ci REG("sched_group_id", S_IRUGO|S_IWUGO, proc_pid_sched_group_id_operations), 35228c2ecf20Sopenharmony_ci#endif 35238c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_XPM 35248c2ecf20Sopenharmony_ci REG("xpm_region", S_IRUGO, proc_xpm_region_operations), 35258c2ecf20Sopenharmony_ci#endif 35268c2ecf20Sopenharmony_ci}; 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_cistatic int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx) 35298c2ecf20Sopenharmony_ci{ 35308c2ecf20Sopenharmony_ci return proc_pident_readdir(file, ctx, 35318c2ecf20Sopenharmony_ci tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff)); 35328c2ecf20Sopenharmony_ci} 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_cistatic const struct file_operations proc_tgid_base_operations = { 35358c2ecf20Sopenharmony_ci .read = generic_read_dir, 35368c2ecf20Sopenharmony_ci .iterate_shared = proc_tgid_base_readdir, 35378c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 35388c2ecf20Sopenharmony_ci}; 35398c2ecf20Sopenharmony_ci 35408c2ecf20Sopenharmony_cistruct pid *tgid_pidfd_to_pid(const struct file *file) 35418c2ecf20Sopenharmony_ci{ 35428c2ecf20Sopenharmony_ci if (file->f_op != &proc_tgid_base_operations) 35438c2ecf20Sopenharmony_ci return ERR_PTR(-EBADF); 35448c2ecf20Sopenharmony_ci 35458c2ecf20Sopenharmony_ci return proc_pid(file_inode(file)); 35468c2ecf20Sopenharmony_ci} 35478c2ecf20Sopenharmony_ci 35488c2ecf20Sopenharmony_cistatic struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 35498c2ecf20Sopenharmony_ci{ 35508c2ecf20Sopenharmony_ci return proc_pident_lookup(dir, dentry, 35518c2ecf20Sopenharmony_ci tgid_base_stuff, 35528c2ecf20Sopenharmony_ci tgid_base_stuff + ARRAY_SIZE(tgid_base_stuff)); 35538c2ecf20Sopenharmony_ci} 35548c2ecf20Sopenharmony_ci 35558c2ecf20Sopenharmony_cistatic const struct inode_operations proc_tgid_base_inode_operations = { 35568c2ecf20Sopenharmony_ci .lookup = proc_tgid_base_lookup, 35578c2ecf20Sopenharmony_ci .getattr = pid_getattr, 35588c2ecf20Sopenharmony_ci .setattr = proc_setattr, 35598c2ecf20Sopenharmony_ci .permission = proc_pid_permission, 35608c2ecf20Sopenharmony_ci}; 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_ci/** 35638c2ecf20Sopenharmony_ci * proc_flush_pid - Remove dcache entries for @pid from the /proc dcache. 35648c2ecf20Sopenharmony_ci * @pid: pid that should be flushed. 35658c2ecf20Sopenharmony_ci * 35668c2ecf20Sopenharmony_ci * This function walks a list of inodes (that belong to any proc 35678c2ecf20Sopenharmony_ci * filesystem) that are attached to the pid and flushes them from 35688c2ecf20Sopenharmony_ci * the dentry cache. 35698c2ecf20Sopenharmony_ci * 35708c2ecf20Sopenharmony_ci * It is safe and reasonable to cache /proc entries for a task until 35718c2ecf20Sopenharmony_ci * that task exits. After that they just clog up the dcache with 35728c2ecf20Sopenharmony_ci * useless entries, possibly causing useful dcache entries to be 35738c2ecf20Sopenharmony_ci * flushed instead. This routine is provided to flush those useless 35748c2ecf20Sopenharmony_ci * dcache entries when a process is reaped. 35758c2ecf20Sopenharmony_ci * 35768c2ecf20Sopenharmony_ci * NOTE: This routine is just an optimization so it does not guarantee 35778c2ecf20Sopenharmony_ci * that no dcache entries will exist after a process is reaped 35788c2ecf20Sopenharmony_ci * it just makes it very unlikely that any will persist. 35798c2ecf20Sopenharmony_ci */ 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_civoid proc_flush_pid(struct pid *pid) 35828c2ecf20Sopenharmony_ci{ 35838c2ecf20Sopenharmony_ci proc_invalidate_siblings_dcache(&pid->inodes, &pid->lock); 35848c2ecf20Sopenharmony_ci} 35858c2ecf20Sopenharmony_ci 35868c2ecf20Sopenharmony_cistatic struct dentry *proc_pid_instantiate(struct dentry * dentry, 35878c2ecf20Sopenharmony_ci struct task_struct *task, const void *ptr) 35888c2ecf20Sopenharmony_ci{ 35898c2ecf20Sopenharmony_ci struct inode *inode; 35908c2ecf20Sopenharmony_ci 35918c2ecf20Sopenharmony_ci inode = proc_pid_make_base_inode(dentry->d_sb, task, 35928c2ecf20Sopenharmony_ci S_IFDIR | S_IRUGO | S_IXUGO); 35938c2ecf20Sopenharmony_ci if (!inode) 35948c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 35958c2ecf20Sopenharmony_ci 35968c2ecf20Sopenharmony_ci inode->i_op = &proc_tgid_base_inode_operations; 35978c2ecf20Sopenharmony_ci inode->i_fop = &proc_tgid_base_operations; 35988c2ecf20Sopenharmony_ci inode->i_flags|=S_IMMUTABLE; 35998c2ecf20Sopenharmony_ci 36008c2ecf20Sopenharmony_ci set_nlink(inode, nlink_tgid); 36018c2ecf20Sopenharmony_ci pid_update_inode(task, inode); 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_ci d_set_d_op(dentry, &pid_dentry_operations); 36048c2ecf20Sopenharmony_ci return d_splice_alias(inode, dentry); 36058c2ecf20Sopenharmony_ci} 36068c2ecf20Sopenharmony_ci 36078c2ecf20Sopenharmony_cistruct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags) 36088c2ecf20Sopenharmony_ci{ 36098c2ecf20Sopenharmony_ci struct task_struct *task; 36108c2ecf20Sopenharmony_ci unsigned tgid; 36118c2ecf20Sopenharmony_ci struct proc_fs_info *fs_info; 36128c2ecf20Sopenharmony_ci struct pid_namespace *ns; 36138c2ecf20Sopenharmony_ci struct dentry *result = ERR_PTR(-ENOENT); 36148c2ecf20Sopenharmony_ci 36158c2ecf20Sopenharmony_ci tgid = name_to_int(&dentry->d_name); 36168c2ecf20Sopenharmony_ci if (tgid == ~0U) 36178c2ecf20Sopenharmony_ci goto out; 36188c2ecf20Sopenharmony_ci 36198c2ecf20Sopenharmony_ci fs_info = proc_sb_info(dentry->d_sb); 36208c2ecf20Sopenharmony_ci ns = fs_info->pid_ns; 36218c2ecf20Sopenharmony_ci rcu_read_lock(); 36228c2ecf20Sopenharmony_ci task = find_task_by_pid_ns(tgid, ns); 36238c2ecf20Sopenharmony_ci if (task) 36248c2ecf20Sopenharmony_ci get_task_struct(task); 36258c2ecf20Sopenharmony_ci rcu_read_unlock(); 36268c2ecf20Sopenharmony_ci if (!task) 36278c2ecf20Sopenharmony_ci goto out; 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_ci /* Limit procfs to only ptraceable tasks */ 36308c2ecf20Sopenharmony_ci if (fs_info->hide_pid == HIDEPID_NOT_PTRACEABLE) { 36318c2ecf20Sopenharmony_ci if (!has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS)) 36328c2ecf20Sopenharmony_ci goto out_put_task; 36338c2ecf20Sopenharmony_ci } 36348c2ecf20Sopenharmony_ci 36358c2ecf20Sopenharmony_ci result = proc_pid_instantiate(dentry, task, NULL); 36368c2ecf20Sopenharmony_ciout_put_task: 36378c2ecf20Sopenharmony_ci put_task_struct(task); 36388c2ecf20Sopenharmony_ciout: 36398c2ecf20Sopenharmony_ci return result; 36408c2ecf20Sopenharmony_ci} 36418c2ecf20Sopenharmony_ci 36428c2ecf20Sopenharmony_ci/* 36438c2ecf20Sopenharmony_ci * Find the first task with tgid >= tgid 36448c2ecf20Sopenharmony_ci * 36458c2ecf20Sopenharmony_ci */ 36468c2ecf20Sopenharmony_cistruct tgid_iter { 36478c2ecf20Sopenharmony_ci unsigned int tgid; 36488c2ecf20Sopenharmony_ci struct task_struct *task; 36498c2ecf20Sopenharmony_ci}; 36508c2ecf20Sopenharmony_cistatic struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter iter) 36518c2ecf20Sopenharmony_ci{ 36528c2ecf20Sopenharmony_ci struct pid *pid; 36538c2ecf20Sopenharmony_ci 36548c2ecf20Sopenharmony_ci if (iter.task) 36558c2ecf20Sopenharmony_ci put_task_struct(iter.task); 36568c2ecf20Sopenharmony_ci rcu_read_lock(); 36578c2ecf20Sopenharmony_ciretry: 36588c2ecf20Sopenharmony_ci iter.task = NULL; 36598c2ecf20Sopenharmony_ci pid = find_ge_pid(iter.tgid, ns); 36608c2ecf20Sopenharmony_ci if (pid) { 36618c2ecf20Sopenharmony_ci iter.tgid = pid_nr_ns(pid, ns); 36628c2ecf20Sopenharmony_ci iter.task = pid_task(pid, PIDTYPE_TGID); 36638c2ecf20Sopenharmony_ci if (!iter.task) { 36648c2ecf20Sopenharmony_ci iter.tgid += 1; 36658c2ecf20Sopenharmony_ci goto retry; 36668c2ecf20Sopenharmony_ci } 36678c2ecf20Sopenharmony_ci get_task_struct(iter.task); 36688c2ecf20Sopenharmony_ci } 36698c2ecf20Sopenharmony_ci rcu_read_unlock(); 36708c2ecf20Sopenharmony_ci return iter; 36718c2ecf20Sopenharmony_ci} 36728c2ecf20Sopenharmony_ci 36738c2ecf20Sopenharmony_ci#define TGID_OFFSET (FIRST_PROCESS_ENTRY + 2) 36748c2ecf20Sopenharmony_ci 36758c2ecf20Sopenharmony_ci/* for the /proc/ directory itself, after non-process stuff has been done */ 36768c2ecf20Sopenharmony_ciint proc_pid_readdir(struct file *file, struct dir_context *ctx) 36778c2ecf20Sopenharmony_ci{ 36788c2ecf20Sopenharmony_ci struct tgid_iter iter; 36798c2ecf20Sopenharmony_ci struct proc_fs_info *fs_info = proc_sb_info(file_inode(file)->i_sb); 36808c2ecf20Sopenharmony_ci struct pid_namespace *ns = proc_pid_ns(file_inode(file)->i_sb); 36818c2ecf20Sopenharmony_ci loff_t pos = ctx->pos; 36828c2ecf20Sopenharmony_ci 36838c2ecf20Sopenharmony_ci if (pos >= PID_MAX_LIMIT + TGID_OFFSET) 36848c2ecf20Sopenharmony_ci return 0; 36858c2ecf20Sopenharmony_ci 36868c2ecf20Sopenharmony_ci if (pos == TGID_OFFSET - 2) { 36878c2ecf20Sopenharmony_ci struct inode *inode = d_inode(fs_info->proc_self); 36888c2ecf20Sopenharmony_ci if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK)) 36898c2ecf20Sopenharmony_ci return 0; 36908c2ecf20Sopenharmony_ci ctx->pos = pos = pos + 1; 36918c2ecf20Sopenharmony_ci } 36928c2ecf20Sopenharmony_ci if (pos == TGID_OFFSET - 1) { 36938c2ecf20Sopenharmony_ci struct inode *inode = d_inode(fs_info->proc_thread_self); 36948c2ecf20Sopenharmony_ci if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK)) 36958c2ecf20Sopenharmony_ci return 0; 36968c2ecf20Sopenharmony_ci ctx->pos = pos = pos + 1; 36978c2ecf20Sopenharmony_ci } 36988c2ecf20Sopenharmony_ci iter.tgid = pos - TGID_OFFSET; 36998c2ecf20Sopenharmony_ci iter.task = NULL; 37008c2ecf20Sopenharmony_ci for (iter = next_tgid(ns, iter); 37018c2ecf20Sopenharmony_ci iter.task; 37028c2ecf20Sopenharmony_ci iter.tgid += 1, iter = next_tgid(ns, iter)) { 37038c2ecf20Sopenharmony_ci char name[10 + 1]; 37048c2ecf20Sopenharmony_ci unsigned int len; 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_ci cond_resched(); 37078c2ecf20Sopenharmony_ci if (!has_pid_permissions(fs_info, iter.task, HIDEPID_INVISIBLE)) 37088c2ecf20Sopenharmony_ci continue; 37098c2ecf20Sopenharmony_ci 37108c2ecf20Sopenharmony_ci len = snprintf(name, sizeof(name), "%u", iter.tgid); 37118c2ecf20Sopenharmony_ci ctx->pos = iter.tgid + TGID_OFFSET; 37128c2ecf20Sopenharmony_ci if (!proc_fill_cache(file, ctx, name, len, 37138c2ecf20Sopenharmony_ci proc_pid_instantiate, iter.task, NULL)) { 37148c2ecf20Sopenharmony_ci put_task_struct(iter.task); 37158c2ecf20Sopenharmony_ci return 0; 37168c2ecf20Sopenharmony_ci } 37178c2ecf20Sopenharmony_ci } 37188c2ecf20Sopenharmony_ci ctx->pos = PID_MAX_LIMIT + TGID_OFFSET; 37198c2ecf20Sopenharmony_ci return 0; 37208c2ecf20Sopenharmony_ci} 37218c2ecf20Sopenharmony_ci 37228c2ecf20Sopenharmony_ci/* 37238c2ecf20Sopenharmony_ci * proc_tid_comm_permission is a special permission function exclusively 37248c2ecf20Sopenharmony_ci * used for the node /proc/<pid>/task/<tid>/comm. 37258c2ecf20Sopenharmony_ci * It bypasses generic permission checks in the case where a task of the same 37268c2ecf20Sopenharmony_ci * task group attempts to access the node. 37278c2ecf20Sopenharmony_ci * The rationale behind this is that glibc and bionic access this node for 37288c2ecf20Sopenharmony_ci * cross thread naming (pthread_set/getname_np(!self)). However, if 37298c2ecf20Sopenharmony_ci * PR_SET_DUMPABLE gets set to 0 this node among others becomes uid=0 gid=0, 37308c2ecf20Sopenharmony_ci * which locks out the cross thread naming implementation. 37318c2ecf20Sopenharmony_ci * This function makes sure that the node is always accessible for members of 37328c2ecf20Sopenharmony_ci * same thread group. 37338c2ecf20Sopenharmony_ci */ 37348c2ecf20Sopenharmony_cistatic int proc_tid_comm_permission(struct inode *inode, int mask) 37358c2ecf20Sopenharmony_ci{ 37368c2ecf20Sopenharmony_ci bool is_same_tgroup; 37378c2ecf20Sopenharmony_ci struct task_struct *task; 37388c2ecf20Sopenharmony_ci 37398c2ecf20Sopenharmony_ci task = get_proc_task(inode); 37408c2ecf20Sopenharmony_ci if (!task) 37418c2ecf20Sopenharmony_ci return -ESRCH; 37428c2ecf20Sopenharmony_ci is_same_tgroup = same_thread_group(current, task); 37438c2ecf20Sopenharmony_ci put_task_struct(task); 37448c2ecf20Sopenharmony_ci 37458c2ecf20Sopenharmony_ci if (likely(is_same_tgroup && !(mask & MAY_EXEC))) { 37468c2ecf20Sopenharmony_ci /* This file (/proc/<pid>/task/<tid>/comm) can always be 37478c2ecf20Sopenharmony_ci * read or written by the members of the corresponding 37488c2ecf20Sopenharmony_ci * thread group. 37498c2ecf20Sopenharmony_ci */ 37508c2ecf20Sopenharmony_ci return 0; 37518c2ecf20Sopenharmony_ci } 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_ci return generic_permission(inode, mask); 37548c2ecf20Sopenharmony_ci} 37558c2ecf20Sopenharmony_ci 37568c2ecf20Sopenharmony_cistatic const struct inode_operations proc_tid_comm_inode_operations = { 37578c2ecf20Sopenharmony_ci .setattr = proc_setattr, 37588c2ecf20Sopenharmony_ci .permission = proc_tid_comm_permission, 37598c2ecf20Sopenharmony_ci}; 37608c2ecf20Sopenharmony_ci 37618c2ecf20Sopenharmony_ci/* 37628c2ecf20Sopenharmony_ci * Tasks 37638c2ecf20Sopenharmony_ci */ 37648c2ecf20Sopenharmony_cistatic const struct pid_entry tid_base_stuff[] = { 37658c2ecf20Sopenharmony_ci DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), 37668c2ecf20Sopenharmony_ci DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), 37678c2ecf20Sopenharmony_ci DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), 37688c2ecf20Sopenharmony_ci#ifdef CONFIG_NET 37698c2ecf20Sopenharmony_ci DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), 37708c2ecf20Sopenharmony_ci#endif 37718c2ecf20Sopenharmony_ci REG("environ", S_IRUSR, proc_environ_operations), 37728c2ecf20Sopenharmony_ci REG("auxv", S_IRUSR, proc_auxv_operations), 37738c2ecf20Sopenharmony_ci ONE("status", S_IRUGO, proc_pid_status), 37748c2ecf20Sopenharmony_ci ONE("personality", S_IRUSR, proc_pid_personality), 37758c2ecf20Sopenharmony_ci ONE("limits", S_IRUGO, proc_pid_limits), 37768c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_DEBUG 37778c2ecf20Sopenharmony_ci REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), 37788c2ecf20Sopenharmony_ci#endif 37798c2ecf20Sopenharmony_ci NOD("comm", S_IFREG|S_IRUGO|S_IWUSR, 37808c2ecf20Sopenharmony_ci &proc_tid_comm_inode_operations, 37818c2ecf20Sopenharmony_ci &proc_pid_set_comm_operations, {}), 37828c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_TRACEHOOK 37838c2ecf20Sopenharmony_ci ONE("syscall", S_IRUSR, proc_pid_syscall), 37848c2ecf20Sopenharmony_ci#endif 37858c2ecf20Sopenharmony_ci REG("cmdline", S_IRUGO, proc_pid_cmdline_ops), 37868c2ecf20Sopenharmony_ci ONE("stat", S_IRUGO, proc_tid_stat), 37878c2ecf20Sopenharmony_ci ONE("statm", S_IRUGO, proc_pid_statm), 37888c2ecf20Sopenharmony_ci REG("maps", S_IRUGO, proc_pid_maps_operations), 37898c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_CHILDREN 37908c2ecf20Sopenharmony_ci REG("children", S_IRUGO, proc_tid_children_operations), 37918c2ecf20Sopenharmony_ci#endif 37928c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA 37938c2ecf20Sopenharmony_ci REG("numa_maps", S_IRUGO, proc_pid_numa_maps_operations), 37948c2ecf20Sopenharmony_ci#endif 37958c2ecf20Sopenharmony_ci REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations), 37968c2ecf20Sopenharmony_ci LNK("cwd", proc_cwd_link), 37978c2ecf20Sopenharmony_ci LNK("root", proc_root_link), 37988c2ecf20Sopenharmony_ci LNK("exe", proc_exe_link), 37998c2ecf20Sopenharmony_ci REG("mounts", S_IRUGO, proc_mounts_operations), 38008c2ecf20Sopenharmony_ci REG("mountinfo", S_IRUGO, proc_mountinfo_operations), 38018c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_PAGE_MONITOR 38028c2ecf20Sopenharmony_ci REG("clear_refs", S_IWUSR, proc_clear_refs_operations), 38038c2ecf20Sopenharmony_ci REG("smaps", S_IRUGO, proc_pid_smaps_operations), 38048c2ecf20Sopenharmony_ci REG("smaps_rollup", S_IRUGO, proc_pid_smaps_rollup_operations), 38058c2ecf20Sopenharmony_ci REG("pagemap", S_IRUSR, proc_pagemap_operations), 38068c2ecf20Sopenharmony_ci#endif 38078c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY 38088c2ecf20Sopenharmony_ci DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), 38098c2ecf20Sopenharmony_ci#endif 38108c2ecf20Sopenharmony_ci#ifdef CONFIG_KALLSYMS 38118c2ecf20Sopenharmony_ci ONE("wchan", S_IRUGO, proc_pid_wchan), 38128c2ecf20Sopenharmony_ci#endif 38138c2ecf20Sopenharmony_ci#ifdef CONFIG_STACKTRACE 38148c2ecf20Sopenharmony_ci ONE("stack", S_IRUSR, proc_pid_stack), 38158c2ecf20Sopenharmony_ci#endif 38168c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_INFO 38178c2ecf20Sopenharmony_ci ONE("schedstat", S_IRUGO, proc_pid_schedstat), 38188c2ecf20Sopenharmony_ci#endif 38198c2ecf20Sopenharmony_ci#ifdef CONFIG_LATENCYTOP 38208c2ecf20Sopenharmony_ci REG("latency", S_IRUGO, proc_lstats_operations), 38218c2ecf20Sopenharmony_ci#endif 38228c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_PID_CPUSET 38238c2ecf20Sopenharmony_ci ONE("cpuset", S_IRUGO, proc_cpuset_show), 38248c2ecf20Sopenharmony_ci#endif 38258c2ecf20Sopenharmony_ci#ifdef CONFIG_CGROUPS 38268c2ecf20Sopenharmony_ci ONE("cgroup", S_IRUGO, proc_cgroup_show), 38278c2ecf20Sopenharmony_ci#endif 38288c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_CPU_RESCTRL 38298c2ecf20Sopenharmony_ci ONE("cpu_resctrl_groups", S_IRUGO, proc_resctrl_show), 38308c2ecf20Sopenharmony_ci#endif 38318c2ecf20Sopenharmony_ci ONE("oom_score", S_IRUGO, proc_oom_score), 38328c2ecf20Sopenharmony_ci REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations), 38338c2ecf20Sopenharmony_ci REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), 38348c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 38358c2ecf20Sopenharmony_ci REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), 38368c2ecf20Sopenharmony_ci REG("sessionid", S_IRUGO, proc_sessionid_operations), 38378c2ecf20Sopenharmony_ci#endif 38388c2ecf20Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION 38398c2ecf20Sopenharmony_ci REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), 38408c2ecf20Sopenharmony_ci REG("fail-nth", 0644, proc_fail_nth_operations), 38418c2ecf20Sopenharmony_ci#endif 38428c2ecf20Sopenharmony_ci#ifdef CONFIG_TASK_IO_ACCOUNTING 38438c2ecf20Sopenharmony_ci ONE("io", S_IRUSR, proc_tid_io_accounting), 38448c2ecf20Sopenharmony_ci#endif 38458c2ecf20Sopenharmony_ci#ifdef CONFIG_USER_NS 38468c2ecf20Sopenharmony_ci REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), 38478c2ecf20Sopenharmony_ci REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), 38488c2ecf20Sopenharmony_ci REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), 38498c2ecf20Sopenharmony_ci REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations), 38508c2ecf20Sopenharmony_ci#endif 38518c2ecf20Sopenharmony_ci#ifdef CONFIG_LIVEPATCH 38528c2ecf20Sopenharmony_ci ONE("patch_state", S_IRUSR, proc_pid_patch_state), 38538c2ecf20Sopenharmony_ci#endif 38548c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_PID_ARCH_STATUS 38558c2ecf20Sopenharmony_ci ONE("arch_status", S_IRUGO, proc_pid_arch_status), 38568c2ecf20Sopenharmony_ci#endif 38578c2ecf20Sopenharmony_ci#ifdef CONFIG_ACCESS_TOKENID 38588c2ecf20Sopenharmony_ci ONE("tokenid", S_IRUSR, proc_token_operations), 38598c2ecf20Sopenharmony_ci#endif 38608c2ecf20Sopenharmony_ci#ifdef CONFIG_QOS_CTRL 38618c2ecf20Sopenharmony_ci REG("sched_qos_ctrl", S_IRUGO|S_IWUGO, proc_qos_ctrl_operations), 38628c2ecf20Sopenharmony_ci#endif 38638c2ecf20Sopenharmony_ci#ifdef CONFIG_SCHED_RTG_DEBUG 38648c2ecf20Sopenharmony_ci REG("sched_group_id", S_IRUGO|S_IWUGO, proc_pid_sched_group_id_operations), 38658c2ecf20Sopenharmony_ci#endif 38668c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_XPM 38678c2ecf20Sopenharmony_ci REG("xpm_region", S_IRUGO, proc_xpm_region_operations), 38688c2ecf20Sopenharmony_ci#endif 38698c2ecf20Sopenharmony_ci}; 38708c2ecf20Sopenharmony_ci 38718c2ecf20Sopenharmony_cistatic int proc_tid_base_readdir(struct file *file, struct dir_context *ctx) 38728c2ecf20Sopenharmony_ci{ 38738c2ecf20Sopenharmony_ci return proc_pident_readdir(file, ctx, 38748c2ecf20Sopenharmony_ci tid_base_stuff, ARRAY_SIZE(tid_base_stuff)); 38758c2ecf20Sopenharmony_ci} 38768c2ecf20Sopenharmony_ci 38778c2ecf20Sopenharmony_cistatic struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 38788c2ecf20Sopenharmony_ci{ 38798c2ecf20Sopenharmony_ci return proc_pident_lookup(dir, dentry, 38808c2ecf20Sopenharmony_ci tid_base_stuff, 38818c2ecf20Sopenharmony_ci tid_base_stuff + ARRAY_SIZE(tid_base_stuff)); 38828c2ecf20Sopenharmony_ci} 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_cistatic const struct file_operations proc_tid_base_operations = { 38858c2ecf20Sopenharmony_ci .read = generic_read_dir, 38868c2ecf20Sopenharmony_ci .iterate_shared = proc_tid_base_readdir, 38878c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 38888c2ecf20Sopenharmony_ci}; 38898c2ecf20Sopenharmony_ci 38908c2ecf20Sopenharmony_cistatic const struct inode_operations proc_tid_base_inode_operations = { 38918c2ecf20Sopenharmony_ci .lookup = proc_tid_base_lookup, 38928c2ecf20Sopenharmony_ci .getattr = pid_getattr, 38938c2ecf20Sopenharmony_ci .setattr = proc_setattr, 38948c2ecf20Sopenharmony_ci}; 38958c2ecf20Sopenharmony_ci 38968c2ecf20Sopenharmony_cistatic struct dentry *proc_task_instantiate(struct dentry *dentry, 38978c2ecf20Sopenharmony_ci struct task_struct *task, const void *ptr) 38988c2ecf20Sopenharmony_ci{ 38998c2ecf20Sopenharmony_ci struct inode *inode; 39008c2ecf20Sopenharmony_ci inode = proc_pid_make_base_inode(dentry->d_sb, task, 39018c2ecf20Sopenharmony_ci S_IFDIR | S_IRUGO | S_IXUGO); 39028c2ecf20Sopenharmony_ci if (!inode) 39038c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 39048c2ecf20Sopenharmony_ci 39058c2ecf20Sopenharmony_ci inode->i_op = &proc_tid_base_inode_operations; 39068c2ecf20Sopenharmony_ci inode->i_fop = &proc_tid_base_operations; 39078c2ecf20Sopenharmony_ci inode->i_flags |= S_IMMUTABLE; 39088c2ecf20Sopenharmony_ci 39098c2ecf20Sopenharmony_ci set_nlink(inode, nlink_tid); 39108c2ecf20Sopenharmony_ci pid_update_inode(task, inode); 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_ci d_set_d_op(dentry, &pid_dentry_operations); 39138c2ecf20Sopenharmony_ci return d_splice_alias(inode, dentry); 39148c2ecf20Sopenharmony_ci} 39158c2ecf20Sopenharmony_ci 39168c2ecf20Sopenharmony_cistatic struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) 39178c2ecf20Sopenharmony_ci{ 39188c2ecf20Sopenharmony_ci struct task_struct *task; 39198c2ecf20Sopenharmony_ci struct task_struct *leader = get_proc_task(dir); 39208c2ecf20Sopenharmony_ci unsigned tid; 39218c2ecf20Sopenharmony_ci struct proc_fs_info *fs_info; 39228c2ecf20Sopenharmony_ci struct pid_namespace *ns; 39238c2ecf20Sopenharmony_ci struct dentry *result = ERR_PTR(-ENOENT); 39248c2ecf20Sopenharmony_ci 39258c2ecf20Sopenharmony_ci if (!leader) 39268c2ecf20Sopenharmony_ci goto out_no_task; 39278c2ecf20Sopenharmony_ci 39288c2ecf20Sopenharmony_ci tid = name_to_int(&dentry->d_name); 39298c2ecf20Sopenharmony_ci if (tid == ~0U) 39308c2ecf20Sopenharmony_ci goto out; 39318c2ecf20Sopenharmony_ci 39328c2ecf20Sopenharmony_ci fs_info = proc_sb_info(dentry->d_sb); 39338c2ecf20Sopenharmony_ci ns = fs_info->pid_ns; 39348c2ecf20Sopenharmony_ci rcu_read_lock(); 39358c2ecf20Sopenharmony_ci task = find_task_by_pid_ns(tid, ns); 39368c2ecf20Sopenharmony_ci if (task) 39378c2ecf20Sopenharmony_ci get_task_struct(task); 39388c2ecf20Sopenharmony_ci rcu_read_unlock(); 39398c2ecf20Sopenharmony_ci if (!task) 39408c2ecf20Sopenharmony_ci goto out; 39418c2ecf20Sopenharmony_ci if (!same_thread_group(leader, task)) 39428c2ecf20Sopenharmony_ci goto out_drop_task; 39438c2ecf20Sopenharmony_ci 39448c2ecf20Sopenharmony_ci result = proc_task_instantiate(dentry, task, NULL); 39458c2ecf20Sopenharmony_ciout_drop_task: 39468c2ecf20Sopenharmony_ci put_task_struct(task); 39478c2ecf20Sopenharmony_ciout: 39488c2ecf20Sopenharmony_ci put_task_struct(leader); 39498c2ecf20Sopenharmony_ciout_no_task: 39508c2ecf20Sopenharmony_ci return result; 39518c2ecf20Sopenharmony_ci} 39528c2ecf20Sopenharmony_ci 39538c2ecf20Sopenharmony_ci/* 39548c2ecf20Sopenharmony_ci * Find the first tid of a thread group to return to user space. 39558c2ecf20Sopenharmony_ci * 39568c2ecf20Sopenharmony_ci * Usually this is just the thread group leader, but if the users 39578c2ecf20Sopenharmony_ci * buffer was too small or there was a seek into the middle of the 39588c2ecf20Sopenharmony_ci * directory we have more work todo. 39598c2ecf20Sopenharmony_ci * 39608c2ecf20Sopenharmony_ci * In the case of a short read we start with find_task_by_pid. 39618c2ecf20Sopenharmony_ci * 39628c2ecf20Sopenharmony_ci * In the case of a seek we start with the leader and walk nr 39638c2ecf20Sopenharmony_ci * threads past it. 39648c2ecf20Sopenharmony_ci */ 39658c2ecf20Sopenharmony_cistatic struct task_struct *first_tid(struct pid *pid, int tid, loff_t f_pos, 39668c2ecf20Sopenharmony_ci struct pid_namespace *ns) 39678c2ecf20Sopenharmony_ci{ 39688c2ecf20Sopenharmony_ci struct task_struct *pos, *task; 39698c2ecf20Sopenharmony_ci unsigned long nr = f_pos; 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci if (nr != f_pos) /* 32bit overflow? */ 39728c2ecf20Sopenharmony_ci return NULL; 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_ci rcu_read_lock(); 39758c2ecf20Sopenharmony_ci task = pid_task(pid, PIDTYPE_PID); 39768c2ecf20Sopenharmony_ci if (!task) 39778c2ecf20Sopenharmony_ci goto fail; 39788c2ecf20Sopenharmony_ci 39798c2ecf20Sopenharmony_ci /* Attempt to start with the tid of a thread */ 39808c2ecf20Sopenharmony_ci if (tid && nr) { 39818c2ecf20Sopenharmony_ci pos = find_task_by_pid_ns(tid, ns); 39828c2ecf20Sopenharmony_ci if (pos && same_thread_group(pos, task)) 39838c2ecf20Sopenharmony_ci goto found; 39848c2ecf20Sopenharmony_ci } 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_ci /* If nr exceeds the number of threads there is nothing todo */ 39878c2ecf20Sopenharmony_ci if (nr >= get_nr_threads(task)) 39888c2ecf20Sopenharmony_ci goto fail; 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci /* If we haven't found our starting place yet start 39918c2ecf20Sopenharmony_ci * with the leader and walk nr threads forward. 39928c2ecf20Sopenharmony_ci */ 39938c2ecf20Sopenharmony_ci pos = task = task->group_leader; 39948c2ecf20Sopenharmony_ci do { 39958c2ecf20Sopenharmony_ci if (!nr--) 39968c2ecf20Sopenharmony_ci goto found; 39978c2ecf20Sopenharmony_ci } while_each_thread(task, pos); 39988c2ecf20Sopenharmony_cifail: 39998c2ecf20Sopenharmony_ci pos = NULL; 40008c2ecf20Sopenharmony_ci goto out; 40018c2ecf20Sopenharmony_cifound: 40028c2ecf20Sopenharmony_ci get_task_struct(pos); 40038c2ecf20Sopenharmony_ciout: 40048c2ecf20Sopenharmony_ci rcu_read_unlock(); 40058c2ecf20Sopenharmony_ci return pos; 40068c2ecf20Sopenharmony_ci} 40078c2ecf20Sopenharmony_ci 40088c2ecf20Sopenharmony_ci/* 40098c2ecf20Sopenharmony_ci * Find the next thread in the thread list. 40108c2ecf20Sopenharmony_ci * Return NULL if there is an error or no next thread. 40118c2ecf20Sopenharmony_ci * 40128c2ecf20Sopenharmony_ci * The reference to the input task_struct is released. 40138c2ecf20Sopenharmony_ci */ 40148c2ecf20Sopenharmony_cistatic struct task_struct *next_tid(struct task_struct *start) 40158c2ecf20Sopenharmony_ci{ 40168c2ecf20Sopenharmony_ci struct task_struct *pos = NULL; 40178c2ecf20Sopenharmony_ci rcu_read_lock(); 40188c2ecf20Sopenharmony_ci if (pid_alive(start)) { 40198c2ecf20Sopenharmony_ci pos = next_thread(start); 40208c2ecf20Sopenharmony_ci if (thread_group_leader(pos)) 40218c2ecf20Sopenharmony_ci pos = NULL; 40228c2ecf20Sopenharmony_ci else 40238c2ecf20Sopenharmony_ci get_task_struct(pos); 40248c2ecf20Sopenharmony_ci } 40258c2ecf20Sopenharmony_ci rcu_read_unlock(); 40268c2ecf20Sopenharmony_ci put_task_struct(start); 40278c2ecf20Sopenharmony_ci return pos; 40288c2ecf20Sopenharmony_ci} 40298c2ecf20Sopenharmony_ci 40308c2ecf20Sopenharmony_ci/* for the /proc/TGID/task/ directories */ 40318c2ecf20Sopenharmony_cistatic int proc_task_readdir(struct file *file, struct dir_context *ctx) 40328c2ecf20Sopenharmony_ci{ 40338c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 40348c2ecf20Sopenharmony_ci struct task_struct *task; 40358c2ecf20Sopenharmony_ci struct pid_namespace *ns; 40368c2ecf20Sopenharmony_ci int tid; 40378c2ecf20Sopenharmony_ci 40388c2ecf20Sopenharmony_ci if (proc_inode_is_dead(inode)) 40398c2ecf20Sopenharmony_ci return -ENOENT; 40408c2ecf20Sopenharmony_ci 40418c2ecf20Sopenharmony_ci if (!dir_emit_dots(file, ctx)) 40428c2ecf20Sopenharmony_ci return 0; 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_ci /* f_version caches the tgid value that the last readdir call couldn't 40458c2ecf20Sopenharmony_ci * return. lseek aka telldir automagically resets f_version to 0. 40468c2ecf20Sopenharmony_ci */ 40478c2ecf20Sopenharmony_ci ns = proc_pid_ns(inode->i_sb); 40488c2ecf20Sopenharmony_ci tid = (int)file->f_version; 40498c2ecf20Sopenharmony_ci file->f_version = 0; 40508c2ecf20Sopenharmony_ci for (task = first_tid(proc_pid(inode), tid, ctx->pos - 2, ns); 40518c2ecf20Sopenharmony_ci task; 40528c2ecf20Sopenharmony_ci task = next_tid(task), ctx->pos++) { 40538c2ecf20Sopenharmony_ci char name[10 + 1]; 40548c2ecf20Sopenharmony_ci unsigned int len; 40558c2ecf20Sopenharmony_ci tid = task_pid_nr_ns(task, ns); 40568c2ecf20Sopenharmony_ci len = snprintf(name, sizeof(name), "%u", tid); 40578c2ecf20Sopenharmony_ci if (!proc_fill_cache(file, ctx, name, len, 40588c2ecf20Sopenharmony_ci proc_task_instantiate, task, NULL)) { 40598c2ecf20Sopenharmony_ci /* returning this tgid failed, save it as the first 40608c2ecf20Sopenharmony_ci * pid for the next readir call */ 40618c2ecf20Sopenharmony_ci file->f_version = (u64)tid; 40628c2ecf20Sopenharmony_ci put_task_struct(task); 40638c2ecf20Sopenharmony_ci break; 40648c2ecf20Sopenharmony_ci } 40658c2ecf20Sopenharmony_ci } 40668c2ecf20Sopenharmony_ci 40678c2ecf20Sopenharmony_ci return 0; 40688c2ecf20Sopenharmony_ci} 40698c2ecf20Sopenharmony_ci 40708c2ecf20Sopenharmony_cistatic int proc_task_getattr(const struct path *path, struct kstat *stat, 40718c2ecf20Sopenharmony_ci u32 request_mask, unsigned int query_flags) 40728c2ecf20Sopenharmony_ci{ 40738c2ecf20Sopenharmony_ci struct inode *inode = d_inode(path->dentry); 40748c2ecf20Sopenharmony_ci struct task_struct *p = get_proc_task(inode); 40758c2ecf20Sopenharmony_ci generic_fillattr(inode, stat); 40768c2ecf20Sopenharmony_ci 40778c2ecf20Sopenharmony_ci if (p) { 40788c2ecf20Sopenharmony_ci stat->nlink += get_nr_threads(p); 40798c2ecf20Sopenharmony_ci put_task_struct(p); 40808c2ecf20Sopenharmony_ci } 40818c2ecf20Sopenharmony_ci 40828c2ecf20Sopenharmony_ci return 0; 40838c2ecf20Sopenharmony_ci} 40848c2ecf20Sopenharmony_ci 40858c2ecf20Sopenharmony_cistatic const struct inode_operations proc_task_inode_operations = { 40868c2ecf20Sopenharmony_ci .lookup = proc_task_lookup, 40878c2ecf20Sopenharmony_ci .getattr = proc_task_getattr, 40888c2ecf20Sopenharmony_ci .setattr = proc_setattr, 40898c2ecf20Sopenharmony_ci .permission = proc_pid_permission, 40908c2ecf20Sopenharmony_ci}; 40918c2ecf20Sopenharmony_ci 40928c2ecf20Sopenharmony_cistatic const struct file_operations proc_task_operations = { 40938c2ecf20Sopenharmony_ci .read = generic_read_dir, 40948c2ecf20Sopenharmony_ci .iterate_shared = proc_task_readdir, 40958c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 40968c2ecf20Sopenharmony_ci}; 40978c2ecf20Sopenharmony_ci 40988c2ecf20Sopenharmony_civoid __init set_proc_pid_nlink(void) 40998c2ecf20Sopenharmony_ci{ 41008c2ecf20Sopenharmony_ci nlink_tid = pid_entry_nlink(tid_base_stuff, ARRAY_SIZE(tid_base_stuff)); 41018c2ecf20Sopenharmony_ci nlink_tgid = pid_entry_nlink(tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff)); 41028c2ecf20Sopenharmony_ci} 4103