]> xenbits.xensource.com Git - people/royger/freebsd.git/commitdiff
fd: add close_range(..., CLOSE_RANGE_CLOEXEC)
authorMateusz Guzik <mjg@FreeBSD.org>
Thu, 3 Mar 2022 12:45:11 +0000 (13:45 +0100)
committerMateusz Guzik <mjg@FreeBSD.org>
Mon, 7 Mar 2022 12:15:47 +0000 (12:15 +0000)
For compatibility with Linux.

MFC after: 3 days
Reviewed by: markj
Differential Revision: https://reviews.freebsd.org/D34424

(cherry picked from commit f3f3e3c44d3b1776653bbf19eab17ce006a815d8)

12 files changed:
lib/libc/sys/closefrom.2
lib/libsysdecode/flags.c
lib/libsysdecode/mktables
lib/libsysdecode/sysdecode.h
lib/libsysdecode/sysdecode_mask.3
sys/kern/kern_descrip.c
sys/sys/syscallsubr.h
sys/sys/unistd.h
tests/sys/file/closefrom_test.c
usr.bin/kdump/kdump.c
usr.bin/truss/syscall.h
usr.bin/truss/syscalls.c

index db41c617dc7f4ff31e18c69129833095e1c6f1be..64c210f7897af89130bda1fadaf70117e336e4a5 100644 (file)
@@ -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
index df461cf0dca150ea9c40ea8dd101e568fc03806b..35bce1ff77f9690f2ee6782b16b94d2b139553d0 100644 (file)
@@ -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)
 {
index 77cfa15bd1f5f1146e2438276b56a093da3d1dbb..c9c6830b04aa7ea32d3c8c0451c03c45e61596ec 100644 (file)
@@ -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"
index cdb9205f3da1af8bfd715091d5a63a2b147b5ce9..47e37aeeed988063d5de550b31f5a6351d21c2b7 100644 (file)
@@ -45,6 +45,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);
index 54e182db31d76f0f7c937c4461d5e9930c1f806d..45464e333eb409bfc1a62b7a529911ea3d37fb3a 100644 (file)
@@ -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 1cf88be09a27995b5b510b369f9a6cd0a55e3522..03498d5a9ce9722f3320b0851d1c045044ba8afa 100644 (file)
@@ -1400,23 +1400,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);
@@ -1447,6 +1463,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;
@@ -1462,10 +1498,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
@@ -1490,7 +1525,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 */
 
index 71e76f072693ccc0ba53af7a22d4762c30ade50c..bd246019bcc9c11e883bad07d33e38919be68b7a 100644 (file)
@@ -108,7 +108,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);
index 2d9544652f91b6a830eb8608451da85b208d6eb0..007abbdfbba56dd07ab0332f5ca0a6d25f83fca7 100644 (file)
 
 #define        SWAPOFF_FORCE   0x00000001
 
+/*
+ * close_range() options.
+ */
+#define        CLOSE_RANGE_CLOEXEC     (1<<2)
+
 #endif /* __BSD_VISIBLE */
 
 #endif /* !_SYS_UNISTD_H_ */
index 8516f7f2598c72b30783ea0f13093cf0113c2d49..d11faa22b55df297437417436055ddb0203827dc 100644 (file)
@@ -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);
 }
index d863fffea774efc2b1d886396c3e535263d5db61..19616338fc1f86c500e9be25e0603b5a49701bfc 100644 (file)
@@ -869,6 +869,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);
index fc163067724285ed4e02fbdb23ad63a91997651d..f25cbd81ede5a5ab352d51c69cff160e10cb89d4 100644 (file)
@@ -91,6 +91,7 @@ enum Argtype {
        Atfd,
        Atflags,
        CapFcntlRights,
+       Closerangeflags,
        Extattrnamespace,
        Fadvice,
        Fcntl,
index efabe1086932445b07dc4e082c9dcb05d85a5b0f..7c9172e070d79919bd4b2f4542d5fea2032fdccc 100644 (file)
@@ -184,6 +184,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,
@@ -2166,6 +2168,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;