Hi, I got a new hardware in my testlab and could panic this machine easily with the tdb refcount diff.
Adding tdb refcounts for timeout fixes this for me. This allows to get rid of the timeout reaper. I refcount all successful timeout_add() and decrease in timeout handler. There are no timeout_del() left. Maybe we should do timeout_del() in tdb_delete(). This diff does not address the other bugs that mvs@ sees. There is more to fix. I want to show my current work. As usual I ignore veb(4) #if 0. bluhm Index: net/if_bridge.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_bridge.c,v retrieving revision 1.358 diff -u -p -r1.358 if_bridge.c --- net/if_bridge.c 11 Nov 2021 18:08:17 -0000 1.358 +++ net/if_bridge.c 19 Nov 2021 15:18:18 -0000 @@ -1567,20 +1567,28 @@ bridge_ipsec(struct ifnet *ifp, struct e tdb->tdb_xform != NULL) { if (tdb->tdb_first_use == 0) { tdb->tdb_first_use = gettime(); - if (tdb->tdb_flags & TDBF_FIRSTUSE) - timeout_add_sec(&tdb->tdb_first_tmo, - tdb->tdb_exp_first_use); - if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) - timeout_add_sec(&tdb->tdb_sfirst_tmo, - tdb->tdb_soft_first_use); + if (tdb->tdb_flags & TDBF_FIRSTUSE) { + if (timeout_add_sec( + &tdb->tdb_first_tmo, + tdb->tdb_exp_first_use)) + tdb_ref(tdb); + } + if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) { + if (timeout_add_sec( + &tdb->tdb_sfirst_tmo, + tdb->tdb_soft_first_use)) + tdb_ref(tdb); + } } prot = (*(tdb->tdb_xform->xf_input))(&m, tdb, hlen, off); + tdb_unref(tdb); if (prot != IPPROTO_DONE) ip_deliver(&m, &hlen, prot, af); return (1); } else { + tdb_unref(tdb); skiplookup: /* XXX do an input policy lookup */ return (0); Index: net/if_pfsync.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_pfsync.c,v retrieving revision 1.298 diff -u -p -r1.298 if_pfsync.c --- net/if_pfsync.c 11 Nov 2021 12:35:01 -0000 1.298 +++ net/if_pfsync.c 19 Nov 2021 13:04:58 -0000 @@ -1325,11 +1325,13 @@ pfsync_update_net_tdb(struct pfsync_tdb /* Neither replay nor byte counter should ever decrease. */ if (pt->rpl < tdb->tdb_rpl || pt->cur_bytes < tdb->tdb_cur_bytes) { + tdb_unref(tdb); goto bad; } tdb->tdb_rpl = pt->rpl; tdb->tdb_cur_bytes = pt->cur_bytes; + tdb_unref(tdb); } return; Index: net/pfkeyv2.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/net/pfkeyv2.c,v retrieving revision 1.221 diff -u -p -r1.221 pfkeyv2.c --- net/pfkeyv2.c 25 Oct 2021 18:25:01 -0000 1.221 +++ net/pfkeyv2.c 19 Nov 2021 13:04:58 -0000 @@ -1044,7 +1044,8 @@ pfkeyv2_sa_flush(struct tdb *tdb, void * if (!(*((u_int8_t *) satype_vp)) || tdb->tdb_satype == *((u_int8_t *) satype_vp)) { tdb_unlink_locked(tdb); - tdb_free(tdb); + tdb_unbundle(tdb); + tdb_unref(tdb); } return (0); } @@ -1327,7 +1328,7 @@ pfkeyv2_send(struct socket *so, void *me if ((rval = pfkeyv2_get_proto_alg(newsa->tdb_satype, &newsa->tdb_sproto, &alg))) { - tdb_free(freeme); + tdb_unref(freeme); freeme = NULL; NET_UNLOCK(); goto ret; @@ -1363,7 +1364,7 @@ pfkeyv2_send(struct socket *so, void *me headers[SADB_X_EXT_DST_MASK], headers[SADB_X_EXT_PROTOCOL], headers[SADB_X_EXT_FLOW_TYPE]))) { - tdb_free(freeme); + tdb_unref(freeme); freeme = NULL; NET_UNLOCK(); goto ret; @@ -1386,7 +1387,7 @@ pfkeyv2_send(struct socket *so, void *me rval = tdb_init(newsa, alg, &ii); if (rval) { rval = EINVAL; - tdb_free(freeme); + tdb_unref(freeme); freeme = NULL; NET_UNLOCK(); goto ret; @@ -1397,7 +1398,7 @@ pfkeyv2_send(struct socket *so, void *me /* Delete old version of the SA, insert new one */ tdb_delete(sa2); puttdb((struct tdb *) freeme); - sa2 = freeme = NULL; + freeme = NULL; } else { /* * The SA is already initialized, so we're only allowed to @@ -1503,7 +1504,7 @@ pfkeyv2_send(struct socket *so, void *me newsa->tdb_satype = smsg->sadb_msg_satype; if ((rval = pfkeyv2_get_proto_alg(newsa->tdb_satype, &newsa->tdb_sproto, &alg))) { - tdb_free(freeme); + tdb_unref(freeme); freeme = NULL; NET_UNLOCK(); goto ret; @@ -1541,7 +1542,7 @@ pfkeyv2_send(struct socket *so, void *me headers[SADB_X_EXT_DST_MASK], headers[SADB_X_EXT_PROTOCOL], headers[SADB_X_EXT_FLOW_TYPE]))) { - tdb_free(freeme); + tdb_unref(freeme); freeme = NULL; NET_UNLOCK(); goto ret; @@ -1564,7 +1565,7 @@ pfkeyv2_send(struct socket *so, void *me rval = tdb_init(newsa, alg, &ii); if (rval) { rval = EINVAL; - tdb_free(freeme); + tdb_unref(freeme); freeme = NULL; NET_UNLOCK(); goto ret; @@ -1596,7 +1597,6 @@ pfkeyv2_send(struct socket *so, void *me tdb_delete(sa2); NET_UNLOCK(); - sa2 = NULL; break; case SADB_X_ASKPOLICY: @@ -1786,6 +1786,7 @@ pfkeyv2_send(struct socket *so, void *me ssa->sadb_sa_spi, sunionp, SADB_X_GETSPROTO(sa_proto->sadb_protocol_proto)); if (tdb2 == NULL) { + tdb_unref(tdb1); rval = ESRCH; NET_UNLOCK(); goto ret; @@ -1794,6 +1795,8 @@ pfkeyv2_send(struct socket *so, void *me /* Detect cycles */ for (tdb3 = tdb2; tdb3; tdb3 = tdb3->tdb_onext) if (tdb3 == tdb1) { + tdb_unref(tdb1); + tdb_unref(tdb2); rval = ESRCH; NET_UNLOCK(); goto ret; @@ -1801,12 +1804,16 @@ pfkeyv2_send(struct socket *so, void *me /* Maintenance */ if ((tdb1->tdb_onext) && - (tdb1->tdb_onext->tdb_inext == tdb1)) + (tdb1->tdb_onext->tdb_inext == tdb1)) { + tdb_unref(tdb1->tdb_onext->tdb_inext); tdb1->tdb_onext->tdb_inext = NULL; + } if ((tdb2->tdb_inext) && - (tdb2->tdb_inext->tdb_onext == tdb2)) + (tdb2->tdb_inext->tdb_onext == tdb2)) { + tdb_unref(tdb2->tdb_inext->tdb_onext); tdb2->tdb_inext->tdb_onext = NULL; + } /* Link them */ tdb1->tdb_onext = tdb2; @@ -2008,10 +2015,12 @@ pfkeyv2_send(struct socket *so, void *me (caddr_t)&ipo->ipo_mask, rnh, ipo->ipo_nodes, 0)) == NULL) { /* Remove from linked list of policies on TDB */ - if (ipo->ipo_tdb) - TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, + if (ipo->ipo_tdb != NULL) { + TAILQ_REMOVE( + &ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); - + tdb_unref(ipo->ipo_tdb); + } if (ipo->ipo_ids) ipsp_ids_free(ipo->ipo_ids); pool_put(&ipsec_policy_pool, ipo); @@ -2127,6 +2136,10 @@ realret: free(message, M_PFKEY, len); free(sa1, M_PFKEY, sizeof(*sa1)); + + NET_LOCK(); + tdb_unref(sa2); + NET_UNLOCK(); return (rval); } Index: net/pfkeyv2_convert.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/net/pfkeyv2_convert.c,v retrieving revision 1.75 diff -u -p -r1.75 pfkeyv2_convert.c --- net/pfkeyv2_convert.c 22 Oct 2021 12:30:53 -0000 1.75 +++ net/pfkeyv2_convert.c 19 Nov 2021 15:18:18 -0000 @@ -299,8 +299,9 @@ import_lifetime(struct tdb *tdb, struct if ((tdb->tdb_exp_timeout = sadb_lifetime->sadb_lifetime_addtime) != 0) { tdb->tdb_flags |= TDBF_TIMER; - timeout_add_sec(&tdb->tdb_timer_tmo, - tdb->tdb_exp_timeout); + if (timeout_add_sec(&tdb->tdb_timer_tmo, + tdb->tdb_exp_timeout)) + tdb_ref(tdb); } else tdb->tdb_flags &= ~TDBF_TIMER; @@ -327,8 +328,9 @@ import_lifetime(struct tdb *tdb, struct if ((tdb->tdb_soft_timeout = sadb_lifetime->sadb_lifetime_addtime) != 0) { tdb->tdb_flags |= TDBF_SOFT_TIMER; - timeout_add_sec(&tdb->tdb_stimer_tmo, - tdb->tdb_soft_timeout); + if (timeout_add_sec(&tdb->tdb_stimer_tmo, + tdb->tdb_soft_timeout)) + tdb_ref(tdb); } else tdb->tdb_flags &= ~TDBF_SOFT_TIMER; Index: netinet/ip_ipsp.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipsp.c,v retrieving revision 1.251 diff -u -p -r1.251 ip_ipsp.c --- netinet/ip_ipsp.c 18 Nov 2021 11:04:10 -0000 1.251 +++ netinet/ip_ipsp.c 19 Nov 2021 16:56:53 -0000 @@ -85,7 +85,6 @@ void tdb_hashstats(void); #endif int tdb_rehash(void); -void tdb_reaper(void *); void tdb_timeout(void *); void tdb_firstuse(void *); void tdb_soft_timeout(void *); @@ -297,9 +296,10 @@ reserve_spi(u_int rdomain, u_int32_t ssp /* Check whether we're using this SPI already. */ exists = gettdb(rdomain, spi, dst, sproto); - if (exists) + if (exists != NULL) { + tdb_unref(exists); continue; - + } tdbp->tdb_spi = spi; memcpy(&tdbp->tdb_dst.sa, &dst->sa, dst->sa.sa_len); @@ -314,8 +314,9 @@ reserve_spi(u_int rdomain, u_int32_t ssp if (ipsec_keep_invalid > 0) { tdbp->tdb_flags |= TDBF_TIMER; tdbp->tdb_exp_timeout = ipsec_keep_invalid; - timeout_add_sec(&tdbp->tdb_timer_tmo, - ipsec_keep_invalid); + if (timeout_add_sec(&tdbp->tdb_timer_tmo, + ipsec_keep_invalid)) + tdb_ref(tdbp); } #endif @@ -351,6 +352,7 @@ gettdb_dir(u_int rdomain, u_int32_t spi, !memcmp(&tdbp->tdb_dst, dst, dst->sa.sa_len)) break; + tdb_ref(tdbp); mtx_leave(&tdb_sadb_mtx); return tdbp; } @@ -383,6 +385,7 @@ gettdbbysrcdst_dir(u_int rdomain, u_int3 break; if (tdbp != NULL) { + tdb_ref(tdbp); mtx_leave(&tdb_sadb_mtx); return tdbp; } @@ -402,6 +405,7 @@ gettdbbysrcdst_dir(u_int rdomain, u_int3 tdbp->tdb_src.sa.sa_family == AF_UNSPEC) break; + tdb_ref(tdbp); mtx_leave(&tdb_sadb_mtx); return tdbp; } @@ -469,6 +473,7 @@ gettdbbydst(u_int rdomain, union sockadd break; } + tdb_ref(tdbp); mtx_leave(&tdb_sadb_mtx); return tdbp; } @@ -499,6 +504,7 @@ gettdbbysrc(u_int rdomain, union sockadd break; } + tdb_ref(tdbp); mtx_leave(&tdb_sadb_mtx); return tdbp; } @@ -548,6 +554,7 @@ tdb_printit(void *addr, int full, int (* DUMP(inext, "%p"); DUMP(onext, "%p"); DUMP(xform, "%p"); + pr("%18s: %d\n", "refcnt", tdb->tdb_refcnt.refs); DUMP(encalgxform, "%p"); DUMP(authalgxform, "%p"); DUMP(compalgxform, "%p"); @@ -607,6 +614,7 @@ tdb_printit(void *addr, int full, int (* pr(" %s", ipsp_address(&tdb->tdb_src, buf, sizeof(buf))); pr("->%s", ipsp_address(&tdb->tdb_dst, buf, sizeof(buf))); pr(":%d", tdb->tdb_sproto); + pr(" #%d", tdb->tdb_refcnt.refs); pr(" %08x\n", tdb->tdb_flags); } } @@ -655,6 +663,9 @@ tdb_timeout(void *v) if (!(tdb->tdb_flags & TDBF_INVALID)) pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); tdb_delete(tdb); + } else { + /* decrement refcount of the timeout argument */ + tdb_unref(tdb); } NET_UNLOCK(); } @@ -670,6 +681,9 @@ tdb_firstuse(void *v) if (tdb->tdb_first_use != 0) pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); tdb_delete(tdb); + } else { + /* decrement refcount of the timeout argument */ + tdb_unref(tdb); } NET_UNLOCK(); } @@ -684,6 +698,9 @@ tdb_soft_timeout(void *v) /* Soft expirations. */ pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); tdb->tdb_flags &= ~TDBF_SOFT_TIMER; + } else { + /* decrement refcount of the timeout argument */ + tdb_unref(tdb); } NET_UNLOCK(); } @@ -699,6 +716,9 @@ tdb_soft_firstuse(void *v) if (tdb->tdb_first_use != 0) pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); tdb->tdb_flags &= ~TDBF_SOFT_FIRSTUSE; + } else { + /* decrement refcount of the timeout argument */ + tdb_unref(tdb); } NET_UNLOCK(); } @@ -890,12 +910,55 @@ tdb_unlink_locked(struct tdb *tdbp) } void +tdb_unbundle(struct tdb *tdbp) +{ + if (tdbp->tdb_onext) { + if (tdbp->tdb_onext->tdb_inext == tdbp) { + tdb_unref(tdbp); /* to us */ + tdbp->tdb_onext->tdb_inext = NULL; + } + tdb_unref(tdbp->tdb_onext); /* to other */ + tdbp->tdb_onext = NULL; + } + if (tdbp->tdb_inext) { + if (tdbp->tdb_inext->tdb_onext == tdbp) { + tdb_unref(tdbp); /* to us */ + tdbp->tdb_inext->tdb_onext = NULL; + } + tdb_unref(tdbp->tdb_inext); /* to other */ + tdbp->tdb_inext = NULL; + } +} + +struct tdb * +tdb_ref(struct tdb *tdb) +{ + if (tdb == NULL) + return NULL; + refcnt_take(&tdb->tdb_refcnt); + return tdb; +} + +void +tdb_unref(struct tdb *tdb) +{ + if (tdb == NULL) + return; + if (refcnt_rele(&tdb->tdb_refcnt) == 0) + return; + tdb_free(tdb); +} + +void tdb_delete(struct tdb *tdbp) { NET_ASSERT_LOCKED(); tdb_unlink(tdbp); - tdb_free(tdbp); + /* release tdb_onext/tdb_inext references */ + tdb_unbundle(tdbp); + /* release the reference for tdb_unlink() */ + tdb_unref(tdbp); } /* @@ -910,6 +973,7 @@ tdb_alloc(u_int rdomain) tdbp = pool_get(&tdb_pool, PR_WAITOK | PR_ZERO); + refcnt_init(&tdbp->tdb_refcnt); TAILQ_INIT(&tdbp->tdb_policy_head); /* Record establishment time. */ @@ -946,9 +1010,9 @@ tdb_free(struct tdb *tdbp) #endif /* Cleanup SPD references. */ - for (ipo = TAILQ_FIRST(&tdbp->tdb_policy_head); ipo; - ipo = TAILQ_FIRST(&tdbp->tdb_policy_head)) { + while ((ipo = TAILQ_FIRST(&tdbp->tdb_policy_head)) != NULL) { TAILQ_REMOVE(&tdbp->tdb_policy_head, ipo, ipo_tdb_next); + tdb_unref(ipo->ipo_tdb); ipo->ipo_tdb = NULL; ipo->ipo_last_searched = 0; /* Force a re-search. */ } @@ -965,28 +1029,13 @@ tdb_free(struct tdb *tdbp) } #endif - if ((tdbp->tdb_onext) && (tdbp->tdb_onext->tdb_inext == tdbp)) - tdbp->tdb_onext->tdb_inext = NULL; - - if ((tdbp->tdb_inext) && (tdbp->tdb_inext->tdb_onext == tdbp)) - tdbp->tdb_inext->tdb_onext = NULL; - /* Remove expiration timeouts. */ tdbp->tdb_flags &= ~(TDBF_FIRSTUSE | TDBF_SOFT_FIRSTUSE | TDBF_TIMER | TDBF_SOFT_TIMER); - timeout_del(&tdbp->tdb_timer_tmo); - timeout_del(&tdbp->tdb_first_tmo); - timeout_del(&tdbp->tdb_stimer_tmo); - timeout_del(&tdbp->tdb_sfirst_tmo); - - timeout_set_proc(&tdbp->tdb_timer_tmo, tdb_reaper, tdbp); - timeout_add(&tdbp->tdb_timer_tmo, 0); -} - -void -tdb_reaper(void *xtdbp) -{ - struct tdb *tdbp = xtdbp; + KASSERT(timeout_pending(&tdbp->tdb_timer_tmo) == 0); + KASSERT(timeout_pending(&tdbp->tdb_first_tmo) == 0); + KASSERT(timeout_pending(&tdbp->tdb_stimer_tmo) == 0); + KASSERT(timeout_pending(&tdbp->tdb_sfirst_tmo) == 0); pool_put(&tdb_pool, tdbp); } Index: netinet/ip_ipsp.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipsp.h,v retrieving revision 1.220 diff -u -p -r1.220 ip_ipsp.h --- netinet/ip_ipsp.h 16 Nov 2021 13:53:14 -0000 1.220 +++ netinet/ip_ipsp.h 19 Nov 2021 16:56:36 -0000 @@ -322,6 +322,8 @@ struct tdb { /* tunnel descriptor blo struct tdb *tdb_inext; struct tdb *tdb_onext; + struct refcnt tdb_refcnt; + const struct xformsw *tdb_xform; /* Transform to use */ const struct enc_xform *tdb_encalgxform; /* Enc algorithm */ const struct auth_hash *tdb_authalgxform; /* Auth algorithm */ @@ -562,10 +564,13 @@ struct tdb *gettdbbysrcdst_dir(u_int, u_ void puttdb(struct tdb *); void tdb_delete(struct tdb *); struct tdb *tdb_alloc(u_int); +struct tdb *tdb_ref(struct tdb *); +void tdb_unref(struct tdb *); void tdb_free(struct tdb *); int tdb_init(struct tdb *, u_int16_t, struct ipsecinit *); void tdb_unlink(struct tdb *); void tdb_unlink_locked(struct tdb *); +void tdb_unbundle(struct tdb *); int tdb_walk(u_int, int (*)(struct tdb *, void *, int), void *); void tdb_printit(void *, int, int (*)(const char *, ...)); Index: netinet/ip_spd.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_spd.c,v retrieving revision 1.104 diff -u -p -r1.104 ip_spd.c --- netinet/ip_spd.c 8 Jul 2021 16:39:55 -0000 1.104 +++ netinet/ip_spd.c 19 Nov 2021 13:04:58 -0000 @@ -368,9 +368,11 @@ ipsp_spd_lookup(struct mbuf *m, int af, } /* Do we have a cached entry ? If so, check if it's still valid. */ - if ((ipo->ipo_tdb) && (ipo->ipo_tdb->tdb_flags & TDBF_INVALID)) { + if (ipo->ipo_tdb != NULL && + (ipo->ipo_tdb->tdb_flags & TDBF_INVALID)) { TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); + tdb_unref(ipo->ipo_tdb); ipo->ipo_tdb = NULL; } @@ -398,7 +400,7 @@ ipsp_spd_lookup(struct mbuf *m, int af, ids = ipsp_ids_lookup(ipsecflowinfo); /* Check that the cached TDB (if present), is appropriate. */ - if (ipo->ipo_tdb) { + if (ipo->ipo_tdb != NULL) { if ((ipo->ipo_last_searched <= ipsec_last_added) || (ipo->ipo_sproto != ipo->ipo_tdb->tdb_sproto) || memcmp(dignore ? &sdst : &ipo->ipo_dst, @@ -420,6 +422,7 @@ ipsp_spd_lookup(struct mbuf *m, int af, /* Cached TDB was not good. */ TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); + tdb_unref(ipo->ipo_tdb); ipo->ipo_tdb = NULL; ipo->ipo_last_searched = 0; } @@ -439,14 +442,14 @@ ipsp_spd_lookup(struct mbuf *m, int af, ipo->ipo_last_searched = getuptime(); /* Find an appropriate SA from the existing ones. */ - ipo->ipo_tdb = - gettdbbydst(rdomain, - dignore ? &sdst : &ipo->ipo_dst, - ipo->ipo_sproto, - ids ? ids: ipo->ipo_ids, - &ipo->ipo_addr, &ipo->ipo_mask); - if (ipo->ipo_tdb) { - TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head, + ipo->ipo_tdb = gettdbbydst(rdomain, + dignore ? &sdst : &ipo->ipo_dst, + ipo->ipo_sproto, ids ? ids: ipo->ipo_ids, + &ipo->ipo_addr, &ipo->ipo_mask); + if (ipo->ipo_tdb != NULL) { + /* gettdbbydst() has already refcounted tdb */ + TAILQ_INSERT_TAIL( + &ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); *error = 0; return ipsp_spd_inp(m, af, hlen, error, @@ -520,10 +523,12 @@ ipsp_spd_lookup(struct mbuf *m, int af, goto nomatchin; /* Add it to the cache. */ - if (ipo->ipo_tdb) + if (ipo->ipo_tdb != NULL) { TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); - ipo->ipo_tdb = tdbp; + tdb_unref(ipo->ipo_tdb); + } + ipo->ipo_tdb = tdb_ref(tdbp); TAILQ_INSERT_TAIL(&tdbp->tdb_policy_head, ipo, ipo_tdb_next); *error = 0; @@ -535,7 +540,7 @@ ipsp_spd_lookup(struct mbuf *m, int af, } /* Check whether cached entry applies. */ - if (ipo->ipo_tdb) { + if (ipo->ipo_tdb != NULL) { /* * We only need to check that the correct * security protocol and security gateway are @@ -551,8 +556,9 @@ ipsp_spd_lookup(struct mbuf *m, int af, /* Not applicable, unlink. */ TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); - ipo->ipo_last_searched = 0; + tdb_unref(ipo->ipo_tdb); ipo->ipo_tdb = NULL; + ipo->ipo_last_searched = 0; } /* Find whether there exists an appropriate SA. */ @@ -560,14 +566,16 @@ ipsp_spd_lookup(struct mbuf *m, int af, if (dignore == 0) ipo->ipo_last_searched = getuptime(); - ipo->ipo_tdb = - gettdbbysrc(rdomain, - dignore ? &ssrc : &ipo->ipo_dst, - ipo->ipo_sproto, ipo->ipo_ids, - &ipo->ipo_addr, &ipo->ipo_mask); - if (ipo->ipo_tdb) - TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head, + ipo->ipo_tdb = gettdbbysrc(rdomain, + dignore ? &ssrc : &ipo->ipo_dst, + ipo->ipo_sproto, ipo->ipo_ids, + &ipo->ipo_addr, &ipo->ipo_mask); + if (ipo->ipo_tdb != NULL) { + /* gettdbbysrc() has already refcounted tdb */ + TAILQ_INSERT_TAIL( + &ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); + } } skipinputsearch: @@ -637,9 +645,12 @@ ipsec_delete_policy(struct ipsec_policy rn_delete(&ipo->ipo_addr, &ipo->ipo_mask, rnh, rn) == NULL) return (ESRCH); - if (ipo->ipo_tdb != NULL) + if (ipo->ipo_tdb != NULL) { TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next); + tdb_unref(ipo->ipo_tdb); + ipo->ipo_tdb = NULL; + } while ((ipa = TAILQ_FIRST(&ipo->ipo_acquires)) != NULL) ipsp_delete_acquire(ipa); Index: netinet/ipsec_input.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ipsec_input.c,v retrieving revision 1.191 diff -u -p -r1.191 ipsec_input.c --- netinet/ipsec_input.c 11 Nov 2021 18:08:18 -0000 1.191 +++ netinet/ipsec_input.c 19 Nov 2021 15:18:18 -0000 @@ -328,12 +328,16 @@ ipsec_common_input(struct mbuf **mp, int /* Register first use, setup expiration timer. */ if (tdbp->tdb_first_use == 0) { tdbp->tdb_first_use = gettime(); - if (tdbp->tdb_flags & TDBF_FIRSTUSE) - timeout_add_sec(&tdbp->tdb_first_tmo, - tdbp->tdb_exp_first_use); - if (tdbp->tdb_flags & TDBF_SOFT_FIRSTUSE) - timeout_add_sec(&tdbp->tdb_sfirst_tmo, - tdbp->tdb_soft_first_use); + if (tdbp->tdb_flags & TDBF_FIRSTUSE) { + if (timeout_add_sec(&tdbp->tdb_first_tmo, + tdbp->tdb_exp_first_use)) + tdb_ref(tdbp); + } + if (tdbp->tdb_flags & TDBF_SOFT_FIRSTUSE) { + if (timeout_add_sec(&tdbp->tdb_sfirst_tmo, + tdbp->tdb_soft_first_use)) + tdb_ref(tdbp); + } } tdbp->tdb_ipackets++; @@ -348,6 +352,7 @@ ipsec_common_input(struct mbuf **mp, int ipsecstat_inc(ipsec_idrops); tdbp->tdb_idrops++; } + tdb_unref(tdbp); return prot; drop: @@ -355,6 +360,7 @@ ipsec_common_input(struct mbuf **mp, int ipsecstat_inc(ipsec_idrops); if (tdbp != NULL) tdbp->tdb_idrops++; + tdb_unref(tdbp); return IPPROTO_DONE; } @@ -937,6 +943,7 @@ ipsec_common_ctlinput(u_int rdomain, int tdbp = gettdb_rev(rdomain, spi, (union sockaddr_union *)&dst, proto); ipsec_set_mtu(tdbp, mtu); + tdb_unref(tdbp); } } @@ -944,7 +951,7 @@ void udpencap_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *v) { struct ip *ip = v; - struct tdb *tdbp; + struct tdb *tdbp, *first; struct icmp *icp; u_int32_t mtu; struct sockaddr_in dst, src; @@ -973,10 +980,9 @@ udpencap_ctlinput(int cmd, struct sockad src.sin_addr.s_addr = ip->ip_src.s_addr; su_src = (union sockaddr_union *)&src; - tdbp = gettdbbysrcdst_rev(rdomain, 0, su_src, su_dst, - IPPROTO_ESP); + first = gettdbbysrcdst_rev(rdomain, 0, su_src, su_dst, IPPROTO_ESP); - for (; tdbp != NULL; tdbp = tdbp->tdb_snext) { + for (tdbp = first; tdbp != NULL; tdbp = tdbp->tdb_snext) { if (tdbp->tdb_sproto == IPPROTO_ESP && ((tdbp->tdb_flags & (TDBF_INVALID|TDBF_UDPENCAP)) == TDBF_UDPENCAP) && @@ -985,6 +991,7 @@ udpencap_ctlinput(int cmd, struct sockad ipsec_set_mtu(tdbp, mtu); } } + tdb_unref(first); } void @@ -1070,6 +1077,7 @@ ipsec_forward_check(struct mbuf *m, int } else tdb = NULL; ipsp_spd_lookup(m, af, hlen, &error, IPSP_DIRECTION_IN, tdb, NULL, 0); + tdb_unref(tdb); return error; } @@ -1142,6 +1150,7 @@ ipsec_local_check(struct mbuf *m, int hl tdb = NULL; ipsp_spd_lookup(m, af, hlen, &error, IPSP_DIRECTION_IN, tdb, NULL, 0); + tdb_unref(tdb); return error; } Index: netinet/ipsec_output.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ipsec_output.c,v retrieving revision 1.91 diff -u -p -r1.91 ipsec_output.c --- netinet/ipsec_output.c 23 Oct 2021 15:42:35 -0000 1.91 +++ netinet/ipsec_output.c 19 Nov 2021 15:18:18 -0000 @@ -139,12 +139,16 @@ ipsp_process_packet(struct mbuf *m, stru */ if (tdb->tdb_first_use == 0) { tdb->tdb_first_use = gettime(); - if (tdb->tdb_flags & TDBF_FIRSTUSE) - timeout_add_sec(&tdb->tdb_first_tmo, - tdb->tdb_exp_first_use); - if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) - timeout_add_sec(&tdb->tdb_sfirst_tmo, - tdb->tdb_soft_first_use); + if (tdb->tdb_flags & TDBF_FIRSTUSE) { + if (timeout_add_sec(&tdb->tdb_first_tmo, + tdb->tdb_exp_first_use)) + tdb_ref(tdb); + } + if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) { + if (timeout_add_sec(&tdb->tdb_sfirst_tmo, + tdb->tdb_soft_first_use)) + tdb_ref(tdb); + } } /* @@ -388,6 +392,7 @@ ipsp_process_done(struct mbuf *m, struct #ifdef INET6 struct ip6_hdr *ip6; #endif /* INET6 */ + struct tdb *tdbo; struct tdb_ident *tdbi; struct m_tag *mtag; int roff, error; @@ -501,9 +506,13 @@ ipsp_process_done(struct mbuf *m, struct tdb->tdb_obytes += m->m_pkthdr.len; /* If there's another (bundled) TDB to apply, do so. */ - if (tdb->tdb_onext) - return ipsp_process_packet(m, tdb->tdb_onext, + tdbo = tdb_ref(tdb->tdb_onext); + if (tdbo != NULL) { + error = ipsp_process_packet(m, tdbo, tdb->tdb_dst.sa.sa_family, 0); + tdb_unref(tdbo); + return error; + } #if NPF > 0 /* Add pf tag if requested. */ @@ -615,13 +624,16 @@ ipsec_adjust_mtu(struct mbuf *m, u_int32 if (tdbp == NULL) break; - if ((adjust = ipsec_hdrsz(tdbp)) == -1) + if ((adjust = ipsec_hdrsz(tdbp)) == -1) { + tdb_unref(tdbp); break; + } mtu -= adjust; tdbp->tdb_mtu = mtu; tdbp->tdb_mtutimeout = gettime() + ip_mtudisc_timeout; DPRINTF("spi %08x mtu %d adjust %ld mbuf %p", ntohl(tdbp->tdb_spi), tdbp->tdb_mtu, adjust, m); + tdb_unref(tdbp); } } Index: netinet/tcp_input.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_input.c,v retrieving revision 1.370 diff -u -p -r1.370 tcp_input.c --- netinet/tcp_input.c 9 Aug 2021 17:03:08 -0000 1.370 +++ netinet/tcp_input.c 19 Nov 2021 13:04:58 -0000 @@ -380,12 +380,6 @@ tcp_input(struct mbuf **mp, int *offp, i #ifdef INET6 struct ip6_hdr *ip6 = NULL; #endif /* INET6 */ -#ifdef IPSEC - struct m_tag *mtag; - struct tdb_ident *tdbi; - struct tdb *tdb; - int error; -#endif /* IPSEC */ #ifdef TCP_ECN u_char iptos; #endif @@ -571,16 +565,22 @@ findpcb: } #ifdef IPSEC if (ipsec_in_use) { + struct m_tag *mtag; + struct tdb *tdb = NULL; + int error; + /* Find most recent IPsec tag */ mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); if (mtag != NULL) { + struct tdb_ident *tdbi; + tdbi = (struct tdb_ident *)(mtag + 1); tdb = gettdb(tdbi->rdomain, tdbi->spi, &tdbi->dst, tdbi->proto); - } else - tdb = NULL; + } ipsp_spd_lookup(m, af, iphlen, &error, IPSP_DIRECTION_IN, tdb, inp, 0); + tdb_unref(tdb); if (error) { tcpstat_inc(tcps_rcvnosec); goto drop; @@ -2197,7 +2197,7 @@ tcp_dooptions(struct tcpcb *tp, u_char * continue; if (sigp && timingsafe_bcmp(sigp, cp + 2, 16)) - return (-1); + goto bad; sigp = cp + 2; break; @@ -2248,7 +2248,7 @@ tcp_dooptions(struct tcpcb *tp, u_char * if ((sigp ? TF_SIGNATURE : 0) ^ (tp->t_flags & TF_SIGNATURE)) { tcpstat_inc(tcps_rcvbadsig); - return (-1); + goto bad; } if (sigp) { @@ -2256,22 +2256,30 @@ tcp_dooptions(struct tcpcb *tp, u_char * if (tdb == NULL) { tcpstat_inc(tcps_rcvbadsig); - return (-1); + goto bad; } if (tcp_signature(tdb, tp->pf, m, th, iphlen, 1, sig) < 0) - return (-1); + goto bad; if (timingsafe_bcmp(sig, sigp, 16)) { tcpstat_inc(tcps_rcvbadsig); - return (-1); + goto bad; } tcpstat_inc(tcps_rcvgoodsig); } + + tdb_unref(tdb); #endif /* TCP_SIGNATURE */ return (0); + + bad: +#ifdef TCP_SIGNATURE + tdb_unref(tdb); +#endif /* TCP_SIGNATURE */ + return (-1); } u_long @@ -4056,8 +4064,10 @@ syn_cache_respond(struct syn_cache *sc, if (tcp_signature(tdb, sc->sc_src.sa.sa_family, m, th, hlen, 0, optp) < 0) { m_freem(m); + tdb_unref(tdb); return (EINVAL); } + tdb_unref(tdb); optp += 16; /* Pad options list to the next 32 bit boundary and Index: netinet/tcp_output.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_output.c,v retrieving revision 1.130 diff -u -p -r1.130 tcp_output.c --- netinet/tcp_output.c 8 Feb 2021 19:37:15 -0000 1.130 +++ netinet/tcp_output.c 19 Nov 2021 13:04:58 -0000 @@ -879,8 +879,10 @@ send: if (tcp_signature(tdb, tp->pf, m, th, iphlen, 0, mtod(m, caddr_t) + hdrlen - optlen + sigoff) < 0) { m_freem(m); + tdb_unref(tdb); return (EINVAL); } + tdb_unref(tdb); } #endif /* TCP_SIGNATURE */ Index: netinet/udp_usrreq.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/udp_usrreq.c,v retrieving revision 1.264 diff -u -p -r1.264 udp_usrreq.c --- netinet/udp_usrreq.c 11 Nov 2021 18:08:18 -0000 1.264 +++ netinet/udp_usrreq.c 19 Nov 2021 13:04:58 -0000 @@ -514,11 +514,13 @@ udp_input(struct mbuf **mp, int *offp, i IPSP_DIRECTION_IN, tdb, inp, 0); if (error) { udpstat_inc(udps_nosec); + tdb_unref(tdb); goto bad; } /* create ipsec options while we know that tdb cannot be modified */ if (tdb && tdb->tdb_ids) ipsecflowinfo = tdb->tdb_ids->id_flow; + tdb_unref(tdb); } #endif /*IPSEC */