aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/kern_descrip.c
diff options
context:
space:
mode:
authorMateusz Guzik <mjg@FreeBSD.org>2022-03-03 12:45:11 +0000
committerMateusz Guzik <mjg@FreeBSD.org>2022-03-03 17:21:58 +0000
commitf3f3e3c44d3b1776653bbf19eab17ce006a815d8 (patch)
tree6e9ee13aff676e1e89dc7a9ea6ff72511caf326f /sys/kern/kern_descrip.c
parent33cbbf268f7d0f3daff0c2aa06836d932faf56a9 (diff)
downloadsrc-f3f3e3c44d3b1776653bbf19eab17ce006a815d8.tar.gz
src-f3f3e3c44d3b1776653bbf19eab17ce006a815d8.zip
fd: add close_range(..., CLOSE_RANGE_CLOEXEC)
For compatibility with Linux. MFC after: 3 days Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D34424
Diffstat (limited to 'sys/kern/kern_descrip.c')
-rw-r--r--sys/kern/kern_descrip.c67
1 files changed, 51 insertions, 16 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index ed9d0bc3c253..07984b9a4640 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1393,23 +1393,39 @@ kern_close(struct thread *td, int fd)
return (closefp(fdp, fd, fp, td, true, true));
}
-int
-kern_close_range(struct thread *td, u_int lowfd, u_int highfd)
+static int
+close_range_cloexec(struct thread *td, u_int lowfd, u_int highfd)
{
struct filedesc *fdp;
- const struct fdescenttbl *fdt;
- struct file *fp;
+ struct fdescenttbl *fdt;
+ struct filedescent *fde;
int fd;
- /*
- * Check this prior to clamping; closefrom(3) with only fd 0, 1, and 2
- * open should not be a usage error. From a close_range() perspective,
- * close_range(3, ~0U, 0) in the same scenario should also likely not
- * be a usage error as all fd above 3 are in-fact already closed.
- */
- if (highfd < lowfd) {
- return (EINVAL);
+ fdp = td->td_proc->p_fd;
+ FILEDESC_XLOCK(fdp);
+ fdt = atomic_load_ptr(&fdp->fd_files);
+ highfd = MIN(highfd, fdt->fdt_nfiles - 1);
+ fd = lowfd;
+ if (__predict_false(fd > highfd)) {
+ goto out_locked;
+ }
+ for (; fd <= highfd; fd++) {
+ fde = &fdt->fdt_ofiles[fd];
+ if (fde->fde_file != NULL)
+ fde->fde_flags |= UF_EXCLOSE;
}
+out_locked:
+ FILEDESC_XUNLOCK(fdp);
+ return (0);
+}
+
+static int
+close_range_impl(struct thread *td, u_int lowfd, u_int highfd)
+{
+ struct filedesc *fdp;
+ const struct fdescenttbl *fdt;
+ struct file *fp;
+ int fd;
fdp = td->td_proc->p_fd;
FILEDESC_XLOCK(fdp);
@@ -1440,6 +1456,26 @@ out_unlocked:
return (0);
}
+int
+kern_close_range(struct thread *td, int flags, u_int lowfd, u_int highfd)
+{
+
+ /*
+ * Check this prior to clamping; closefrom(3) with only fd 0, 1, and 2
+ * open should not be a usage error. From a close_range() perspective,
+ * close_range(3, ~0U, 0) in the same scenario should also likely not
+ * be a usage error as all fd above 3 are in-fact already closed.
+ */
+ if (highfd < lowfd) {
+ return (EINVAL);
+ }
+
+ if ((flags & CLOSE_RANGE_CLOEXEC) != 0)
+ return (close_range_cloexec(td, lowfd, highfd));
+
+ return (close_range_impl(td, lowfd, highfd));
+}
+
#ifndef _SYS_SYSPROTO_H_
struct close_range_args {
u_int lowfd;
@@ -1455,10 +1491,9 @@ sys_close_range(struct thread *td, struct close_range_args *uap)
AUDIT_ARG_CMD(uap->highfd);
AUDIT_ARG_FFLAGS(uap->flags);
- /* No flags currently defined */
- if (uap->flags != 0)
+ if ((uap->flags & ~(CLOSE_RANGE_CLOEXEC)) != 0)
return (EINVAL);
- return (kern_close_range(td, uap->lowfd, uap->highfd));
+ return (kern_close_range(td, uap->flags, uap->lowfd, uap->highfd));
}
#ifdef COMPAT_FREEBSD12
@@ -1483,7 +1518,7 @@ freebsd12_closefrom(struct thread *td, struct freebsd12_closefrom_args *uap)
* closefrom(0) which closes all files.
*/
lowfd = MAX(0, uap->lowfd);
- return (kern_close_range(td, lowfd, ~0U));
+ return (kern_close_range(td, 0, lowfd, ~0U));
}
#endif /* COMPAT_FREEBSD12 */