aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2026-06-01 16:44:15 +0000
committerMark Johnston <markj@FreeBSD.org>2026-06-01 18:22:57 +0000
commit68004e56fdc22c11b4ec680e83309b4ea2bfe13a (patch)
tree205025e5ed68c4e52b039027536348304f171802
parent49d90d9ddfc1ecda9ad9b6cb5565e5fbdcc14964 (diff)
net: Fix handling of unmapped user pages in if_getgroup()
We cannot call copyout() while in a net epoch section, unless the user memory is wired. Use the global ifnet lock to synchronize the accesses instead. Reported by: emaste Reviewed by: zlei MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D57154
-rw-r--r--sys/net/if.c56
-rw-r--r--sys/net/if_private.h2
2 files changed, 24 insertions, 34 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index e421dd3bd494..440b40102d53 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -1375,11 +1375,8 @@ if_addgroup(struct ifnet *ifp, const char *groupname)
ifgl->ifgl_group = ifg;
ifgm->ifgm_ifp = ifp;
- IF_ADDR_WLOCK(ifp);
CK_STAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next);
CK_STAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next);
- IF_ADDR_WUNLOCK(ifp);
-
IFNET_WUNLOCK();
if (new)
@@ -1402,9 +1399,7 @@ _if_delgroup_locked(struct ifnet *ifp, struct ifg_list *ifgl,
IFNET_WLOCK_ASSERT();
- IF_ADDR_WLOCK(ifp);
CK_STAILQ_REMOVE(&ifp->if_groups, ifgl, ifg_list, ifgl_next);
- IF_ADDR_WUNLOCK(ifp);
CK_STAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next) {
if (ifgm->ifgm_ifp == ifp) {
@@ -1479,34 +1474,35 @@ if_delgroups(struct ifnet *ifp)
static int
if_getgroup(struct ifgroupreq *ifgr, struct ifnet *ifp)
{
- int len, error;
- struct ifg_list *ifgl;
- struct ifg_req ifgrq, *ifgp;
-
- NET_EPOCH_ASSERT();
+ struct ifg_list *ifgl;
+ struct ifg_req ifgrq, *ifgp;
+ int len, error;
+ IFNET_RLOCK();
if (ifgr->ifgr_len == 0) {
CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
ifgr->ifgr_len += sizeof(struct ifg_req);
- return (0);
- }
-
- len = ifgr->ifgr_len;
- ifgp = ifgr->ifgr_groups;
- /* XXX: wire */
- CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
- if (len < sizeof(ifgrq))
- return (EINVAL);
- bzero(&ifgrq, sizeof ifgrq);
- strlcpy(ifgrq.ifgrq_group, ifgl->ifgl_group->ifg_group,
- sizeof(ifgrq.ifgrq_group));
- if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req))))
- return (error);
- len -= sizeof(ifgrq);
- ifgp++;
+ error = 0;
+ } else {
+ len = ifgr->ifgr_len;
+ ifgp = ifgr->ifgr_groups;
+ CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
+ if (len < sizeof(ifgrq)) {
+ error = EINVAL;
+ break;
+ }
+ bzero(&ifgrq, sizeof ifgrq);
+ strlcpy(ifgrq.ifgrq_group, ifgl->ifgl_group->ifg_group,
+ sizeof(ifgrq.ifgrq_group));
+ if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req))))
+ break;
+ len -= sizeof(ifgrq);
+ ifgp++;
+ }
}
+ IFNET_RUNLOCK();
- return (0);
+ return (error);
}
/*
@@ -2756,14 +2752,8 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
break;
}
case SIOCGIFGROUP:
- {
- struct epoch_tracker et;
-
- NET_EPOCH_ENTER(et);
error = if_getgroup((struct ifgroupreq *)data, ifp);
- NET_EPOCH_EXIT(et);
break;
- }
case SIOCDIFGROUP:
{
diff --git a/sys/net/if_private.h b/sys/net/if_private.h
index c4ade7308df4..5a76fd788c1b 100644
--- a/sys/net/if_private.h
+++ b/sys/net/if_private.h
@@ -41,7 +41,7 @@ struct ifnet {
CK_STAILQ_ENTRY(ifnet) if_link; /* all struct ifnets are chained (CK_) */
LIST_ENTRY(ifnet) if_clones; /* interfaces of a cloner */
CK_STAILQ_HEAD(, ifg_list) if_groups; /* linked list of groups per if (CK_) */
- /* protected by if_addr_lock */
+ /* protected by ifnet_sxlock */
u_char if_alloctype; /* if_type at time of allocation */
uint8_t if_numa_domain; /* NUMA domain of device */
/* Driver and protocol specific information that remains stable. */