On Mon, Apr 24, 2023 at 06:31:03PM +0300, Vitaliy Makkoveev wrote:
> ... 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?
I did run this though perform test. Full regress still running due
to unrelated tree breakage. I don't expect fallout.
OK bluhm@
> 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);