afs: Avoid touching CBRs after free 65/14165/6
authorAndrew Deason <adeason@dson.org>
Mon, 27 Apr 2020 18:28:33 +0000 (13:28 -0500)
committerBenjamin Kaduk <kaduk@mit.edu>
Sun, 5 Sep 2021 16:15:43 +0000 (12:15 -0400)
Currently, we free our CBR structures in shutdown_vcache, but later on
in shutdown_server, we call afs_FreeCBR on each one that's attached to
a struct server. afs_FreeCBR doesn't actually free the memory; it just
modifies some pointers to put the CBR on the free list. Since we do
this after the underlying memory has been freed, it can cause a panic
during shutdown since the structures are no longer valid.

To avoid this, make the afs_FreeCBR calls inside shutdown_vcache,
right before the memory is freed.

Change-Id: I142126d6aa811762b6c234d05abdac3764dad887
Reviewed-on: https://gerrit.openafs.org/14165
Reviewed-by: Michael Meffie <mmeffie@sinenomine.net>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
Tested-by: BuildBot <buildbot@rampaginggeek.com>

src/afs/afs_init.c
src/afs/afs_vcache.c

index d32237e..4d1984c 100644 (file)
@@ -746,7 +746,6 @@ static void
 shutdown_server(void)
 {
     int i;
-    struct afs_cbr *tcbrp, *tbrp;
     struct srvAddr *sa;
 
     for (i = 0; i < NSERVERS; i++) {
@@ -764,13 +763,6 @@ shutdown_server(void)
                    afs_ReleaseConns(sa->conns);
                }
            }
-           for (tcbrp = ts->cbrs; tcbrp; tcbrp = tbrp) {
-               /*
-                * Free all server's callback structs
-                */
-               tbrp = tcbrp->next;
-               afs_FreeCBR(tcbrp);
-           }
            afs_osi_Free(ts, sizeof(struct server));
            ts = next;
        }
index 6ff81b9..670ad62 100644 (file)
@@ -2978,6 +2978,9 @@ shutdown_vcache(void)
 {
     int i;
     struct afs_cbr *tsp;
+    struct afs_cbr *cbr, *cbr_next;
+    struct server *ts;
+
     /*
      * XXX We may potentially miss some of the vcaches because if when
      * there are no free vcache entries and all the vcache entries are active
@@ -3047,6 +3050,20 @@ shutdown_vcache(void)
            afs_vhashT[i] = 0;
        }
     }
+
+    /*
+     * Remove any reference to CBRs in the server structs before we free the
+     * memory for our CBRs below.
+     */
+    for (i = 0; i < NSERVERS; i++) {
+       for (ts = afs_servers[i]; ts; ts = ts->next) {
+           for (cbr = ts->cbrs; cbr; cbr = cbr_next) {
+               cbr_next = cbr->next;
+               afs_FreeCBR(cbr);
+           }
+       }
+    }
+
     /*
      * Free any leftover callback queue
      */