git: 89ddfbbac84c - main - jail: Fix regression panic from eb8dcdeac22d
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 13 Jan 2023 10:46:09 UTC
The branch main has been updated by zlei: URL: https://cgit.FreeBSD.org/src/commit/?id=89ddfbbac84cb923e41782c014dc581352e498a9 commit 89ddfbbac84cb923e41782c014dc581352e498a9 Author: Zhenlei Huang <zlei@FreeBSD.org> AuthorDate: 2023-01-13 10:15:06 +0000 Commit: Zhenlei Huang <zlei@FreeBSD.org> CommitDate: 2023-01-13 10:45:14 +0000 jail: Fix regression panic from eb8dcdeac22d And possibly infinite loop calling prison_ip_restrict() in kern_jail_set() [2]. [1] It is possible that prisons do not have any IPv4 or IPv6 addresses. [2] If prison_ip_restrict() is not provided with prison_ip, when it allocates prison_ip successfully, then it should return false to indicate not redo prison_ip_restrict() later. Reviewed by: glebius Approved by: kp (mentor) Fixes: eb8dcdeac22d jail: network epoch protection for IP address lists Differential Revision: https://reviews.freebsd.org/D37906 --- sys/kern/kern_jail.c | 55 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index c8ae362c652c..e9fc8ddae144 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -777,7 +777,7 @@ prison_ip_set(struct prison *pr, const pr_family_t af, struct prison_ip *new) /* * Restrict a prison's IP address list with its parent's, possibly replacing - * it. Return true if the replacement buffer was used (or would have been). + * it. Return true if the replacement buffer was used (or should redo). * kern_jail_set() helper. */ static bool @@ -789,7 +789,7 @@ prison_ip_restrict(struct prison *pr, const pr_family_t af, int (*const cmp)(const void *, const void *) = pr_families[af].cmp; const size_t size = pr_families[af].size; uint32_t ips; - bool alloced; + bool alloced, used; mtx_assert(&pr->pr_mtx, MA_OWNED); @@ -800,28 +800,44 @@ prison_ip_restrict(struct prison *pr, const pr_family_t af, * screw up sorting, and in case of IPv6 we can't even atomically write * one. */ - ips = (pr->pr_flags & pr_families[af].ip_flag) ? pip->ips : ppip->ips; - if (ips == 0) { - prison_ip_set(pr, af, NULL); + if (ppip == NULL) { + if (pip != NULL) + prison_ip_set(pr, af, NULL); return (false); } - if (new == NULL) { - new = prison_ip_alloc(af, ips, M_NOWAIT); - if (new == NULL) - return (true); - alloced = true; - } else - alloced = false; + if (!(pr->pr_flags & pr_families[af].ip_flag)) { + if (new == NULL) { + new = prison_ip_alloc(af, ppip->ips, M_NOWAIT); + if (new == NULL) + return (true); /* redo */ + used = false; + } else + used = true; /* This has no user settings, so just copy the parent's list. */ - bcopy(ppip + 1, new + 1, ips * size); - } else { + MPASS(new->ips == ppip->ips); + bcopy(ppip + 1, new + 1, ppip->ips * size); + prison_ip_set(pr, af, new); + return (used); + } else if (pip != NULL) { /* Remove addresses that aren't in the parent. */ int i; i = 0; /* index in pip */ ips = 0; /* index in new */ + used = true; + if (new == NULL) { + new = prison_ip_alloc(af, pip->ips, M_NOWAIT); + if (new == NULL) + return (true); /* redo */ + used = false; + alloced = true; + } else { + used = true; + alloced = false; + } + for (int pi = 0; pi < ppip->ips; pi++) if (cmp(PR_IP(pip, 0), PR_IP(ppip, pi)) == 0) { /* Found our primary address in parent. */ @@ -860,10 +876,17 @@ prison_ip_restrict(struct prison *pr, const pr_family_t af, if (alloced) prison_ip_free(new); new = NULL; + used = false; + } else { + /* Shrink to real size */ + KASSERT((new->ips >= ips), + ("Out-of-bounds write to prison_ip %p", new)); + new->ips = ips; } + prison_ip_set(pr, af, new); + return (used); } - prison_ip_set(pr, af, new); - return (new != NULL ? true : false); + return (false); } /*