Hello,

On Thu, Feb 24, 2022 at 10:42:58PM +0100, Alexander Bluhm wrote:
> Hi,
> 
> Hrvoje reported some crashes with pfsync, IPsec and parallel
> forwarding.  Some locks were missing around the tdb flags in pfsync.
> 
> ok?
> 

    change looks good to me. I just have a single concern
    about pfsync_update_tdb() which I think deserves some
    attention:

2474 void
2475 pfsync_update_tdb(struct tdb *t, int output)
2476 {
2477         struct pfsync_softc *sc = pfsyncif;
2478         size_t nlen, sc_len;
2479 
2480         if (sc == NULL)
2481                 return;
2482 
2483         if (!ISSET(t->tdb_flags, TDBF_PFSYNC)) {
2484                 do {
2485                         mtx_enter(&sc->sc_tdb_mtx);
2486                         nlen = sizeof(struct pfsync_tdb);
2487 
2488                         if (TAILQ_EMPTY(&sc->sc_tdb_q))
2489                                 nlen += sizeof(struct pfsync_subheader);
2490 
2491                         sc_len = atomic_add_long_nv(&sc->sc_len, nlen);
2492                         if (sc_len > sc->sc_if.if_mtu) {
2493                                 atomic_sub_long(&sc->sc_len, nlen);
2494                                 mtx_leave(&sc->sc_tdb_mtx);
2495                                 pfsync_sendout();
2496                                 continue;
2497                         }

    my concern is we check ->tdb_flags at line 2483 _without_ holding
    ->tdb_mtx. I think we should re-check the flag as soon as we
    grab ->tdb_mtx in the 'do {} while ()' loop. diff below does that.
    it applies on top of your diff. with tweak suggested below the change
    is OK sashan@

thanks and
regards
sashan

--------8<---------------8<---------------8<------------------8<--------
diff --git a/sys/net/if_pfsync.c b/sys/net/if_pfsync.c
index c934392af0f..620aa73060b 100644
--- a/sys/net/if_pfsync.c
+++ b/sys/net/if_pfsync.c
@@ -2485,19 +2485,27 @@ pfsync_update_tdb(struct tdb *t, int output)
                        mtx_enter(&sc->sc_tdb_mtx);
                        nlen = sizeof(struct pfsync_tdb);
 
+                       mtx_enter(&t->tdb_mtx);
+                       if (ISSET(t->tdb_flags, TDBF_PFSYNC)) {
+                               /* we've lost race, no action for us then */
+                               mtx_leave(&t->tdb_mtx);
+                               mtx_leave(&sc->sc_tdb_mtx);
+                               break;
+                       }
+
                        if (TAILQ_EMPTY(&sc->sc_tdb_q))
                                nlen += sizeof(struct pfsync_subheader);
 
                        sc_len = atomic_add_long_nv(&sc->sc_len, nlen);
                        if (sc_len > sc->sc_if.if_mtu) {
                                atomic_sub_long(&sc->sc_len, nlen);
+                               mtx_leave(&t->tdb_mtx);
                                mtx_leave(&sc->sc_tdb_mtx);
                                pfsync_sendout();
                                continue;
                        }
 
                        TAILQ_INSERT_TAIL(&sc->sc_tdb_q, t, tdb_sync_entry);
-                       mtx_enter(&t->tdb_mtx);
                        SET(t->tdb_flags, TDBF_PFSYNC);
                        mtx_leave(&t->tdb_mtx);
 

Reply via email to