162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/fcntl.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/syscalls.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/mm.h> 1162306a36Sopenharmony_ci#include <linux/sched/task.h> 1262306a36Sopenharmony_ci#include <linux/fs.h> 1362306a36Sopenharmony_ci#include <linux/filelock.h> 1462306a36Sopenharmony_ci#include <linux/file.h> 1562306a36Sopenharmony_ci#include <linux/fdtable.h> 1662306a36Sopenharmony_ci#include <linux/capability.h> 1762306a36Sopenharmony_ci#include <linux/dnotify.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/pipe_fs_i.h> 2162306a36Sopenharmony_ci#include <linux/security.h> 2262306a36Sopenharmony_ci#include <linux/ptrace.h> 2362306a36Sopenharmony_ci#include <linux/signal.h> 2462306a36Sopenharmony_ci#include <linux/rcupdate.h> 2562306a36Sopenharmony_ci#include <linux/pid_namespace.h> 2662306a36Sopenharmony_ci#include <linux/user_namespace.h> 2762306a36Sopenharmony_ci#include <linux/memfd.h> 2862306a36Sopenharmony_ci#include <linux/compat.h> 2962306a36Sopenharmony_ci#include <linux/mount.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/poll.h> 3262306a36Sopenharmony_ci#include <asm/siginfo.h> 3362306a36Sopenharmony_ci#include <linux/uaccess.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic int setfl(int fd, struct file * filp, unsigned int arg) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct inode * inode = file_inode(filp); 4062306a36Sopenharmony_ci int error = 0; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci /* 4362306a36Sopenharmony_ci * O_APPEND cannot be cleared if the file is marked as append-only 4462306a36Sopenharmony_ci * and the file is open for write. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci if (((arg ^ filp->f_flags) & O_APPEND) && IS_APPEND(inode)) 4762306a36Sopenharmony_ci return -EPERM; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* O_NOATIME can only be set by the owner or superuser */ 5062306a36Sopenharmony_ci if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME)) 5162306a36Sopenharmony_ci if (!inode_owner_or_capable(file_mnt_idmap(filp), inode)) 5262306a36Sopenharmony_ci return -EPERM; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* required for strict SunOS emulation */ 5562306a36Sopenharmony_ci if (O_NONBLOCK != O_NDELAY) 5662306a36Sopenharmony_ci if (arg & O_NDELAY) 5762306a36Sopenharmony_ci arg |= O_NONBLOCK; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* Pipe packetized mode is controlled by O_DIRECT flag */ 6062306a36Sopenharmony_ci if (!S_ISFIFO(inode->i_mode) && 6162306a36Sopenharmony_ci (arg & O_DIRECT) && 6262306a36Sopenharmony_ci !(filp->f_mode & FMODE_CAN_ODIRECT)) 6362306a36Sopenharmony_ci return -EINVAL; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (filp->f_op->check_flags) 6662306a36Sopenharmony_ci error = filp->f_op->check_flags(arg); 6762306a36Sopenharmony_ci if (error) 6862306a36Sopenharmony_ci return error; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* 7162306a36Sopenharmony_ci * ->fasync() is responsible for setting the FASYNC bit. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci if (((arg ^ filp->f_flags) & FASYNC) && filp->f_op->fasync) { 7462306a36Sopenharmony_ci error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0); 7562306a36Sopenharmony_ci if (error < 0) 7662306a36Sopenharmony_ci goto out; 7762306a36Sopenharmony_ci if (error > 0) 7862306a36Sopenharmony_ci error = 0; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci spin_lock(&filp->f_lock); 8162306a36Sopenharmony_ci filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK); 8262306a36Sopenharmony_ci filp->f_iocb_flags = iocb_flags(filp); 8362306a36Sopenharmony_ci spin_unlock(&filp->f_lock); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci out: 8662306a36Sopenharmony_ci return error; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void f_modown(struct file *filp, struct pid *pid, enum pid_type type, 9062306a36Sopenharmony_ci int force) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci write_lock_irq(&filp->f_owner.lock); 9362306a36Sopenharmony_ci if (force || !filp->f_owner.pid) { 9462306a36Sopenharmony_ci put_pid(filp->f_owner.pid); 9562306a36Sopenharmony_ci filp->f_owner.pid = get_pid(pid); 9662306a36Sopenharmony_ci filp->f_owner.pid_type = type; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (pid) { 9962306a36Sopenharmony_ci const struct cred *cred = current_cred(); 10062306a36Sopenharmony_ci filp->f_owner.uid = cred->uid; 10162306a36Sopenharmony_ci filp->f_owner.euid = cred->euid; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci write_unlock_irq(&filp->f_owner.lock); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_civoid __f_setown(struct file *filp, struct pid *pid, enum pid_type type, 10862306a36Sopenharmony_ci int force) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci security_file_set_fowner(filp); 11162306a36Sopenharmony_ci f_modown(filp, pid, type, force); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ciEXPORT_SYMBOL(__f_setown); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ciint f_setown(struct file *filp, int who, int force) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci enum pid_type type; 11862306a36Sopenharmony_ci struct pid *pid = NULL; 11962306a36Sopenharmony_ci int ret = 0; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci type = PIDTYPE_TGID; 12262306a36Sopenharmony_ci if (who < 0) { 12362306a36Sopenharmony_ci /* avoid overflow below */ 12462306a36Sopenharmony_ci if (who == INT_MIN) 12562306a36Sopenharmony_ci return -EINVAL; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci type = PIDTYPE_PGID; 12862306a36Sopenharmony_ci who = -who; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci rcu_read_lock(); 13262306a36Sopenharmony_ci if (who) { 13362306a36Sopenharmony_ci pid = find_vpid(who); 13462306a36Sopenharmony_ci if (!pid) 13562306a36Sopenharmony_ci ret = -ESRCH; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (!ret) 13962306a36Sopenharmony_ci __f_setown(filp, pid, type, force); 14062306a36Sopenharmony_ci rcu_read_unlock(); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return ret; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ciEXPORT_SYMBOL(f_setown); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_civoid f_delown(struct file *filp) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci f_modown(filp, NULL, PIDTYPE_TGID, 1); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cipid_t f_getown(struct file *filp) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci pid_t pid = 0; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci read_lock_irq(&filp->f_owner.lock); 15662306a36Sopenharmony_ci rcu_read_lock(); 15762306a36Sopenharmony_ci if (pid_task(filp->f_owner.pid, filp->f_owner.pid_type)) { 15862306a36Sopenharmony_ci pid = pid_vnr(filp->f_owner.pid); 15962306a36Sopenharmony_ci if (filp->f_owner.pid_type == PIDTYPE_PGID) 16062306a36Sopenharmony_ci pid = -pid; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci rcu_read_unlock(); 16362306a36Sopenharmony_ci read_unlock_irq(&filp->f_owner.lock); 16462306a36Sopenharmony_ci return pid; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic int f_setown_ex(struct file *filp, unsigned long arg) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct f_owner_ex __user *owner_p = (void __user *)arg; 17062306a36Sopenharmony_ci struct f_owner_ex owner; 17162306a36Sopenharmony_ci struct pid *pid; 17262306a36Sopenharmony_ci int type; 17362306a36Sopenharmony_ci int ret; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci ret = copy_from_user(&owner, owner_p, sizeof(owner)); 17662306a36Sopenharmony_ci if (ret) 17762306a36Sopenharmony_ci return -EFAULT; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci switch (owner.type) { 18062306a36Sopenharmony_ci case F_OWNER_TID: 18162306a36Sopenharmony_ci type = PIDTYPE_PID; 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci case F_OWNER_PID: 18562306a36Sopenharmony_ci type = PIDTYPE_TGID; 18662306a36Sopenharmony_ci break; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci case F_OWNER_PGRP: 18962306a36Sopenharmony_ci type = PIDTYPE_PGID; 19062306a36Sopenharmony_ci break; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci default: 19362306a36Sopenharmony_ci return -EINVAL; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci rcu_read_lock(); 19762306a36Sopenharmony_ci pid = find_vpid(owner.pid); 19862306a36Sopenharmony_ci if (owner.pid && !pid) 19962306a36Sopenharmony_ci ret = -ESRCH; 20062306a36Sopenharmony_ci else 20162306a36Sopenharmony_ci __f_setown(filp, pid, type, 1); 20262306a36Sopenharmony_ci rcu_read_unlock(); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci return ret; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic int f_getown_ex(struct file *filp, unsigned long arg) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct f_owner_ex __user *owner_p = (void __user *)arg; 21062306a36Sopenharmony_ci struct f_owner_ex owner = {}; 21162306a36Sopenharmony_ci int ret = 0; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci read_lock_irq(&filp->f_owner.lock); 21462306a36Sopenharmony_ci rcu_read_lock(); 21562306a36Sopenharmony_ci if (pid_task(filp->f_owner.pid, filp->f_owner.pid_type)) 21662306a36Sopenharmony_ci owner.pid = pid_vnr(filp->f_owner.pid); 21762306a36Sopenharmony_ci rcu_read_unlock(); 21862306a36Sopenharmony_ci switch (filp->f_owner.pid_type) { 21962306a36Sopenharmony_ci case PIDTYPE_PID: 22062306a36Sopenharmony_ci owner.type = F_OWNER_TID; 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci case PIDTYPE_TGID: 22462306a36Sopenharmony_ci owner.type = F_OWNER_PID; 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci case PIDTYPE_PGID: 22862306a36Sopenharmony_ci owner.type = F_OWNER_PGRP; 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci default: 23262306a36Sopenharmony_ci WARN_ON(1); 23362306a36Sopenharmony_ci ret = -EINVAL; 23462306a36Sopenharmony_ci break; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci read_unlock_irq(&filp->f_owner.lock); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (!ret) { 23962306a36Sopenharmony_ci ret = copy_to_user(owner_p, &owner, sizeof(owner)); 24062306a36Sopenharmony_ci if (ret) 24162306a36Sopenharmony_ci ret = -EFAULT; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci return ret; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci#ifdef CONFIG_CHECKPOINT_RESTORE 24762306a36Sopenharmony_cistatic int f_getowner_uids(struct file *filp, unsigned long arg) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct user_namespace *user_ns = current_user_ns(); 25062306a36Sopenharmony_ci uid_t __user *dst = (void __user *)arg; 25162306a36Sopenharmony_ci uid_t src[2]; 25262306a36Sopenharmony_ci int err; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci read_lock_irq(&filp->f_owner.lock); 25562306a36Sopenharmony_ci src[0] = from_kuid(user_ns, filp->f_owner.uid); 25662306a36Sopenharmony_ci src[1] = from_kuid(user_ns, filp->f_owner.euid); 25762306a36Sopenharmony_ci read_unlock_irq(&filp->f_owner.lock); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci err = put_user(src[0], &dst[0]); 26062306a36Sopenharmony_ci err |= put_user(src[1], &dst[1]); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return err; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci#else 26562306a36Sopenharmony_cistatic int f_getowner_uids(struct file *filp, unsigned long arg) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci return -EINVAL; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci#endif 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic bool rw_hint_valid(u64 hint) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci switch (hint) { 27462306a36Sopenharmony_ci case RWH_WRITE_LIFE_NOT_SET: 27562306a36Sopenharmony_ci case RWH_WRITE_LIFE_NONE: 27662306a36Sopenharmony_ci case RWH_WRITE_LIFE_SHORT: 27762306a36Sopenharmony_ci case RWH_WRITE_LIFE_MEDIUM: 27862306a36Sopenharmony_ci case RWH_WRITE_LIFE_LONG: 27962306a36Sopenharmony_ci case RWH_WRITE_LIFE_EXTREME: 28062306a36Sopenharmony_ci return true; 28162306a36Sopenharmony_ci default: 28262306a36Sopenharmony_ci return false; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic long fcntl_rw_hint(struct file *file, unsigned int cmd, 28762306a36Sopenharmony_ci unsigned long arg) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct inode *inode = file_inode(file); 29062306a36Sopenharmony_ci u64 __user *argp = (u64 __user *)arg; 29162306a36Sopenharmony_ci u64 hint; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci switch (cmd) { 29462306a36Sopenharmony_ci case F_GET_RW_HINT: 29562306a36Sopenharmony_ci hint = inode->i_write_hint; 29662306a36Sopenharmony_ci if (copy_to_user(argp, &hint, sizeof(*argp))) 29762306a36Sopenharmony_ci return -EFAULT; 29862306a36Sopenharmony_ci return 0; 29962306a36Sopenharmony_ci case F_SET_RW_HINT: 30062306a36Sopenharmony_ci if (copy_from_user(&hint, argp, sizeof(hint))) 30162306a36Sopenharmony_ci return -EFAULT; 30262306a36Sopenharmony_ci if (!rw_hint_valid(hint)) 30362306a36Sopenharmony_ci return -EINVAL; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci inode_lock(inode); 30662306a36Sopenharmony_ci inode->i_write_hint = hint; 30762306a36Sopenharmony_ci inode_unlock(inode); 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci default: 31062306a36Sopenharmony_ci return -EINVAL; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic long do_fcntl(int fd, unsigned int cmd, unsigned long arg, 31562306a36Sopenharmony_ci struct file *filp) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 31862306a36Sopenharmony_ci int argi = (int)arg; 31962306a36Sopenharmony_ci struct flock flock; 32062306a36Sopenharmony_ci long err = -EINVAL; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci switch (cmd) { 32362306a36Sopenharmony_ci case F_DUPFD: 32462306a36Sopenharmony_ci err = f_dupfd(argi, filp, 0); 32562306a36Sopenharmony_ci break; 32662306a36Sopenharmony_ci case F_DUPFD_CLOEXEC: 32762306a36Sopenharmony_ci err = f_dupfd(argi, filp, O_CLOEXEC); 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci case F_GETFD: 33062306a36Sopenharmony_ci err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci case F_SETFD: 33362306a36Sopenharmony_ci err = 0; 33462306a36Sopenharmony_ci set_close_on_exec(fd, argi & FD_CLOEXEC); 33562306a36Sopenharmony_ci break; 33662306a36Sopenharmony_ci case F_GETFL: 33762306a36Sopenharmony_ci err = filp->f_flags; 33862306a36Sopenharmony_ci break; 33962306a36Sopenharmony_ci case F_SETFL: 34062306a36Sopenharmony_ci err = setfl(fd, filp, argi); 34162306a36Sopenharmony_ci break; 34262306a36Sopenharmony_ci#if BITS_PER_LONG != 32 34362306a36Sopenharmony_ci /* 32-bit arches must use fcntl64() */ 34462306a36Sopenharmony_ci case F_OFD_GETLK: 34562306a36Sopenharmony_ci#endif 34662306a36Sopenharmony_ci case F_GETLK: 34762306a36Sopenharmony_ci if (copy_from_user(&flock, argp, sizeof(flock))) 34862306a36Sopenharmony_ci return -EFAULT; 34962306a36Sopenharmony_ci err = fcntl_getlk(filp, cmd, &flock); 35062306a36Sopenharmony_ci if (!err && copy_to_user(argp, &flock, sizeof(flock))) 35162306a36Sopenharmony_ci return -EFAULT; 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci#if BITS_PER_LONG != 32 35462306a36Sopenharmony_ci /* 32-bit arches must use fcntl64() */ 35562306a36Sopenharmony_ci case F_OFD_SETLK: 35662306a36Sopenharmony_ci case F_OFD_SETLKW: 35762306a36Sopenharmony_ci fallthrough; 35862306a36Sopenharmony_ci#endif 35962306a36Sopenharmony_ci case F_SETLK: 36062306a36Sopenharmony_ci case F_SETLKW: 36162306a36Sopenharmony_ci if (copy_from_user(&flock, argp, sizeof(flock))) 36262306a36Sopenharmony_ci return -EFAULT; 36362306a36Sopenharmony_ci err = fcntl_setlk(fd, filp, cmd, &flock); 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci case F_GETOWN: 36662306a36Sopenharmony_ci /* 36762306a36Sopenharmony_ci * XXX If f_owner is a process group, the 36862306a36Sopenharmony_ci * negative return value will get converted 36962306a36Sopenharmony_ci * into an error. Oops. If we keep the 37062306a36Sopenharmony_ci * current syscall conventions, the only way 37162306a36Sopenharmony_ci * to fix this will be in libc. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_ci err = f_getown(filp); 37462306a36Sopenharmony_ci force_successful_syscall_return(); 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci case F_SETOWN: 37762306a36Sopenharmony_ci err = f_setown(filp, argi, 1); 37862306a36Sopenharmony_ci break; 37962306a36Sopenharmony_ci case F_GETOWN_EX: 38062306a36Sopenharmony_ci err = f_getown_ex(filp, arg); 38162306a36Sopenharmony_ci break; 38262306a36Sopenharmony_ci case F_SETOWN_EX: 38362306a36Sopenharmony_ci err = f_setown_ex(filp, arg); 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci case F_GETOWNER_UIDS: 38662306a36Sopenharmony_ci err = f_getowner_uids(filp, arg); 38762306a36Sopenharmony_ci break; 38862306a36Sopenharmony_ci case F_GETSIG: 38962306a36Sopenharmony_ci err = filp->f_owner.signum; 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci case F_SETSIG: 39262306a36Sopenharmony_ci /* arg == 0 restores default behaviour. */ 39362306a36Sopenharmony_ci if (!valid_signal(argi)) { 39462306a36Sopenharmony_ci break; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci err = 0; 39762306a36Sopenharmony_ci filp->f_owner.signum = argi; 39862306a36Sopenharmony_ci break; 39962306a36Sopenharmony_ci case F_GETLEASE: 40062306a36Sopenharmony_ci err = fcntl_getlease(filp); 40162306a36Sopenharmony_ci break; 40262306a36Sopenharmony_ci case F_SETLEASE: 40362306a36Sopenharmony_ci err = fcntl_setlease(fd, filp, argi); 40462306a36Sopenharmony_ci break; 40562306a36Sopenharmony_ci case F_NOTIFY: 40662306a36Sopenharmony_ci err = fcntl_dirnotify(fd, filp, argi); 40762306a36Sopenharmony_ci break; 40862306a36Sopenharmony_ci case F_SETPIPE_SZ: 40962306a36Sopenharmony_ci case F_GETPIPE_SZ: 41062306a36Sopenharmony_ci err = pipe_fcntl(filp, cmd, argi); 41162306a36Sopenharmony_ci break; 41262306a36Sopenharmony_ci case F_ADD_SEALS: 41362306a36Sopenharmony_ci case F_GET_SEALS: 41462306a36Sopenharmony_ci err = memfd_fcntl(filp, cmd, argi); 41562306a36Sopenharmony_ci break; 41662306a36Sopenharmony_ci case F_GET_RW_HINT: 41762306a36Sopenharmony_ci case F_SET_RW_HINT: 41862306a36Sopenharmony_ci err = fcntl_rw_hint(filp, cmd, arg); 41962306a36Sopenharmony_ci break; 42062306a36Sopenharmony_ci default: 42162306a36Sopenharmony_ci break; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci return err; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic int check_fcntl_cmd(unsigned cmd) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci switch (cmd) { 42962306a36Sopenharmony_ci case F_DUPFD: 43062306a36Sopenharmony_ci case F_DUPFD_CLOEXEC: 43162306a36Sopenharmony_ci case F_GETFD: 43262306a36Sopenharmony_ci case F_SETFD: 43362306a36Sopenharmony_ci case F_GETFL: 43462306a36Sopenharmony_ci return 1; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ciSYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct fd f = fdget_raw(fd); 44262306a36Sopenharmony_ci long err = -EBADF; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (!f.file) 44562306a36Sopenharmony_ci goto out; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (unlikely(f.file->f_mode & FMODE_PATH)) { 44862306a36Sopenharmony_ci if (!check_fcntl_cmd(cmd)) 44962306a36Sopenharmony_ci goto out1; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci err = security_file_fcntl(f.file, cmd, arg); 45362306a36Sopenharmony_ci if (!err) 45462306a36Sopenharmony_ci err = do_fcntl(fd, cmd, arg, f.file); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ciout1: 45762306a36Sopenharmony_ci fdput(f); 45862306a36Sopenharmony_ciout: 45962306a36Sopenharmony_ci return err; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci#if BITS_PER_LONG == 32 46362306a36Sopenharmony_ciSYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, 46462306a36Sopenharmony_ci unsigned long, arg) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 46762306a36Sopenharmony_ci struct fd f = fdget_raw(fd); 46862306a36Sopenharmony_ci struct flock64 flock; 46962306a36Sopenharmony_ci long err = -EBADF; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (!f.file) 47262306a36Sopenharmony_ci goto out; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (unlikely(f.file->f_mode & FMODE_PATH)) { 47562306a36Sopenharmony_ci if (!check_fcntl_cmd(cmd)) 47662306a36Sopenharmony_ci goto out1; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci err = security_file_fcntl(f.file, cmd, arg); 48062306a36Sopenharmony_ci if (err) 48162306a36Sopenharmony_ci goto out1; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci switch (cmd) { 48462306a36Sopenharmony_ci case F_GETLK64: 48562306a36Sopenharmony_ci case F_OFD_GETLK: 48662306a36Sopenharmony_ci err = -EFAULT; 48762306a36Sopenharmony_ci if (copy_from_user(&flock, argp, sizeof(flock))) 48862306a36Sopenharmony_ci break; 48962306a36Sopenharmony_ci err = fcntl_getlk64(f.file, cmd, &flock); 49062306a36Sopenharmony_ci if (!err && copy_to_user(argp, &flock, sizeof(flock))) 49162306a36Sopenharmony_ci err = -EFAULT; 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci case F_SETLK64: 49462306a36Sopenharmony_ci case F_SETLKW64: 49562306a36Sopenharmony_ci case F_OFD_SETLK: 49662306a36Sopenharmony_ci case F_OFD_SETLKW: 49762306a36Sopenharmony_ci err = -EFAULT; 49862306a36Sopenharmony_ci if (copy_from_user(&flock, argp, sizeof(flock))) 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci err = fcntl_setlk64(fd, f.file, cmd, &flock); 50162306a36Sopenharmony_ci break; 50262306a36Sopenharmony_ci default: 50362306a36Sopenharmony_ci err = do_fcntl(fd, cmd, arg, f.file); 50462306a36Sopenharmony_ci break; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ciout1: 50762306a36Sopenharmony_ci fdput(f); 50862306a36Sopenharmony_ciout: 50962306a36Sopenharmony_ci return err; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci#endif 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 51462306a36Sopenharmony_ci/* careful - don't use anywhere else */ 51562306a36Sopenharmony_ci#define copy_flock_fields(dst, src) \ 51662306a36Sopenharmony_ci (dst)->l_type = (src)->l_type; \ 51762306a36Sopenharmony_ci (dst)->l_whence = (src)->l_whence; \ 51862306a36Sopenharmony_ci (dst)->l_start = (src)->l_start; \ 51962306a36Sopenharmony_ci (dst)->l_len = (src)->l_len; \ 52062306a36Sopenharmony_ci (dst)->l_pid = (src)->l_pid; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic int get_compat_flock(struct flock *kfl, const struct compat_flock __user *ufl) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci struct compat_flock fl; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (copy_from_user(&fl, ufl, sizeof(struct compat_flock))) 52762306a36Sopenharmony_ci return -EFAULT; 52862306a36Sopenharmony_ci copy_flock_fields(kfl, &fl); 52962306a36Sopenharmony_ci return 0; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic int get_compat_flock64(struct flock *kfl, const struct compat_flock64 __user *ufl) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct compat_flock64 fl; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (copy_from_user(&fl, ufl, sizeof(struct compat_flock64))) 53762306a36Sopenharmony_ci return -EFAULT; 53862306a36Sopenharmony_ci copy_flock_fields(kfl, &fl); 53962306a36Sopenharmony_ci return 0; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic int put_compat_flock(const struct flock *kfl, struct compat_flock __user *ufl) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct compat_flock fl; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci memset(&fl, 0, sizeof(struct compat_flock)); 54762306a36Sopenharmony_ci copy_flock_fields(&fl, kfl); 54862306a36Sopenharmony_ci if (copy_to_user(ufl, &fl, sizeof(struct compat_flock))) 54962306a36Sopenharmony_ci return -EFAULT; 55062306a36Sopenharmony_ci return 0; 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic int put_compat_flock64(const struct flock *kfl, struct compat_flock64 __user *ufl) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci struct compat_flock64 fl; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(kfl->l_start) > sizeof(ufl->l_start)); 55862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(kfl->l_len) > sizeof(ufl->l_len)); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci memset(&fl, 0, sizeof(struct compat_flock64)); 56162306a36Sopenharmony_ci copy_flock_fields(&fl, kfl); 56262306a36Sopenharmony_ci if (copy_to_user(ufl, &fl, sizeof(struct compat_flock64))) 56362306a36Sopenharmony_ci return -EFAULT; 56462306a36Sopenharmony_ci return 0; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci#undef copy_flock_fields 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic unsigned int 56962306a36Sopenharmony_ciconvert_fcntl_cmd(unsigned int cmd) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci switch (cmd) { 57262306a36Sopenharmony_ci case F_GETLK64: 57362306a36Sopenharmony_ci return F_GETLK; 57462306a36Sopenharmony_ci case F_SETLK64: 57562306a36Sopenharmony_ci return F_SETLK; 57662306a36Sopenharmony_ci case F_SETLKW64: 57762306a36Sopenharmony_ci return F_SETLKW; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci return cmd; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci/* 58462306a36Sopenharmony_ci * GETLK was successful and we need to return the data, but it needs to fit in 58562306a36Sopenharmony_ci * the compat structure. 58662306a36Sopenharmony_ci * l_start shouldn't be too big, unless the original start + end is greater than 58762306a36Sopenharmony_ci * COMPAT_OFF_T_MAX, in which case the app was asking for trouble, so we return 58862306a36Sopenharmony_ci * -EOVERFLOW in that case. l_len could be too big, in which case we just 58962306a36Sopenharmony_ci * truncate it, and only allow the app to see that part of the conflicting lock 59062306a36Sopenharmony_ci * that might make sense to it anyway 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_cistatic int fixup_compat_flock(struct flock *flock) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci if (flock->l_start > COMPAT_OFF_T_MAX) 59562306a36Sopenharmony_ci return -EOVERFLOW; 59662306a36Sopenharmony_ci if (flock->l_len > COMPAT_OFF_T_MAX) 59762306a36Sopenharmony_ci flock->l_len = COMPAT_OFF_T_MAX; 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic long do_compat_fcntl64(unsigned int fd, unsigned int cmd, 60262306a36Sopenharmony_ci compat_ulong_t arg) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct fd f = fdget_raw(fd); 60562306a36Sopenharmony_ci struct flock flock; 60662306a36Sopenharmony_ci long err = -EBADF; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (!f.file) 60962306a36Sopenharmony_ci return err; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (unlikely(f.file->f_mode & FMODE_PATH)) { 61262306a36Sopenharmony_ci if (!check_fcntl_cmd(cmd)) 61362306a36Sopenharmony_ci goto out_put; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci err = security_file_fcntl(f.file, cmd, arg); 61762306a36Sopenharmony_ci if (err) 61862306a36Sopenharmony_ci goto out_put; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci switch (cmd) { 62162306a36Sopenharmony_ci case F_GETLK: 62262306a36Sopenharmony_ci err = get_compat_flock(&flock, compat_ptr(arg)); 62362306a36Sopenharmony_ci if (err) 62462306a36Sopenharmony_ci break; 62562306a36Sopenharmony_ci err = fcntl_getlk(f.file, convert_fcntl_cmd(cmd), &flock); 62662306a36Sopenharmony_ci if (err) 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci err = fixup_compat_flock(&flock); 62962306a36Sopenharmony_ci if (!err) 63062306a36Sopenharmony_ci err = put_compat_flock(&flock, compat_ptr(arg)); 63162306a36Sopenharmony_ci break; 63262306a36Sopenharmony_ci case F_GETLK64: 63362306a36Sopenharmony_ci case F_OFD_GETLK: 63462306a36Sopenharmony_ci err = get_compat_flock64(&flock, compat_ptr(arg)); 63562306a36Sopenharmony_ci if (err) 63662306a36Sopenharmony_ci break; 63762306a36Sopenharmony_ci err = fcntl_getlk(f.file, convert_fcntl_cmd(cmd), &flock); 63862306a36Sopenharmony_ci if (!err) 63962306a36Sopenharmony_ci err = put_compat_flock64(&flock, compat_ptr(arg)); 64062306a36Sopenharmony_ci break; 64162306a36Sopenharmony_ci case F_SETLK: 64262306a36Sopenharmony_ci case F_SETLKW: 64362306a36Sopenharmony_ci err = get_compat_flock(&flock, compat_ptr(arg)); 64462306a36Sopenharmony_ci if (err) 64562306a36Sopenharmony_ci break; 64662306a36Sopenharmony_ci err = fcntl_setlk(fd, f.file, convert_fcntl_cmd(cmd), &flock); 64762306a36Sopenharmony_ci break; 64862306a36Sopenharmony_ci case F_SETLK64: 64962306a36Sopenharmony_ci case F_SETLKW64: 65062306a36Sopenharmony_ci case F_OFD_SETLK: 65162306a36Sopenharmony_ci case F_OFD_SETLKW: 65262306a36Sopenharmony_ci err = get_compat_flock64(&flock, compat_ptr(arg)); 65362306a36Sopenharmony_ci if (err) 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci err = fcntl_setlk(fd, f.file, convert_fcntl_cmd(cmd), &flock); 65662306a36Sopenharmony_ci break; 65762306a36Sopenharmony_ci default: 65862306a36Sopenharmony_ci err = do_fcntl(fd, cmd, arg, f.file); 65962306a36Sopenharmony_ci break; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ciout_put: 66262306a36Sopenharmony_ci fdput(f); 66362306a36Sopenharmony_ci return err; 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, 66762306a36Sopenharmony_ci compat_ulong_t, arg) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci return do_compat_fcntl64(fd, cmd, arg); 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, 67362306a36Sopenharmony_ci compat_ulong_t, arg) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci switch (cmd) { 67662306a36Sopenharmony_ci case F_GETLK64: 67762306a36Sopenharmony_ci case F_SETLK64: 67862306a36Sopenharmony_ci case F_SETLKW64: 67962306a36Sopenharmony_ci case F_OFD_GETLK: 68062306a36Sopenharmony_ci case F_OFD_SETLK: 68162306a36Sopenharmony_ci case F_OFD_SETLKW: 68262306a36Sopenharmony_ci return -EINVAL; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci return do_compat_fcntl64(fd, cmd, arg); 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci#endif 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci/* Table to convert sigio signal codes into poll band bitmaps */ 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic const __poll_t band_table[NSIGPOLL] = { 69162306a36Sopenharmony_ci EPOLLIN | EPOLLRDNORM, /* POLL_IN */ 69262306a36Sopenharmony_ci EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND, /* POLL_OUT */ 69362306a36Sopenharmony_ci EPOLLIN | EPOLLRDNORM | EPOLLMSG, /* POLL_MSG */ 69462306a36Sopenharmony_ci EPOLLERR, /* POLL_ERR */ 69562306a36Sopenharmony_ci EPOLLPRI | EPOLLRDBAND, /* POLL_PRI */ 69662306a36Sopenharmony_ci EPOLLHUP | EPOLLERR /* POLL_HUP */ 69762306a36Sopenharmony_ci}; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic inline int sigio_perm(struct task_struct *p, 70062306a36Sopenharmony_ci struct fown_struct *fown, int sig) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci const struct cred *cred; 70362306a36Sopenharmony_ci int ret; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci rcu_read_lock(); 70662306a36Sopenharmony_ci cred = __task_cred(p); 70762306a36Sopenharmony_ci ret = ((uid_eq(fown->euid, GLOBAL_ROOT_UID) || 70862306a36Sopenharmony_ci uid_eq(fown->euid, cred->suid) || uid_eq(fown->euid, cred->uid) || 70962306a36Sopenharmony_ci uid_eq(fown->uid, cred->suid) || uid_eq(fown->uid, cred->uid)) && 71062306a36Sopenharmony_ci !security_file_send_sigiotask(p, fown, sig)); 71162306a36Sopenharmony_ci rcu_read_unlock(); 71262306a36Sopenharmony_ci return ret; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic void send_sigio_to_task(struct task_struct *p, 71662306a36Sopenharmony_ci struct fown_struct *fown, 71762306a36Sopenharmony_ci int fd, int reason, enum pid_type type) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci /* 72062306a36Sopenharmony_ci * F_SETSIG can change ->signum lockless in parallel, make 72162306a36Sopenharmony_ci * sure we read it once and use the same value throughout. 72262306a36Sopenharmony_ci */ 72362306a36Sopenharmony_ci int signum = READ_ONCE(fown->signum); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (!sigio_perm(p, fown, signum)) 72662306a36Sopenharmony_ci return; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci switch (signum) { 72962306a36Sopenharmony_ci default: { 73062306a36Sopenharmony_ci kernel_siginfo_t si; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* Queue a rt signal with the appropriate fd as its 73362306a36Sopenharmony_ci value. We use SI_SIGIO as the source, not 73462306a36Sopenharmony_ci SI_KERNEL, since kernel signals always get 73562306a36Sopenharmony_ci delivered even if we can't queue. Failure to 73662306a36Sopenharmony_ci queue in this case _should_ be reported; we fall 73762306a36Sopenharmony_ci back to SIGIO in that case. --sct */ 73862306a36Sopenharmony_ci clear_siginfo(&si); 73962306a36Sopenharmony_ci si.si_signo = signum; 74062306a36Sopenharmony_ci si.si_errno = 0; 74162306a36Sopenharmony_ci si.si_code = reason; 74262306a36Sopenharmony_ci /* 74362306a36Sopenharmony_ci * Posix definies POLL_IN and friends to be signal 74462306a36Sopenharmony_ci * specific si_codes for SIG_POLL. Linux extended 74562306a36Sopenharmony_ci * these si_codes to other signals in a way that is 74662306a36Sopenharmony_ci * ambiguous if other signals also have signal 74762306a36Sopenharmony_ci * specific si_codes. In that case use SI_SIGIO instead 74862306a36Sopenharmony_ci * to remove the ambiguity. 74962306a36Sopenharmony_ci */ 75062306a36Sopenharmony_ci if ((signum != SIGPOLL) && sig_specific_sicodes(signum)) 75162306a36Sopenharmony_ci si.si_code = SI_SIGIO; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* Make sure we are called with one of the POLL_* 75462306a36Sopenharmony_ci reasons, otherwise we could leak kernel stack into 75562306a36Sopenharmony_ci userspace. */ 75662306a36Sopenharmony_ci BUG_ON((reason < POLL_IN) || ((reason - POLL_IN) >= NSIGPOLL)); 75762306a36Sopenharmony_ci if (reason - POLL_IN >= NSIGPOLL) 75862306a36Sopenharmony_ci si.si_band = ~0L; 75962306a36Sopenharmony_ci else 76062306a36Sopenharmony_ci si.si_band = mangle_poll(band_table[reason - POLL_IN]); 76162306a36Sopenharmony_ci si.si_fd = fd; 76262306a36Sopenharmony_ci if (!do_send_sig_info(signum, &si, p, type)) 76362306a36Sopenharmony_ci break; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci fallthrough; /* fall back on the old plain SIGIO signal */ 76662306a36Sopenharmony_ci case 0: 76762306a36Sopenharmony_ci do_send_sig_info(SIGIO, SEND_SIG_PRIV, p, type); 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_civoid send_sigio(struct fown_struct *fown, int fd, int band) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci struct task_struct *p; 77462306a36Sopenharmony_ci enum pid_type type; 77562306a36Sopenharmony_ci unsigned long flags; 77662306a36Sopenharmony_ci struct pid *pid; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci read_lock_irqsave(&fown->lock, flags); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci type = fown->pid_type; 78162306a36Sopenharmony_ci pid = fown->pid; 78262306a36Sopenharmony_ci if (!pid) 78362306a36Sopenharmony_ci goto out_unlock_fown; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (type <= PIDTYPE_TGID) { 78662306a36Sopenharmony_ci rcu_read_lock(); 78762306a36Sopenharmony_ci p = pid_task(pid, PIDTYPE_PID); 78862306a36Sopenharmony_ci if (p) 78962306a36Sopenharmony_ci send_sigio_to_task(p, fown, fd, band, type); 79062306a36Sopenharmony_ci rcu_read_unlock(); 79162306a36Sopenharmony_ci } else { 79262306a36Sopenharmony_ci read_lock(&tasklist_lock); 79362306a36Sopenharmony_ci do_each_pid_task(pid, type, p) { 79462306a36Sopenharmony_ci send_sigio_to_task(p, fown, fd, band, type); 79562306a36Sopenharmony_ci } while_each_pid_task(pid, type, p); 79662306a36Sopenharmony_ci read_unlock(&tasklist_lock); 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci out_unlock_fown: 79962306a36Sopenharmony_ci read_unlock_irqrestore(&fown->lock, flags); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic void send_sigurg_to_task(struct task_struct *p, 80362306a36Sopenharmony_ci struct fown_struct *fown, enum pid_type type) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci if (sigio_perm(p, fown, SIGURG)) 80662306a36Sopenharmony_ci do_send_sig_info(SIGURG, SEND_SIG_PRIV, p, type); 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ciint send_sigurg(struct fown_struct *fown) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci struct task_struct *p; 81262306a36Sopenharmony_ci enum pid_type type; 81362306a36Sopenharmony_ci struct pid *pid; 81462306a36Sopenharmony_ci unsigned long flags; 81562306a36Sopenharmony_ci int ret = 0; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci read_lock_irqsave(&fown->lock, flags); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci type = fown->pid_type; 82062306a36Sopenharmony_ci pid = fown->pid; 82162306a36Sopenharmony_ci if (!pid) 82262306a36Sopenharmony_ci goto out_unlock_fown; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci ret = 1; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (type <= PIDTYPE_TGID) { 82762306a36Sopenharmony_ci rcu_read_lock(); 82862306a36Sopenharmony_ci p = pid_task(pid, PIDTYPE_PID); 82962306a36Sopenharmony_ci if (p) 83062306a36Sopenharmony_ci send_sigurg_to_task(p, fown, type); 83162306a36Sopenharmony_ci rcu_read_unlock(); 83262306a36Sopenharmony_ci } else { 83362306a36Sopenharmony_ci read_lock(&tasklist_lock); 83462306a36Sopenharmony_ci do_each_pid_task(pid, type, p) { 83562306a36Sopenharmony_ci send_sigurg_to_task(p, fown, type); 83662306a36Sopenharmony_ci } while_each_pid_task(pid, type, p); 83762306a36Sopenharmony_ci read_unlock(&tasklist_lock); 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci out_unlock_fown: 84062306a36Sopenharmony_ci read_unlock_irqrestore(&fown->lock, flags); 84162306a36Sopenharmony_ci return ret; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(fasync_lock); 84562306a36Sopenharmony_cistatic struct kmem_cache *fasync_cache __read_mostly; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic void fasync_free_rcu(struct rcu_head *head) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci kmem_cache_free(fasync_cache, 85062306a36Sopenharmony_ci container_of(head, struct fasync_struct, fa_rcu)); 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci/* 85462306a36Sopenharmony_ci * Remove a fasync entry. If successfully removed, return 85562306a36Sopenharmony_ci * positive and clear the FASYNC flag. If no entry exists, 85662306a36Sopenharmony_ci * do nothing and return 0. 85762306a36Sopenharmony_ci * 85862306a36Sopenharmony_ci * NOTE! It is very important that the FASYNC flag always 85962306a36Sopenharmony_ci * match the state "is the filp on a fasync list". 86062306a36Sopenharmony_ci * 86162306a36Sopenharmony_ci */ 86262306a36Sopenharmony_ciint fasync_remove_entry(struct file *filp, struct fasync_struct **fapp) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct fasync_struct *fa, **fp; 86562306a36Sopenharmony_ci int result = 0; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci spin_lock(&filp->f_lock); 86862306a36Sopenharmony_ci spin_lock(&fasync_lock); 86962306a36Sopenharmony_ci for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { 87062306a36Sopenharmony_ci if (fa->fa_file != filp) 87162306a36Sopenharmony_ci continue; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci write_lock_irq(&fa->fa_lock); 87462306a36Sopenharmony_ci fa->fa_file = NULL; 87562306a36Sopenharmony_ci write_unlock_irq(&fa->fa_lock); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci *fp = fa->fa_next; 87862306a36Sopenharmony_ci call_rcu(&fa->fa_rcu, fasync_free_rcu); 87962306a36Sopenharmony_ci filp->f_flags &= ~FASYNC; 88062306a36Sopenharmony_ci result = 1; 88162306a36Sopenharmony_ci break; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci spin_unlock(&fasync_lock); 88462306a36Sopenharmony_ci spin_unlock(&filp->f_lock); 88562306a36Sopenharmony_ci return result; 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistruct fasync_struct *fasync_alloc(void) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci return kmem_cache_alloc(fasync_cache, GFP_KERNEL); 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci/* 89462306a36Sopenharmony_ci * NOTE! This can be used only for unused fasync entries: 89562306a36Sopenharmony_ci * entries that actually got inserted on the fasync list 89662306a36Sopenharmony_ci * need to be released by rcu - see fasync_remove_entry. 89762306a36Sopenharmony_ci */ 89862306a36Sopenharmony_civoid fasync_free(struct fasync_struct *new) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci kmem_cache_free(fasync_cache, new); 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci/* 90462306a36Sopenharmony_ci * Insert a new entry into the fasync list. Return the pointer to the 90562306a36Sopenharmony_ci * old one if we didn't use the new one. 90662306a36Sopenharmony_ci * 90762306a36Sopenharmony_ci * NOTE! It is very important that the FASYNC flag always 90862306a36Sopenharmony_ci * match the state "is the filp on a fasync list". 90962306a36Sopenharmony_ci */ 91062306a36Sopenharmony_cistruct fasync_struct *fasync_insert_entry(int fd, struct file *filp, struct fasync_struct **fapp, struct fasync_struct *new) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci struct fasync_struct *fa, **fp; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci spin_lock(&filp->f_lock); 91562306a36Sopenharmony_ci spin_lock(&fasync_lock); 91662306a36Sopenharmony_ci for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { 91762306a36Sopenharmony_ci if (fa->fa_file != filp) 91862306a36Sopenharmony_ci continue; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci write_lock_irq(&fa->fa_lock); 92162306a36Sopenharmony_ci fa->fa_fd = fd; 92262306a36Sopenharmony_ci write_unlock_irq(&fa->fa_lock); 92362306a36Sopenharmony_ci goto out; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci rwlock_init(&new->fa_lock); 92762306a36Sopenharmony_ci new->magic = FASYNC_MAGIC; 92862306a36Sopenharmony_ci new->fa_file = filp; 92962306a36Sopenharmony_ci new->fa_fd = fd; 93062306a36Sopenharmony_ci new->fa_next = *fapp; 93162306a36Sopenharmony_ci rcu_assign_pointer(*fapp, new); 93262306a36Sopenharmony_ci filp->f_flags |= FASYNC; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ciout: 93562306a36Sopenharmony_ci spin_unlock(&fasync_lock); 93662306a36Sopenharmony_ci spin_unlock(&filp->f_lock); 93762306a36Sopenharmony_ci return fa; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci/* 94162306a36Sopenharmony_ci * Add a fasync entry. Return negative on error, positive if 94262306a36Sopenharmony_ci * added, and zero if did nothing but change an existing one. 94362306a36Sopenharmony_ci */ 94462306a36Sopenharmony_cistatic int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci struct fasync_struct *new; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci new = fasync_alloc(); 94962306a36Sopenharmony_ci if (!new) 95062306a36Sopenharmony_ci return -ENOMEM; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci /* 95362306a36Sopenharmony_ci * fasync_insert_entry() returns the old (update) entry if 95462306a36Sopenharmony_ci * it existed. 95562306a36Sopenharmony_ci * 95662306a36Sopenharmony_ci * So free the (unused) new entry and return 0 to let the 95762306a36Sopenharmony_ci * caller know that we didn't add any new fasync entries. 95862306a36Sopenharmony_ci */ 95962306a36Sopenharmony_ci if (fasync_insert_entry(fd, filp, fapp, new)) { 96062306a36Sopenharmony_ci fasync_free(new); 96162306a36Sopenharmony_ci return 0; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci return 1; 96562306a36Sopenharmony_ci} 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci/* 96862306a36Sopenharmony_ci * fasync_helper() is used by almost all character device drivers 96962306a36Sopenharmony_ci * to set up the fasync queue, and for regular files by the file 97062306a36Sopenharmony_ci * lease code. It returns negative on error, 0 if it did no changes 97162306a36Sopenharmony_ci * and positive if it added/deleted the entry. 97262306a36Sopenharmony_ci */ 97362306a36Sopenharmony_ciint fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci if (!on) 97662306a36Sopenharmony_ci return fasync_remove_entry(filp, fapp); 97762306a36Sopenharmony_ci return fasync_add_entry(fd, filp, fapp); 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ciEXPORT_SYMBOL(fasync_helper); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci/* 98362306a36Sopenharmony_ci * rcu_read_lock() is held 98462306a36Sopenharmony_ci */ 98562306a36Sopenharmony_cistatic void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band) 98662306a36Sopenharmony_ci{ 98762306a36Sopenharmony_ci while (fa) { 98862306a36Sopenharmony_ci struct fown_struct *fown; 98962306a36Sopenharmony_ci unsigned long flags; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci if (fa->magic != FASYNC_MAGIC) { 99262306a36Sopenharmony_ci printk(KERN_ERR "kill_fasync: bad magic number in " 99362306a36Sopenharmony_ci "fasync_struct!\n"); 99462306a36Sopenharmony_ci return; 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci read_lock_irqsave(&fa->fa_lock, flags); 99762306a36Sopenharmony_ci if (fa->fa_file) { 99862306a36Sopenharmony_ci fown = &fa->fa_file->f_owner; 99962306a36Sopenharmony_ci /* Don't send SIGURG to processes which have not set a 100062306a36Sopenharmony_ci queued signum: SIGURG has its own default signalling 100162306a36Sopenharmony_ci mechanism. */ 100262306a36Sopenharmony_ci if (!(sig == SIGURG && fown->signum == 0)) 100362306a36Sopenharmony_ci send_sigio(fown, fa->fa_fd, band); 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci read_unlock_irqrestore(&fa->fa_lock, flags); 100662306a36Sopenharmony_ci fa = rcu_dereference(fa->fa_next); 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_civoid kill_fasync(struct fasync_struct **fp, int sig, int band) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci /* First a quick test without locking: usually 101362306a36Sopenharmony_ci * the list is empty. 101462306a36Sopenharmony_ci */ 101562306a36Sopenharmony_ci if (*fp) { 101662306a36Sopenharmony_ci rcu_read_lock(); 101762306a36Sopenharmony_ci kill_fasync_rcu(rcu_dereference(*fp), sig, band); 101862306a36Sopenharmony_ci rcu_read_unlock(); 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ciEXPORT_SYMBOL(kill_fasync); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_cistatic int __init fcntl_init(void) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci /* 102662306a36Sopenharmony_ci * Please add new bits here to ensure allocation uniqueness. 102762306a36Sopenharmony_ci * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY 102862306a36Sopenharmony_ci * is defined as O_NONBLOCK on some platforms and not on others. 102962306a36Sopenharmony_ci */ 103062306a36Sopenharmony_ci BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != 103162306a36Sopenharmony_ci HWEIGHT32( 103262306a36Sopenharmony_ci (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | 103362306a36Sopenharmony_ci __FMODE_EXEC | __FMODE_NONOTIFY)); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci fasync_cache = kmem_cache_create("fasync_cache", 103662306a36Sopenharmony_ci sizeof(struct fasync_struct), 0, 103762306a36Sopenharmony_ci SLAB_PANIC | SLAB_ACCOUNT, NULL); 103862306a36Sopenharmony_ci return 0; 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cimodule_init(fcntl_init) 1042