Add ifunit_ref(), a version of ifunit(), that returns not just an
interface pointer, but also a reference to it. Modify ifioctl() to use ifunit_ref(), holding the reference until all ioctls, etc, have completed. This closes a class of reader-writer races in which interfaces could be removed during long-running ioctls, leading to crashes. Many other consumers of ifunit() should now use ifunit_ref() to avoid similar races. MFC after: 3 weeks
This commit is contained in:
parent
111c6b617b
commit
6064c5d362
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=191423
34
sys/net/if.c
34
sys/net/if.c
@ -1788,9 +1788,26 @@ if_slowtimo(void *arg)
|
||||
}
|
||||
|
||||
/*
|
||||
* Map interface name to
|
||||
* interface structure pointer.
|
||||
* Map interface name to interface structure pointer, with or without
|
||||
* returning a reference.
|
||||
*/
|
||||
struct ifnet *
|
||||
ifunit_ref(const char *name)
|
||||
{
|
||||
INIT_VNET_NET(curvnet);
|
||||
struct ifnet *ifp;
|
||||
|
||||
IFNET_RLOCK();
|
||||
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
||||
if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0)
|
||||
break;
|
||||
}
|
||||
if (ifp != NULL)
|
||||
if_ref(ifp);
|
||||
IFNET_RUNLOCK();
|
||||
return (ifp);
|
||||
}
|
||||
|
||||
struct ifnet *
|
||||
ifunit(const char *name)
|
||||
{
|
||||
@ -2167,17 +2184,21 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
|
||||
return (if_getgroupmembers((struct ifgroupreq *)data));
|
||||
}
|
||||
|
||||
ifp = ifunit(ifr->ifr_name);
|
||||
if (ifp == 0)
|
||||
ifp = ifunit_ref(ifr->ifr_name);
|
||||
if (ifp == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
error = ifhwioctl(cmd, ifp, data, td);
|
||||
if (error != ENOIOCTL)
|
||||
if (error != ENOIOCTL) {
|
||||
if_rele(ifp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
oif_flags = ifp->if_flags;
|
||||
if (so->so_proto == 0)
|
||||
if (so->so_proto == NULL) {
|
||||
if_rele(ifp);
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
#ifndef COMPAT_43
|
||||
error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
|
||||
data,
|
||||
@ -2250,6 +2271,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if_rele(ifp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -776,6 +776,7 @@ void if_up(struct ifnet *);
|
||||
int ifioctl(struct socket *, u_long, caddr_t, struct thread *);
|
||||
int ifpromisc(struct ifnet *, int);
|
||||
struct ifnet *ifunit(const char *);
|
||||
struct ifnet *ifunit_ref(const char *);
|
||||
|
||||
void ifq_attach(struct ifaltq *, struct ifnet *ifp);
|
||||
void ifq_detach(struct ifaltq *);
|
||||
|
Loading…
Reference in New Issue
Block a user