162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * This file contains the procedures for the handling of select and poll 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Created for Linux based loosely upon Mathius Lattner's minix 662306a36Sopenharmony_ci * patches by Peter MacDonald. Heavily edited by Linus. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * 4 February 1994 962306a36Sopenharmony_ci * COFF/ELF binary emulation. If the process has the STICKY_TIMEOUTS 1062306a36Sopenharmony_ci * flag set in its personality we do *not* modify the given timeout 1162306a36Sopenharmony_ci * parameter to reflect time remaining. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * 24 January 2000 1462306a36Sopenharmony_ci * Changed sys_poll()/do_poll() to use PAGE_SIZE chunk-based allocation 1562306a36Sopenharmony_ci * of fds to overcome nfds < 16390 descriptors limit (Tigran Aivazian). 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/compat.h> 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/sched/signal.h> 2162306a36Sopenharmony_ci#include <linux/sched/rt.h> 2262306a36Sopenharmony_ci#include <linux/syscalls.h> 2362306a36Sopenharmony_ci#include <linux/export.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/poll.h> 2662306a36Sopenharmony_ci#include <linux/personality.h> /* for STICKY_TIMEOUTS */ 2762306a36Sopenharmony_ci#include <linux/file.h> 2862306a36Sopenharmony_ci#include <linux/fdtable.h> 2962306a36Sopenharmony_ci#include <linux/fs.h> 3062306a36Sopenharmony_ci#include <linux/rcupdate.h> 3162306a36Sopenharmony_ci#include <linux/hrtimer.h> 3262306a36Sopenharmony_ci#include <linux/freezer.h> 3362306a36Sopenharmony_ci#include <net/busy_poll.h> 3462306a36Sopenharmony_ci#include <linux/vmalloc.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <linux/uaccess.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * Estimate expected accuracy in ns from a timeval. 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * After quite a bit of churning around, we've settled on 4362306a36Sopenharmony_ci * a simple thing of taking 0.1% of the timeout as the 4462306a36Sopenharmony_ci * slack, with a cap of 100 msec. 4562306a36Sopenharmony_ci * "nice" tasks get a 0.5% slack instead. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * Consider this comment an open invitation to come up with even 4862306a36Sopenharmony_ci * better solutions.. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define MAX_SLACK (100 * NSEC_PER_MSEC) 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic long __estimate_accuracy(struct timespec64 *tv) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci long slack; 5662306a36Sopenharmony_ci int divfactor = 1000; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (tv->tv_sec < 0) 5962306a36Sopenharmony_ci return 0; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (task_nice(current) > 0) 6262306a36Sopenharmony_ci divfactor = divfactor / 5; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (tv->tv_sec > MAX_SLACK / (NSEC_PER_SEC/divfactor)) 6562306a36Sopenharmony_ci return MAX_SLACK; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci slack = tv->tv_nsec / divfactor; 6862306a36Sopenharmony_ci slack += tv->tv_sec * (NSEC_PER_SEC/divfactor); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (slack > MAX_SLACK) 7162306a36Sopenharmony_ci return MAX_SLACK; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return slack; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciu64 select_estimate_accuracy(struct timespec64 *tv) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci u64 ret; 7962306a36Sopenharmony_ci struct timespec64 now; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* 8262306a36Sopenharmony_ci * Realtime tasks get a slack of 0 for obvious reasons. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (rt_task(current)) 8662306a36Sopenharmony_ci return 0; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci ktime_get_ts64(&now); 8962306a36Sopenharmony_ci now = timespec64_sub(*tv, now); 9062306a36Sopenharmony_ci ret = __estimate_accuracy(&now); 9162306a36Sopenharmony_ci if (ret < current->timer_slack_ns) 9262306a36Sopenharmony_ci return current->timer_slack_ns; 9362306a36Sopenharmony_ci return ret; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistruct poll_table_page { 9962306a36Sopenharmony_ci struct poll_table_page * next; 10062306a36Sopenharmony_ci struct poll_table_entry * entry; 10162306a36Sopenharmony_ci struct poll_table_entry entries[]; 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#define POLL_TABLE_FULL(table) \ 10562306a36Sopenharmony_ci ((unsigned long)((table)->entry+1) > PAGE_SIZE + (unsigned long)(table)) 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* 10862306a36Sopenharmony_ci * Ok, Peter made a complicated, but straightforward multiple_wait() function. 10962306a36Sopenharmony_ci * I have rewritten this, taking some shortcuts: This code may not be easy to 11062306a36Sopenharmony_ci * follow, but it should be free of race-conditions, and it's practical. If you 11162306a36Sopenharmony_ci * understand what I'm doing here, then you understand how the linux 11262306a36Sopenharmony_ci * sleep/wakeup mechanism works. 11362306a36Sopenharmony_ci * 11462306a36Sopenharmony_ci * Two very simple procedures, poll_wait() and poll_freewait() make all the 11562306a36Sopenharmony_ci * work. poll_wait() is an inline-function defined in <linux/poll.h>, 11662306a36Sopenharmony_ci * as all select/poll functions have to call it to add an entry to the 11762306a36Sopenharmony_ci * poll table. 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_cistatic void __pollwait(struct file *filp, wait_queue_head_t *wait_address, 12062306a36Sopenharmony_ci poll_table *p); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_civoid poll_initwait(struct poll_wqueues *pwq) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci init_poll_funcptr(&pwq->pt, __pollwait); 12562306a36Sopenharmony_ci pwq->polling_task = current; 12662306a36Sopenharmony_ci pwq->triggered = 0; 12762306a36Sopenharmony_ci pwq->error = 0; 12862306a36Sopenharmony_ci pwq->table = NULL; 12962306a36Sopenharmony_ci pwq->inline_index = 0; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ciEXPORT_SYMBOL(poll_initwait); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic void free_poll_entry(struct poll_table_entry *entry) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci remove_wait_queue(entry->wait_address, &entry->wait); 13662306a36Sopenharmony_ci fput(entry->filp); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_civoid poll_freewait(struct poll_wqueues *pwq) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct poll_table_page * p = pwq->table; 14262306a36Sopenharmony_ci int i; 14362306a36Sopenharmony_ci for (i = 0; i < pwq->inline_index; i++) 14462306a36Sopenharmony_ci free_poll_entry(pwq->inline_entries + i); 14562306a36Sopenharmony_ci while (p) { 14662306a36Sopenharmony_ci struct poll_table_entry * entry; 14762306a36Sopenharmony_ci struct poll_table_page *old; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci entry = p->entry; 15062306a36Sopenharmony_ci do { 15162306a36Sopenharmony_ci entry--; 15262306a36Sopenharmony_ci free_poll_entry(entry); 15362306a36Sopenharmony_ci } while (entry > p->entries); 15462306a36Sopenharmony_ci old = p; 15562306a36Sopenharmony_ci p = p->next; 15662306a36Sopenharmony_ci free_page((unsigned long) old); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ciEXPORT_SYMBOL(poll_freewait); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic struct poll_table_entry *poll_get_entry(struct poll_wqueues *p) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct poll_table_page *table = p->table; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (p->inline_index < N_INLINE_POLL_ENTRIES) 16662306a36Sopenharmony_ci return p->inline_entries + p->inline_index++; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (!table || POLL_TABLE_FULL(table)) { 16962306a36Sopenharmony_ci struct poll_table_page *new_table; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci new_table = (struct poll_table_page *) __get_free_page(GFP_KERNEL); 17262306a36Sopenharmony_ci if (!new_table) { 17362306a36Sopenharmony_ci p->error = -ENOMEM; 17462306a36Sopenharmony_ci return NULL; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci new_table->entry = new_table->entries; 17762306a36Sopenharmony_ci new_table->next = table; 17862306a36Sopenharmony_ci p->table = new_table; 17962306a36Sopenharmony_ci table = new_table; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return table->entry++; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int __pollwake(wait_queue_entry_t *wait, unsigned mode, int sync, void *key) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct poll_wqueues *pwq = wait->private; 18862306a36Sopenharmony_ci DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* 19162306a36Sopenharmony_ci * Although this function is called under waitqueue lock, LOCK 19262306a36Sopenharmony_ci * doesn't imply write barrier and the users expect write 19362306a36Sopenharmony_ci * barrier semantics on wakeup functions. The following 19462306a36Sopenharmony_ci * smp_wmb() is equivalent to smp_wmb() in try_to_wake_up() 19562306a36Sopenharmony_ci * and is paired with smp_store_mb() in poll_schedule_timeout. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_ci smp_wmb(); 19862306a36Sopenharmony_ci pwq->triggered = 1; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* 20162306a36Sopenharmony_ci * Perform the default wake up operation using a dummy 20262306a36Sopenharmony_ci * waitqueue. 20362306a36Sopenharmony_ci * 20462306a36Sopenharmony_ci * TODO: This is hacky but there currently is no interface to 20562306a36Sopenharmony_ci * pass in @sync. @sync is scheduled to be removed and once 20662306a36Sopenharmony_ci * that happens, wake_up_process() can be used directly. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci return default_wake_function(&dummy_wait, mode, sync, key); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic int pollwake(wait_queue_entry_t *wait, unsigned mode, int sync, void *key) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct poll_table_entry *entry; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci entry = container_of(wait, struct poll_table_entry, wait); 21662306a36Sopenharmony_ci if (key && !(key_to_poll(key) & entry->key)) 21762306a36Sopenharmony_ci return 0; 21862306a36Sopenharmony_ci return __pollwake(wait, mode, sync, key); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/* Add a new entry */ 22262306a36Sopenharmony_cistatic void __pollwait(struct file *filp, wait_queue_head_t *wait_address, 22362306a36Sopenharmony_ci poll_table *p) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt); 22662306a36Sopenharmony_ci struct poll_table_entry *entry = poll_get_entry(pwq); 22762306a36Sopenharmony_ci if (!entry) 22862306a36Sopenharmony_ci return; 22962306a36Sopenharmony_ci entry->filp = get_file(filp); 23062306a36Sopenharmony_ci entry->wait_address = wait_address; 23162306a36Sopenharmony_ci entry->key = p->_key; 23262306a36Sopenharmony_ci init_waitqueue_func_entry(&entry->wait, pollwake); 23362306a36Sopenharmony_ci entry->wait.private = pwq; 23462306a36Sopenharmony_ci add_wait_queue(wait_address, &entry->wait); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int poll_schedule_timeout(struct poll_wqueues *pwq, int state, 23862306a36Sopenharmony_ci ktime_t *expires, unsigned long slack) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci int rc = -EINTR; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci set_current_state(state); 24362306a36Sopenharmony_ci if (!pwq->triggered) 24462306a36Sopenharmony_ci rc = schedule_hrtimeout_range(expires, slack, HRTIMER_MODE_ABS); 24562306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* 24862306a36Sopenharmony_ci * Prepare for the next iteration. 24962306a36Sopenharmony_ci * 25062306a36Sopenharmony_ci * The following smp_store_mb() serves two purposes. First, it's 25162306a36Sopenharmony_ci * the counterpart rmb of the wmb in pollwake() such that data 25262306a36Sopenharmony_ci * written before wake up is always visible after wake up. 25362306a36Sopenharmony_ci * Second, the full barrier guarantees that triggered clearing 25462306a36Sopenharmony_ci * doesn't pass event check of the next iteration. Note that 25562306a36Sopenharmony_ci * this problem doesn't exist for the first iteration as 25662306a36Sopenharmony_ci * add_wait_queue() has full barrier semantics. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci smp_store_mb(pwq->triggered, 0); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return rc; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci/** 26462306a36Sopenharmony_ci * poll_select_set_timeout - helper function to setup the timeout value 26562306a36Sopenharmony_ci * @to: pointer to timespec64 variable for the final timeout 26662306a36Sopenharmony_ci * @sec: seconds (from user space) 26762306a36Sopenharmony_ci * @nsec: nanoseconds (from user space) 26862306a36Sopenharmony_ci * 26962306a36Sopenharmony_ci * Note, we do not use a timespec for the user space value here, That 27062306a36Sopenharmony_ci * way we can use the function for timeval and compat interfaces as well. 27162306a36Sopenharmony_ci * 27262306a36Sopenharmony_ci * Returns -EINVAL if sec/nsec are not normalized. Otherwise 0. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_ciint poll_select_set_timeout(struct timespec64 *to, time64_t sec, long nsec) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct timespec64 ts = {.tv_sec = sec, .tv_nsec = nsec}; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (!timespec64_valid(&ts)) 27962306a36Sopenharmony_ci return -EINVAL; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Optimize for the zero timeout value here */ 28262306a36Sopenharmony_ci if (!sec && !nsec) { 28362306a36Sopenharmony_ci to->tv_sec = to->tv_nsec = 0; 28462306a36Sopenharmony_ci } else { 28562306a36Sopenharmony_ci ktime_get_ts64(to); 28662306a36Sopenharmony_ci *to = timespec64_add_safe(*to, ts); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cienum poll_time_type { 29262306a36Sopenharmony_ci PT_TIMEVAL = 0, 29362306a36Sopenharmony_ci PT_OLD_TIMEVAL = 1, 29462306a36Sopenharmony_ci PT_TIMESPEC = 2, 29562306a36Sopenharmony_ci PT_OLD_TIMESPEC = 3, 29662306a36Sopenharmony_ci}; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int poll_select_finish(struct timespec64 *end_time, 29962306a36Sopenharmony_ci void __user *p, 30062306a36Sopenharmony_ci enum poll_time_type pt_type, int ret) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct timespec64 rts; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci restore_saved_sigmask_unless(ret == -ERESTARTNOHAND); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (!p) 30762306a36Sopenharmony_ci return ret; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (current->personality & STICKY_TIMEOUTS) 31062306a36Sopenharmony_ci goto sticky; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* No update for zero timeout */ 31362306a36Sopenharmony_ci if (!end_time->tv_sec && !end_time->tv_nsec) 31462306a36Sopenharmony_ci return ret; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci ktime_get_ts64(&rts); 31762306a36Sopenharmony_ci rts = timespec64_sub(*end_time, rts); 31862306a36Sopenharmony_ci if (rts.tv_sec < 0) 31962306a36Sopenharmony_ci rts.tv_sec = rts.tv_nsec = 0; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci switch (pt_type) { 32362306a36Sopenharmony_ci case PT_TIMEVAL: 32462306a36Sopenharmony_ci { 32562306a36Sopenharmony_ci struct __kernel_old_timeval rtv; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (sizeof(rtv) > sizeof(rtv.tv_sec) + sizeof(rtv.tv_usec)) 32862306a36Sopenharmony_ci memset(&rtv, 0, sizeof(rtv)); 32962306a36Sopenharmony_ci rtv.tv_sec = rts.tv_sec; 33062306a36Sopenharmony_ci rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC; 33162306a36Sopenharmony_ci if (!copy_to_user(p, &rtv, sizeof(rtv))) 33262306a36Sopenharmony_ci return ret; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci break; 33562306a36Sopenharmony_ci case PT_OLD_TIMEVAL: 33662306a36Sopenharmony_ci { 33762306a36Sopenharmony_ci struct old_timeval32 rtv; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci rtv.tv_sec = rts.tv_sec; 34062306a36Sopenharmony_ci rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC; 34162306a36Sopenharmony_ci if (!copy_to_user(p, &rtv, sizeof(rtv))) 34262306a36Sopenharmony_ci return ret; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci break; 34562306a36Sopenharmony_ci case PT_TIMESPEC: 34662306a36Sopenharmony_ci if (!put_timespec64(&rts, p)) 34762306a36Sopenharmony_ci return ret; 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci case PT_OLD_TIMESPEC: 35062306a36Sopenharmony_ci if (!put_old_timespec32(&rts, p)) 35162306a36Sopenharmony_ci return ret; 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci default: 35462306a36Sopenharmony_ci BUG(); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci /* 35762306a36Sopenharmony_ci * If an application puts its timeval in read-only memory, we 35862306a36Sopenharmony_ci * don't want the Linux-specific update to the timeval to 35962306a36Sopenharmony_ci * cause a fault after the select has completed 36062306a36Sopenharmony_ci * successfully. However, because we're not updating the 36162306a36Sopenharmony_ci * timeval, we can't restart the system call. 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cisticky: 36562306a36Sopenharmony_ci if (ret == -ERESTARTNOHAND) 36662306a36Sopenharmony_ci ret = -EINTR; 36762306a36Sopenharmony_ci return ret; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci/* 37162306a36Sopenharmony_ci * Scalable version of the fd_set. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_citypedef struct { 37562306a36Sopenharmony_ci unsigned long *in, *out, *ex; 37662306a36Sopenharmony_ci unsigned long *res_in, *res_out, *res_ex; 37762306a36Sopenharmony_ci} fd_set_bits; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/* 38062306a36Sopenharmony_ci * How many longwords for "nr" bits? 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci#define FDS_BITPERLONG (8*sizeof(long)) 38362306a36Sopenharmony_ci#define FDS_LONGS(nr) (((nr)+FDS_BITPERLONG-1)/FDS_BITPERLONG) 38462306a36Sopenharmony_ci#define FDS_BYTES(nr) (FDS_LONGS(nr)*sizeof(long)) 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci/* 38762306a36Sopenharmony_ci * Use "unsigned long" accesses to let user-mode fd_set's be long-aligned. 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_cistatic inline 39062306a36Sopenharmony_ciint get_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci nr = FDS_BYTES(nr); 39362306a36Sopenharmony_ci if (ufdset) 39462306a36Sopenharmony_ci return copy_from_user(fdset, ufdset, nr) ? -EFAULT : 0; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci memset(fdset, 0, nr); 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic inline unsigned long __must_check 40162306a36Sopenharmony_ciset_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci if (ufdset) 40462306a36Sopenharmony_ci return __copy_to_user(ufdset, fdset, FDS_BYTES(nr)); 40562306a36Sopenharmony_ci return 0; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic inline 40962306a36Sopenharmony_civoid zero_fd_set(unsigned long nr, unsigned long *fdset) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci memset(fdset, 0, FDS_BYTES(nr)); 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci#define FDS_IN(fds, n) (fds->in + n) 41562306a36Sopenharmony_ci#define FDS_OUT(fds, n) (fds->out + n) 41662306a36Sopenharmony_ci#define FDS_EX(fds, n) (fds->ex + n) 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci#define BITS(fds, n) (*FDS_IN(fds, n)|*FDS_OUT(fds, n)|*FDS_EX(fds, n)) 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic int max_select_fd(unsigned long n, fd_set_bits *fds) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci unsigned long *open_fds; 42362306a36Sopenharmony_ci unsigned long set; 42462306a36Sopenharmony_ci int max; 42562306a36Sopenharmony_ci struct fdtable *fdt; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* handle last in-complete long-word first */ 42862306a36Sopenharmony_ci set = ~(~0UL << (n & (BITS_PER_LONG-1))); 42962306a36Sopenharmony_ci n /= BITS_PER_LONG; 43062306a36Sopenharmony_ci fdt = files_fdtable(current->files); 43162306a36Sopenharmony_ci open_fds = fdt->open_fds + n; 43262306a36Sopenharmony_ci max = 0; 43362306a36Sopenharmony_ci if (set) { 43462306a36Sopenharmony_ci set &= BITS(fds, n); 43562306a36Sopenharmony_ci if (set) { 43662306a36Sopenharmony_ci if (!(set & ~*open_fds)) 43762306a36Sopenharmony_ci goto get_max; 43862306a36Sopenharmony_ci return -EBADF; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci while (n) { 44262306a36Sopenharmony_ci open_fds--; 44362306a36Sopenharmony_ci n--; 44462306a36Sopenharmony_ci set = BITS(fds, n); 44562306a36Sopenharmony_ci if (!set) 44662306a36Sopenharmony_ci continue; 44762306a36Sopenharmony_ci if (set & ~*open_fds) 44862306a36Sopenharmony_ci return -EBADF; 44962306a36Sopenharmony_ci if (max) 45062306a36Sopenharmony_ci continue; 45162306a36Sopenharmony_ciget_max: 45262306a36Sopenharmony_ci do { 45362306a36Sopenharmony_ci max++; 45462306a36Sopenharmony_ci set >>= 1; 45562306a36Sopenharmony_ci } while (set); 45662306a36Sopenharmony_ci max += n * BITS_PER_LONG; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return max; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci#define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR |\ 46362306a36Sopenharmony_ci EPOLLNVAL) 46462306a36Sopenharmony_ci#define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT | EPOLLERR |\ 46562306a36Sopenharmony_ci EPOLLNVAL) 46662306a36Sopenharmony_ci#define POLLEX_SET (EPOLLPRI | EPOLLNVAL) 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic inline void wait_key_set(poll_table *wait, unsigned long in, 46962306a36Sopenharmony_ci unsigned long out, unsigned long bit, 47062306a36Sopenharmony_ci __poll_t ll_flag) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci wait->_key = POLLEX_SET | ll_flag; 47362306a36Sopenharmony_ci if (in & bit) 47462306a36Sopenharmony_ci wait->_key |= POLLIN_SET; 47562306a36Sopenharmony_ci if (out & bit) 47662306a36Sopenharmony_ci wait->_key |= POLLOUT_SET; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic noinline_for_stack int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci ktime_t expire, *to = NULL; 48262306a36Sopenharmony_ci struct poll_wqueues table; 48362306a36Sopenharmony_ci poll_table *wait; 48462306a36Sopenharmony_ci int retval, i, timed_out = 0; 48562306a36Sopenharmony_ci u64 slack = 0; 48662306a36Sopenharmony_ci __poll_t busy_flag = net_busy_loop_on() ? POLL_BUSY_LOOP : 0; 48762306a36Sopenharmony_ci unsigned long busy_start = 0; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci rcu_read_lock(); 49062306a36Sopenharmony_ci retval = max_select_fd(n, fds); 49162306a36Sopenharmony_ci rcu_read_unlock(); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (retval < 0) 49462306a36Sopenharmony_ci return retval; 49562306a36Sopenharmony_ci n = retval; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci poll_initwait(&table); 49862306a36Sopenharmony_ci wait = &table.pt; 49962306a36Sopenharmony_ci if (end_time && !end_time->tv_sec && !end_time->tv_nsec) { 50062306a36Sopenharmony_ci wait->_qproc = NULL; 50162306a36Sopenharmony_ci timed_out = 1; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (end_time && !timed_out) 50562306a36Sopenharmony_ci slack = select_estimate_accuracy(end_time); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci retval = 0; 50862306a36Sopenharmony_ci for (;;) { 50962306a36Sopenharmony_ci unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp; 51062306a36Sopenharmony_ci bool can_busy_loop = false; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci inp = fds->in; outp = fds->out; exp = fds->ex; 51362306a36Sopenharmony_ci rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci for (i = 0; i < n; ++rinp, ++routp, ++rexp) { 51662306a36Sopenharmony_ci unsigned long in, out, ex, all_bits, bit = 1, j; 51762306a36Sopenharmony_ci unsigned long res_in = 0, res_out = 0, res_ex = 0; 51862306a36Sopenharmony_ci __poll_t mask; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci in = *inp++; out = *outp++; ex = *exp++; 52162306a36Sopenharmony_ci all_bits = in | out | ex; 52262306a36Sopenharmony_ci if (all_bits == 0) { 52362306a36Sopenharmony_ci i += BITS_PER_LONG; 52462306a36Sopenharmony_ci continue; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci for (j = 0; j < BITS_PER_LONG; ++j, ++i, bit <<= 1) { 52862306a36Sopenharmony_ci struct fd f; 52962306a36Sopenharmony_ci if (i >= n) 53062306a36Sopenharmony_ci break; 53162306a36Sopenharmony_ci if (!(bit & all_bits)) 53262306a36Sopenharmony_ci continue; 53362306a36Sopenharmony_ci mask = EPOLLNVAL; 53462306a36Sopenharmony_ci f = fdget(i); 53562306a36Sopenharmony_ci if (f.file) { 53662306a36Sopenharmony_ci wait_key_set(wait, in, out, bit, 53762306a36Sopenharmony_ci busy_flag); 53862306a36Sopenharmony_ci mask = vfs_poll(f.file, wait); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci fdput(f); 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci if ((mask & POLLIN_SET) && (in & bit)) { 54362306a36Sopenharmony_ci res_in |= bit; 54462306a36Sopenharmony_ci retval++; 54562306a36Sopenharmony_ci wait->_qproc = NULL; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci if ((mask & POLLOUT_SET) && (out & bit)) { 54862306a36Sopenharmony_ci res_out |= bit; 54962306a36Sopenharmony_ci retval++; 55062306a36Sopenharmony_ci wait->_qproc = NULL; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci if ((mask & POLLEX_SET) && (ex & bit)) { 55362306a36Sopenharmony_ci res_ex |= bit; 55462306a36Sopenharmony_ci retval++; 55562306a36Sopenharmony_ci wait->_qproc = NULL; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci /* got something, stop busy polling */ 55862306a36Sopenharmony_ci if (retval) { 55962306a36Sopenharmony_ci can_busy_loop = false; 56062306a36Sopenharmony_ci busy_flag = 0; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* 56362306a36Sopenharmony_ci * only remember a returned 56462306a36Sopenharmony_ci * POLL_BUSY_LOOP if we asked for it 56562306a36Sopenharmony_ci */ 56662306a36Sopenharmony_ci } else if (busy_flag & mask) 56762306a36Sopenharmony_ci can_busy_loop = true; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci if (res_in) 57162306a36Sopenharmony_ci *rinp = res_in; 57262306a36Sopenharmony_ci if (res_out) 57362306a36Sopenharmony_ci *routp = res_out; 57462306a36Sopenharmony_ci if (res_ex) 57562306a36Sopenharmony_ci *rexp = res_ex; 57662306a36Sopenharmony_ci cond_resched(); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci wait->_qproc = NULL; 57962306a36Sopenharmony_ci if (retval || timed_out || signal_pending(current)) 58062306a36Sopenharmony_ci break; 58162306a36Sopenharmony_ci if (table.error) { 58262306a36Sopenharmony_ci retval = table.error; 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* only if found POLL_BUSY_LOOP sockets && not out of time */ 58762306a36Sopenharmony_ci if (can_busy_loop && !need_resched()) { 58862306a36Sopenharmony_ci if (!busy_start) { 58962306a36Sopenharmony_ci busy_start = busy_loop_current_time(); 59062306a36Sopenharmony_ci continue; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci if (!busy_loop_timeout(busy_start)) 59362306a36Sopenharmony_ci continue; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci busy_flag = 0; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* 59862306a36Sopenharmony_ci * If this is the first loop and we have a timeout 59962306a36Sopenharmony_ci * given, then we convert to ktime_t and set the to 60062306a36Sopenharmony_ci * pointer to the expiry value. 60162306a36Sopenharmony_ci */ 60262306a36Sopenharmony_ci if (end_time && !to) { 60362306a36Sopenharmony_ci expire = timespec64_to_ktime(*end_time); 60462306a36Sopenharmony_ci to = &expire; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci if (!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE, 60862306a36Sopenharmony_ci to, slack)) 60962306a36Sopenharmony_ci timed_out = 1; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci poll_freewait(&table); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci return retval; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci/* 61862306a36Sopenharmony_ci * We can actually return ERESTARTSYS instead of EINTR, but I'd 61962306a36Sopenharmony_ci * like to be certain this leads to no problems. So I return 62062306a36Sopenharmony_ci * EINTR just for safety. 62162306a36Sopenharmony_ci * 62262306a36Sopenharmony_ci * Update: ERESTARTSYS breaks at least the xview clock binary, so 62362306a36Sopenharmony_ci * I'm trying ERESTARTNOHAND which restart only when you want to. 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ciint core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, 62662306a36Sopenharmony_ci fd_set __user *exp, struct timespec64 *end_time) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci fd_set_bits fds; 62962306a36Sopenharmony_ci void *bits; 63062306a36Sopenharmony_ci int ret, max_fds; 63162306a36Sopenharmony_ci size_t size, alloc_size; 63262306a36Sopenharmony_ci struct fdtable *fdt; 63362306a36Sopenharmony_ci /* Allocate small arguments on the stack to save memory and be faster */ 63462306a36Sopenharmony_ci long stack_fds[SELECT_STACK_ALLOC/sizeof(long)]; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ret = -EINVAL; 63762306a36Sopenharmony_ci if (n < 0) 63862306a36Sopenharmony_ci goto out_nofds; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* max_fds can increase, so grab it once to avoid race */ 64162306a36Sopenharmony_ci rcu_read_lock(); 64262306a36Sopenharmony_ci fdt = files_fdtable(current->files); 64362306a36Sopenharmony_ci max_fds = fdt->max_fds; 64462306a36Sopenharmony_ci rcu_read_unlock(); 64562306a36Sopenharmony_ci if (n > max_fds) 64662306a36Sopenharmony_ci n = max_fds; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* 64962306a36Sopenharmony_ci * We need 6 bitmaps (in/out/ex for both incoming and outgoing), 65062306a36Sopenharmony_ci * since we used fdset we need to allocate memory in units of 65162306a36Sopenharmony_ci * long-words. 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_ci size = FDS_BYTES(n); 65462306a36Sopenharmony_ci bits = stack_fds; 65562306a36Sopenharmony_ci if (size > sizeof(stack_fds) / 6) { 65662306a36Sopenharmony_ci /* Not enough space in on-stack array; must use kmalloc */ 65762306a36Sopenharmony_ci ret = -ENOMEM; 65862306a36Sopenharmony_ci if (size > (SIZE_MAX / 6)) 65962306a36Sopenharmony_ci goto out_nofds; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci alloc_size = 6 * size; 66262306a36Sopenharmony_ci bits = kvmalloc(alloc_size, GFP_KERNEL); 66362306a36Sopenharmony_ci if (!bits) 66462306a36Sopenharmony_ci goto out_nofds; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci fds.in = bits; 66762306a36Sopenharmony_ci fds.out = bits + size; 66862306a36Sopenharmony_ci fds.ex = bits + 2*size; 66962306a36Sopenharmony_ci fds.res_in = bits + 3*size; 67062306a36Sopenharmony_ci fds.res_out = bits + 4*size; 67162306a36Sopenharmony_ci fds.res_ex = bits + 5*size; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if ((ret = get_fd_set(n, inp, fds.in)) || 67462306a36Sopenharmony_ci (ret = get_fd_set(n, outp, fds.out)) || 67562306a36Sopenharmony_ci (ret = get_fd_set(n, exp, fds.ex))) 67662306a36Sopenharmony_ci goto out; 67762306a36Sopenharmony_ci zero_fd_set(n, fds.res_in); 67862306a36Sopenharmony_ci zero_fd_set(n, fds.res_out); 67962306a36Sopenharmony_ci zero_fd_set(n, fds.res_ex); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci ret = do_select(n, &fds, end_time); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (ret < 0) 68462306a36Sopenharmony_ci goto out; 68562306a36Sopenharmony_ci if (!ret) { 68662306a36Sopenharmony_ci ret = -ERESTARTNOHAND; 68762306a36Sopenharmony_ci if (signal_pending(current)) 68862306a36Sopenharmony_ci goto out; 68962306a36Sopenharmony_ci ret = 0; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (set_fd_set(n, inp, fds.res_in) || 69362306a36Sopenharmony_ci set_fd_set(n, outp, fds.res_out) || 69462306a36Sopenharmony_ci set_fd_set(n, exp, fds.res_ex)) 69562306a36Sopenharmony_ci ret = -EFAULT; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ciout: 69862306a36Sopenharmony_ci if (bits != stack_fds) 69962306a36Sopenharmony_ci kvfree(bits); 70062306a36Sopenharmony_ciout_nofds: 70162306a36Sopenharmony_ci return ret; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic int kern_select(int n, fd_set __user *inp, fd_set __user *outp, 70562306a36Sopenharmony_ci fd_set __user *exp, struct __kernel_old_timeval __user *tvp) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci struct timespec64 end_time, *to = NULL; 70862306a36Sopenharmony_ci struct __kernel_old_timeval tv; 70962306a36Sopenharmony_ci int ret; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (tvp) { 71262306a36Sopenharmony_ci if (copy_from_user(&tv, tvp, sizeof(tv))) 71362306a36Sopenharmony_ci return -EFAULT; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci to = &end_time; 71662306a36Sopenharmony_ci if (poll_select_set_timeout(to, 71762306a36Sopenharmony_ci tv.tv_sec + (tv.tv_usec / USEC_PER_SEC), 71862306a36Sopenharmony_ci (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC)) 71962306a36Sopenharmony_ci return -EINVAL; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci ret = core_sys_select(n, inp, outp, exp, to); 72362306a36Sopenharmony_ci return poll_select_finish(&end_time, tvp, PT_TIMEVAL, ret); 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ciSYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp, 72762306a36Sopenharmony_ci fd_set __user *, exp, struct __kernel_old_timeval __user *, tvp) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci return kern_select(n, inp, outp, exp, tvp); 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic long do_pselect(int n, fd_set __user *inp, fd_set __user *outp, 73362306a36Sopenharmony_ci fd_set __user *exp, void __user *tsp, 73462306a36Sopenharmony_ci const sigset_t __user *sigmask, size_t sigsetsize, 73562306a36Sopenharmony_ci enum poll_time_type type) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci struct timespec64 ts, end_time, *to = NULL; 73862306a36Sopenharmony_ci int ret; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (tsp) { 74162306a36Sopenharmony_ci switch (type) { 74262306a36Sopenharmony_ci case PT_TIMESPEC: 74362306a36Sopenharmony_ci if (get_timespec64(&ts, tsp)) 74462306a36Sopenharmony_ci return -EFAULT; 74562306a36Sopenharmony_ci break; 74662306a36Sopenharmony_ci case PT_OLD_TIMESPEC: 74762306a36Sopenharmony_ci if (get_old_timespec32(&ts, tsp)) 74862306a36Sopenharmony_ci return -EFAULT; 74962306a36Sopenharmony_ci break; 75062306a36Sopenharmony_ci default: 75162306a36Sopenharmony_ci BUG(); 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci to = &end_time; 75562306a36Sopenharmony_ci if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) 75662306a36Sopenharmony_ci return -EINVAL; 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci ret = set_user_sigmask(sigmask, sigsetsize); 76062306a36Sopenharmony_ci if (ret) 76162306a36Sopenharmony_ci return ret; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci ret = core_sys_select(n, inp, outp, exp, to); 76462306a36Sopenharmony_ci return poll_select_finish(&end_time, tsp, type, ret); 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci/* 76862306a36Sopenharmony_ci * Most architectures can't handle 7-argument syscalls. So we provide a 76962306a36Sopenharmony_ci * 6-argument version where the sixth argument is a pointer to a structure 77062306a36Sopenharmony_ci * which has a pointer to the sigset_t itself followed by a size_t containing 77162306a36Sopenharmony_ci * the sigset size. 77262306a36Sopenharmony_ci */ 77362306a36Sopenharmony_cistruct sigset_argpack { 77462306a36Sopenharmony_ci sigset_t __user *p; 77562306a36Sopenharmony_ci size_t size; 77662306a36Sopenharmony_ci}; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic inline int get_sigset_argpack(struct sigset_argpack *to, 77962306a36Sopenharmony_ci struct sigset_argpack __user *from) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci // the path is hot enough for overhead of copy_from_user() to matter 78262306a36Sopenharmony_ci if (from) { 78362306a36Sopenharmony_ci if (!user_read_access_begin(from, sizeof(*from))) 78462306a36Sopenharmony_ci return -EFAULT; 78562306a36Sopenharmony_ci unsafe_get_user(to->p, &from->p, Efault); 78662306a36Sopenharmony_ci unsafe_get_user(to->size, &from->size, Efault); 78762306a36Sopenharmony_ci user_read_access_end(); 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci return 0; 79062306a36Sopenharmony_ciEfault: 79162306a36Sopenharmony_ci user_access_end(); 79262306a36Sopenharmony_ci return -EFAULT; 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ciSYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp, 79662306a36Sopenharmony_ci fd_set __user *, exp, struct __kernel_timespec __user *, tsp, 79762306a36Sopenharmony_ci void __user *, sig) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci struct sigset_argpack x = {NULL, 0}; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (get_sigset_argpack(&x, sig)) 80262306a36Sopenharmony_ci return -EFAULT; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci return do_pselect(n, inp, outp, exp, tsp, x.p, x.size, PT_TIMESPEC); 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT) 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ciSYSCALL_DEFINE6(pselect6_time32, int, n, fd_set __user *, inp, fd_set __user *, outp, 81062306a36Sopenharmony_ci fd_set __user *, exp, struct old_timespec32 __user *, tsp, 81162306a36Sopenharmony_ci void __user *, sig) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci struct sigset_argpack x = {NULL, 0}; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (get_sigset_argpack(&x, sig)) 81662306a36Sopenharmony_ci return -EFAULT; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci return do_pselect(n, inp, outp, exp, tsp, x.p, x.size, PT_OLD_TIMESPEC); 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci#endif 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci#ifdef __ARCH_WANT_SYS_OLD_SELECT 82462306a36Sopenharmony_cistruct sel_arg_struct { 82562306a36Sopenharmony_ci unsigned long n; 82662306a36Sopenharmony_ci fd_set __user *inp, *outp, *exp; 82762306a36Sopenharmony_ci struct __kernel_old_timeval __user *tvp; 82862306a36Sopenharmony_ci}; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ciSYSCALL_DEFINE1(old_select, struct sel_arg_struct __user *, arg) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci struct sel_arg_struct a; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (copy_from_user(&a, arg, sizeof(a))) 83562306a36Sopenharmony_ci return -EFAULT; 83662306a36Sopenharmony_ci return kern_select(a.n, a.inp, a.outp, a.exp, a.tvp); 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ci#endif 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistruct poll_list { 84162306a36Sopenharmony_ci struct poll_list *next; 84262306a36Sopenharmony_ci int len; 84362306a36Sopenharmony_ci struct pollfd entries[]; 84462306a36Sopenharmony_ci}; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci#define POLLFD_PER_PAGE ((PAGE_SIZE-sizeof(struct poll_list)) / sizeof(struct pollfd)) 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci/* 84962306a36Sopenharmony_ci * Fish for pollable events on the pollfd->fd file descriptor. We're only 85062306a36Sopenharmony_ci * interested in events matching the pollfd->events mask, and the result 85162306a36Sopenharmony_ci * matching that mask is both recorded in pollfd->revents and returned. The 85262306a36Sopenharmony_ci * pwait poll_table will be used by the fd-provided poll handler for waiting, 85362306a36Sopenharmony_ci * if pwait->_qproc is non-NULL. 85462306a36Sopenharmony_ci */ 85562306a36Sopenharmony_cistatic inline __poll_t do_pollfd(struct pollfd *pollfd, poll_table *pwait, 85662306a36Sopenharmony_ci bool *can_busy_poll, 85762306a36Sopenharmony_ci __poll_t busy_flag) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci int fd = pollfd->fd; 86062306a36Sopenharmony_ci __poll_t mask = 0, filter; 86162306a36Sopenharmony_ci struct fd f; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci if (fd < 0) 86462306a36Sopenharmony_ci goto out; 86562306a36Sopenharmony_ci mask = EPOLLNVAL; 86662306a36Sopenharmony_ci f = fdget(fd); 86762306a36Sopenharmony_ci if (!f.file) 86862306a36Sopenharmony_ci goto out; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* userland u16 ->events contains POLL... bitmap */ 87162306a36Sopenharmony_ci filter = demangle_poll(pollfd->events) | EPOLLERR | EPOLLHUP; 87262306a36Sopenharmony_ci pwait->_key = filter | busy_flag; 87362306a36Sopenharmony_ci mask = vfs_poll(f.file, pwait); 87462306a36Sopenharmony_ci if (mask & busy_flag) 87562306a36Sopenharmony_ci *can_busy_poll = true; 87662306a36Sopenharmony_ci mask &= filter; /* Mask out unneeded events. */ 87762306a36Sopenharmony_ci fdput(f); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ciout: 88062306a36Sopenharmony_ci /* ... and so does ->revents */ 88162306a36Sopenharmony_ci pollfd->revents = mangle_poll(mask); 88262306a36Sopenharmony_ci return mask; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic int do_poll(struct poll_list *list, struct poll_wqueues *wait, 88662306a36Sopenharmony_ci struct timespec64 *end_time) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci poll_table* pt = &wait->pt; 88962306a36Sopenharmony_ci ktime_t expire, *to = NULL; 89062306a36Sopenharmony_ci int timed_out = 0, count = 0; 89162306a36Sopenharmony_ci u64 slack = 0; 89262306a36Sopenharmony_ci __poll_t busy_flag = net_busy_loop_on() ? POLL_BUSY_LOOP : 0; 89362306a36Sopenharmony_ci unsigned long busy_start = 0; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci /* Optimise the no-wait case */ 89662306a36Sopenharmony_ci if (end_time && !end_time->tv_sec && !end_time->tv_nsec) { 89762306a36Sopenharmony_ci pt->_qproc = NULL; 89862306a36Sopenharmony_ci timed_out = 1; 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (end_time && !timed_out) 90262306a36Sopenharmony_ci slack = select_estimate_accuracy(end_time); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci for (;;) { 90562306a36Sopenharmony_ci struct poll_list *walk; 90662306a36Sopenharmony_ci bool can_busy_loop = false; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci for (walk = list; walk != NULL; walk = walk->next) { 90962306a36Sopenharmony_ci struct pollfd * pfd, * pfd_end; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci pfd = walk->entries; 91262306a36Sopenharmony_ci pfd_end = pfd + walk->len; 91362306a36Sopenharmony_ci for (; pfd != pfd_end; pfd++) { 91462306a36Sopenharmony_ci /* 91562306a36Sopenharmony_ci * Fish for events. If we found one, record it 91662306a36Sopenharmony_ci * and kill poll_table->_qproc, so we don't 91762306a36Sopenharmony_ci * needlessly register any other waiters after 91862306a36Sopenharmony_ci * this. They'll get immediately deregistered 91962306a36Sopenharmony_ci * when we break out and return. 92062306a36Sopenharmony_ci */ 92162306a36Sopenharmony_ci if (do_pollfd(pfd, pt, &can_busy_loop, 92262306a36Sopenharmony_ci busy_flag)) { 92362306a36Sopenharmony_ci count++; 92462306a36Sopenharmony_ci pt->_qproc = NULL; 92562306a36Sopenharmony_ci /* found something, stop busy polling */ 92662306a36Sopenharmony_ci busy_flag = 0; 92762306a36Sopenharmony_ci can_busy_loop = false; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci /* 93262306a36Sopenharmony_ci * All waiters have already been registered, so don't provide 93362306a36Sopenharmony_ci * a poll_table->_qproc to them on the next loop iteration. 93462306a36Sopenharmony_ci */ 93562306a36Sopenharmony_ci pt->_qproc = NULL; 93662306a36Sopenharmony_ci if (!count) { 93762306a36Sopenharmony_ci count = wait->error; 93862306a36Sopenharmony_ci if (signal_pending(current)) 93962306a36Sopenharmony_ci count = -ERESTARTNOHAND; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci if (count || timed_out) 94262306a36Sopenharmony_ci break; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* only if found POLL_BUSY_LOOP sockets && not out of time */ 94562306a36Sopenharmony_ci if (can_busy_loop && !need_resched()) { 94662306a36Sopenharmony_ci if (!busy_start) { 94762306a36Sopenharmony_ci busy_start = busy_loop_current_time(); 94862306a36Sopenharmony_ci continue; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci if (!busy_loop_timeout(busy_start)) 95162306a36Sopenharmony_ci continue; 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci busy_flag = 0; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci /* 95662306a36Sopenharmony_ci * If this is the first loop and we have a timeout 95762306a36Sopenharmony_ci * given, then we convert to ktime_t and set the to 95862306a36Sopenharmony_ci * pointer to the expiry value. 95962306a36Sopenharmony_ci */ 96062306a36Sopenharmony_ci if (end_time && !to) { 96162306a36Sopenharmony_ci expire = timespec64_to_ktime(*end_time); 96262306a36Sopenharmony_ci to = &expire; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (!poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack)) 96662306a36Sopenharmony_ci timed_out = 1; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci return count; 96962306a36Sopenharmony_ci} 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci#define N_STACK_PPS ((sizeof(stack_pps) - sizeof(struct poll_list)) / \ 97262306a36Sopenharmony_ci sizeof(struct pollfd)) 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_cistatic int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, 97562306a36Sopenharmony_ci struct timespec64 *end_time) 97662306a36Sopenharmony_ci{ 97762306a36Sopenharmony_ci struct poll_wqueues table; 97862306a36Sopenharmony_ci int err = -EFAULT, fdcount, len; 97962306a36Sopenharmony_ci /* Allocate small arguments on the stack to save memory and be 98062306a36Sopenharmony_ci faster - use long to make sure the buffer is aligned properly 98162306a36Sopenharmony_ci on 64 bit archs to avoid unaligned access */ 98262306a36Sopenharmony_ci long stack_pps[POLL_STACK_ALLOC/sizeof(long)]; 98362306a36Sopenharmony_ci struct poll_list *const head = (struct poll_list *)stack_pps; 98462306a36Sopenharmony_ci struct poll_list *walk = head; 98562306a36Sopenharmony_ci unsigned long todo = nfds; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci if (nfds > rlimit(RLIMIT_NOFILE)) 98862306a36Sopenharmony_ci return -EINVAL; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci len = min_t(unsigned int, nfds, N_STACK_PPS); 99162306a36Sopenharmony_ci for (;;) { 99262306a36Sopenharmony_ci walk->next = NULL; 99362306a36Sopenharmony_ci walk->len = len; 99462306a36Sopenharmony_ci if (!len) 99562306a36Sopenharmony_ci break; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci if (copy_from_user(walk->entries, ufds + nfds-todo, 99862306a36Sopenharmony_ci sizeof(struct pollfd) * walk->len)) 99962306a36Sopenharmony_ci goto out_fds; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci todo -= walk->len; 100262306a36Sopenharmony_ci if (!todo) 100362306a36Sopenharmony_ci break; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci len = min(todo, POLLFD_PER_PAGE); 100662306a36Sopenharmony_ci walk = walk->next = kmalloc(struct_size(walk, entries, len), 100762306a36Sopenharmony_ci GFP_KERNEL); 100862306a36Sopenharmony_ci if (!walk) { 100962306a36Sopenharmony_ci err = -ENOMEM; 101062306a36Sopenharmony_ci goto out_fds; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci poll_initwait(&table); 101562306a36Sopenharmony_ci fdcount = do_poll(head, &table, end_time); 101662306a36Sopenharmony_ci poll_freewait(&table); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci if (!user_write_access_begin(ufds, nfds * sizeof(*ufds))) 101962306a36Sopenharmony_ci goto out_fds; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci for (walk = head; walk; walk = walk->next) { 102262306a36Sopenharmony_ci struct pollfd *fds = walk->entries; 102362306a36Sopenharmony_ci int j; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci for (j = walk->len; j; fds++, ufds++, j--) 102662306a36Sopenharmony_ci unsafe_put_user(fds->revents, &ufds->revents, Efault); 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci user_write_access_end(); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci err = fdcount; 103162306a36Sopenharmony_ciout_fds: 103262306a36Sopenharmony_ci walk = head->next; 103362306a36Sopenharmony_ci while (walk) { 103462306a36Sopenharmony_ci struct poll_list *pos = walk; 103562306a36Sopenharmony_ci walk = walk->next; 103662306a36Sopenharmony_ci kfree(pos); 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci return err; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ciEfault: 104262306a36Sopenharmony_ci user_write_access_end(); 104362306a36Sopenharmony_ci err = -EFAULT; 104462306a36Sopenharmony_ci goto out_fds; 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cistatic long do_restart_poll(struct restart_block *restart_block) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci struct pollfd __user *ufds = restart_block->poll.ufds; 105062306a36Sopenharmony_ci int nfds = restart_block->poll.nfds; 105162306a36Sopenharmony_ci struct timespec64 *to = NULL, end_time; 105262306a36Sopenharmony_ci int ret; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (restart_block->poll.has_timeout) { 105562306a36Sopenharmony_ci end_time.tv_sec = restart_block->poll.tv_sec; 105662306a36Sopenharmony_ci end_time.tv_nsec = restart_block->poll.tv_nsec; 105762306a36Sopenharmony_ci to = &end_time; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci ret = do_sys_poll(ufds, nfds, to); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (ret == -ERESTARTNOHAND) 106362306a36Sopenharmony_ci ret = set_restart_fn(restart_block, do_restart_poll); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci return ret; 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ciSYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds, 106962306a36Sopenharmony_ci int, timeout_msecs) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci struct timespec64 end_time, *to = NULL; 107262306a36Sopenharmony_ci int ret; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci if (timeout_msecs >= 0) { 107562306a36Sopenharmony_ci to = &end_time; 107662306a36Sopenharmony_ci poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC, 107762306a36Sopenharmony_ci NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC)); 107862306a36Sopenharmony_ci } 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci ret = do_sys_poll(ufds, nfds, to); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (ret == -ERESTARTNOHAND) { 108362306a36Sopenharmony_ci struct restart_block *restart_block; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci restart_block = ¤t->restart_block; 108662306a36Sopenharmony_ci restart_block->poll.ufds = ufds; 108762306a36Sopenharmony_ci restart_block->poll.nfds = nfds; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (timeout_msecs >= 0) { 109062306a36Sopenharmony_ci restart_block->poll.tv_sec = end_time.tv_sec; 109162306a36Sopenharmony_ci restart_block->poll.tv_nsec = end_time.tv_nsec; 109262306a36Sopenharmony_ci restart_block->poll.has_timeout = 1; 109362306a36Sopenharmony_ci } else 109462306a36Sopenharmony_ci restart_block->poll.has_timeout = 0; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci ret = set_restart_fn(restart_block, do_restart_poll); 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci return ret; 109962306a36Sopenharmony_ci} 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ciSYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, 110262306a36Sopenharmony_ci struct __kernel_timespec __user *, tsp, const sigset_t __user *, sigmask, 110362306a36Sopenharmony_ci size_t, sigsetsize) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci struct timespec64 ts, end_time, *to = NULL; 110662306a36Sopenharmony_ci int ret; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (tsp) { 110962306a36Sopenharmony_ci if (get_timespec64(&ts, tsp)) 111062306a36Sopenharmony_ci return -EFAULT; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci to = &end_time; 111362306a36Sopenharmony_ci if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) 111462306a36Sopenharmony_ci return -EINVAL; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci ret = set_user_sigmask(sigmask, sigsetsize); 111862306a36Sopenharmony_ci if (ret) 111962306a36Sopenharmony_ci return ret; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci ret = do_sys_poll(ufds, nfds, to); 112262306a36Sopenharmony_ci return poll_select_finish(&end_time, tsp, PT_TIMESPEC, ret); 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT) 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ciSYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, unsigned int, nfds, 112862306a36Sopenharmony_ci struct old_timespec32 __user *, tsp, const sigset_t __user *, sigmask, 112962306a36Sopenharmony_ci size_t, sigsetsize) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci struct timespec64 ts, end_time, *to = NULL; 113262306a36Sopenharmony_ci int ret; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (tsp) { 113562306a36Sopenharmony_ci if (get_old_timespec32(&ts, tsp)) 113662306a36Sopenharmony_ci return -EFAULT; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci to = &end_time; 113962306a36Sopenharmony_ci if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) 114062306a36Sopenharmony_ci return -EINVAL; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci ret = set_user_sigmask(sigmask, sigsetsize); 114462306a36Sopenharmony_ci if (ret) 114562306a36Sopenharmony_ci return ret; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci ret = do_sys_poll(ufds, nfds, to); 114862306a36Sopenharmony_ci return poll_select_finish(&end_time, tsp, PT_OLD_TIMESPEC, ret); 114962306a36Sopenharmony_ci} 115062306a36Sopenharmony_ci#endif 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 115362306a36Sopenharmony_ci#define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t)) 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci/* 115662306a36Sopenharmony_ci * Ooo, nasty. We need here to frob 32-bit unsigned longs to 115762306a36Sopenharmony_ci * 64-bit unsigned longs. 115862306a36Sopenharmony_ci */ 115962306a36Sopenharmony_cistatic 116062306a36Sopenharmony_ciint compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, 116162306a36Sopenharmony_ci unsigned long *fdset) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci if (ufdset) { 116462306a36Sopenharmony_ci return compat_get_bitmap(fdset, ufdset, nr); 116562306a36Sopenharmony_ci } else { 116662306a36Sopenharmony_ci zero_fd_set(nr, fdset); 116762306a36Sopenharmony_ci return 0; 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_cistatic 117262306a36Sopenharmony_ciint compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, 117362306a36Sopenharmony_ci unsigned long *fdset) 117462306a36Sopenharmony_ci{ 117562306a36Sopenharmony_ci if (!ufdset) 117662306a36Sopenharmony_ci return 0; 117762306a36Sopenharmony_ci return compat_put_bitmap(ufdset, fdset, nr); 117862306a36Sopenharmony_ci} 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci/* 118262306a36Sopenharmony_ci * This is a virtual copy of sys_select from fs/select.c and probably 118362306a36Sopenharmony_ci * should be compared to it from time to time 118462306a36Sopenharmony_ci */ 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci/* 118762306a36Sopenharmony_ci * We can actually return ERESTARTSYS instead of EINTR, but I'd 118862306a36Sopenharmony_ci * like to be certain this leads to no problems. So I return 118962306a36Sopenharmony_ci * EINTR just for safety. 119062306a36Sopenharmony_ci * 119162306a36Sopenharmony_ci * Update: ERESTARTSYS breaks at least the xview clock binary, so 119262306a36Sopenharmony_ci * I'm trying ERESTARTNOHAND which restart only when you want to. 119362306a36Sopenharmony_ci */ 119462306a36Sopenharmony_cistatic int compat_core_sys_select(int n, compat_ulong_t __user *inp, 119562306a36Sopenharmony_ci compat_ulong_t __user *outp, compat_ulong_t __user *exp, 119662306a36Sopenharmony_ci struct timespec64 *end_time) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci fd_set_bits fds; 119962306a36Sopenharmony_ci void *bits; 120062306a36Sopenharmony_ci int size, max_fds, ret = -EINVAL; 120162306a36Sopenharmony_ci struct fdtable *fdt; 120262306a36Sopenharmony_ci long stack_fds[SELECT_STACK_ALLOC/sizeof(long)]; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci if (n < 0) 120562306a36Sopenharmony_ci goto out_nofds; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci /* max_fds can increase, so grab it once to avoid race */ 120862306a36Sopenharmony_ci rcu_read_lock(); 120962306a36Sopenharmony_ci fdt = files_fdtable(current->files); 121062306a36Sopenharmony_ci max_fds = fdt->max_fds; 121162306a36Sopenharmony_ci rcu_read_unlock(); 121262306a36Sopenharmony_ci if (n > max_fds) 121362306a36Sopenharmony_ci n = max_fds; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci /* 121662306a36Sopenharmony_ci * We need 6 bitmaps (in/out/ex for both incoming and outgoing), 121762306a36Sopenharmony_ci * since we used fdset we need to allocate memory in units of 121862306a36Sopenharmony_ci * long-words. 121962306a36Sopenharmony_ci */ 122062306a36Sopenharmony_ci size = FDS_BYTES(n); 122162306a36Sopenharmony_ci bits = stack_fds; 122262306a36Sopenharmony_ci if (size > sizeof(stack_fds) / 6) { 122362306a36Sopenharmony_ci bits = kmalloc_array(6, size, GFP_KERNEL); 122462306a36Sopenharmony_ci ret = -ENOMEM; 122562306a36Sopenharmony_ci if (!bits) 122662306a36Sopenharmony_ci goto out_nofds; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci fds.in = (unsigned long *) bits; 122962306a36Sopenharmony_ci fds.out = (unsigned long *) (bits + size); 123062306a36Sopenharmony_ci fds.ex = (unsigned long *) (bits + 2*size); 123162306a36Sopenharmony_ci fds.res_in = (unsigned long *) (bits + 3*size); 123262306a36Sopenharmony_ci fds.res_out = (unsigned long *) (bits + 4*size); 123362306a36Sopenharmony_ci fds.res_ex = (unsigned long *) (bits + 5*size); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci if ((ret = compat_get_fd_set(n, inp, fds.in)) || 123662306a36Sopenharmony_ci (ret = compat_get_fd_set(n, outp, fds.out)) || 123762306a36Sopenharmony_ci (ret = compat_get_fd_set(n, exp, fds.ex))) 123862306a36Sopenharmony_ci goto out; 123962306a36Sopenharmony_ci zero_fd_set(n, fds.res_in); 124062306a36Sopenharmony_ci zero_fd_set(n, fds.res_out); 124162306a36Sopenharmony_ci zero_fd_set(n, fds.res_ex); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci ret = do_select(n, &fds, end_time); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci if (ret < 0) 124662306a36Sopenharmony_ci goto out; 124762306a36Sopenharmony_ci if (!ret) { 124862306a36Sopenharmony_ci ret = -ERESTARTNOHAND; 124962306a36Sopenharmony_ci if (signal_pending(current)) 125062306a36Sopenharmony_ci goto out; 125162306a36Sopenharmony_ci ret = 0; 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci if (compat_set_fd_set(n, inp, fds.res_in) || 125562306a36Sopenharmony_ci compat_set_fd_set(n, outp, fds.res_out) || 125662306a36Sopenharmony_ci compat_set_fd_set(n, exp, fds.res_ex)) 125762306a36Sopenharmony_ci ret = -EFAULT; 125862306a36Sopenharmony_ciout: 125962306a36Sopenharmony_ci if (bits != stack_fds) 126062306a36Sopenharmony_ci kfree(bits); 126162306a36Sopenharmony_ciout_nofds: 126262306a36Sopenharmony_ci return ret; 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_cistatic int do_compat_select(int n, compat_ulong_t __user *inp, 126662306a36Sopenharmony_ci compat_ulong_t __user *outp, compat_ulong_t __user *exp, 126762306a36Sopenharmony_ci struct old_timeval32 __user *tvp) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci struct timespec64 end_time, *to = NULL; 127062306a36Sopenharmony_ci struct old_timeval32 tv; 127162306a36Sopenharmony_ci int ret; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (tvp) { 127462306a36Sopenharmony_ci if (copy_from_user(&tv, tvp, sizeof(tv))) 127562306a36Sopenharmony_ci return -EFAULT; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci to = &end_time; 127862306a36Sopenharmony_ci if (poll_select_set_timeout(to, 127962306a36Sopenharmony_ci tv.tv_sec + (tv.tv_usec / USEC_PER_SEC), 128062306a36Sopenharmony_ci (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC)) 128162306a36Sopenharmony_ci return -EINVAL; 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci ret = compat_core_sys_select(n, inp, outp, exp, to); 128562306a36Sopenharmony_ci return poll_select_finish(&end_time, tvp, PT_OLD_TIMEVAL, ret); 128662306a36Sopenharmony_ci} 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(select, int, n, compat_ulong_t __user *, inp, 128962306a36Sopenharmony_ci compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, 129062306a36Sopenharmony_ci struct old_timeval32 __user *, tvp) 129162306a36Sopenharmony_ci{ 129262306a36Sopenharmony_ci return do_compat_select(n, inp, outp, exp, tvp); 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_cistruct compat_sel_arg_struct { 129662306a36Sopenharmony_ci compat_ulong_t n; 129762306a36Sopenharmony_ci compat_uptr_t inp; 129862306a36Sopenharmony_ci compat_uptr_t outp; 129962306a36Sopenharmony_ci compat_uptr_t exp; 130062306a36Sopenharmony_ci compat_uptr_t tvp; 130162306a36Sopenharmony_ci}; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE1(old_select, struct compat_sel_arg_struct __user *, arg) 130462306a36Sopenharmony_ci{ 130562306a36Sopenharmony_ci struct compat_sel_arg_struct a; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci if (copy_from_user(&a, arg, sizeof(a))) 130862306a36Sopenharmony_ci return -EFAULT; 130962306a36Sopenharmony_ci return do_compat_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp), 131062306a36Sopenharmony_ci compat_ptr(a.exp), compat_ptr(a.tvp)); 131162306a36Sopenharmony_ci} 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_cistatic long do_compat_pselect(int n, compat_ulong_t __user *inp, 131462306a36Sopenharmony_ci compat_ulong_t __user *outp, compat_ulong_t __user *exp, 131562306a36Sopenharmony_ci void __user *tsp, compat_sigset_t __user *sigmask, 131662306a36Sopenharmony_ci compat_size_t sigsetsize, enum poll_time_type type) 131762306a36Sopenharmony_ci{ 131862306a36Sopenharmony_ci struct timespec64 ts, end_time, *to = NULL; 131962306a36Sopenharmony_ci int ret; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci if (tsp) { 132262306a36Sopenharmony_ci switch (type) { 132362306a36Sopenharmony_ci case PT_OLD_TIMESPEC: 132462306a36Sopenharmony_ci if (get_old_timespec32(&ts, tsp)) 132562306a36Sopenharmony_ci return -EFAULT; 132662306a36Sopenharmony_ci break; 132762306a36Sopenharmony_ci case PT_TIMESPEC: 132862306a36Sopenharmony_ci if (get_timespec64(&ts, tsp)) 132962306a36Sopenharmony_ci return -EFAULT; 133062306a36Sopenharmony_ci break; 133162306a36Sopenharmony_ci default: 133262306a36Sopenharmony_ci BUG(); 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci to = &end_time; 133662306a36Sopenharmony_ci if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) 133762306a36Sopenharmony_ci return -EINVAL; 133862306a36Sopenharmony_ci } 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci ret = set_compat_user_sigmask(sigmask, sigsetsize); 134162306a36Sopenharmony_ci if (ret) 134262306a36Sopenharmony_ci return ret; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci ret = compat_core_sys_select(n, inp, outp, exp, to); 134562306a36Sopenharmony_ci return poll_select_finish(&end_time, tsp, type, ret); 134662306a36Sopenharmony_ci} 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_cistruct compat_sigset_argpack { 134962306a36Sopenharmony_ci compat_uptr_t p; 135062306a36Sopenharmony_ci compat_size_t size; 135162306a36Sopenharmony_ci}; 135262306a36Sopenharmony_cistatic inline int get_compat_sigset_argpack(struct compat_sigset_argpack *to, 135362306a36Sopenharmony_ci struct compat_sigset_argpack __user *from) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci if (from) { 135662306a36Sopenharmony_ci if (!user_read_access_begin(from, sizeof(*from))) 135762306a36Sopenharmony_ci return -EFAULT; 135862306a36Sopenharmony_ci unsafe_get_user(to->p, &from->p, Efault); 135962306a36Sopenharmony_ci unsafe_get_user(to->size, &from->size, Efault); 136062306a36Sopenharmony_ci user_read_access_end(); 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci return 0; 136362306a36Sopenharmony_ciEfault: 136462306a36Sopenharmony_ci user_access_end(); 136562306a36Sopenharmony_ci return -EFAULT; 136662306a36Sopenharmony_ci} 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE6(pselect6_time64, int, n, compat_ulong_t __user *, inp, 136962306a36Sopenharmony_ci compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, 137062306a36Sopenharmony_ci struct __kernel_timespec __user *, tsp, void __user *, sig) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci struct compat_sigset_argpack x = {0, 0}; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci if (get_compat_sigset_argpack(&x, sig)) 137562306a36Sopenharmony_ci return -EFAULT; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(x.p), 137862306a36Sopenharmony_ci x.size, PT_TIMESPEC); 137962306a36Sopenharmony_ci} 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci#if defined(CONFIG_COMPAT_32BIT_TIME) 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE6(pselect6_time32, int, n, compat_ulong_t __user *, inp, 138462306a36Sopenharmony_ci compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, 138562306a36Sopenharmony_ci struct old_timespec32 __user *, tsp, void __user *, sig) 138662306a36Sopenharmony_ci{ 138762306a36Sopenharmony_ci struct compat_sigset_argpack x = {0, 0}; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci if (get_compat_sigset_argpack(&x, sig)) 139062306a36Sopenharmony_ci return -EFAULT; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(x.p), 139362306a36Sopenharmony_ci x.size, PT_OLD_TIMESPEC); 139462306a36Sopenharmony_ci} 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci#endif 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci#if defined(CONFIG_COMPAT_32BIT_TIME) 139962306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, 140062306a36Sopenharmony_ci unsigned int, nfds, struct old_timespec32 __user *, tsp, 140162306a36Sopenharmony_ci const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) 140262306a36Sopenharmony_ci{ 140362306a36Sopenharmony_ci struct timespec64 ts, end_time, *to = NULL; 140462306a36Sopenharmony_ci int ret; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci if (tsp) { 140762306a36Sopenharmony_ci if (get_old_timespec32(&ts, tsp)) 140862306a36Sopenharmony_ci return -EFAULT; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci to = &end_time; 141162306a36Sopenharmony_ci if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) 141262306a36Sopenharmony_ci return -EINVAL; 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci ret = set_compat_user_sigmask(sigmask, sigsetsize); 141662306a36Sopenharmony_ci if (ret) 141762306a36Sopenharmony_ci return ret; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci ret = do_sys_poll(ufds, nfds, to); 142062306a36Sopenharmony_ci return poll_select_finish(&end_time, tsp, PT_OLD_TIMESPEC, ret); 142162306a36Sopenharmony_ci} 142262306a36Sopenharmony_ci#endif 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci/* New compat syscall for 64 bit time_t*/ 142562306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(ppoll_time64, struct pollfd __user *, ufds, 142662306a36Sopenharmony_ci unsigned int, nfds, struct __kernel_timespec __user *, tsp, 142762306a36Sopenharmony_ci const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) 142862306a36Sopenharmony_ci{ 142962306a36Sopenharmony_ci struct timespec64 ts, end_time, *to = NULL; 143062306a36Sopenharmony_ci int ret; 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci if (tsp) { 143362306a36Sopenharmony_ci if (get_timespec64(&ts, tsp)) 143462306a36Sopenharmony_ci return -EFAULT; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci to = &end_time; 143762306a36Sopenharmony_ci if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) 143862306a36Sopenharmony_ci return -EINVAL; 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci ret = set_compat_user_sigmask(sigmask, sigsetsize); 144262306a36Sopenharmony_ci if (ret) 144362306a36Sopenharmony_ci return ret; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci ret = do_sys_poll(ufds, nfds, to); 144662306a36Sopenharmony_ci return poll_select_finish(&end_time, tsp, PT_TIMESPEC, ret); 144762306a36Sopenharmony_ci} 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci#endif 1450