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:
+23
-33
@@ -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:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
Reference in New Issue
Block a user