Merge remote-tracking branch 'sm8350/lineage-20' into lineage-23.0

* sm8350/lineage-20:
  BACKPORT: epoll: fix compat syscall wire up of epoll_pwait2
  BACKPORT: epoll: wire up syscall epoll_pwait2
  UPSTREAM: epoll: add syscall epoll_pwait2
  UPSTREAM: epoll: convert internal api to timespec64
  UPSTREAM: close_range(): fix the logics in descriptor table trimming
  UPSTREAM: fs: fix fd table size alignment properly
  UPSTREAM: fs: fd tables have to be multiples of BITS_PER_LONG
  UPSTREAM: file: simplify logic in __close_range()
  UPSTREAM: file: fix close_range() for unshare+cloexec
  UPSTREAM: close_range: unshare all fds for CLOSE_RANGE_UNSHARE | CLOSE_RANGE_CLOEXEC
  UPSTREAM: fs, close_range: add flag CLOSE_RANGE_CLOEXEC
  BACKPORT: arch: wire-up close_range()
  UPSTREAM: close_range: add CLOSE_RANGE_UNSHARE
  UPSTREAM: open: add close_range()

Change-Id: Ifa546e0fe29af81ccbb2a5baa32a3b9cb42965fa
This commit is contained in:
Michael Bestas 2025-12-22 08:16:29 +02:00
commit 0bf05d890a
No known key found for this signature in database
28 changed files with 362 additions and 87 deletions

View file

@ -475,8 +475,9 @@
543 common fspick sys_fspick
544 common pidfd_open sys_pidfd_open
# 545 reserved for clone3
# 546 reserved for close_range
546 common close_range sys_close_range
# 547 reserved for openat2
# 548 reserved for pidfd_getfd
# 549 reserved for faccessat2
550 common process_madvise sys_process_madvise
551 common epoll_pwait2 sys_epoll_pwait2

View file

@ -449,8 +449,9 @@
433 common fspick sys_fspick
434 common pidfd_open sys_pidfd_open
435 common clone3 sys_clone3
# 436 reserved for close_range
436 common close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2

View file

@ -38,7 +38,7 @@
#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5)
#define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800)
#define __NR_compat_syscalls 441
#define __NR_compat_syscalls 442
#endif
#define __ARCH_WANT_SYS_CLONE

View file

@ -879,8 +879,12 @@ __SYSCALL(__NR_fspick, sys_fspick)
__SYSCALL(__NR_pidfd_open, sys_pidfd_open)
#define __NR_clone3 435
__SYSCALL(__NR_clone3, sys_clone3)
#define __NR_close_range 436
__SYSCALL(__NR_close_range, sys_close_range)
#define __NR_process_madvise 440
__SYSCALL(__NR_process_madvise, sys_process_madvise)
#define __NR_epoll_pwait2 441
__SYSCALL(__NR_epoll_pwait2, compat_sys_epoll_pwait2)
/*
* Please add new compat syscalls above this comment and update

View file

@ -356,8 +356,9 @@
433 common fspick sys_fspick
434 common pidfd_open sys_pidfd_open
# 435 reserved for clone3
# 436 reserved for close_range
436 common close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2

View file

@ -435,8 +435,9 @@
433 common fspick sys_fspick
434 common pidfd_open sys_pidfd_open
# 435 reserved for clone3
# 436 reserved for close_range
436 common close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2

View file

@ -441,8 +441,9 @@
433 common fspick sys_fspick
434 common pidfd_open sys_pidfd_open
435 common clone3 sys_clone3
# 436 reserved for close_range
436 common close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2

View file

@ -374,8 +374,9 @@
433 n32 fspick sys_fspick
434 n32 pidfd_open sys_pidfd_open
435 n32 clone3 __sys_clone3
# 436 reserved for close_range
436 n32 close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 n32 process_madvise sys_process_madvise
441 n32 epoll_pwait2 compat_sys_epoll_pwait2

View file

@ -350,8 +350,9 @@
433 n64 fspick sys_fspick
434 n64 pidfd_open sys_pidfd_open
435 n64 clone3 __sys_clone3
# 436 reserved for close_range
436 n64 close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 n64 process_madvise sys_process_madvise
441 n64 epoll_pwait2 sys_epoll_pwait2

View file

@ -423,3 +423,5 @@
433 o32 fspick sys_fspick
434 o32 pidfd_open sys_pidfd_open
435 o32 clone3 __sys_clone3
436 o32 close_range sys_close_range
441 o32 epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2

View file

@ -433,8 +433,9 @@
433 common fspick sys_fspick
434 common pidfd_open sys_pidfd_open
435 common clone3 sys_clone3_wrapper
# 436 reserved for close_range
436 common close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2

View file

@ -517,8 +517,9 @@
433 common fspick sys_fspick
434 common pidfd_open sys_pidfd_open
435 nospu clone3 ppc_clone3
# 436 reserved for close_range
436 common close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2

View file

@ -438,8 +438,9 @@
433 common fspick sys_fspick sys_fspick
434 common pidfd_open sys_pidfd_open sys_pidfd_open
435 common clone3 sys_clone3 sys_clone3
# 436 reserved for close_range
436 common close_range sys_close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 common process_madvise sys_process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2

View file

@ -438,8 +438,9 @@
433 common fspick sys_fspick
434 common pidfd_open sys_pidfd_open
# 435 reserved for clone3
# 436 reserved for close_range
436 common close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2

View file

@ -481,8 +481,9 @@
433 common fspick sys_fspick
434 common pidfd_open sys_pidfd_open
# 435 reserved for clone3
# 436 reserved for close_range
436 common close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2

View file

@ -440,8 +440,9 @@
433 i386 fspick sys_fspick __ia32_sys_fspick
434 i386 pidfd_open sys_pidfd_open __ia32_sys_pidfd_open
435 i386 clone3 sys_clone3 __ia32_sys_clone3
# 436 reserved for close_range
436 i386 close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 i386 process_madvise sys_process_madvise
441 i386 epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2

View file

@ -357,11 +357,12 @@
433 common fspick __x64_sys_fspick
434 common pidfd_open __x64_sys_pidfd_open
435 common clone3 __x64_sys_clone3/ptregs
# 436 reserved for close_range
436 common close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2
#
# x32-specific system call numbers start at 512 to avoid cache impact

View file

@ -406,8 +406,9 @@
433 common fspick sys_fspick
434 common pidfd_open sys_pidfd_open
435 common clone3 sys_clone3
# 436 reserved for close_range
436 common close_range sys_close_range
# 437 reserved for openat2
# 438 reserved for pidfd_getfd
# 439 reserved for faccessat2
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2

View file

@ -1803,15 +1803,25 @@ static int ep_send_events(struct eventpoll *ep,
return esed.res;
}
static inline struct timespec64 ep_set_mstimeout(long ms)
static struct timespec64 *ep_timeout_to_timespec(struct timespec64 *to, long ms)
{
struct timespec64 now, ts = {
.tv_sec = ms / MSEC_PER_SEC,
.tv_nsec = NSEC_PER_MSEC * (ms % MSEC_PER_SEC),
};
struct timespec64 now;
if (ms < 0)
return NULL;
if (!ms) {
to->tv_sec = 0;
to->tv_nsec = 0;
return to;
}
to->tv_sec = ms / MSEC_PER_SEC;
to->tv_nsec = NSEC_PER_MSEC * (ms % MSEC_PER_SEC);
ktime_get_ts64(&now);
return timespec64_add_safe(now, ts);
*to = timespec64_add_safe(now, *to);
return to;
}
/*
@ -1842,8 +1852,8 @@ static int ep_autoremove_wake_function(struct wait_queue_entry *wq_entry,
* stored.
* @maxevents: Size (in terms of number of events) of the caller event buffer.
* @timeout: Maximum timeout for the ready events fetch operation, in
* milliseconds. If the @timeout is zero, the function will not block,
* while if the @timeout is less than zero, the function will block
* timespec. If the timeout is zero, the function will not block,
* while if the @timeout ptr is NULL, the function will block
* until at least one event has been retrieved (or an error
* occurred).
*
@ -1851,7 +1861,7 @@ static int ep_autoremove_wake_function(struct wait_queue_entry *wq_entry,
* error code, in case of error.
*/
static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
int maxevents, long timeout)
int maxevents, struct timespec64 *timeout)
{
int res = 0, eavail, timed_out = 0;
u64 slack = 0;
@ -1860,13 +1870,11 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
lockdep_assert_irqs_enabled();
if (timeout > 0) {
struct timespec64 end_time = ep_set_mstimeout(timeout);
slack = select_estimate_accuracy(&end_time);
if (timeout && (timeout->tv_sec | timeout->tv_nsec)) {
slack = select_estimate_accuracy(timeout);
to = &expires;
*to = timespec64_to_ktime(end_time);
} else if (timeout == 0) {
*to = timespec64_to_ktime(*timeout);
} else if (timeout) {
/*
* Avoid the unnecessary trip to the wait queue loop, if the
* caller specified a non blocking operation. We still need
@ -2305,7 +2313,7 @@ error_return:
* part of the user space epoll_wait(2).
*/
static int do_epoll_wait(int epfd, struct epoll_event __user *events,
int maxevents, int timeout)
int maxevents, struct timespec64 *to)
{
int error;
struct fd f;
@ -2339,7 +2347,7 @@ static int do_epoll_wait(int epfd, struct epoll_event __user *events,
ep = f.file->private_data;
/* Time to fish for events ... */
error = ep_poll(ep, events, maxevents, timeout);
error = ep_poll(ep, events, maxevents, to);
error_fput:
fdput(f);
@ -2349,16 +2357,19 @@ error_fput:
SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events,
int, maxevents, int, timeout)
{
return do_epoll_wait(epfd, events, maxevents, timeout);
struct timespec64 to;
return do_epoll_wait(epfd, events, maxevents,
ep_timeout_to_timespec(&to, timeout));
}
/*
* Implement the event wait interface for the eventpoll file. It is the kernel
* part of the user space epoll_pwait(2).
*/
SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
int, maxevents, int, timeout, const sigset_t __user *, sigmask,
size_t, sigsetsize)
static int do_epoll_pwait(int epfd, struct epoll_event __user *events,
int maxevents, struct timespec64 *to,
const sigset_t __user *sigmask, size_t sigsetsize)
{
int error;
@ -2370,18 +2381,47 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
if (error)
return error;
error = do_epoll_wait(epfd, events, maxevents, timeout);
error = do_epoll_wait(epfd, events, maxevents, to);
restore_saved_sigmask_unless(error == -EINTR);
return error;
}
SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
int, maxevents, int, timeout, const sigset_t __user *, sigmask,
size_t, sigsetsize)
{
struct timespec64 to;
return do_epoll_pwait(epfd, events, maxevents,
ep_timeout_to_timespec(&to, timeout),
sigmask, sigsetsize);
}
SYSCALL_DEFINE6(epoll_pwait2, int, epfd, struct epoll_event __user *, events,
int, maxevents, const struct __kernel_timespec __user *, timeout,
const sigset_t __user *, sigmask, size_t, sigsetsize)
{
struct timespec64 ts, *to = NULL;
if (timeout) {
if (get_timespec64(&ts, timeout))
return -EFAULT;
to = &ts;
if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
return -EINVAL;
}
return do_epoll_pwait(epfd, events, maxevents, to,
sigmask, sigsetsize);
}
#ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
struct epoll_event __user *, events,
int, maxevents, int, timeout,
const compat_sigset_t __user *, sigmask,
compat_size_t, sigsetsize)
static int do_compat_epoll_pwait(int epfd, struct epoll_event __user *events,
int maxevents, struct timespec64 *timeout,
const compat_sigset_t __user *sigmask,
compat_size_t sigsetsize)
{
long err;
@ -2394,10 +2434,46 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
return err;
err = do_epoll_wait(epfd, events, maxevents, timeout);
restore_saved_sigmask_unless(err == -EINTR);
return err;
}
COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
struct epoll_event __user *, events,
int, maxevents, int, timeout,
const compat_sigset_t __user *, sigmask,
compat_size_t, sigsetsize)
{
struct timespec64 to;
return do_compat_epoll_pwait(epfd, events, maxevents,
ep_timeout_to_timespec(&to, timeout),
sigmask, sigsetsize);
}
COMPAT_SYSCALL_DEFINE6(epoll_pwait2, int, epfd,
struct epoll_event __user *, events,
int, maxevents,
const struct __kernel_timespec __user *, timeout,
const compat_sigset_t __user *, sigmask,
compat_size_t, sigsetsize)
{
struct timespec64 ts, *to = NULL;
if (timeout) {
if (get_timespec64(&ts, timeout))
return -EFAULT;
to = &ts;
if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
return -EINVAL;
}
return do_compat_epoll_pwait(epfd, events, maxevents, to,
sigmask, sigsetsize);
}
#endif
static int __init eventpoll_init(void)

185
fs/file.c
View file

@ -10,6 +10,7 @@
#include <linux/syscalls.h>
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/sched/signal.h>
#include <linux/slab.h>
@ -18,6 +19,7 @@
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <linux/close_range.h>
unsigned int sysctl_nr_open __read_mostly = 1024*1024;
unsigned int sysctl_nr_open_min = BITS_PER_LONG;
@ -84,6 +86,14 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt)
* 'unsigned long' in some places, but simply because that is how the Linux
* kernel bitmaps are defined to work: they are not "bits in an array of bytes",
* they are very much "bits in an array of unsigned long".
*
* The ALIGN(nr, BITS_PER_LONG) here is for clarity: since we just multiplied
* by that "1024/sizeof(ptr)" before, we already know there are sufficient
* clear low bits. Clang seems to realize that, gcc ends up being confused.
*
* On a 128-bit machine, the ALIGN() would actually matter. In the meantime,
* let's consider it documentation (and maybe a test-case for gcc to improve
* its code generation ;)
*/
static struct fdtable *alloc_fdtable(unsigned int slots_wanted)
{
@ -272,36 +282,45 @@ static inline void __clear_open_fd(unsigned int fd, struct fdtable *fdt)
__clear_bit(fd / BITS_PER_LONG, fdt->full_fds_bits);
}
static unsigned int count_open_files(struct fdtable *fdt)
/*
* Note that a sane fdtable size always has to be a multiple of
* BITS_PER_LONG, since we have bitmaps that are sized by this.
*
* punch_hole is optional - when close_range() is asked to unshare
* and close, we don't need to copy descriptors in that range, so
* a smaller cloned descriptor table might suffice if the last
* currently opened descriptor falls into that range.
*/
static unsigned int sane_fdtable_size(struct fdtable *fdt, struct fd_range *punch_hole)
{
unsigned int size = fdt->max_fds;
unsigned int i;
unsigned int last = find_last_bit(fdt->open_fds, fdt->max_fds);
/* Find the last open fd */
for (i = size / BITS_PER_LONG; i > 0; ) {
if (fdt->open_fds[--i])
break;
if (last == fdt->max_fds)
return NR_OPEN_DEFAULT;
if (punch_hole && punch_hole->to >= last && punch_hole->from <= last) {
last = find_last_bit(fdt->open_fds, punch_hole->from);
if (last == punch_hole->from)
return NR_OPEN_DEFAULT;
}
i = (i + 1) * BITS_PER_LONG;
return i;
return ALIGN(last + 1, BITS_PER_LONG);
}
/*
* Allocate a new files structure and copy contents from the
* passed in files structure.
* errorp will be valid only when the returned files_struct is NULL.
* Allocate a new descriptor table and copy contents from the passed in
* instance. Returns a pointer to cloned table on success, ERR_PTR()
* on failure. For 'punch_hole' see sane_fdtable_size().
*/
struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
struct files_struct *dup_fd(struct files_struct *oldf, struct fd_range *punch_hole)
{
struct files_struct *newf;
struct file **old_fds, **new_fds;
unsigned int open_files, i;
struct fdtable *old_fdt, *new_fdt;
int error;
*errorp = -ENOMEM;
newf = kmem_cache_alloc(files_cachep, GFP_KERNEL);
if (!newf)
goto out;
return ERR_PTR(-ENOMEM);
atomic_set(&newf->count, 1);
@ -318,7 +337,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
spin_lock(&oldf->file_lock);
old_fdt = files_fdtable(oldf);
open_files = count_open_files(old_fdt);
open_files = sane_fdtable_size(old_fdt, punch_hole);
/*
* Check whether we need to allocate a larger fd array and fd set.
@ -331,7 +350,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
new_fdt = alloc_fdtable(open_files);
if (IS_ERR(new_fdt)) {
*errorp = PTR_ERR(new_fdt);
error = PTR_ERR(new_fdt);
goto out_release;
}
@ -342,7 +361,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
*/
spin_lock(&oldf->file_lock);
old_fdt = files_fdtable(oldf);
open_files = count_open_files(old_fdt);
open_files = sane_fdtable_size(old_fdt, punch_hole);
}
copy_fd_bitmaps(new_fdt, old_fdt, open_files / BITS_PER_LONG);
@ -376,8 +395,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
out_release:
kmem_cache_free(files_cachep, newf);
out:
return NULL;
return ERR_PTR(error);
}
static struct fdtable *close_files(struct files_struct * files)
@ -630,12 +648,9 @@ void fd_install(unsigned int fd, struct file *file)
EXPORT_SYMBOL(fd_install);
/*
* The same warnings as for __alloc_fd()/__fd_install() apply here...
*/
int __close_fd(struct files_struct *files, unsigned fd)
static struct file *pick_file(struct files_struct *files, unsigned fd)
{
struct file *file;
struct file *file = NULL;
struct fdtable *fdt;
spin_lock(&files->file_lock);
@ -647,15 +662,129 @@ int __close_fd(struct files_struct *files, unsigned fd)
goto out_unlock;
rcu_assign_pointer(fdt->fd[fd], NULL);
__put_unused_fd(files, fd);
spin_unlock(&files->file_lock);
return filp_close(file, files);
out_unlock:
spin_unlock(&files->file_lock);
return -EBADF;
return file;
}
/*
* The same warnings as for __alloc_fd()/__fd_install() apply here...
*/
int __close_fd(struct files_struct *files, unsigned fd)
{
struct file *file;
file = pick_file(files, fd);
if (!file)
return -EBADF;
return filp_close(file, files);
}
EXPORT_SYMBOL(__close_fd); /* for ksys_close() */
/**
* last_fd - return last valid index into fd table
* @cur_fds: files struct
*
* Context: Either rcu read lock or files_lock must be held.
*
* Returns: Last valid index into fdtable.
*/
static inline unsigned last_fd(struct fdtable *fdt)
{
return fdt->max_fds - 1;
}
static inline void __range_cloexec(struct files_struct *cur_fds,
unsigned int fd, unsigned int max_fd)
{
struct fdtable *fdt;
/* make sure we're using the correct maximum value */
spin_lock(&cur_fds->file_lock);
fdt = files_fdtable(cur_fds);
max_fd = min(last_fd(fdt), max_fd);
if (fd <= max_fd)
bitmap_set(fdt->close_on_exec, fd, max_fd - fd + 1);
spin_unlock(&cur_fds->file_lock);
}
static inline void __range_close(struct files_struct *cur_fds, unsigned int fd,
unsigned int max_fd)
{
while (fd <= max_fd) {
struct file *file;
file = pick_file(cur_fds, fd++);
if (!file)
continue;
filp_close(file, cur_fds);
cond_resched();
}
}
/**
* __close_range() - Close all file descriptors in a given range.
*
* @fd: starting file descriptor to close
* @max_fd: last file descriptor to close
*
* This closes a range of file descriptors. All file descriptors
* from @fd up to and including @max_fd are closed.
*/
int __close_range(unsigned fd, unsigned max_fd, unsigned int flags)
{
struct task_struct *me = current;
struct files_struct *cur_fds = me->files, *fds = NULL;
if (flags & ~(CLOSE_RANGE_UNSHARE | CLOSE_RANGE_CLOEXEC))
return -EINVAL;
if (fd > max_fd)
return -EINVAL;
if ((flags & CLOSE_RANGE_UNSHARE) && atomic_read(&cur_fds->count) > 1) {
struct fd_range range = {fd, max_fd}, *punch_hole = &range;
/*
* If the caller requested all fds to be made cloexec we always
* copy all of the file descriptors since they still want to
* use them.
*/
if (flags & CLOSE_RANGE_CLOEXEC)
punch_hole = NULL;
fds = dup_fd(cur_fds, punch_hole);
if (IS_ERR(fds))
return PTR_ERR(fds);
/*
* We used to share our file descriptor table, and have now
* created a private one, make sure we're using it below.
*/
swap(cur_fds, fds);
}
if (flags & CLOSE_RANGE_CLOEXEC)
__range_cloexec(cur_fds, fd, max_fd);
else
__range_close(cur_fds, fd, max_fd);
if (fds) {
/*
* We're done closing the files we were supposed to. Time to install
* the new file descriptor table and drop the old one.
*/
task_lock(me);
me->files = cur_fds;
task_unlock(me);
put_files_struct(fds);
}
return 0;
}
/*
* variant of __close_fd that gets a ref on the file for later fput
*/

View file

@ -1211,6 +1211,23 @@ SYSCALL_DEFINE1(close, unsigned int, fd)
return retval;
}
/**
* close_range() - Close all file descriptors in a given range.
*
* @fd: starting file descriptor to close
* @max_fd: last file descriptor to close
* @flags: reserved for future extensions
*
* This closes a range of file descriptors. All file descriptors
* from @fd up to and including @max_fd are closed.
* Currently, errors to close a given file descriptor are ignored.
*/
SYSCALL_DEFINE3(close_range, unsigned int, fd, unsigned int, max_fd,
unsigned int, flags)
{
return __close_range(fd, max_fd, flags);
}
/*
* This routine simulates a hangup on the tty, to arrange that users
* are given clean terminals at login time.

View file

@ -539,6 +539,12 @@ asmlinkage long compat_sys_epoll_pwait(int epfd,
int maxevents, int timeout,
const compat_sigset_t __user *sigmask,
compat_size_t sigsetsize);
asmlinkage long compat_sys_epoll_pwait2(int epfd,
struct epoll_event __user *events,
int maxevents,
const struct __kernel_timespec __user *timeout,
const compat_sigset_t __user *sigmask,
compat_size_t sigsetsize);
/* fs/fcntl.c */
asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,

View file

@ -109,7 +109,10 @@ struct files_struct *get_files_struct(struct task_struct *);
void put_files_struct(struct files_struct *fs);
void reset_files_struct(struct files_struct *);
int unshare_files(struct files_struct **);
struct files_struct *dup_fd(struct files_struct *, int *) __latent_entropy;
struct fd_range {
unsigned int from, to;
};
struct files_struct *dup_fd(struct files_struct *, struct fd_range *) __latent_entropy;
void do_close_on_exec(struct files_struct *);
int iterate_fd(struct files_struct *, unsigned,
int (*)(const void *, struct file *, unsigned),
@ -121,6 +124,7 @@ extern void __fd_install(struct files_struct *files,
unsigned int fd, struct file *file);
extern int __close_fd(struct files_struct *files,
unsigned int fd);
extern int __close_range(unsigned int fd, unsigned int max_fd, unsigned int flags);
extern int __close_fd_get_file(unsigned int fd, struct file **res);
extern struct kmem_cache *files_cachep;

View file

@ -364,6 +364,11 @@ asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
int maxevents, int timeout,
const sigset_t __user *sigmask,
size_t sigsetsize);
asmlinkage long sys_epoll_pwait2(int epfd, struct epoll_event __user *events,
int maxevents,
const struct __kernel_timespec __user *timeout,
const sigset_t __user *sigmask,
size_t sigsetsize);
/* fs/fcntl.c */
asmlinkage long sys_dup(unsigned int fildes);
@ -441,6 +446,8 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group);
asmlinkage long sys_openat(int dfd, const char __user *filename, int flags,
umode_t mode);
asmlinkage long sys_close(unsigned int fd);
asmlinkage long sys_close_range(unsigned int fd, unsigned int max_fd,
unsigned int flags);
asmlinkage long sys_vhangup(void);
/* fs/pipe.c */

View file

@ -850,11 +850,15 @@ __SYSCALL(__NR_pidfd_open, sys_pidfd_open)
#define __NR_clone3 435
__SYSCALL(__NR_clone3, sys_clone3)
#endif
#define __NR_close_range 436
__SYSCALL(__NR_close_range, sys_close_range)
#define __NR_process_madvise 440
__SYSCALL(__NR_process_madvise, sys_process_madvise)
#define __NR_epoll_pwait2 441
__SC_COMP(__NR_epoll_pwait2, sys_epoll_pwait2, compat_sys_epoll_pwait2)
#undef __NR_syscalls
#define __NR_syscalls 441
#define __NR_syscalls 442
/*
* 32 bit systems traditionally used different

View file

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI_LINUX_CLOSE_RANGE_H
#define _UAPI_LINUX_CLOSE_RANGE_H
/* Unshare the file descriptor table before closing file descriptors. */
#define CLOSE_RANGE_UNSHARE (1U << 1)
/* Set the FD_CLOEXEC bit instead of closing the file descriptor. */
#define CLOSE_RANGE_CLOEXEC (1U << 2)
#endif /* _UAPI_LINUX_CLOSE_RANGE_H */

View file

@ -1477,28 +1477,25 @@ static int copy_fs(unsigned long clone_flags, struct task_struct *tsk)
static int copy_files(unsigned long clone_flags, struct task_struct *tsk)
{
struct files_struct *oldf, *newf;
int error = 0;
/*
* A background process may not have any files ...
*/
oldf = current->files;
if (!oldf)
goto out;
return 0;
if (clone_flags & CLONE_FILES) {
atomic_inc(&oldf->count);
goto out;
return 0;
}
newf = dup_fd(oldf, &error);
if (!newf)
goto out;
newf = dup_fd(oldf, NULL);
if (IS_ERR(newf))
return PTR_ERR(newf);
tsk->files = newf;
error = 0;
out:
return error;
return 0;
}
static int copy_io(unsigned long clone_flags, struct task_struct *tsk)
@ -2923,13 +2920,13 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp)
{
struct files_struct *fd = current->files;
int error = 0;
if ((unshare_flags & CLONE_FILES) &&
(fd && atomic_read(&fd->count) > 1)) {
*new_fdp = dup_fd(fd, &error);
if (!*new_fdp)
return error;
fd = dup_fd(fd, NULL);
if (IS_ERR(fd))
return PTR_ERR(fd);
*new_fdp = fd;
}
return 0;

View file

@ -68,6 +68,8 @@ COND_SYSCALL(epoll_create1);
COND_SYSCALL(epoll_ctl);
COND_SYSCALL(epoll_pwait);
COND_SYSCALL_COMPAT(epoll_pwait);
COND_SYSCALL(epoll_pwait2);
COND_SYSCALL_COMPAT(epoll_pwait2);
/* fs/fcntl.c */