Hi, I would like to protect the write access to the TDB flags field with a mutex. Clearing the timeout flags just before pool put in tdb_free() does not make sense. Move this to tdb_delete().
While there make the parentheses in the flag check consistent. ok? bluhm Index: net/pfkeyv2_convert.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/net/pfkeyv2_convert.c,v retrieving revision 1.76 diff -u -p -r1.76 pfkeyv2_convert.c --- net/pfkeyv2_convert.c 25 Nov 2021 13:46:02 -0000 1.76 +++ net/pfkeyv2_convert.c 9 Dec 2021 15:15:34 -0000 @@ -122,6 +122,7 @@ import_sa(struct tdb *tdb, struct sadb_s if (!sadb_sa) return; + mtx_enter(&tdb->tdb_mtx); if (ii) { ii->ii_encalg = sadb_sa->sadb_sa_encrypt; ii->ii_authalg = sadb_sa->sadb_sa_auth; @@ -145,6 +146,7 @@ import_sa(struct tdb *tdb, struct sadb_s if (sadb_sa->sadb_sa_state != SADB_SASTATE_MATURE) tdb->tdb_flags |= TDBF_INVALID; + mtx_leave(&tdb->tdb_mtx); } /* @@ -282,6 +284,7 @@ import_lifetime(struct tdb *tdb, struct if (!sadb_lifetime) return; + mtx_enter(&tdb->tdb_mtx); switch (type) { case PFKEYV2_LIFETIME_HARD: if ((tdb->tdb_exp_allocations = @@ -348,6 +351,7 @@ import_lifetime(struct tdb *tdb, struct tdb->tdb_established = sadb_lifetime->sadb_lifetime_addtime; tdb->tdb_first_use = sadb_lifetime->sadb_lifetime_usetime; } + mtx_leave(&tdb->tdb_mtx); } /* Index: netinet/ip_ah.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ah.c,v retrieving revision 1.168 diff -u -p -r1.168 ip_ah.c --- netinet/ip_ah.c 2 Dec 2021 12:39:15 -0000 1.168 +++ netinet/ip_ah.c 9 Dec 2021 17:46:28 -0000 @@ -612,8 +612,8 @@ ah_input(struct mbuf **mp, struct tdb *t ahstat_add(ahs_ibytes, ibytes); /* Hard expiration. */ - if (tdb->tdb_flags & TDBF_BYTES && - tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes) { + if ((tdb->tdb_flags & TDBF_BYTES) && + (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) { ipsecstat_inc(ipsec_exctdb); pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); tdb_delete(tdb); @@ -621,11 +621,15 @@ ah_input(struct mbuf **mp, struct tdb *t } /* Notify on expiration. */ - if (tdb->tdb_flags & TDBF_SOFT_BYTES && - tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes) { + mtx_enter(&tdb->tdb_mtx); + if ((tdb->tdb_flags & TDBF_SOFT_BYTES) && + (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) { + tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ + mtx_leave(&tdb->tdb_mtx); + /* may sleep in solock() for the pfkey socket */ pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); - tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking. */ - } + } else + mtx_leave(&tdb->tdb_mtx); /* Get crypto descriptors. */ crp = crypto_getreq(1); @@ -952,8 +956,8 @@ ah_output(struct mbuf *m, struct tdb *td ahstat_add(ahs_obytes, m->m_pkthdr.len - skip); /* Hard expiration. */ - if (tdb->tdb_flags & TDBF_BYTES && - tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes) { + if ((tdb->tdb_flags & TDBF_BYTES) && + (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) { ipsecstat_inc(ipsec_exctdb); pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); tdb_delete(tdb); @@ -962,11 +966,15 @@ ah_output(struct mbuf *m, struct tdb *td } /* Notify on expiration. */ - if (tdb->tdb_flags & TDBF_SOFT_BYTES && - tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes) { + mtx_enter(&tdb->tdb_mtx); + if ((tdb->tdb_flags & TDBF_SOFT_BYTES) && + (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) { + tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ + mtx_leave(&tdb->tdb_mtx); + /* may sleep in solock() for the pfkey socket */ pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); - tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ - } + } else + mtx_leave(&tdb->tdb_mtx); /* * Loop through mbuf chain; if we find a readonly mbuf, Index: netinet/ip_esp.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_esp.c,v retrieving revision 1.188 diff -u -p -r1.188 ip_esp.c --- netinet/ip_esp.c 21 Nov 2021 16:17:48 -0000 1.188 +++ netinet/ip_esp.c 9 Dec 2021 17:47:28 -0000 @@ -433,11 +433,15 @@ esp_input(struct mbuf **mp, struct tdb * } /* Notify on soft expiration */ + mtx_enter(&tdb->tdb_mtx); if ((tdb->tdb_flags & TDBF_SOFT_BYTES) && (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) { + tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ + mtx_leave(&tdb->tdb_mtx); + /* may sleep in solock() for the pfkey socket */ pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); - tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ - } + } else + mtx_leave(&tdb->tdb_mtx); /* Get crypto descriptors */ crp = crypto_getreq(esph && espx ? 2 : 1); @@ -781,8 +785,8 @@ esp_output(struct mbuf *m, struct tdb *t espstat_add(esps_obytes, m->m_pkthdr.len - skip); /* Hard byte expiration. */ - if (tdb->tdb_flags & TDBF_BYTES && - tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes) { + if ((tdb->tdb_flags & TDBF_BYTES) && + (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) { ipsecstat_inc(ipsec_exctdb); pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); tdb_delete(tdb); @@ -791,11 +795,15 @@ esp_output(struct mbuf *m, struct tdb *t } /* Soft byte expiration. */ - if (tdb->tdb_flags & TDBF_SOFT_BYTES && - tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes) { + mtx_enter(&tdb->tdb_mtx); + if ((tdb->tdb_flags & TDBF_SOFT_BYTES) && + (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) { + tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ + mtx_leave(&tdb->tdb_mtx); + /* may sleep in solock() for the pfkey socket */ pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); - tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking. */ - } + } else + mtx_leave(&tdb->tdb_mtx); /* * Loop through mbuf chain; if we find a readonly mbuf, Index: netinet/ip_ipcomp.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipcomp.c,v retrieving revision 1.88 diff -u -p -r1.88 ip_ipcomp.c --- netinet/ip_ipcomp.c 21 Nov 2021 16:17:48 -0000 1.88 +++ netinet/ip_ipcomp.c 9 Dec 2021 17:48:06 -0000 @@ -205,11 +205,15 @@ ipcomp_input(struct mbuf **mp, struct td goto drop; } /* Notify on soft expiration */ + mtx_enter(&tdb->tdb_mtx); if ((tdb->tdb_flags & TDBF_SOFT_BYTES) && (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) { + tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ + mtx_leave(&tdb->tdb_mtx); + /* may sleep in solock() for the pfkey socket */ pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); - tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ - } + } else + mtx_leave(&tdb->tdb_mtx); /* In case it's not done already, adjust the size of the mbuf chain */ m->m_pkthdr.len = clen + hlen + skip; @@ -393,12 +397,18 @@ ipcomp_output(struct mbuf *m, struct tdb error = EINVAL; goto drop; } + /* Soft byte expiration */ + mtx_enter(&tdb->tdb_mtx); if ((tdb->tdb_flags & TDBF_SOFT_BYTES) && (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) { + tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ + mtx_leave(&tdb->tdb_mtx); + /* may sleep in solock() for the pfkey socket */ pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); - tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ - } + } else + mtx_leave(&tdb->tdb_mtx); + /* * Loop through mbuf chain; if we find a readonly mbuf, * copy the packet. Index: netinet/ip_ipsp.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipsp.c,v retrieving revision 1.263 diff -u -p -r1.263 ip_ipsp.c --- netinet/ip_ipsp.c 8 Dec 2021 14:24:18 -0000 1.263 +++ netinet/ip_ipsp.c 9 Dec 2021 17:50:12 -0000 @@ -311,11 +311,13 @@ reserve_spi(u_int rdomain, u_int32_t ssp #ifdef IPSEC /* Setup a "silent" expiration (since TDBF_INVALID's set). */ if (ipsec_keep_invalid > 0) { + mtx_enter(&tdbp->tdb_mtx); tdbp->tdb_flags |= TDBF_TIMER; tdbp->tdb_exp_timeout = ipsec_keep_invalid; if (timeout_add_sec(&tdbp->tdb_timer_tmo, ipsec_keep_invalid)) tdb_ref(tdbp); + mtx_leave(&tdbp->tdb_mtx); } #endif @@ -701,11 +703,14 @@ tdb_soft_timeout(void *v) struct tdb *tdb = v; NET_LOCK(); + mtx_enter(&tdb->tdb_mtx); if (tdb->tdb_flags & TDBF_SOFT_TIMER) { + tdb->tdb_flags &= ~TDBF_SOFT_TIMER; + mtx_leave(&tdb->tdb_mtx); /* Soft expirations. */ pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); - tdb->tdb_flags &= ~TDBF_SOFT_TIMER; - } + } else + mtx_leave(&tdb->tdb_mtx); /* decrement refcount of the timeout argument */ tdb_unref(tdb); NET_UNLOCK(); @@ -717,12 +722,15 @@ tdb_soft_firstuse(void *v) struct tdb *tdb = v; NET_LOCK(); + mtx_enter(&tdb->tdb_mtx); if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) { + tdb->tdb_flags &= ~TDBF_SOFT_FIRSTUSE; + mtx_leave(&tdb->tdb_mtx); /* If the TDB hasn't been used, don't renew it. */ if (tdb->tdb_first_use != 0) pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); - tdb->tdb_flags &= ~TDBF_SOFT_FIRSTUSE; - } + } else + mtx_leave(&tdb->tdb_mtx); /* decrement refcount of the timeout argument */ tdb_unref(tdb); NET_UNLOCK(); @@ -958,6 +966,9 @@ tdb_unbundle(struct tdb *tdbp) void tdb_deltimeouts(struct tdb *tdbp) { + mtx_enter(&tdbp->tdb_mtx); + tdbp->tdb_flags &= ~(TDBF_FIRSTUSE | TDBF_SOFT_FIRSTUSE | TDBF_TIMER | + TDBF_SOFT_TIMER); if (timeout_del(&tdbp->tdb_timer_tmo)) tdb_unref(tdbp); if (timeout_del(&tdbp->tdb_first_tmo)) @@ -966,6 +977,7 @@ tdb_deltimeouts(struct tdb *tdbp) tdb_unref(tdbp); if (timeout_del(&tdbp->tdb_sfirst_tmo)) tdb_unref(tdbp); + mtx_leave(&tdbp->tdb_mtx); } struct tdb * @@ -1005,9 +1017,13 @@ tdb_dodelete(struct tdb *tdbp, int locke { NET_ASSERT_LOCKED(); - if (tdbp->tdb_flags & TDBF_DELETED) + mtx_enter(&tdbp->tdb_mtx); + if (tdbp->tdb_flags & TDBF_DELETED) { + mtx_leave(&tdbp->tdb_mtx); return; + } tdbp->tdb_flags |= TDBF_DELETED; + mtx_leave(&tdbp->tdb_mtx); if (locked) tdb_unlink_locked(tdbp); else @@ -1034,6 +1050,7 @@ tdb_alloc(u_int rdomain) tdbp = pool_get(&tdb_pool, PR_WAITOK | PR_ZERO); refcnt_init(&tdbp->tdb_refcnt); + mtx_init(&tdbp->tdb_mtx, IPL_SOFTNET); TAILQ_INIT(&tdbp->tdb_policy_head); /* Record establishment time. */ @@ -1085,8 +1102,6 @@ tdb_free(struct tdb *tdbp) KASSERT(tdbp->tdb_inext == NULL); /* Remove expiration timeouts. */ - tdbp->tdb_flags &= ~(TDBF_FIRSTUSE | TDBF_SOFT_FIRSTUSE | TDBF_TIMER | - TDBF_SOFT_TIMER); KASSERT(timeout_pending(&tdbp->tdb_timer_tmo) == 0); KASSERT(timeout_pending(&tdbp->tdb_first_tmo) == 0); KASSERT(timeout_pending(&tdbp->tdb_stimer_tmo) == 0); Index: netinet/ip_ipsp.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipsp.h,v retrieving revision 1.229 diff -u -p -r1.229 ip_ipsp.h --- netinet/ip_ipsp.h 8 Dec 2021 14:24:18 -0000 1.229 +++ netinet/ip_ipsp.h 9 Dec 2021 13:55:59 -0000 @@ -314,6 +314,7 @@ struct ipsec_policy { * I immutable after creation * N net lock * s tdb_sadb_mtx + * m tdb_mtx */ struct tdb { /* tunnel descriptor block */ /* @@ -331,6 +332,7 @@ struct tdb { /* tunnel descriptor blo struct tdb *tdb_onext; struct refcnt tdb_refcnt; + struct mutex tdb_mtx; const struct xformsw *tdb_xform; /* Transform to use */ const struct enc_xform *tdb_encalgxform; /* Enc algorithm */ @@ -364,7 +366,7 @@ struct tdb { /* tunnel descriptor blo "\21USEDTUNNEL\22UDPENCAP\23PFSYNC\24PFSYNC_RPL" \ "\25ESN") - u_int32_t tdb_flags; /* Flags related to this TDB */ + u_int32_t tdb_flags; /* [m] Flags related to this TDB */ struct timeout tdb_timer_tmo; struct timeout tdb_first_tmo; Index: netinet/ipsec_output.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ipsec_output.c,v retrieving revision 1.93 diff -u -p -r1.93 ipsec_output.c --- netinet/ipsec_output.c 2 Dec 2021 12:39:15 -0000 1.93 +++ netinet/ipsec_output.c 9 Dec 2021 15:19:22 -0000 @@ -268,7 +268,9 @@ ipsp_process_packet(struct mbuf *m, stru } /* Remember that we appended a tunnel header. */ + mtx_enter(&tdb->tdb_mtx); tdb->tdb_flags |= TDBF_USEDTUNNEL; + mtx_leave(&tdb->tdb_mtx); } }