The branch main has been updated by zlei:

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

commit 89ddfbbac84cb923e41782c014dc581352e498a9
Author:     Zhenlei Huang <z...@freebsd.org>
AuthorDate: 2023-01-13 10:15:06 +0000
Commit:     Zhenlei Huang <z...@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);
 }
 
 /*

Reply via email to