git: b7eecc86c3bd - stable/14 - kernel: add RLIMIT_PIPEBUF

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sat, 05 Oct 2024 07:11:06 UTC
The branch stable/14 has been updated by kib:

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

commit b7eecc86c3bdf124ca64e2cdc65e05a2093614a7
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-09-10 03:57:58 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-10-05 07:08:54 +0000

    kernel: add RLIMIT_PIPEBUF
    
    (cherry picked from commit 3458bbd397783f3bb62713c54ae87f19eeb98dc0)
---
 sys/kern/kern_resource.c |  7 +++++++
 sys/kern/sys_pipe.c      | 16 ++++++++++++++++
 sys/sys/pipe.h           |  1 +
 sys/sys/resource.h       |  3 ++-
 sys/sys/resourcevar.h    |  2 ++
 5 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c
index ac086618b8b1..f3755d625572 100644
--- a/sys/kern/kern_resource.c
+++ b/sys/kern/kern_resource.c
@@ -1610,3 +1610,10 @@ chgumtxcnt(struct uidinfo *uip, int diff, rlim_t max)
 
 	return (chglimit(uip, &uip->ui_umtxcnt, diff, max, "umtxcnt"));
 }
+
+int
+chgpipecnt(struct uidinfo *uip, int diff, rlim_t max)
+{
+
+	return (chglimit(uip, &uip->ui_pipecnt, diff, max, "pipecnt"));
+}
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index 4c6f010a03f6..dc8b9ca2c9af 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -376,6 +376,7 @@ pipe_paircreate(struct thread *td, struct pipepair **p_pp)
 #endif
 	rpipe = &pp->pp_rpipe;
 	wpipe = &pp->pp_wpipe;
+	pp->pp_owner = crhold(td->td_ucred);
 
 	knlist_init_mtx(&rpipe->pipe_sel.si_note, PIPE_MTX(rpipe));
 	knlist_init_mtx(&wpipe->pipe_sel.si_note, PIPE_MTX(wpipe));
@@ -409,6 +410,7 @@ pipe_paircreate(struct thread *td, struct pipepair **p_pp)
 fail:
 	knlist_destroy(&rpipe->pipe_sel.si_note);
 	knlist_destroy(&wpipe->pipe_sel.si_note);
+	crfree(pp->pp_owner);
 #ifdef MAC
 	mac_pipe_destroy(pp);
 #endif
@@ -575,9 +577,20 @@ retry:
 	size = round_page(size);
 	buffer = (caddr_t) vm_map_min(pipe_map);
 
+	if (!chgpipecnt(cpipe->pipe_pair->pp_owner->cr_ruidinfo,
+	    size, lim_cur(curthread, RLIMIT_PIPEBUF))) {
+		if (cpipe->pipe_buffer.buffer == NULL &&
+		    size > SMALL_PIPE_SIZE) {
+			size = SMALL_PIPE_SIZE;
+			goto retry;
+		}
+		return (ENOMEM);
+	}
+
 	error = vm_map_find(pipe_map, NULL, 0, (vm_offset_t *)&buffer, size, 0,
 	    VMFS_ANY_SPACE, VM_PROT_RW, VM_PROT_RW, 0);
 	if (error != KERN_SUCCESS) {
+		chgpipecnt(cpipe->pipe_pair->pp_owner->cr_ruidinfo, -size, 0);
 		if (cpipe->pipe_buffer.buffer == NULL &&
 		    size > SMALL_PIPE_SIZE) {
 			size = SMALL_PIPE_SIZE;
@@ -1646,6 +1659,8 @@ pipe_free_kmem(struct pipe *cpipe)
 
 	if (cpipe->pipe_buffer.buffer != NULL) {
 		atomic_subtract_long(&amountpipekva, cpipe->pipe_buffer.size);
+		chgpipecnt(cpipe->pipe_pair->pp_owner->cr_uidinfo,
+		    -cpipe->pipe_buffer.size, 0);
 		vm_map_remove(pipe_map,
 		    (vm_offset_t)cpipe->pipe_buffer.buffer,
 		    (vm_offset_t)cpipe->pipe_buffer.buffer + cpipe->pipe_buffer.size);
@@ -1732,6 +1747,7 @@ pipeclose(struct pipe *cpipe)
 	 */
 	if (ppipe->pipe_present == PIPE_FINALIZED) {
 		PIPE_UNLOCK(cpipe);
+		crfree(cpipe->pipe_pair->pp_owner);
 #ifdef MAC
 		mac_pipe_destroy(pp);
 #endif
diff --git a/sys/sys/pipe.h b/sys/sys/pipe.h
index 61fb57480605..0f35316432eb 100644
--- a/sys/sys/pipe.h
+++ b/sys/sys/pipe.h
@@ -136,6 +136,7 @@ struct pipepair {
 	struct pipe	pp_wpipe;
 	struct mtx	pp_mtx;
 	struct label	*pp_label;
+	struct ucred	*pp_owner;	/* to dec pipe usage count */
 };
 
 #define PIPE_MTX(pipe)		(&(pipe)->pipe_pair->pp_mtx)
diff --git a/sys/sys/resource.h b/sys/sys/resource.h
index 5100501fb2b8..3b582e83d553 100644
--- a/sys/sys/resource.h
+++ b/sys/sys/resource.h
@@ -116,8 +116,9 @@ struct __wrusage {
 #define	RLIMIT_SWAP	12		/* swap used */
 #define	RLIMIT_KQUEUES	13		/* kqueues allocated */
 #define	RLIMIT_UMTXP	14		/* process-shared umtx */
+#define	RLIMIT_PIPEBUF	15		/* pipes/fifos buffers */
 
-#define	RLIM_NLIMITS	15		/* number of resource limits */
+#define	RLIM_NLIMITS	16		/* number of resource limits */
 
 #define	RLIM_INFINITY	((rlim_t)(((__uint64_t)1 << 63) - 1))
 #define	RLIM_SAVED_MAX	RLIM_INFINITY
diff --git a/sys/sys/resourcevar.h b/sys/sys/resourcevar.h
index 49119651665e..8449201dee67 100644
--- a/sys/sys/resourcevar.h
+++ b/sys/sys/resourcevar.h
@@ -123,6 +123,7 @@ struct uidinfo {
 	long	ui_ptscnt;		/* (b) number of pseudo-terminals */
 	long	ui_kqcnt;		/* (b) number of kqueues */
 	long	ui_umtxcnt;		/* (b) number of shared umtxs */
+	long	ui_pipecnt;		/* (b) consumption of pipe buffers */
 	uid_t	ui_uid;			/* (a) uid */
 	u_int	ui_ref;			/* (b) reference count */
 #ifdef	RACCT
@@ -144,6 +145,7 @@ int	 chgsbsize(struct uidinfo *uip, u_int *hiwat, u_int to,
 	    rlim_t maxval);
 int	 chgptscnt(struct uidinfo *uip, int diff, rlim_t maxval);
 int	 chgumtxcnt(struct uidinfo *uip, int diff, rlim_t maxval);
+int	 chgpipecnt(struct uidinfo *uip, int diff, rlim_t max);
 int	 kern_proc_setrlimit(struct thread *td, struct proc *p, u_int which,
 	    struct rlimit *limp);
 struct plimit