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 *);

Reply via email to