Hi,
To find the ref counting bugs in IPsec tdb I use this trace code.
Per default there is no change due to #ifdef.
ddb{2}> show tdb /f 0xffff8000080164b0
tdb at 0xffff8000080164b0
...
refcnt: 2
...
trace_idx: 3767579
...
tdb_trace[64]: 3944868: refs 6 +0 cpu1 ipsec_forward_check:1077
tdb_trace[65]: 3944869: refs 6 -1 cpu1 ipsec_forward_check:1081
tdb_trace[66]: 3944870: refs 5 +1 cpu1 gettdb_dir:360
tdb_trace[67]: 3944871: refs 6 +0 cpu1 ipsec_common_input:273
tdb_trace[68]: 3944872: refs 6 -1 cpu1 ipsec_common_input:355
tdb_trace[69]: 3944873: refs 5 +1 cpu1 gettdb_dir:360
tdb_trace[70]: 3944874: refs 6 +0 cpu1 ipsec_forward_check:1077
tdb_trace[71]: 3944875: refs 6 -1 cpu1 ipsec_forward_check:1081
tdb_trace[72]: 3944909: refs 5 +1 cpu1 gettdb_dir:360
tdb_trace[73]: 3944910: refs 6 +0 cpu1 pfkeyv2_send:1598
tdb_trace[74]: 3944911: refs 6 +0 cpu1 pfkeyv2_send:1605
tdb_trace[75]: 3944912: refs 6 -1 cpu1 tdb_deltimeouts:960
tdb_trace[76]: 3944913: refs 5 -1 cpu1 tdb_deltimeouts:964
tdb_trace[77]: 3944914: refs 4 -1 cpu1 tdb_delete0:1004
tdb_trace[78]: 3944915: refs 3 -1 cpu1 pfkeyv2_send:2149
Do we want to have that in tree?
bluhm
Index: netinet/ip_ipsp.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipsp.c,v
retrieving revision 1.254
diff -u -p -r1.254 ip_ipsp.c
--- netinet/ip_ipsp.c 25 Nov 2021 13:46:02 -0000 1.254
+++ netinet/ip_ipsp.c 25 Nov 2021 17:05:19 -0000
@@ -209,6 +209,11 @@ ipsp_init(void)
M_WAITOK | M_ZERO);
}
+#ifdef TDB_TRACE_MAX
+int tdb_trace_level;
+unsigned int tdb_trace_stamp;
+#endif /* TDB_TRACE_MAX */
+
/*
* Our hashing function needs to stir things with a non-zero random multiplier
* so we cannot be DoS-attacked via choosing of the data to hash.
@@ -452,7 +457,7 @@ ipsp_aux_match(struct tdb *tdb,
* the desired IDs.
*/
struct tdb *
-gettdbbydst(u_int rdomain, union sockaddr_union *dst, u_int8_t sproto,
+gettdbbydst0(u_int rdomain, union sockaddr_union *dst, u_int8_t sproto,
struct ipsec_ids *ids,
struct sockaddr_encap *filter, struct sockaddr_encap *filtermask)
{
@@ -483,7 +488,7 @@ gettdbbydst(u_int rdomain, union sockadd
* the desired IDs.
*/
struct tdb *
-gettdbbysrc(u_int rdomain, union sockaddr_union *src, u_int8_t sproto,
+gettdbbysrc0(u_int rdomain, union sockaddr_union *src, u_int8_t sproto,
struct ipsec_ids *ids,
struct sockaddr_encap *filter, struct sockaddr_encap *filtermask)
{
@@ -608,6 +613,24 @@ tdb_printit(void *addr, int full, int (*
/* tdb_filtermask */
/* tdb_policy_head */
/* tdb_sync_entry */
+#ifdef TDB_TRACE_MAX
+ {
+ struct tdb_trace *tt;
+ unsigned int idx, i;
+
+ DUMP(trace_idx, "%d");
+ for (i = 0; i < TDB_TRACE_MAX; i++) {
+ idx = (tdb->tdb_trace_idx + i) % TDB_TRACE_MAX;
+ tt = &tdb->tdb_trace[idx];
+ if (tt->tt_stamp == 0)
+ continue;
+ pr(" tdb_trace[%2u]: "
+ "%u: refs %u %+d cpu%d %s:%d\n",
+ idx, tt->tt_stamp, tt->tt_refs, tt->tt_op,
+ tt->tt_cpu, tt->tt_func, tt->tt_line);
+ }
+ }
+#endif /* TDB_TRACE_MAX */
} else {
pr("%p:", tdb);
pr(" %08x", ntohl(tdb->tdb_spi));
@@ -944,7 +967,7 @@ tdb_deltimeouts(struct tdb *tdbp)
}
struct tdb *
-tdb_ref(struct tdb *tdb)
+tdb_ref0(struct tdb *tdb)
{
if (tdb == NULL)
return NULL;
@@ -953,7 +976,7 @@ tdb_ref(struct tdb *tdb)
}
void
-tdb_unref(struct tdb *tdb)
+tdb_unref0(struct tdb *tdb)
{
if (tdb == NULL)
return;
@@ -963,7 +986,7 @@ tdb_unref(struct tdb *tdb)
}
void
-tdb_delete(struct tdb *tdbp)
+tdb_delete0(struct tdb *tdbp)
{
/* keep in sync with pfkeyv2_sa_flush() */
NET_ASSERT_LOCKED();
Index: netinet/ip_ipsp.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipsp.h,v
retrieving revision 1.222
diff -u -p -r1.222 ip_ipsp.h
--- netinet/ip_ipsp.h 25 Nov 2021 13:46:02 -0000 1.222
+++ netinet/ip_ipsp.h 25 Nov 2021 17:56:31 -0000
@@ -309,6 +309,18 @@ struct ipsec_policy {
#define IPSP_IDENTITY_USERFQDN 3
#define IPSP_IDENTITY_ASN1_DN 4
+/* #define TDB_TRACE_MAX 100 */
+#ifdef TDB_TRACE_MAX
+struct tdb_trace {
+ const char * tt_func;
+ int tt_line;
+ unsigned int tt_stamp;
+ unsigned int tt_refs;
+ int tt_op;
+ int tt_cpu;
+};
+#endif /* TDB_TRACE_MAX */
+
struct tdb { /* tunnel descriptor block */
/*
* Each TDB is on three hash tables: one keyed on dst/spi/sproto,
@@ -432,6 +444,10 @@ struct tdb { /* tunnel
descriptor blo
TAILQ_HEAD(tdb_policy_head, ipsec_policy) tdb_policy_head;
TAILQ_ENTRY(tdb) tdb_sync_entry;
+#ifdef TDB_TRACE_MAX
+ unsigned int tdb_trace_idx;
+ struct tdb_trace tdb_trace[TDB_TRACE_MAX];
+#endif /* TDB_TRACE_MAX */
};
#define tdb_ipackets tdb_data.tdd_ipackets
#define tdb_opackets tdb_data.tdd_opackets
@@ -550,25 +566,107 @@ int spd_table_walk(unsigned int,
/* TDB management routines */
uint32_t reserve_spi(u_int, u_int32_t, u_int32_t, union sockaddr_union *,
- union sockaddr_union *, u_int8_t, int *);
-struct tdb *gettdb_dir(u_int, u_int32_t, union sockaddr_union *, u_int8_t,
int);
+ union sockaddr_union *, u_int8_t, int *);
+struct tdb *gettdb_dir(u_int, u_int32_t, union sockaddr_union *, u_int8_t,
+ int);
+struct tdb *gettdbbysrcdst_dir(u_int, u_int32_t, union sockaddr_union *,
+ union sockaddr_union *, u_int8_t, int);
+struct tdb *gettdbbydst0(u_int, union sockaddr_union *, u_int8_t,
+ struct ipsec_ids *, struct sockaddr_encap *, struct sockaddr_encap *);
+struct tdb *gettdbbysrc0(u_int, union sockaddr_union *, u_int8_t,
+ struct ipsec_ids *, struct sockaddr_encap *, struct sockaddr_encap *);
+void puttdb(struct tdb *);
+void tdb_delete0(struct tdb *);
+struct tdb *tdb_alloc(u_int);
+struct tdb *tdb_ref0(struct tdb *);
+void tdb_unref0(struct tdb *);
+
+#ifdef TDB_TRACE_MAX
+extern int tdb_trace_level;
+extern unsigned int tdb_trace_stamp;
+
+#define TDB_TRACE_RECORD(y, f, l, op) do { \
+ struct tdb *x = y; \
+ if (x) { \
+ struct tdb_trace *tt; \
+ unsigned int idx; \
+ \
+ idx = atomic_inc_int_nv(&x->tdb_trace_idx); \
+ tt = &x->tdb_trace[(idx - 1) % TDB_TRACE_MAX]; \
+ tt->tt_stamp = atomic_inc_int_nv(&tdb_trace_stamp); \
+ tt->tt_func = f; \
+ tt->tt_line = l; \
+ tt->tt_op = op; \
+ tt->tt_cpu = cpu_number(); \
+ tt->tt_refs = x->tdb_refcnt.refs; /* RACE */ \
+ if (tdb_trace_level > 0) \
+ printf("tdb %p: %u: refs %u %+d cpu%d %s:%d\n", \
+ x, tt->tt_stamp, tt->tt_refs, tt->tt_op, \
+ tt->tt_cpu, tt->tt_func, tt->tt_line); \
+ } \
+ } while(0)
+#define tdb_ref(x) ({ \
+ struct tdb *y; \
+ TDB_TRACE_RECORD(x, __func__, __LINE__, 1); \
+ y = tdb_ref0(x); \
+ y; \
+ })
+#define tdb_unref(x) do { \
+ TDB_TRACE_RECORD(x, __func__, __LINE__, -1); \
+ tdb_unref0(x); \
+ } while(0)
+#define tdb_delete(x) do { \
+ TDB_TRACE_RECORD(x, __func__, __LINE__, 0); \
+ tdb_delete0(x); \
+ } while(0)
+#define gettdb(a,b,c,d) ({ \
+ struct tdb *y; \
+ y = gettdb_dir((a),(b),(c),(d),0); \
+ TDB_TRACE_RECORD(y, __func__, __LINE__, 0); \
+ y; \
+ })
+#define gettdb_rev(a,b,c,d) ({ \
+ struct tdb *y; \
+ y = gettdb_dir((a),(b),(c),(d),1); \
+ TDB_TRACE_RECORD(y, __func__, __LINE__, 0); \
+ y; \
+ })
+#define gettdbbysrcdst(a,b,c,d,e) ({ \
+ struct tdb *y; \
+ y = gettdbbysrcdst_dir((a),(b),(c),(d),(e),0); \
+ TDB_TRACE_RECORD(y, __func__, __LINE__, 0); \
+ y; \
+ })
+#define gettdbbysrcdst_rev(a,b,c,d,e) ({ \
+ struct tdb *y; \
+ y = gettdbbysrcdst_dir((a),(b),(c),(d),(e),1); \
+ TDB_TRACE_RECORD(y, __func__, __LINE__, 0); \
+ y; \
+ })
+#define gettdbbydst(a,b,c,d,e,f) ({ \
+ struct tdb *y; \
+ y = gettdbbydst0((a),(b),(c),(d),(e),(f)); \
+ TDB_TRACE_RECORD(y, __func__, __LINE__, 0); \
+ y; \
+ })
+#define gettdbbysrc(a,b,c,d,e,f) ({ \
+ struct tdb *y; \
+ y = gettdbbysrc0((a),(b),(c),(d),(e),(f)); \
+ TDB_TRACE_RECORD(y, __func__, __LINE__, 0); \
+ y; \
+ })
+#else /* TDB_TRACE_MAX */
+#define tdb_ref(x) tdb_ref0(x)
+#define tdb_unref(x) tdb_unref0(x)
+#define tdb_delete(x) tdb_delete0(x)
#define gettdb(a,b,c,d) gettdb_dir((a),(b),(c),(d),0)
#define gettdb_rev(a,b,c,d) gettdb_dir((a),(b),(c),(d),1)
-struct tdb *gettdbbydst(u_int, union sockaddr_union *, u_int8_t,
- struct ipsec_ids *,
- struct sockaddr_encap *, struct sockaddr_encap *);
-struct tdb *gettdbbysrc(u_int, union sockaddr_union *, u_int8_t,
- struct ipsec_ids *,
- struct sockaddr_encap *, struct sockaddr_encap *);
-struct tdb *gettdbbysrcdst_dir(u_int, u_int32_t, union sockaddr_union *,
- union sockaddr_union *, u_int8_t, int);
#define gettdbbysrcdst(a,b,c,d,e) gettdbbysrcdst_dir((a),(b),(c),(d),(e),0)
#define gettdbbysrcdst_rev(a,b,c,d,e) gettdbbysrcdst_dir((a),(b),(c),(d),(e),1)
-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 *);
+#define gettdbbydst(a,b,c,d,e,f) gettdbbydst0((a),(b),(c),(d),(e),(f))
+#define gettdbbysrc(a,b,c,d,e,f) gettdbbysrc0((a),(b),(c),(d),(e),(f))
+#endif /* TDB_TRACE_MAX */
+
void tdb_free(struct tdb *);
int tdb_init(struct tdb *, u_int16_t, struct ipsecinit *);
void tdb_unlink(struct tdb *);