git: 794d3e8e63f4 - main - fcntl(2): add F_KINFO operation

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Mon, 06 Dec 2021 20:18:34 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=794d3e8e63f4a6ebc8926030b6c937109ddc5485

commit 794d3e8e63f4a6ebc8926030b6c937109ddc5485
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-12-05 18:45:50 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-12-06 20:18:09 +0000

    fcntl(2): add F_KINFO operation
    
    that returns struct kinfo_file for the given file descriptor.  Among
    other data, it also returns kf_path, if file op was able to restore file
    path.
    
    Reviewed by:    jhb, markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D33277
---
 lib/libc/sys/fcntl.2                  | 17 ++++++++++++++--
 sys/compat/freebsd32/freebsd32_misc.c |  1 +
 sys/kern/kern_descrip.c               | 38 ++++++++++++++++++++++++++++++++++-
 sys/sys/fcntl.h                       |  1 +
 4 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/lib/libc/sys/fcntl.2 b/lib/libc/sys/fcntl.2
index 33ad7a5673e1..c0a13ee6df18 100644
--- a/lib/libc/sys/fcntl.2
+++ b/lib/libc/sys/fcntl.2
@@ -28,7 +28,7 @@
 .\"     @(#)fcntl.2	8.2 (Berkeley) 1/12/94
 .\" $FreeBSD$
 .\"
-.Dd January 6, 2021
+.Dd December 7, 2021
 .Dt FCNTL 2
 .Os
 .Sh NAME
@@ -53,7 +53,7 @@ Depending on the value of
 .Fa cmd ,
 .Fn fcntl
 can take an additional third argument
-.Fa "int arg" .
+.Fa "long arg" .
 .Bl -tag -width F_DUP2FD_CLOEXEC
 .It Dv F_DUPFD
 Return a new descriptor as follows:
@@ -190,6 +190,19 @@ Check if the vnode is part of a union stack (either the "union" flag from
 .Xr mount 2
 or unionfs).
 This is a hack not intended to be used outside of libc.
+.It Dv F_KINFO
+Fills a
+.Vt struct kinfo_file
+for the file referenced by the specified file descriptor.
+The
+.Fa arg
+argument should point to the storage for
+.Vt struct kinfo_file .
+The
+.Va kf_structsize
+member of the passed structure must be initialized with the sizeof of
+.Vt struct kinfo_file ,
+to allow for the interface versioning and evolution.
 .El
 .Pp
 The flags for the
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index a51daec85fcd..89322772a83c 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -3767,6 +3767,7 @@ freebsd32_fcntl(struct thread *td, struct freebsd32_fcntl_args *uap)
 	case F_OGETLK:
 	case F_OSETLK:
 	case F_OSETLKW:
+	case F_KINFO:
 		tmp = (unsigned int)(uap->arg);
 		break;
 	default:
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 8970e80a9818..03cc77ff31ba 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -480,7 +480,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
 	struct proc *p;
 	struct vnode *vp;
 	struct mount *mp;
-	int error, flg, seals, tmp;
+	struct kinfo_file *kif;
+	int error, flg, kif_sz, seals, tmp;
 	uint64_t bsize;
 	off_t foffset;
 
@@ -855,6 +856,41 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
 		fdrop(fp, td);
 		break;
 
+	case F_KINFO:
+#ifdef CAPABILITY_MODE
+		if (IN_CAPABILITY_MODE(td)) {
+			error = ECAPMODE;
+			break;
+		}
+#endif
+		error = copyin((void *)arg, &kif_sz, sizeof(kif_sz));
+		if (error != 0)
+			break;
+		if (kif_sz != sizeof(*kif)) {
+			error = EINVAL;
+			break;
+		}
+		kif = malloc(sizeof(*kif), M_TEMP, M_WAITOK | M_ZERO);
+		FILEDESC_SLOCK(fdp);
+		error = fget_cap_locked(fdp, fd, &cap_fcntl_rights, &fp, NULL);
+		if (error == 0 && fhold(fp)) {
+			export_file_to_kinfo(fp, fd, NULL, kif, fdp, 0);
+			FILEDESC_SUNLOCK(fdp);
+			fdrop(fp, td);
+			if ((kif->kf_status & KF_ATTR_VALID) != 0) {
+				kif->kf_structsize = sizeof(*kif);
+				error = copyout(kif, (void *)arg, sizeof(*kif));
+			} else {
+				error = EBADF;
+			}
+		} else {
+			FILEDESC_SUNLOCK(fdp);
+			if (error == 0)
+				error = EBADF;
+		}
+		free(kif, M_TEMP);
+		break;
+
 	default:
 		error = EINVAL;
 		break;
diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h
index 934c648aecc0..491b0172a1e6 100644
--- a/sys/sys/fcntl.h
+++ b/sys/sys/fcntl.h
@@ -270,6 +270,7 @@ typedef	__pid_t		pid_t;
 #define	F_ADD_SEALS	19
 #define	F_GET_SEALS	20
 #define	F_ISUNIONSTACK	21		/* Kludge for libc, don't use it. */
+#define	F_KINFO		22		/* Return kinfo_file for this fd */
 
 /* Seals (F_ADD_SEALS, F_GET_SEALS). */
 #define	F_SEAL_SEAL	0x0001		/* Prevent adding sealings */