Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219// SPDX-License-Identifier: GPL-2.0#include <linux/anon_inodes.h>#include <linux/compat.h>#include <linux/exportfs.h>#include <linux/file.h>#include <linux/fs.h>#include <linux/cgroup.h>#include <linux/magic.h>#include <linux/mount.h>#include <linux/pid.h>#include <linux/pidfs.h>#include <linux/sched/signal.h>#include <linux/signal.h>#include <linux/pid_namespace.h>#include <linux/poll.h>#include <linux/proc_fs.h>#include <linux/proc_ns.h>#include <linux/pseudo_fs.h>#include <linux/ptrace.h>#include <linux/seq_file.h>#include <uapi/linux/pidfd.h>#include <linux/ipc_namespace.h>#include <linux/time_namespace.h>#include <linux/utsname.h>#include <net/net_namespace.h>#include <linux/coredump.h>#include <linux/rhashtable.h>#include <linux/llist.h>#include <linux/xattr.h>#include <linux/cookie.h>
#include "internal.h"#include "mount.h"
#define PIDFS_PID_DEAD ERR_PTR(-ESRCH)
static struct kmem_cache *pidfs_attr_cachep __ro_after_init;
static struct path pidfs_root_path = {};
static struct simple_xattr_cache pidfs_xa_cache;
void pidfs_get_root(struct path *path){ *path = pidfs_root_path; path_get(path);}
enum pidfs_attr_mask_bits { PIDFS_ATTR_BIT_EXIT = 0, PIDFS_ATTR_BIT_COREDUMP = 1,};
struct pidfs_anon_attr { unsigned long attr_mask; struct /* exit info */ { __u64 cgroupid; __s32 exit_code; }; __u32 coredump_mask; __u32 coredump_signal; __u32 coredump_code;};
static struct rhashtable pidfs_ino_ht;
static const struct rhashtable_params pidfs_ino_ht_params = { .key_offset = offsetof(struct pid, ino), .key_len = sizeof(u64), .head_offset = offsetof(struct pid, pidfs_hash), .automatic_shrinking = true,};
/* * inode number handling * * On 64 bit nothing special happens. The 64bit number assigned * to struct pid is the inode number. * * On 32 bit the 64 bit number assigned to struct pid is split * into two 32 bit numbers. The lower 32 bits are used as the * inode number and the upper 32 bits are used as the inode * generation number. * * On 32 bit pidfs_ino() will return the lower 32 bit. When * pidfs_ino() returns zero a wrap around happened. When a * wraparound happens the 64 bit number will be incremented by 1 * so inode numbering starts at 1 again. * * On 64 bit comparing two pidfds is as simple as comparing * inode numbers. * * When a wraparound happens on 32 bit multiple pidfds with the * same inode number are likely to exist (This isn't a problem * since before pidfs pidfds used the anonymous inode meaning * all pidfds had the same inode number.). Userspace can * reconstruct the 64 bit identifier by retrieving both the * inode number and the inode generation number to compare or * use file handles. */struct pidfs_attr { struct list_head xattrs; union { struct pidfs_anon_attr; struct llist_node pidfs_llist; };};
#if BITS_PER_LONG == 32
static DEFINE_SPINLOCK(pidfs_ino_lock);static u64 pidfs_ino_nr = 1;
static inline unsigned long pidfs_ino(u64 ino){ return lower_32_bits(ino);}
/* On 32 bit the generation number are the upper 32 bits. */static inline u32 pidfs_gen(u64 ino){ return upper_32_bits(ino);}
static inline u64 pidfs_alloc_ino(void){ u64 ino;
spin_lock(&pidfs_ino_lock); if (pidfs_ino(pidfs_ino_nr) == 0) pidfs_ino_nr++; ino = pidfs_ino_nr++; spin_unlock(&pidfs_ino_lock); return ino;}
#else
/* On 64 bit simply return ino. */static inline unsigned long pidfs_ino(u64 ino){ return ino;}
/* On 64 bit the generation number is 0. */static inline u32 pidfs_gen(u64 ino){ return 0;}
DEFINE_COOKIE(pidfs_ino_cookie);
static u64 pidfs_alloc_ino(void){ u64 ino;
preempt_disable(); ino = gen_cookie_next(&pidfs_ino_cookie); preempt_enable();
VFS_WARN_ON_ONCE(ino < 1); return ino;}
#endif
void pidfs_prepare_pid(struct pid *pid){ pid->stashed = NULL; pid->attr = NULL; pid->ino = 0;}
int pidfs_add_pid(struct pid *pid){ int ret;
pid->ino = pidfs_alloc_ino(); ret = rhashtable_insert_fast(&pidfs_ino_ht, &pid->pidfs_hash, pidfs_ino_ht_params); if (unlikely(ret)) pid->ino = 0; return ret;}
void pidfs_remove_pid(struct pid *pid){ if (likely(pid->ino)) rhashtable_remove_fast(&pidfs_ino_ht, &pid->pidfs_hash, pidfs_ino_ht_params);}
static LLIST_HEAD(pidfs_free_list);
static void pidfs_free_attr_work(struct work_struct *work){ struct pidfs_attr *attr, *next; struct llist_node *head;
head = llist_del_all(&pidfs_free_list); llist_for_each_entry_safe(attr, next, head, pidfs_llist) { simple_xattrs_free(&pidfs_xa_cache, &attr->xattrs, NULL); kfree(attr); }}
static DECLARE_WORK(pidfs_free_work, pidfs_free_attr_work);
void pidfs_free_pid(struct pid *pid){ struct pidfs_attr *attr = pid->attr;
/* * Any dentry must've been wiped from the pid by now. * Otherwise there's a reference count bug. */ VFS_WARN_ON_ONCE(pid->stashed);
/* * This if an error occurred during e.g., task creation that * causes us to never go through the exit path. */ if (unlikely(!attr)) return;
/* This never had a pidfd created. */ if (IS_ERR(attr)) return;
if (likely(list_empty(&attr->xattrs))) kfree(attr); else if (llist_add(&attr->pidfs_llist, &pidfs_free_list)) schedule_work(&pidfs_free_work);}
#ifdef CONFIG_PROC_FS/** * pidfd_show_fdinfo - print information about a pidfd * @m: proc fdinfo file * @f: file referencing a pidfd * * Pid: * This function will print the pid that a given pidfd refers to in the * pid namespace of the procfs instance. * If the pid namespace of the process is not a descendant of the pid * namespace of the procfs instance 0 will be shown as its pid. This is * similar to calling getppid() on a process whose parent is outside of * its pid namespace. * * NSpid: * If pid namespaces are supported then this function will also print * the pid of a given pidfd refers to for all descendant pid namespaces * starting from the current pid namespace of the instance, i.e. the * Pid field and the first entry in the NSpid field will be identical. * If the pid namespace of the process is not a descendant of the pid * namespace of the procfs instance 0 will be shown as its first NSpid * entry and no others will be shown. * Note that this differs from the Pid and NSpid fields in * /proc/<pid>/status where Pid and NSpid are always shown relative to * the pid namespace of the procfs instance. The difference becomes * obvious when sending around a pidfd between pid namespaces from a * different branch of the tree, i.e. where no ancestral relation is * present between the pid namespaces: * - create two new pid namespaces ns1 and ns2 in the initial pid * namespace (also take care to create new mount namespaces in the * new pid namespace and mount procfs) * - create a process with a pidfd in ns1 * - send pidfd from ns1 to ns2 * - read /proc/self/fdinfo/<pidfd> and observe that both Pid and NSpid * have exactly one entry, which is 0 */static void pidfd_show_fdinfo(struct seq_file *m, struct file *f){ struct pid *pid = pidfd_pid(f); struct pid_namespace *ns; pid_t nr = -1;
if (likely(pid_has_task(pid, PIDTYPE_PID))) { ns = proc_pid_ns(file_inode(m->file)->i_sb); nr = pid_nr_ns(pid, ns); }
seq_put_decimal_ll(m, "Pid:\t", nr);
#ifdef CONFIG_PID_NS seq_put_decimal_ll(m, "\nNSpid:\t", nr); if (nr > 0) { int i;
/* If nr is non-zero it means that 'pid' is valid and that * ns, i.e. the pid namespace associated with the procfs * instance, is in the pid namespace hierarchy of pid. * Start at one below the already printed level. */ for (i = ns->level + 1; i <= pid->level; i++) seq_put_decimal_ll(m, "\t", pid->numbers[i].nr); }#endif seq_putc(m, '\n');}#endif
/* * Poll support for process exit notification. */static __poll_t pidfd_poll(struct file *file, struct poll_table_struct *pts){ struct pid *pid = pidfd_pid(file); struct task_struct *task; __poll_t poll_flags = 0;
poll_wait(file, &pid->wait_pidfd, pts); /* * Don't wake waiters if the thread-group leader exited * prematurely. They either get notified when the last subthread * exits or not at all if one of the remaining subthreads execs * and assumes the struct pid of the old thread-group leader. */ guard(rcu)(); task = pid_task(pid, PIDTYPE_PID); if (!task) poll_flags = EPOLLIN | EPOLLRDNORM | EPOLLHUP; else if (task->exit_state && !delay_group_leader(task)) poll_flags = EPOLLIN | EPOLLRDNORM;
return poll_flags;}
static inline bool pid_in_current_pidns(const struct pid *pid){ const struct pid_namespace *ns = task_active_pid_ns(current);
if (ns->level <= pid->level) return pid->numbers[ns->level].ns == ns;
return false;}
static __u32 pidfs_coredump_mask(enum task_dumpable dumpable){ switch (dumpable) { case TASK_DUMPABLE_OWNER: return PIDFD_COREDUMP_USER; case TASK_DUMPABLE_ROOT: return PIDFD_COREDUMP_ROOT; case TASK_DUMPABLE_OFF: return PIDFD_COREDUMP_SKIP; default: WARN_ON_ONCE(true); }
return 0;}
/* This must be updated whenever a new flag is added */#define PIDFD_INFO_SUPPORTED (PIDFD_INFO_PID | \ PIDFD_INFO_CREDS | \ PIDFD_INFO_CGROUPID | \ PIDFD_INFO_EXIT | \ PIDFD_INFO_COREDUMP | \ PIDFD_INFO_SUPPORTED_MASK | \ PIDFD_INFO_COREDUMP_SIGNAL | \ PIDFD_INFO_COREDUMP_CODE)
static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg){ struct pidfd_info __user *uinfo = (struct pidfd_info __user *)arg; struct task_struct *task __free(put_task) = NULL; struct pid *pid = pidfd_pid(file); size_t usize = _IOC_SIZE(cmd); struct pidfd_info kinfo = {}; struct user_namespace *user_ns; struct pidfs_attr *attr; const struct cred *c; __u64 mask;
BUILD_BUG_ON(sizeof(struct pidfd_info) != PIDFD_INFO_SIZE_VER3);
if (!uinfo) return -EINVAL; if (usize < PIDFD_INFO_SIZE_VER0) return -EINVAL; /* First version, no smaller struct possible */
if (copy_from_user(&mask, &uinfo->mask, sizeof(mask))) return -EFAULT;
/* * Restrict information retrieval to tasks within the caller's pid * namespace hierarchy. */ if (!pid_in_current_pidns(pid)) return -EREMOTE;
attr = READ_ONCE(pid->attr); if (mask & PIDFD_INFO_EXIT) { if (test_bit(PIDFS_ATTR_BIT_EXIT, &attr->attr_mask)) { smp_rmb(); kinfo.mask |= PIDFD_INFO_EXIT;#ifdef CONFIG_CGROUPS kinfo.cgroupid = attr->cgroupid; kinfo.mask |= PIDFD_INFO_CGROUPID;#endif kinfo.exit_code = attr->exit_code; } }
if (mask & PIDFD_INFO_COREDUMP) { if (test_bit(PIDFS_ATTR_BIT_COREDUMP, &attr->attr_mask)) { smp_rmb(); kinfo.mask |= PIDFD_INFO_COREDUMP | PIDFD_INFO_COREDUMP_SIGNAL | PIDFD_INFO_COREDUMP_CODE; kinfo.coredump_mask = attr->coredump_mask; kinfo.coredump_signal = attr->coredump_signal; kinfo.coredump_code = attr->coredump_code; } }
task = get_pid_task(pid, PIDTYPE_PID); if (!task) { /* * If the task has already been reaped, only exit * information is available */ if (!(mask & PIDFD_INFO_EXIT)) return -ESRCH;
goto copy_out; }
c = get_task_cred(task); if (!c) return -ESRCH;
if ((mask & PIDFD_INFO_COREDUMP) && !kinfo.coredump_mask) { kinfo.coredump_mask = pidfs_coredump_mask(task_exec_state_get_dumpable(task)); kinfo.mask |= PIDFD_INFO_COREDUMP; /* No coredump actually took place, so no coredump signal. */ }
/* Unconditionally return identifiers and credentials, the rest only on request */
user_ns = current_user_ns(); kinfo.ruid = from_kuid_munged(user_ns, c->uid); kinfo.rgid = from_kgid_munged(user_ns, c->gid); kinfo.euid = from_kuid_munged(user_ns, c->euid); kinfo.egid = from_kgid_munged(user_ns, c->egid); kinfo.suid = from_kuid_munged(user_ns, c->suid); kinfo.sgid = from_kgid_munged(user_ns, c->sgid); kinfo.fsuid = from_kuid_munged(user_ns, c->fsuid); kinfo.fsgid = from_kgid_munged(user_ns, c->fsgid); kinfo.mask |= PIDFD_INFO_CREDS; put_cred(c);
#ifdef CONFIG_CGROUPS if (!kinfo.cgroupid) { struct cgroup *cgrp;
rcu_read_lock(); cgrp = task_dfl_cgroup(task); kinfo.cgroupid = cgroup_id(cgrp); kinfo.mask |= PIDFD_INFO_CGROUPID; rcu_read_unlock(); }#endif
/* * Copy pid/tgid last, to reduce the chances the information might be * stale. Note that it is not possible to ensure it will be valid as the * task might return as soon as the copy_to_user finishes, but that's ok * and userspace expects that might happen and can act accordingly, so * this is just best-effort. What we can do however is checking that all * the fields are set correctly, or return ESRCH to avoid providing * incomplete information. */
kinfo.ppid = task_ppid_vnr(task); kinfo.tgid = task_tgid_vnr(task); kinfo.pid = task_pid_vnr(task); kinfo.mask |= PIDFD_INFO_PID;
if (kinfo.pid == 0 || kinfo.tgid == 0) return -ESRCH;
copy_out: if (mask & PIDFD_INFO_SUPPORTED_MASK) { kinfo.mask |= PIDFD_INFO_SUPPORTED_MASK; kinfo.supported_mask = PIDFD_INFO_SUPPORTED; }
/* Are there bits in the return mask not present in PIDFD_INFO_SUPPORTED? */ WARN_ON_ONCE(~PIDFD_INFO_SUPPORTED & kinfo.mask); /* * If userspace and the kernel have the same struct size it can just * be copied. If userspace provides an older struct, only the bits that * userspace knows about will be copied. If userspace provides a new * struct, only the bits that the kernel knows about will be copied. */ return copy_struct_to_user(uinfo, usize, &kinfo, sizeof(kinfo), NULL);}
static bool pidfs_ioctl_valid(unsigned int cmd){ switch (cmd) { case FS_IOC_GETVERSION: case PIDFD_GET_CGROUP_NAMESPACE: case PIDFD_GET_IPC_NAMESPACE: case PIDFD_GET_MNT_NAMESPACE: case PIDFD_GET_NET_NAMESPACE: case PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE: case PIDFD_GET_TIME_NAMESPACE: case PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE: case PIDFD_GET_UTS_NAMESPACE: case PIDFD_GET_USER_NAMESPACE: case PIDFD_GET_PID_NAMESPACE: return true; }
/* Extensible ioctls require some more careful checks. */ switch (_IOC_NR(cmd)) { case _IOC_NR(PIDFD_GET_INFO): /* * Try to prevent performing a pidfd ioctl when someone * erronously mistook the file descriptor for a pidfd. * This is not perfect but will catch most cases. */ return extensible_ioctl_valid(cmd, PIDFD_GET_INFO, PIDFD_INFO_SIZE_VER0); }
return false;}
static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ struct task_struct *task __free(put_task) = NULL; struct nsproxy *nsp __free(put_nsproxy) = NULL; struct ns_common *ns_common = NULL; int error;
if (!pidfs_ioctl_valid(cmd)) return -ENOIOCTLCMD;
if (cmd == FS_IOC_GETVERSION) { if (!arg) return -EINVAL;
__u32 __user *argp = (__u32 __user *)arg; return put_user(file_inode(file)->i_generation, argp); }
/* Extensible IOCTL that does not open namespace FDs, take a shortcut */ if (_IOC_NR(cmd) == _IOC_NR(PIDFD_GET_INFO)) return pidfd_info(file, cmd, arg);
task = get_pid_task(pidfd_pid(file), PIDTYPE_PID); if (!task) return -ESRCH;
if (arg) return -EINVAL;
/* * We're trying to open a file descriptor to the namespace so perform a * filesystem cred ptrace check. Hold @task's exec_update_lock for the * duration of the ptrace check and the namespace lookup so that the * credentials used for the access decision match those of @task at the * time its namespace is read, preventing a concurrent execve() from * swapping the task's credentials in between the check and the use. We * mirror nsfs behavior. */ error = down_read_killable(&task->signal->exec_update_lock); if (error) return error;
if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) { error = -EACCES; goto out_unlock; }
scoped_guard(task_lock, task) { nsp = task->nsproxy; if (nsp) get_nsproxy(nsp); } if (!nsp) { error = -ESRCH; /* just pretend it didn't exist */ goto out_unlock; }
switch (cmd) { /* Namespaces that hang of nsproxy. */ case PIDFD_GET_CGROUP_NAMESPACE:#ifdef CONFIG_CGROUPS if (!ns_ref_get(nsp->cgroup_ns)) break; ns_common = to_ns_common(nsp->cgroup_ns);#endif break; case PIDFD_GET_IPC_NAMESPACE:#ifdef CONFIG_IPC_NS if (!ns_ref_get(nsp->ipc_ns)) break; ns_common = to_ns_common(nsp->ipc_ns);#endif break; case PIDFD_GET_MNT_NAMESPACE: if (!ns_ref_get(nsp->mnt_ns)) break; ns_common = to_ns_common(nsp->mnt_ns); break; case PIDFD_GET_NET_NAMESPACE:#ifdef CONFIG_NET_NS if (!ns_ref_get(nsp->net_ns)) break; ns_common = to_ns_common(nsp->net_ns);#endif break; case PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE:#ifdef CONFIG_PID_NS if (!ns_ref_get(nsp->pid_ns_for_children)) break; ns_common = to_ns_common(nsp->pid_ns_for_children);#endif break; case PIDFD_GET_TIME_NAMESPACE:#ifdef CONFIG_TIME_NS if (!ns_ref_get(nsp->time_ns)) break; ns_common = to_ns_common(nsp->time_ns);#endif break; case PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE:#ifdef CONFIG_TIME_NS if (!ns_ref_get(nsp->time_ns_for_children)) break; ns_common = to_ns_common(nsp->time_ns_for_children);#endif break; case PIDFD_GET_UTS_NAMESPACE:#ifdef CONFIG_UTS_NS if (!ns_ref_get(nsp->uts_ns)) break; ns_common = to_ns_common(nsp->uts_ns);#endif break; /* Namespaces that don't hang of nsproxy. */ case PIDFD_GET_USER_NAMESPACE:#ifdef CONFIG_USER_NS scoped_guard(rcu) { struct user_namespace *user_ns;
user_ns = task_cred_xxx(task, user_ns); if (ns_ref_get(user_ns)) ns_common = to_ns_common(user_ns); }#endif break; case PIDFD_GET_PID_NAMESPACE:#ifdef CONFIG_PID_NS scoped_guard(rcu) { struct pid_namespace *pid_ns;
pid_ns = task_active_pid_ns(task); if (ns_ref_get(pid_ns)) ns_common = to_ns_common(pid_ns); }#endif break; default: error = -ENOIOCTLCMD; }
if (!error && !ns_common) error = -EOPNOTSUPP;
out_unlock: up_read(&task->signal->exec_update_lock); if (error) return error;
/* open_namespace() unconditionally consumes the reference */ return open_namespace(ns_common);}
#ifdef CONFIG_COMPATstatic long pidfd_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ if (cmd == FS_IOC32_GETVERSION) cmd = FS_IOC_GETVERSION;
return pidfd_ioctl(file, cmd, (unsigned long)compat_ptr(arg));}#endif
static int pidfs_file_release(struct inode *inode, struct file *file){ struct pid *pid = inode->i_private; struct task_struct *task;
if (!(file->f_flags & PIDFD_AUTOKILL)) return 0;
guard(rcu)(); task = pid_task(pid, PIDTYPE_TGID); if (!task) return 0;
/* Not available for kthreads or user workers for now. */ if (WARN_ON_ONCE(task->flags & (PF_KTHREAD | PF_USER_WORKER))) return 0; do_send_sig_info(SIGKILL, SEND_SIG_PRIV, task, PIDTYPE_TGID); return 0;}
static const struct file_operations pidfs_file_operations = { .release = pidfs_file_release, .poll = pidfd_poll,#ifdef CONFIG_PROC_FS .show_fdinfo = pidfd_show_fdinfo,#endif .unlocked_ioctl = pidfd_ioctl,#ifdef CONFIG_COMPAT .compat_ioctl = pidfd_compat_ioctl,#endif};
struct pid *pidfd_pid(const struct file *file){ if (file->f_op != &pidfs_file_operations) return ERR_PTR(-EBADF); return file_inode(file)->i_private;}
/* * We're called from release_task(). We know there's at least one * reference to struct pid being held that won't be released until the * task has been reaped which cannot happen until we're out of * release_task(). * * If this struct pid has at least once been referred to by a pidfd then * pid->attr will be allocated. If not we mark the struct pid as dead so * anyone who is trying to register it with pidfs will fail to do so. * Otherwise we would hand out pidfs for reaped tasks without having * exit information available. * * Worst case is that we've filled in the info and the pid gets freed * right away in free_pid() when no one holds a pidfd anymore. Since * pidfs_exit() currently is placed after exit_task_work() we know that * it cannot be us aka the exiting task holding a pidfd to itself. */void pidfs_exit(struct task_struct *tsk){ struct pid *pid = task_pid(tsk); struct pidfs_attr *attr;#ifdef CONFIG_CGROUPS struct cgroup *cgrp;#endif
might_sleep();
/* Synchronize with pidfs_register_pid(). */ scoped_guard(spinlock_irq, &pid->wait_pidfd.lock) { attr = pid->attr; if (!attr) { /* * No one ever held a pidfd for this struct pid. * Mark it as dead so no one can add a pidfs * entry anymore. We're about to be reaped and * so no exit information would be available. */ pid->attr = PIDFS_PID_DEAD; return; } }
/* * If @pid->attr is set someone might still legitimately hold a * pidfd to @pid or someone might concurrently still be getting * a reference to an already stashed dentry from @pid->stashed. * So defer cleaning @pid->attr until the last reference to @pid * is put */
#ifdef CONFIG_CGROUPS rcu_read_lock(); cgrp = task_dfl_cgroup(tsk); attr->cgroupid = cgroup_id(cgrp); rcu_read_unlock();#endif attr->exit_code = tsk->exit_code;
/* Ensure that PIDFD_GET_INFO sees either all or nothing. */ smp_wmb(); set_bit(PIDFS_ATTR_BIT_EXIT, &attr->attr_mask);}
#ifdef CONFIG_COREDUMPstatic void pidfs_coredump_pid(struct pid *pid, const struct coredump_params *cprm){ struct pidfs_attr *attr;
attr = READ_ONCE(pid->attr);
VFS_WARN_ON_ONCE(!attr); VFS_WARN_ON_ONCE(attr == PIDFS_PID_DEAD);
/* Note how we were coredumped and that we coredumped. */ attr->coredump_mask = pidfs_coredump_mask(cprm->dumpable) | PIDFD_COREDUMPED; /* If coredumping is set to skip we should never end up here. */ VFS_WARN_ON_ONCE(attr->coredump_mask & PIDFD_COREDUMP_SKIP); /* Expose the signal number and code that caused the coredump. */ attr->coredump_signal = cprm->siginfo->si_signo; attr->coredump_code = cprm->siginfo->si_code; smp_wmb(); set_bit(PIDFS_ATTR_BIT_COREDUMP, &attr->attr_mask);}
void pidfs_coredump(const struct coredump_params *cprm){ /* The dumping thread's pidfd reports the coredump as well. */ for (enum pid_type type = PIDTYPE_PID; type <= pids_last(cprm->pid); type++) pidfs_coredump_pid(cprm->pid[type], cprm);}#endif
static struct vfsmount *pidfs_mnt __ro_after_init;
/* * The vfs falls back to simple_setattr() if i_op->setattr() isn't * implemented. Let's reject it completely until we have a clean * permission concept for pidfds. */static int pidfs_setattr(const struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *attr){ return anon_inode_setattr(idmap, dentry, attr);}
static int pidfs_getattr(const struct mnt_idmap *idmap, const struct path *path, struct kstat *stat, u32 request_mask, unsigned int query_flags){ return anon_inode_getattr(idmap, path, stat, request_mask, query_flags);}
static ssize_t pidfs_listxattr(struct dentry *dentry, char *buf, size_t size){ struct inode *inode = d_inode(dentry); struct pid *pid = inode->i_private;
return simple_xattr_list(inode, &pid->attr->xattrs, buf, size);}
static const struct inode_operations pidfs_inode_operations = { .getattr = pidfs_getattr, .setattr = pidfs_setattr, .listxattr = pidfs_listxattr,};
static void pidfs_evict_inode(struct inode *inode){ struct pid *pid = inode->i_private;
clear_inode(inode); put_pid(pid);}
static const struct super_operations pidfs_sops = { .drop_inode = inode_just_drop, .evict_inode = pidfs_evict_inode, .statfs = simple_statfs,};
/* * 'lsof' has knowledge of out historical anon_inode use, and expects * the pidfs dentry name to start with 'anon_inode'. */static char *pidfs_dname(struct dentry *dentry, char *buffer, int buflen){ return dynamic_dname(buffer, buflen, "anon_inode:[pidfd]");}
const struct dentry_operations pidfs_dentry_operations = { .d_dname = pidfs_dname, .d_prune = stashed_dentry_prune,};
static int pidfs_encode_fh(struct inode *inode, u32 *fh, int *max_len, struct inode *parent){ const struct pid *pid = inode->i_private;
if (*max_len < 2) { *max_len = 2; return FILEID_INVALID; }
*max_len = 2; *(u64 *)fh = pid->ino; return FILEID_KERNFS;}
/* Find a struct pid based on the inode number. */static struct pid *pidfs_ino_get_pid(u64 ino){ struct pid *pid; struct pidfs_attr *attr;
guard(rcu)(); pid = rhashtable_lookup(&pidfs_ino_ht, &ino, pidfs_ino_ht_params); if (!pid) return NULL; attr = READ_ONCE(pid->attr); if (IS_ERR_OR_NULL(attr)) return NULL; if (test_bit(PIDFS_ATTR_BIT_EXIT, &attr->attr_mask)) return NULL; /* Within our pid namespace hierarchy? */ if (pid_vnr(pid) == 0) return NULL; return get_pid(pid);}
static struct dentry *pidfs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type){ int ret; u64 pid_ino; struct path path; struct pid *pid;
if (fh_len < 2) return NULL;
switch (fh_type) { case FILEID_KERNFS: pid_ino = *(u64 *)fid; break; default: return NULL; }
pid = pidfs_ino_get_pid(pid_ino); if (!pid) return NULL;
ret = path_from_stashed(&pid->stashed, pidfs_mnt, pid, &path); if (ret < 0) return ERR_PTR(ret);
VFS_WARN_ON_ONCE(!pid->attr);
mntput(path.mnt); return path.dentry;}
static struct file *pidfs_dentry_open(const struct path *path, unsigned int flags, const struct cred *cred){ struct file *file;
/* pidfds are always O_RDWR. */ file = dentry_open(path, flags | O_RDWR, cred); /* do_dentry_open() strips O_EXCL and O_TRUNC. */ if (!IS_ERR(file)) file->f_flags |= flags & (PIDFD_THREAD | PIDFD_AUTOKILL); return file;}
/* * Make sure that we reject any nonsensical flags that users pass via * open_by_handle_at(). Note that PIDFD_THREAD is defined as O_EXCL, and * PIDFD_NONBLOCK as O_NONBLOCK. */#define VALID_FILE_HANDLE_OPEN_FLAGS \ (O_RDONLY | O_WRONLY | O_RDWR | O_NONBLOCK | O_CLOEXEC | O_EXCL)
static int pidfs_export_permission(struct handle_to_path_ctx *ctx, unsigned int oflags){ if (oflags & ~(VALID_FILE_HANDLE_OPEN_FLAGS | O_LARGEFILE)) return -EINVAL;
/* * pidfd_ino_get_pid() will verify that the struct pid is part * of the caller's pid namespace hierarchy. No further * permission checks are needed. */ return 0;}
static struct file *pidfs_export_open(const struct path *path, unsigned int oflags){ /* * Opening via file handle may never raise PIDFD_AUTOKILL. That can * only be done at task creation! */ if (WARN_ON_ONCE(oflags & PIDFD_AUTOKILL)) return ERR_PTR(-EINVAL); /* Clear O_LARGEFILE as open_by_handle_at() forces it. */ return pidfs_dentry_open(path, oflags & ~O_LARGEFILE, current_cred());}
static const struct export_operations pidfs_export_operations = { .encode_fh = pidfs_encode_fh, .fh_to_dentry = pidfs_fh_to_dentry, .open = pidfs_export_open, .permission = pidfs_export_permission,};
static int pidfs_init_inode(struct inode *inode, void *data){ const struct pid *pid = data;
inode->i_private = data; inode->i_flags |= S_PRIVATE | S_ANON_INODE; /* We allow to set xattrs. */ inode->i_flags &= ~S_IMMUTABLE; inode->i_mode |= S_IRWXU; inode->i_op = &pidfs_inode_operations; inode->i_fop = &pidfs_file_operations; inode->i_ino = pidfs_ino(pid->ino); inode->i_generation = pidfs_gen(pid->ino); return 0;}
static void pidfs_put_data(void *data){ struct pid *pid = data; put_pid(pid);}
/** * pidfs_register_pid_gfp - register a struct pid in pidfs with custom GFP * flags * @pid: pid to pin * @gfp: GFP flags for memory allocation * * Register a struct pid in pidfs with custom GFP flags. * * Return: On success zero, on error a negative error code is returned. */int pidfs_register_pid_gfp(struct pid *pid, gfp_t gfp){ struct pidfs_attr *new_attr __free(kfree) = NULL; struct pidfs_attr *attr;
might_sleep();
if (!pid) return 0;
attr = READ_ONCE(pid->attr); if (unlikely(attr == PIDFS_PID_DEAD)) return PTR_ERR(PIDFS_PID_DEAD); if (attr) return 0;
new_attr = kmem_cache_zalloc(pidfs_attr_cachep, gfp); if (!new_attr) return -ENOMEM;
INIT_LIST_HEAD_RCU(&new_attr->xattrs);
/* Synchronize with pidfs_exit(). */ guard(spinlock_irq)(&pid->wait_pidfd.lock);
attr = pid->attr; if (unlikely(attr == PIDFS_PID_DEAD)) return PTR_ERR(PIDFS_PID_DEAD); if (unlikely(attr)) return 0;
pid->attr = no_free_ptr(new_attr); return 0;}
/* Register the pids up to pid type @last of @pids in pidfs. */int __pidfs_register_pids(struct pid *const *pids, enum pid_type last){ if (WARN_ON_ONCE(last >= PIDTYPE_MAX)) return -EINVAL;
for (enum pid_type type = PIDTYPE_PID; type <= last; type++) { int ret = pidfs_register_pid(pids[type]);
if (unlikely(ret)) return ret; }
return 0;}
static struct dentry *pidfs_stash_dentry(struct dentry **stashed, struct dentry *dentry){ int ret; struct pid *pid = d_inode(dentry)->i_private;
VFS_WARN_ON_ONCE(stashed != &pid->stashed);
ret = pidfs_register_pid(pid); if (ret) return ERR_PTR(ret);
return stash_dentry(stashed, dentry);}
static const struct stashed_operations pidfs_stashed_ops = { .stash_dentry = pidfs_stash_dentry, .init_inode = pidfs_init_inode, .put_data = pidfs_put_data,};
static int pidfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused, struct inode *inode, const char *suffix, void *value, size_t size){ struct pid *pid = inode->i_private; const char *name = xattr_full_name(handler, suffix);
return simple_xattr_get(&pidfs_xa_cache, &pid->attr->xattrs, name, value, size);}
static int pidfs_xattr_set(const struct xattr_handler *handler, const struct mnt_idmap *idmap, struct dentry *unused, struct inode *inode, const char *suffix, const void *value, size_t size, int flags){ struct pid *pid = inode->i_private; const char *name = xattr_full_name(handler, suffix); struct simple_xattr *old_xattr;
/* Ensure we're the only one to set @attr->xattrs. */ WARN_ON_ONCE(!inode_is_locked(inode));
old_xattr = simple_xattr_set(&pidfs_xa_cache, &pid->attr->xattrs, name, value, size, flags); if (IS_ERR(old_xattr)) return PTR_ERR(old_xattr);
simple_xattr_free_rcu(old_xattr); return 0;}
static const struct xattr_handler pidfs_trusted_xattr_handler = { .prefix = XATTR_TRUSTED_PREFIX, .get = pidfs_xattr_get, .set = pidfs_xattr_set,};
static const struct xattr_handler *const pidfs_xattr_handlers[] = { &pidfs_trusted_xattr_handler, NULL};
static int pidfs_init_fs_context(struct fs_context *fc){ struct pseudo_fs_context *ctx;
ctx = init_pseudo(fc, PID_FS_MAGIC); if (!ctx) return -ENOMEM;
ctx->s_d_flags |= DCACHE_DONTCACHE; ctx->ops = &pidfs_sops; ctx->eops = &pidfs_export_operations; ctx->dops = &pidfs_dentry_operations; ctx->xattr = pidfs_xattr_handlers; fc->s_fs_info = (void *)&pidfs_stashed_ops; return 0;}
static struct file_system_type pidfs_type = { .name = "pidfs", .init_fs_context = pidfs_init_fs_context, .kill_sb = kill_anon_super,};
struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags){ struct path path __free(path_put) = {}; int ret;
/* * Ensure that internal pidfd flags don't overlap with each * other or with uapi pidfd flags. */ BUILD_BUG_ON(hweight32(PIDFD_THREAD | PIDFD_NONBLOCK | PIDFD_STALE | PIDFD_AUTOKILL) != 4);
ret = path_from_stashed(&pid->stashed, pidfs_mnt, get_pid(pid), &path); if (ret < 0) return ERR_PTR(ret);
VFS_WARN_ON_ONCE(!pid->attr);
flags &= ~PIDFD_STALE; return pidfs_dentry_open(&path, flags, current_cred());}
void __init pidfs_init(void){ if (rhashtable_init(&pidfs_ino_ht, &pidfs_ino_ht_params)) panic("Failed to initialize pidfs hashtable");
pidfs_attr_cachep = kmem_cache_create("pidfs_attr_cache", sizeof(struct pidfs_attr), 0, (SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT | SLAB_PANIC), NULL);
pidfs_mnt = kern_mount(&pidfs_type); if (IS_ERR(pidfs_mnt)) panic("Failed to mount pidfs pseudo filesystem");
pidfs_root_path.mnt = pidfs_mnt; pidfs_root_path.dentry = pidfs_mnt->mnt_root;}