aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--lib/libc/sys/closefrom.210
-rw-r--r--lib/libsysdecode/flags.c7
-rw-r--r--lib/libsysdecode/mktables1
-rw-r--r--lib/libsysdecode/sysdecode.h1
-rw-r--r--lib/libsysdecode/sysdecode_mask.35
-rw-r--r--sys/kern/kern_descrip.c67
-rw-r--r--sys/sys/syscallsubr.h2
-rw-r--r--sys/sys/unistd.h5
-rw-r--r--tests/sys/file/closefrom_test.c35
-rw-r--r--usr.bin/kdump/kdump.c8
-rw-r--r--usr.bin/truss/syscall.h1
-rw-r--r--usr.bin/truss/syscalls.c5
12 files changed, 125 insertions, 22 deletions
diff --git a/lib/libc/sys/closefrom.2 b/lib/libc/sys/closefrom.2
index db41c617dc7f..64c210f7897a 100644
--- a/lib/libc/sys/closefrom.2
+++ b/lib/libc/sys/closefrom.2
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 12, 2020
+.Dd March 3, 2022
.Dt CLOSEFROM 2
.Os
.Sh NAME
@@ -56,8 +56,12 @@ and
.Fa highfd
inclusive, clamped to the range of open file descriptors.
Any errors encountered while closing file descriptors are ignored.
-There are currently no defined
-.Fa flags .
+Supported
+.Fa flags :
+.Bl -tag -width ".Dv CLOSE_RANGE_CLOEXEC"
+.It Dv CLOSE_RANGE_CLOEXEC
+Set the close-on-exec flag on descriptors in the range instead of closing them.
+.El
.Sh RETURN VALUES
Upon successful completion,
.Fn close_range
diff --git a/lib/libsysdecode/flags.c b/lib/libsysdecode/flags.c
index df461cf0dca1..35bce1ff77f9 100644
--- a/lib/libsysdecode/flags.c
+++ b/lib/libsysdecode/flags.c
@@ -400,6 +400,13 @@ sysdecode_cap_fcntlrights(FILE *fp, uint32_t rights, uint32_t *rem)
return (print_mask_int(fp, capfcntl, rights, rem));
}
+bool
+sysdecode_close_range_flags(FILE *fp, int flags, int *rem)
+{
+
+ return (print_mask_int(fp, closerangeflags, flags, rem));
+}
+
const char *
sysdecode_extattrnamespace(int namespace)
{
diff --git a/lib/libsysdecode/mktables b/lib/libsysdecode/mktables
index afc8d82d1556..66f243eab6e6 100644
--- a/lib/libsysdecode/mktables
+++ b/lib/libsysdecode/mktables
@@ -94,6 +94,7 @@ gen_table "accessmode" "[A-Z]_OK[[:space:]]+0?x?[0-9A-Fa-f]+" "sys/
gen_table "acltype" "ACL_TYPE_[A-Z4_]+[[:space:]]+0x[0-9]+" "sys/acl.h"
gen_table "atflags" "AT_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/fcntl.h"
gen_table "capfcntl" "CAP_FCNTL_[A-Z]+[[:space:]]+\(1" "sys/capsicum.h"
+gen_table "closerangeflags" "CLOSE_RANGE_[A-Z]+[[:space:]]+\([0-9]+<<[0-9]+\)" "sys/unistd.h"
gen_table "extattrns" "EXTATTR_NAMESPACE_[A-Z]+[[:space:]]+0x[0-9]+" "sys/extattr.h"
gen_table "fadvisebehav" "POSIX_FADV_[A-Z]+[[:space:]]+[0-9]+" "sys/fcntl.h"
gen_table "openflags" "O_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/fcntl.h" "O_RDONLY|O_RDWR|O_WRONLY"
diff --git a/lib/libsysdecode/sysdecode.h b/lib/libsysdecode/sysdecode.h
index 1a35d0c9d685..5ab17340818c 100644
--- a/lib/libsysdecode/sysdecode.h
+++ b/lib/libsysdecode/sysdecode.h
@@ -43,6 +43,7 @@ const char *sysdecode_atfd(int _fd);
bool sysdecode_atflags(FILE *_fp, int _flags, int *_rem);
bool sysdecode_cap_fcntlrights(FILE *_fp, uint32_t _rights, uint32_t *_rem);
void sysdecode_cap_rights(FILE *_fp, cap_rights_t *_rightsp);
+bool sysdecode_close_range_flags(FILE *_fp, int _flags, int *_rem);
const char *sysdecode_cmsg_type(int _cmsg_level, int _cmsg_type);
const char *sysdecode_extattrnamespace(int _namespace);
const char *sysdecode_fadvice(int _advice);
diff --git a/lib/libsysdecode/sysdecode_mask.3 b/lib/libsysdecode/sysdecode_mask.3
index 54e182db31d7..45464e333eb4 100644
--- a/lib/libsysdecode/sysdecode_mask.3
+++ b/lib/libsysdecode/sysdecode_mask.3
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 16, 2018
+.Dd March 3, 2022
.Dt sysdecode_mask 3
.Os
.Sh NAME
@@ -32,6 +32,7 @@
.Nm sysdecode_accessmode ,
.Nm sysdecode_atflags ,
.Nm sysdecode_capfcntlrights ,
+.Nm sysdecode_close_range_flags ,
.Nm sysdecode_fcntl_fileflags ,
.Nm sysdecode_fileflags ,
.Nm sysdecode_filemode ,
@@ -74,6 +75,8 @@
.Ft bool
.Fn sysdecode_cap_fcntlrights "FILE *fp" "uint32_t rights" "uint32_t *rem"
.Ft bool
+.Fn sysdecode_close_range_flags "FILE *fp" "int flags" "int *rem"
+.Ft bool
.Fn sysdecode_fcntl_fileflags "FILE *fp" "int flags" "int *rem"
.Ft bool
.Fn sysdecode_fileflags "FILE *fp" "fflags_t flags" "fflags_t *rem"
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 */
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index 62dde37c0c1f..c66a34536444 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -111,7 +111,7 @@ int kern_clock_settime(struct thread *td, clockid_t clock_id,
struct timespec *ats);
void kern_thread_cputime(struct thread *targettd, struct timespec *ats);
void kern_process_cputime(struct proc *targetp, struct timespec *ats);
-int kern_close_range(struct thread *td, u_int lowfd, u_int highfd);
+int kern_close_range(struct thread *td, int flags, u_int lowfd, u_int highfd);
int kern_close(struct thread *td, int fd);
int kern_connectat(struct thread *td, int dirfd, int fd,
struct sockaddr *sa);
diff --git a/sys/sys/unistd.h b/sys/sys/unistd.h
index be71edbd6e23..449d35678275 100644
--- a/sys/sys/unistd.h
+++ b/sys/sys/unistd.h
@@ -200,6 +200,11 @@
#define SWAPOFF_FORCE 0x00000001
+/*
+ * close_range() options.
+ */
+#define CLOSE_RANGE_CLOEXEC (1<<2)
+
#endif /* __BSD_VISIBLE */
#endif /* !_SYS_UNISTD_H_ */
diff --git a/tests/sys/file/closefrom_test.c b/tests/sys/file/closefrom_test.c
index 8516f7f2598c..d11faa22b55d 100644
--- a/tests/sys/file/closefrom_test.c
+++ b/tests/sys/file/closefrom_test.c
@@ -144,7 +144,7 @@ main(void)
{
struct shared_info *info;
pid_t pid;
- int fd, i, start;
+ int fd, flags, i, start;
printf("1..20\n");
@@ -325,5 +325,38 @@ main(void)
fail(info->tag, "%s", info->message);
ok(info->tag);
+ /* test CLOSE_RANGE_CLOEXEC */
+ for (i = 0; i < 8; i++)
+ (void)devnull();
+ fd = highest_fd();
+ start = fd - 8;
+ if (close_range(start + 1, start + 4, CLOSE_RANGE_CLOEXEC) < 0)
+ fail_err("close_range(..., CLOSE_RANGE_CLOEXEC)");
+ flags = fcntl(start, F_GETFD);
+ if (flags < 0)
+ fail_err("fcntl(.., F_GETFD)");
+ if ((flags & FD_CLOEXEC) != 0)
+ fail("close_range", "CLOSE_RANGE_CLOEXEC set close-on-exec "
+ "when it should not have on fd %d", start);
+ for (i = start + 1; i <= start + 4; i++) {
+ flags = fcntl(i, F_GETFD);
+ if (flags < 0)
+ fail_err("fcntl(.., F_GETFD)");
+ if ((flags & FD_CLOEXEC) == 0)
+ fail("close_range", "CLOSE_RANGE_CLOEXEC did not set "
+ "close-on-exec on fd %d", i);
+ }
+ for (; i < start + 8; i++) {
+ flags = fcntl(i, F_GETFD);
+ if (flags < 0)
+ fail_err("fcntl(.., F_GETFD)");
+ if ((flags & FD_CLOEXEC) != 0)
+ fail("close_range", "CLOSE_RANGE_CLOEXEC set close-on-exec "
+ "when it should not have on fd %d", i);
+ }
+ if (close_range(start, start + 8, 0) < 0)
+ fail_err("close_range");
+ ok("close_range(..., CLOSE_RANGE_CLOEXEC)");
+
return (0);
}
diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c
index 611c9021cd78..845e2000a4c2 100644
--- a/usr.bin/kdump/kdump.c
+++ b/usr.bin/kdump/kdump.c
@@ -864,6 +864,14 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags)
ip++;
narg--;
break;
+ case SYS_close_range:
+ print_number(ip, narg, c);
+ print_number(ip, narg, c);
+ putchar(',');
+ print_mask_arg(sysdecode_close_range_flags, *ip);
+ ip += 3;
+ narg -= 3;
+ break;
case SYS_open:
case SYS_openat:
print_number(ip, narg, c);
diff --git a/usr.bin/truss/syscall.h b/usr.bin/truss/syscall.h
index 7a403d5b680d..53a1fd6ee8d7 100644
--- a/usr.bin/truss/syscall.h
+++ b/usr.bin/truss/syscall.h
@@ -91,6 +91,7 @@ enum Argtype {
Atfd,
Atflags,
CapFcntlRights,
+ Closerangeflags,
Extattrnamespace,
Fadvice,
Fcntl,
diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c
index 586b583c3209..d611f3f73471 100644
--- a/usr.bin/truss/syscalls.c
+++ b/usr.bin/truss/syscalls.c
@@ -183,6 +183,8 @@ static const struct syscall_decode decoded_syscalls[] = {
.args = { { Int, 0 } } },
{ .name = "closefrom", .ret_type = 1, .nargs = 1,
.args = { { Int, 0 } } },
+ { .name = "close_range", .ret_type = 1, .nargs = 3,
+ .args = { { Int, 0 }, { Int, 1 }, { Closerangeflags, 2 } } },
{ .name = "compat11.fstat", .ret_type = 1, .nargs = 2,
.args = { { Int, 0 }, { Stat11 | OUT, 1 } } },
{ .name = "compat11.fstatat", .ret_type = 1, .nargs = 4,
@@ -1983,6 +1985,9 @@ print_arg(struct syscall_arg *sc, unsigned long *args, register_t *retval,
case Fcntl:
print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
break;
+ case Closerangeflags:
+ print_mask_arg(sysdecode_close_range_flags, fp, args[sc->offset]);
+ break;
case Mprot:
print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
break;