git: 3ae9b75f6bad - stable/13 - Split kern_poll() on two counterparts.

From: Dmitry Chagin <dchagin_at_FreeBSD.org>
Date: Fri, 17 Jun 2022 19:31:55 UTC
The branch stable/13 has been updated by dchagin:

URL: https://cgit.FreeBSD.org/src/commit/?id=3ae9b75f6bad2456e4b2cd4a5d6734d4737d5af4

commit 3ae9b75f6bad2456e4b2cd4a5d6734d4737d5af4
Author:     Dmitry Chagin <dchagin@FreeBSD.org>
AuthorDate: 2021-06-10 12:11:25 +0000
Commit:     Dmitry Chagin <dchagin@FreeBSD.org>
CommitDate: 2022-06-17 19:30:17 +0000

    Split kern_poll() on two counterparts.
    
    The kern_poll_kfds() operates on clear kernel data, kfds points to an
    array in the kernel, while kern_poll() operates on user supplied pollfd.
    Move nfds check to kern_poll_maxfds().
    
    No functional changes, it's for future use in the Linux emulation layer.
    
    Reviewd by:             kib
    Differential Revision:  https://reviews.freebsd.org/D30690
    MFC after:              2 weeks
    
    (cherry picked from commit e884512ad143952f0dbacad631487ce28363fd08)
---
 sys/kern/sys_generic.c | 83 +++++++++++++++++++++++++++++---------------------
 sys/sys/syscallsubr.h  |  3 ++
 2 files changed, 52 insertions(+), 34 deletions(-)

diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index 0fcb93545e86..541c9f910df1 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -1417,12 +1417,13 @@ sys_poll(struct thread *td, struct poll_args *uap)
 	return (kern_poll(td, uap->fds, uap->nfds, tsp, NULL));
 }
 
+/*
+ * kfds points to an array in the kernel.
+ */
 int
-kern_poll(struct thread *td, struct pollfd *ufds, u_int nfds,
+kern_poll_kfds(struct thread *td, struct pollfd *kfds, u_int nfds,
     struct timespec *tsp, sigset_t *uset)
 {
-	struct pollfd *kfds;
-	struct pollfd stackfds[32];
 	sbintime_t sbt, precision, tmp;
 	time_t over;
 	struct timespec ts;
@@ -1453,28 +1454,11 @@ kern_poll(struct thread *td, struct pollfd *ufds, u_int nfds,
 	} else
 		sbt = -1;
 
-	/*
-	 * This is kinda bogus.  We have fd limits, but that is not
-	 * really related to the size of the pollfd array.  Make sure
-	 * we let the process use at least FD_SETSIZE entries and at
-	 * least enough for the system-wide limits.  We want to be reasonably
-	 * safe, but not overly restrictive.
-	 */
-	if (nfds > maxfilesperproc && nfds > FD_SETSIZE) 
-		return (EINVAL);
-	if (nfds > nitems(stackfds))
-		kfds = mallocarray(nfds, sizeof(*kfds), M_TEMP, M_WAITOK);
-	else
-		kfds = stackfds;
-	error = copyin(ufds, kfds, nfds * sizeof(*kfds));
-	if (error)
-		goto done;
-
 	if (uset != NULL) {
 		error = kern_sigprocmask(td, SIG_SETMASK, uset,
 		    &td->td_oldsigmask, 0);
 		if (error)
-			goto done;
+			return (error);
 		td->td_pflags |= TDP_OLDMASK;
 		/*
 		 * Make sure that ast() is called on return to
@@ -1501,20 +1485,11 @@ kern_poll(struct thread *td, struct pollfd *ufds, u_int nfds,
 	}
 	seltdclear(td);
 
-done:
 	/* poll is not restarted after signals... */
 	if (error == ERESTART)
 		error = EINTR;
 	if (error == EWOULDBLOCK)
 		error = 0;
-	if (error == 0) {
-		error = pollout(td, kfds, ufds, nfds);
-		if (error)
-			goto out;
-	}
-out:
-	if (nfds > nitems(stackfds))
-		free(kfds, M_TEMP);
 	return (error);
 }
 
@@ -1539,12 +1514,52 @@ sys_ppoll(struct thread *td, struct ppoll_args *uap)
 		ssp = &set;
 	} else
 		ssp = NULL;
+	return (kern_poll(td, uap->fds, uap->nfds, tsp, ssp));
+}
+
+/*
+ * ufds points to an array in user space.
+ */
+int
+kern_poll(struct thread *td, struct pollfd *ufds, u_int nfds,
+    struct timespec *tsp, sigset_t *set)
+{
+	struct pollfd *kfds;
+	struct pollfd stackfds[32];
+	int error;
+
+	if (kern_poll_maxfds(nfds))
+		return (EINVAL);
+	if (nfds > nitems(stackfds))
+		kfds = mallocarray(nfds, sizeof(*kfds), M_TEMP, M_WAITOK);
+	else
+		kfds = stackfds;
+	error = copyin(ufds, kfds, nfds * sizeof(*kfds));
+	if (error != 0)
+		goto out;
+
+	error = kern_poll_kfds(td, kfds, nfds, tsp, set);
+	if (error == 0)
+		error = pollout(td, kfds, ufds, nfds);
+
+out:
+	if (nfds > nitems(stackfds))
+		free(kfds, M_TEMP);
+	return (error);
+}
+
+bool
+kern_poll_maxfds(u_int nfds)
+{
+
 	/*
-	 * fds is still a pointer to user space. kern_poll() will
-	 * take care of copyin that array to the kernel space.
+	 * This is kinda bogus.  We have fd limits, but that is not
+	 * really related to the size of the pollfd array.  Make sure
+	 * we let the process use at least FD_SETSIZE entries and at
+	 * least enough for the system-wide limits.  We want to be reasonably
+	 * safe, but not overly restrictive.
 	 */
-
-	return (kern_poll(td, uap->fds, uap->nfds, tsp, ssp));
+	return (nfds > maxfilesperproc && nfds > FD_SETSIZE);
 }
 
 static int
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index b155de1e08bf..09eae475cb2c 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -229,6 +229,9 @@ int	kern_pipe(struct thread *td, int fildes[2], int flags,
 	    struct filecaps *fcaps1, struct filecaps *fcaps2);
 int	kern_poll(struct thread *td, struct pollfd *fds, u_int nfds,
 	    struct timespec *tsp, sigset_t *uset);
+int	kern_poll_kfds(struct thread *td, struct pollfd *fds, u_int nfds,
+	    struct timespec *tsp, sigset_t *uset);
+bool	kern_poll_maxfds(u_int nfds);
 int	kern_posix_error(struct thread *td, int error);
 int	kern_posix_fadvise(struct thread *td, int fd, off_t offset, off_t len,
 	    int advice);