... and use it to protect route labels storage. This time it is not
clean, which lock protects it because we holding kernel and net locks in
various combinations while accessing it. I see no reason to put kernel
lock to all the places. Also netlock could not be used, because rtfree()
which calls rtlabel_unref() has unknown netlock state within.

This new `rtlabel_mtx' mutex(9) protects `rt_labels' list and `label'
entry dereference. Since we don't export 'rt_label' structure, I want to
keep this lock private to net/route.c. For this reason rtlabel_id2name()
now copies label string to externally passed buffer instead of returning
address of `rt_labels' list data. This is the way which rtlabel_id2sa()
already works.

ok?

Index: sys/net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.692
diff -u -p -r1.692 if.c
--- sys/net/if.c        22 Apr 2023 04:39:46 -0000      1.692
+++ sys/net/if.c        24 Apr 2023 15:11:33 -0000
@@ -2383,7 +2383,6 @@ ifioctl_get(u_long cmd, caddr_t data)
        char ifrtlabelbuf[RTLABEL_LEN];
        int error = 0;
        size_t bytesdone;
-       const char *label;
 
        switch(cmd) {
        case SIOCGIFCONF:
@@ -2458,9 +2457,8 @@ ifioctl_get(u_long cmd, caddr_t data)
                break;
 
        case SIOCGIFRTLABEL:
-               if (ifp->if_rtlabelid &&
-                   (label = rtlabel_id2name(ifp->if_rtlabelid)) != NULL) {
-                       strlcpy(ifrtlabelbuf, label, RTLABEL_LEN);
+               if (ifp->if_rtlabelid && rtlabel_id2name(ifp->if_rtlabelid,
+                   ifrtlabelbuf, RTLABEL_LEN) != NULL) {
                        error = copyoutstr(ifrtlabelbuf, ifr->ifr_data,
                            RTLABEL_LEN, &bytesdone);
                } else
Index: sys/net/pf_ioctl.c
===================================================================
RCS file: /cvs/src/sys/net/pf_ioctl.c,v
retrieving revision 1.397
diff -u -p -r1.397 pf_ioctl.c
--- sys/net/pf_ioctl.c  6 Jan 2023 17:44:34 -0000       1.397
+++ sys/net/pf_ioctl.c  24 Apr 2023 15:11:33 -0000
@@ -491,14 +491,10 @@ pf_rtlabel_remove(struct pf_addr_wrap *a
 void
 pf_rtlabel_copyout(struct pf_addr_wrap *a)
 {
-       const char      *name;
-
        if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) {
-               if ((name = rtlabel_id2name(a->v.rtlabel)) == NULL)
+               if (rtlabel_id2name(a->v.rtlabel, a->v.rtlabelname,
+                   sizeof(a->v.rtlabelname)) == NULL)
                        strlcpy(a->v.rtlabelname, "?",
-                           sizeof(a->v.rtlabelname));
-               else
-                       strlcpy(a->v.rtlabelname, name,
                            sizeof(a->v.rtlabelname));
        }
 }
Index: sys/net/route.c
===================================================================
RCS file: /cvs/src/sys/net/route.c,v
retrieving revision 1.416
diff -u -p -r1.416 route.c
--- sys/net/route.c     28 Jan 2023 10:17:16 -0000      1.416
+++ sys/net/route.c     24 Apr 2023 15:11:33 -0000
@@ -113,6 +113,7 @@
 #include <sys/queue.h>
 #include <sys/pool.h>
 #include <sys/atomic.h>
+#include <sys/mutex.h>
 
 #include <net/if.h>
 #include <net/if_var.h>
@@ -137,6 +138,12 @@
 #include <net/bfd.h>
 #endif
 
+/*
+ * Locks used to protect struct members:
+ *      I       immutable after creation
+ *      L       rtlabel_mtx
+ */
+
 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : 
sizeof(long))
 
 /* Give some jitter to hash, to avoid synchronization between routers. */
@@ -163,13 +170,15 @@ static int rt_copysa(struct sockaddr *, 
 #define        LABELID_MAX     50000
 
 struct rt_label {
-       TAILQ_ENTRY(rt_label)   rtl_entry;
-       char                    rtl_name[RTLABEL_LEN];
-       u_int16_t               rtl_id;
-       int                     rtl_ref;
+       TAILQ_ENTRY(rt_label)   rtl_entry;              /* [L] */
+       char                    rtl_name[RTLABEL_LEN];  /* [I] */
+       u_int16_t               rtl_id;                 /* [I] */
+       int                     rtl_ref;                /* [L] */
 };
 
-TAILQ_HEAD(rt_labels, rt_label)        rt_labels = 
TAILQ_HEAD_INITIALIZER(rt_labels);
+TAILQ_HEAD(rt_labels, rt_label)        rt_labels =
+    TAILQ_HEAD_INITIALIZER(rt_labels);         /* [L] */
+struct mutex rtlabel_mtx = MUTEX_INITIALIZER(IPL_NET);
 
 void
 route_init(void)
@@ -1603,15 +1612,17 @@ u_int16_t
 rtlabel_name2id(char *name)
 {
        struct rt_label         *label, *p;
-       u_int16_t                new_id = 1;
+       u_int16_t                new_id = 1, id = 0;
 
        if (!name[0])
                return (0);
 
+       mtx_enter(&rtlabel_mtx);
        TAILQ_FOREACH(label, &rt_labels, rtl_entry)
                if (strcmp(name, label->rtl_name) == 0) {
                        label->rtl_ref++;
-                       return (label->rtl_id);
+                       id = label->rtl_id;
+                       goto out;
                }
 
        /*
@@ -1625,11 +1636,11 @@ rtlabel_name2id(char *name)
                new_id = p->rtl_id + 1;
        }
        if (new_id > LABELID_MAX)
-               return (0);
+               goto out;
 
        label = malloc(sizeof(*label), M_RTABLE, M_NOWAIT|M_ZERO);
        if (label == NULL)
-               return (0);
+               goto out;
        strlcpy(label->rtl_name, name, sizeof(label->rtl_name));
        label->rtl_id = new_id;
        label->rtl_ref++;
@@ -1639,14 +1650,20 @@ rtlabel_name2id(char *name)
        else            /* either list empty or no free slot in between */
                TAILQ_INSERT_TAIL(&rt_labels, label, rtl_entry);
 
-       return (label->rtl_id);
+       id = label->rtl_id;
+out:
+       mtx_leave(&rtlabel_mtx);
+
+       return (id);
 }
 
 const char *
-rtlabel_id2name(u_int16_t id)
+rtlabel_id2name_locked(u_int16_t id)
 {
        struct rt_label *label;
 
+       MUTEX_ASSERT_LOCKED(&rtlabel_mtx);
+
        TAILQ_FOREACH(label, &rt_labels, rtl_entry)
                if (label->rtl_id == id)
                        return (label->rtl_name);
@@ -1654,18 +1671,44 @@ rtlabel_id2name(u_int16_t id)
        return (NULL);
 }
 
+const char *
+rtlabel_id2name(u_int16_t id, char *rtlabelbuf, size_t sz)
+{
+       const char *label;
+
+       if (id == 0)
+               return (NULL);
+
+       mtx_enter(&rtlabel_mtx);
+       if ((label = rtlabel_id2name_locked(id)) != NULL)
+               strlcpy(rtlabelbuf, label, sz);
+       mtx_leave(&rtlabel_mtx);
+
+       if (label == NULL)
+               return (NULL);
+
+       return (rtlabelbuf);
+}
+
 struct sockaddr *
 rtlabel_id2sa(u_int16_t labelid, struct sockaddr_rtlabel *sa_rl)
 {
        const char      *label;
 
-       if (labelid == 0 || (label = rtlabel_id2name(labelid)) == NULL)
+       if (labelid == 0)
                return (NULL);
 
-       bzero(sa_rl, sizeof(*sa_rl));
-       sa_rl->sr_len = sizeof(*sa_rl);
-       sa_rl->sr_family = AF_UNSPEC;
-       strlcpy(sa_rl->sr_label, label, sizeof(sa_rl->sr_label));
+       mtx_enter(&rtlabel_mtx);
+       if ((label = rtlabel_id2name_locked(labelid)) != NULL) {
+               bzero(sa_rl, sizeof(*sa_rl));
+               sa_rl->sr_len = sizeof(*sa_rl);
+               sa_rl->sr_family = AF_UNSPEC;
+               strlcpy(sa_rl->sr_label, label, sizeof(sa_rl->sr_label));
+       }
+       mtx_leave(&rtlabel_mtx);
+
+       if (label == NULL)
+               return (NULL);
 
        return ((struct sockaddr *)sa_rl);
 }
@@ -1678,6 +1721,7 @@ rtlabel_unref(u_int16_t id)
        if (id == 0)
                return;
 
+       mtx_enter(&rtlabel_mtx);
        TAILQ_FOREACH_SAFE(p, &rt_labels, rtl_entry, next) {
                if (id == p->rtl_id) {
                        if (--p->rtl_ref == 0) {
@@ -1687,6 +1731,7 @@ rtlabel_unref(u_int16_t id)
                        break;
                }
        }
+       mtx_leave(&rtlabel_mtx);
 }
 
 int
Index: sys/net/route.h
===================================================================
RCS file: /cvs/src/sys/net/route.h,v
retrieving revision 1.198
diff -u -p -r1.198 route.h
--- sys/net/route.h     28 Jan 2023 10:17:16 -0000      1.198
+++ sys/net/route.h     24 Apr 2023 15:11:33 -0000
@@ -416,7 +416,8 @@ struct rttimer_queue {
        int                             rtq_timeout;    /* [T] */
 };
 
-const char     *rtlabel_id2name(u_int16_t);
+const char     *rtlabel_id2name_locked(u_int16_t);
+const char     *rtlabel_id2name(u_int16_t, char *, size_t);
 u_int16_t       rtlabel_name2id(char *);
 struct sockaddr        *rtlabel_id2sa(u_int16_t, struct sockaddr_rtlabel *);
 void            rtlabel_unref(u_int16_t);

Reply via email to