1
0
mirror of https://git.FreeBSD.org/src.git synced 2026-06-02 11:24:32 +00:00

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
This commit is contained in:
Mark Johnston
2026-06-01 16:44:15 +00:00
parent 49d90d9ddf
commit 68004e56fd
2 changed files with 24 additions and 34 deletions
+23 -33
View File
@@ -1375,11 +1375,8 @@ if_addgroup(struct ifnet *ifp, const char *groupname)
ifgl->ifgl_group = ifg; ifgl->ifgl_group = ifg;
ifgm->ifgm_ifp = ifp; ifgm->ifgm_ifp = ifp;
IF_ADDR_WLOCK(ifp);
CK_STAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next); CK_STAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next);
CK_STAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next); CK_STAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next);
IF_ADDR_WUNLOCK(ifp);
IFNET_WUNLOCK(); IFNET_WUNLOCK();
if (new) if (new)
@@ -1402,9 +1399,7 @@ _if_delgroup_locked(struct ifnet *ifp, struct ifg_list *ifgl,
IFNET_WLOCK_ASSERT(); IFNET_WLOCK_ASSERT();
IF_ADDR_WLOCK(ifp);
CK_STAILQ_REMOVE(&ifp->if_groups, ifgl, ifg_list, ifgl_next); 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) { CK_STAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next) {
if (ifgm->ifgm_ifp == ifp) { if (ifgm->ifgm_ifp == ifp) {
@@ -1479,34 +1474,35 @@ if_delgroups(struct ifnet *ifp)
static int static int
if_getgroup(struct ifgroupreq *ifgr, struct ifnet *ifp) if_getgroup(struct ifgroupreq *ifgr, struct ifnet *ifp)
{ {
int len, error; struct ifg_list *ifgl;
struct ifg_list *ifgl; struct ifg_req ifgrq, *ifgp;
struct ifg_req ifgrq, *ifgp; int len, error;
NET_EPOCH_ASSERT();
IFNET_RLOCK();
if (ifgr->ifgr_len == 0) { if (ifgr->ifgr_len == 0) {
CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
ifgr->ifgr_len += sizeof(struct ifg_req); ifgr->ifgr_len += sizeof(struct ifg_req);
return (0); 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();
len = ifgr->ifgr_len; return (error);
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++;
}
return (0);
} }
/* /*
@@ -2756,14 +2752,8 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
break; break;
} }
case SIOCGIFGROUP: case SIOCGIFGROUP:
{
struct epoch_tracker et;
NET_EPOCH_ENTER(et);
error = if_getgroup((struct ifgroupreq *)data, ifp); error = if_getgroup((struct ifgroupreq *)data, ifp);
NET_EPOCH_EXIT(et);
break; break;
}
case SIOCDIFGROUP: case SIOCDIFGROUP:
{ {
+1 -1
View File
@@ -41,7 +41,7 @@ struct ifnet {
CK_STAILQ_ENTRY(ifnet) if_link; /* all struct ifnets are chained (CK_) */ CK_STAILQ_ENTRY(ifnet) if_link; /* all struct ifnets are chained (CK_) */
LIST_ENTRY(ifnet) if_clones; /* interfaces of a cloner */ LIST_ENTRY(ifnet) if_clones; /* interfaces of a cloner */
CK_STAILQ_HEAD(, ifg_list) if_groups; /* linked list of groups per if (CK_) */ 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 */ u_char if_alloctype; /* if_type at time of allocation */
uint8_t if_numa_domain; /* NUMA domain of device */ uint8_t if_numa_domain; /* NUMA domain of device */
/* Driver and protocol specific information that remains stable. */ /* Driver and protocol specific information that remains stable. */