162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci/* Internal procfs definitions 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. 562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/proc_fs.h> 962306a36Sopenharmony_ci#include <linux/proc_ns.h> 1062306a36Sopenharmony_ci#include <linux/refcount.h> 1162306a36Sopenharmony_ci#include <linux/spinlock.h> 1262306a36Sopenharmony_ci#include <linux/atomic.h> 1362306a36Sopenharmony_ci#include <linux/binfmts.h> 1462306a36Sopenharmony_ci#include <linux/sched/coredump.h> 1562306a36Sopenharmony_ci#include <linux/sched/task.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct ctl_table_header; 1862306a36Sopenharmony_cistruct mempolicy; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* 2162306a36Sopenharmony_ci * This is not completely implemented yet. The idea is to 2262306a36Sopenharmony_ci * create an in-memory tree (like the actual /proc filesystem 2362306a36Sopenharmony_ci * tree) of these proc_dir_entries, so that we can dynamically 2462306a36Sopenharmony_ci * add new files to /proc. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * parent/subdir are used for the directory structure (every /proc file has a 2762306a36Sopenharmony_ci * parent, but "subdir" is empty for all non-directory entries). 2862306a36Sopenharmony_ci * subdir_node is used to build the rb tree "subdir" of the parent. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_cistruct proc_dir_entry { 3162306a36Sopenharmony_ci /* 3262306a36Sopenharmony_ci * number of callers into module in progress; 3362306a36Sopenharmony_ci * negative -> it's going away RSN 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci atomic_t in_use; 3662306a36Sopenharmony_ci refcount_t refcnt; 3762306a36Sopenharmony_ci struct list_head pde_openers; /* who did ->open, but not ->release */ 3862306a36Sopenharmony_ci /* protects ->pde_openers and all struct pde_opener instances */ 3962306a36Sopenharmony_ci spinlock_t pde_unload_lock; 4062306a36Sopenharmony_ci struct completion *pde_unload_completion; 4162306a36Sopenharmony_ci const struct inode_operations *proc_iops; 4262306a36Sopenharmony_ci union { 4362306a36Sopenharmony_ci const struct proc_ops *proc_ops; 4462306a36Sopenharmony_ci const struct file_operations *proc_dir_ops; 4562306a36Sopenharmony_ci }; 4662306a36Sopenharmony_ci const struct dentry_operations *proc_dops; 4762306a36Sopenharmony_ci union { 4862306a36Sopenharmony_ci const struct seq_operations *seq_ops; 4962306a36Sopenharmony_ci int (*single_show)(struct seq_file *, void *); 5062306a36Sopenharmony_ci }; 5162306a36Sopenharmony_ci proc_write_t write; 5262306a36Sopenharmony_ci void *data; 5362306a36Sopenharmony_ci unsigned int state_size; 5462306a36Sopenharmony_ci unsigned int low_ino; 5562306a36Sopenharmony_ci nlink_t nlink; 5662306a36Sopenharmony_ci kuid_t uid; 5762306a36Sopenharmony_ci kgid_t gid; 5862306a36Sopenharmony_ci loff_t size; 5962306a36Sopenharmony_ci struct proc_dir_entry *parent; 6062306a36Sopenharmony_ci struct rb_root subdir; 6162306a36Sopenharmony_ci struct rb_node subdir_node; 6262306a36Sopenharmony_ci char *name; 6362306a36Sopenharmony_ci umode_t mode; 6462306a36Sopenharmony_ci u8 flags; 6562306a36Sopenharmony_ci u8 namelen; 6662306a36Sopenharmony_ci char inline_name[]; 6762306a36Sopenharmony_ci} __randomize_layout; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define SIZEOF_PDE ( \ 7062306a36Sopenharmony_ci sizeof(struct proc_dir_entry) < 128 ? 128 : \ 7162306a36Sopenharmony_ci sizeof(struct proc_dir_entry) < 192 ? 192 : \ 7262306a36Sopenharmony_ci sizeof(struct proc_dir_entry) < 256 ? 256 : \ 7362306a36Sopenharmony_ci sizeof(struct proc_dir_entry) < 512 ? 512 : \ 7462306a36Sopenharmony_ci 0) 7562306a36Sopenharmony_ci#define SIZEOF_PDE_INLINE_NAME (SIZEOF_PDE - sizeof(struct proc_dir_entry)) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic inline bool pde_is_permanent(const struct proc_dir_entry *pde) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci return pde->flags & PROC_ENTRY_PERMANENT; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic inline void pde_make_permanent(struct proc_dir_entry *pde) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci pde->flags |= PROC_ENTRY_PERMANENT; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ciextern struct kmem_cache *proc_dir_entry_cache; 8862306a36Sopenharmony_civoid pde_free(struct proc_dir_entry *pde); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ciunion proc_op { 9162306a36Sopenharmony_ci int (*proc_get_link)(struct dentry *, struct path *); 9262306a36Sopenharmony_ci int (*proc_show)(struct seq_file *m, 9362306a36Sopenharmony_ci struct pid_namespace *ns, struct pid *pid, 9462306a36Sopenharmony_ci struct task_struct *task); 9562306a36Sopenharmony_ci const char *lsm; 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistruct proc_inode { 9962306a36Sopenharmony_ci struct pid *pid; 10062306a36Sopenharmony_ci unsigned int fd; 10162306a36Sopenharmony_ci union proc_op op; 10262306a36Sopenharmony_ci struct proc_dir_entry *pde; 10362306a36Sopenharmony_ci struct ctl_table_header *sysctl; 10462306a36Sopenharmony_ci struct ctl_table *sysctl_entry; 10562306a36Sopenharmony_ci struct hlist_node sibling_inodes; 10662306a36Sopenharmony_ci const struct proc_ns_operations *ns_ops; 10762306a36Sopenharmony_ci struct inode vfs_inode; 10862306a36Sopenharmony_ci} __randomize_layout; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/* 11162306a36Sopenharmony_ci * General functions 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_cistatic inline struct proc_inode *PROC_I(const struct inode *inode) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci return container_of(inode, struct proc_inode, vfs_inode); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic inline struct proc_dir_entry *PDE(const struct inode *inode) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci return PROC_I(inode)->pde; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic inline struct pid *proc_pid(const struct inode *inode) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci return PROC_I(inode)->pid; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic inline struct task_struct *get_proc_task(const struct inode *inode) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci return get_pid_task(proc_pid(inode), PIDTYPE_PID); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_civoid task_dump_owner(struct task_struct *task, umode_t mode, 13462306a36Sopenharmony_ci kuid_t *ruid, kgid_t *rgid); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ciunsigned name_to_int(const struct qstr *qstr); 13762306a36Sopenharmony_ci/* 13862306a36Sopenharmony_ci * Offset of the first process in the /proc root directory.. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci#define FIRST_PROCESS_ENTRY 256 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* Worst case buffer size needed for holding an integer. */ 14362306a36Sopenharmony_ci#define PROC_NUMBUF 13 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* 14662306a36Sopenharmony_ci * array.c 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ciextern const struct file_operations proc_tid_children_operations; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ciextern void proc_task_name(struct seq_file *m, struct task_struct *p, 15162306a36Sopenharmony_ci bool escape); 15262306a36Sopenharmony_ciextern int proc_tid_stat(struct seq_file *, struct pid_namespace *, 15362306a36Sopenharmony_ci struct pid *, struct task_struct *); 15462306a36Sopenharmony_ciextern int proc_tgid_stat(struct seq_file *, struct pid_namespace *, 15562306a36Sopenharmony_ci struct pid *, struct task_struct *); 15662306a36Sopenharmony_ciextern int proc_pid_status(struct seq_file *, struct pid_namespace *, 15762306a36Sopenharmony_ci struct pid *, struct task_struct *); 15862306a36Sopenharmony_ciextern int proc_pid_statm(struct seq_file *, struct pid_namespace *, 15962306a36Sopenharmony_ci struct pid *, struct task_struct *); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* 16262306a36Sopenharmony_ci * base.c 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ciextern const struct dentry_operations pid_dentry_operations; 16562306a36Sopenharmony_ciextern int pid_getattr(struct mnt_idmap *, const struct path *, 16662306a36Sopenharmony_ci struct kstat *, u32, unsigned int); 16762306a36Sopenharmony_ciextern int proc_setattr(struct mnt_idmap *, struct dentry *, 16862306a36Sopenharmony_ci struct iattr *); 16962306a36Sopenharmony_ciextern void proc_pid_evict_inode(struct proc_inode *); 17062306a36Sopenharmony_ciextern struct inode *proc_pid_make_inode(struct super_block *, struct task_struct *, umode_t); 17162306a36Sopenharmony_ciextern void pid_update_inode(struct task_struct *, struct inode *); 17262306a36Sopenharmony_ciextern int pid_delete_dentry(const struct dentry *); 17362306a36Sopenharmony_ciextern int proc_pid_readdir(struct file *, struct dir_context *); 17462306a36Sopenharmony_cistruct dentry *proc_pid_lookup(struct dentry *, unsigned int); 17562306a36Sopenharmony_ciextern loff_t mem_lseek(struct file *, loff_t, int); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/* Lookups */ 17862306a36Sopenharmony_citypedef struct dentry *instantiate_t(struct dentry *, 17962306a36Sopenharmony_ci struct task_struct *, const void *); 18062306a36Sopenharmony_cibool proc_fill_cache(struct file *, struct dir_context *, const char *, unsigned int, 18162306a36Sopenharmony_ci instantiate_t, struct task_struct *, const void *); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* 18462306a36Sopenharmony_ci * generic.c 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_cistruct proc_dir_entry *proc_create_reg(const char *name, umode_t mode, 18762306a36Sopenharmony_ci struct proc_dir_entry **parent, void *data); 18862306a36Sopenharmony_cistruct proc_dir_entry *proc_register(struct proc_dir_entry *dir, 18962306a36Sopenharmony_ci struct proc_dir_entry *dp); 19062306a36Sopenharmony_ciextern struct dentry *proc_lookup(struct inode *, struct dentry *, unsigned int); 19162306a36Sopenharmony_cistruct dentry *proc_lookup_de(struct inode *, struct dentry *, struct proc_dir_entry *); 19262306a36Sopenharmony_ciextern int proc_readdir(struct file *, struct dir_context *); 19362306a36Sopenharmony_ciint proc_readdir_de(struct file *, struct dir_context *, struct proc_dir_entry *); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic inline void pde_get(struct proc_dir_entry *pde) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci refcount_inc(&pde->refcnt); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ciextern void pde_put(struct proc_dir_entry *); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic inline bool is_empty_pde(const struct proc_dir_entry *pde) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci return S_ISDIR(pde->mode) && !pde->proc_iops; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ciextern ssize_t proc_simple_write(struct file *, const char __user *, size_t, loff_t *); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci/* 20862306a36Sopenharmony_ci * inode.c 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_cistruct pde_opener { 21162306a36Sopenharmony_ci struct list_head lh; 21262306a36Sopenharmony_ci struct file *file; 21362306a36Sopenharmony_ci bool closing; 21462306a36Sopenharmony_ci struct completion *c; 21562306a36Sopenharmony_ci} __randomize_layout; 21662306a36Sopenharmony_ciextern const struct inode_operations proc_link_inode_operations; 21762306a36Sopenharmony_ciextern const struct inode_operations proc_pid_link_inode_operations; 21862306a36Sopenharmony_ciextern const struct super_operations proc_sops; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_civoid proc_init_kmemcache(void); 22162306a36Sopenharmony_civoid proc_invalidate_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock); 22262306a36Sopenharmony_civoid set_proc_pid_nlink(void); 22362306a36Sopenharmony_ciextern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); 22462306a36Sopenharmony_ciextern void proc_entry_rundown(struct proc_dir_entry *); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci/* 22762306a36Sopenharmony_ci * proc_namespaces.c 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_ciextern const struct inode_operations proc_ns_dir_inode_operations; 23062306a36Sopenharmony_ciextern const struct file_operations proc_ns_dir_operations; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci/* 23362306a36Sopenharmony_ci * proc_net.c 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_ciextern const struct file_operations proc_net_operations; 23662306a36Sopenharmony_ciextern const struct inode_operations proc_net_inode_operations; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci#ifdef CONFIG_NET 23962306a36Sopenharmony_ciextern int proc_net_init(void); 24062306a36Sopenharmony_ci#else 24162306a36Sopenharmony_cistatic inline int proc_net_init(void) { return 0; } 24262306a36Sopenharmony_ci#endif 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci/* 24562306a36Sopenharmony_ci * proc_self.c 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ciextern int proc_setup_self(struct super_block *); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci/* 25062306a36Sopenharmony_ci * proc_thread_self.c 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_ciextern int proc_setup_thread_self(struct super_block *); 25362306a36Sopenharmony_ciextern void proc_thread_self_init(void); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci/* 25662306a36Sopenharmony_ci * proc_sysctl.c 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci#ifdef CONFIG_PROC_SYSCTL 25962306a36Sopenharmony_ciextern int proc_sys_init(void); 26062306a36Sopenharmony_ciextern void proc_sys_evict_inode(struct inode *inode, 26162306a36Sopenharmony_ci struct ctl_table_header *head); 26262306a36Sopenharmony_ci#else 26362306a36Sopenharmony_cistatic inline void proc_sys_init(void) { } 26462306a36Sopenharmony_cistatic inline void proc_sys_evict_inode(struct inode *inode, 26562306a36Sopenharmony_ci struct ctl_table_header *head) { } 26662306a36Sopenharmony_ci#endif 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/* 26962306a36Sopenharmony_ci * proc_tty.c 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci#ifdef CONFIG_TTY 27262306a36Sopenharmony_ciextern void proc_tty_init(void); 27362306a36Sopenharmony_ci#else 27462306a36Sopenharmony_cistatic inline void proc_tty_init(void) {} 27562306a36Sopenharmony_ci#endif 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci/* 27862306a36Sopenharmony_ci * root.c 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ciextern struct proc_dir_entry proc_root; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ciextern void proc_self_init(void); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/* 28562306a36Sopenharmony_ci * task_[no]mmu.c 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_cistruct mem_size_stats; 28862306a36Sopenharmony_cistruct proc_maps_private { 28962306a36Sopenharmony_ci struct inode *inode; 29062306a36Sopenharmony_ci struct task_struct *task; 29162306a36Sopenharmony_ci struct mm_struct *mm; 29262306a36Sopenharmony_ci struct vma_iterator iter; 29362306a36Sopenharmony_ci#ifdef CONFIG_NUMA 29462306a36Sopenharmony_ci struct mempolicy *task_mempolicy; 29562306a36Sopenharmony_ci#endif 29662306a36Sopenharmony_ci} __randomize_layout; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistruct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ciextern const struct file_operations proc_pid_maps_operations; 30162306a36Sopenharmony_ciextern const struct file_operations proc_pid_numa_maps_operations; 30262306a36Sopenharmony_ciextern const struct file_operations proc_pid_smaps_operations; 30362306a36Sopenharmony_ciextern const struct file_operations proc_pid_smaps_rollup_operations; 30462306a36Sopenharmony_ciextern const struct file_operations proc_clear_refs_operations; 30562306a36Sopenharmony_ciextern const struct file_operations proc_pagemap_operations; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ciextern unsigned long task_vsize(struct mm_struct *); 30862306a36Sopenharmony_ciextern unsigned long task_statm(struct mm_struct *, 30962306a36Sopenharmony_ci unsigned long *, unsigned long *, 31062306a36Sopenharmony_ci unsigned long *, unsigned long *); 31162306a36Sopenharmony_ciextern void task_mem(struct seq_file *, struct mm_struct *); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ciextern const struct dentry_operations proc_net_dentry_ops; 31462306a36Sopenharmony_cistatic inline void pde_force_lookup(struct proc_dir_entry *pde) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci /* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */ 31762306a36Sopenharmony_ci pde->proc_dops = &proc_net_dentry_ops; 31862306a36Sopenharmony_ci} 319