Index: lib/libc/sys/closefrom.2 =================================================================== --- lib/libc/sys/closefrom.2 +++ 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 @@ .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 close-on-exec flag rather than closing +.El .Sh RETURN VALUES Upon successful completion, .Fn close_range Index: lib/libsysdecode/flags.c =================================================================== --- lib/libsysdecode/flags.c +++ lib/libsysdecode/flags.c @@ -400,6 +400,13 @@ 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) { Index: lib/libsysdecode/mktables =================================================================== --- lib/libsysdecode/mktables +++ lib/libsysdecode/mktables @@ -94,6 +94,7 @@ 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" Index: lib/libsysdecode/sysdecode.h =================================================================== --- lib/libsysdecode/sysdecode.h +++ lib/libsysdecode/sysdecode.h @@ -43,6 +43,7 @@ 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); Index: lib/libsysdecode/sysdecode_mask.3 =================================================================== --- lib/libsysdecode/sysdecode_mask.3 +++ 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" Index: sys/kern/kern_descrip.c =================================================================== --- sys/kern/kern_descrip.c +++ sys/kern/kern_descrip.c @@ -1393,23 +1393,39 @@ 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; + } + for (; fd <= highfd; fd++) { + fde = &fdt->fdt_ofiles[fd]; + if (fde->fde_file != NULL) + fde->fde_flags |= UF_EXCLOSE; } + FILEDESC_XUNLOCK(fdp); +out: + 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 @@ 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; @@ -1456,9 +1492,9 @@ 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 +1519,7 @@ * 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 */ Index: sys/sys/syscallsubr.h =================================================================== --- sys/sys/syscallsubr.h +++ sys/sys/syscallsubr.h @@ -111,7 +111,7 @@ 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); Index: sys/sys/unistd.h =================================================================== --- sys/sys/unistd.h +++ 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_ */ Index: usr.bin/kdump/kdump.c =================================================================== --- usr.bin/kdump/kdump.c +++ usr.bin/kdump/kdump.c @@ -864,6 +864,14 @@ 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); Index: usr.bin/truss/syscall.h =================================================================== --- usr.bin/truss/syscall.h +++ usr.bin/truss/syscall.h @@ -91,6 +91,7 @@ Atfd, Atflags, CapFcntlRights, + Closerangeflags, Extattrnamespace, Fadvice, Fcntl, Index: usr.bin/truss/syscalls.c =================================================================== --- usr.bin/truss/syscalls.c +++ usr.bin/truss/syscalls.c @@ -183,6 +183,8 @@ .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 @@ 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;