On 31/05/16(Tue) 15:52, Gerhard Roth wrote: > On Mon, 23 May 2016 17:47:28 +0200 Martin Pieuchot <m...@openbsd.org> wrote: > > On 23/05/16(Mon) 16:51, Gerhard Roth wrote: > > > On Mon, 23 May 2016 16:18:29 +0200 Martin Pieuchot <m...@openbsd.org> > > > wrote: > > > > On 23/05/16(Mon) 15:38, Gerhard Roth wrote: > > > > > > > > This is crazy :) No driver should ever modify `ia' directly. This > > > > code should call in_control() via the ioctl path. > > > > > > As mentioned in a previous mail: this was mostly copied from > > > if_spppsubr.c:sppp_set_ip_addrs(). But doing an SIOCSIFADDR > > > ioctl() from inside the kernel seems weird, too. > > > > SIOCAIFADDR/SIOCDIFADDR It is the way to go. The driver should not > > manipulate addresses or route entry. > > Not manipulating the route entries is simple to fix. Will do that. > > But using SIOCAIFADDR/SIOCDIFADDR seems rather awkward since in_control() > requires a 'struct socket *so' argument (even though it does nothing with > it, except checking 'so->so_state & SS_PRIV'). Creating a socket inside > the driver for this sole purpose seems just as weird as setting up a > fake struct socket. > > Are you really sure, this is the better way to go?
I'm not sure it it is the better way to go. But I'm sure a driver should not manipulate `struct ifa' or `struct rtentry'. Now it should be fairly easy to split in_control() in two and pass a ``privileged'' variable based on the SS_PRIV flag. in6_control() already does half of this ;) I'd be interested to know if the diff below help, and if it does, does it simplifies your actual code? Index: netinet/in.c =================================================================== RCS file: /cvs/src/sys/netinet/in.c,v retrieving revision 1.127 diff -u -p -r1.127 in.c --- netinet/in.c 18 Apr 2016 06:43:51 -0000 1.127 +++ netinet/in.c 1 Jun 2016 07:50:29 -0000 @@ -84,8 +84,8 @@ void in_socktrim(struct sockaddr_in *); void in_len2mask(struct in_addr *, int); -int in_lifaddr_ioctl(struct socket *, u_long, caddr_t, - struct ifnet *); +int in_ioctl(u_long, caddr_t, struct ifnet *, int); +int in_lifaddr_ioctl(u_long, caddr_t, struct ifnet *, int); void in_purgeaddr(struct ifaddr *); int in_addhost(struct in_ifaddr *, struct sockaddr_in *); @@ -172,14 +172,11 @@ in_len2mask(struct in_addr *mask, int le int in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp) { - struct ifreq *ifr = (struct ifreq *)data; - struct ifaddr *ifa; - struct in_ifaddr *ia = NULL; - struct in_aliasreq *ifra = (struct in_aliasreq *)data; - struct sockaddr_in oldaddr; - int error; - int newifaddr; - int s; + int privileged; + + privileged = 0; + if ((so->so_state & SS_PRIV) != 0) + privileged++; switch (cmd) { #ifdef MROUTING @@ -189,18 +186,33 @@ in_control(struct socket *so, u_long cmd #endif /* MROUTING */ case SIOCALIFADDR: case SIOCDLIFADDR: - if ((so->so_state & SS_PRIV) == 0) + if (!privileged) return (EPERM); /* FALLTHROUGH */ case SIOCGLIFADDR: if (ifp == NULL) return (EINVAL); - return in_lifaddr_ioctl(so, cmd, data, ifp); + return in_lifaddr_ioctl(cmd, data, ifp, privileged); default: if (ifp == NULL) return (EOPNOTSUPP); } + return (in_ioctl(cmd, data, ifp, privileged)); +} + +int +in_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, int privileged) +{ + struct ifreq *ifr = (struct ifreq *)data; + struct ifaddr *ifa; + struct in_ifaddr *ia = NULL; + struct in_aliasreq *ifra = (struct in_aliasreq *)data; + struct sockaddr_in oldaddr; + int error; + int newifaddr; + int s; + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family == AF_INET) { ia = ifatoia(ifa); @@ -225,7 +237,7 @@ in_control(struct socket *so, u_long cmd return (EADDRNOTAVAIL); /* FALLTHROUGH */ case SIOCSIFADDR: - if ((so->so_state & SS_PRIV) == 0) + if (!privileged) return (EPERM); if (ia == NULL) { @@ -250,7 +262,7 @@ in_control(struct socket *so, u_long cmd case SIOCSIFNETMASK: case SIOCSIFDSTADDR: case SIOCSIFBRDADDR: - if ((so->so_state & SS_PRIV) == 0) + if (!privileged) return (EPERM); /* FALLTHROUGH */ @@ -410,8 +422,7 @@ in_control(struct socket *so, u_long cmd * other values may be returned from in_ioctl() */ int -in_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data, - struct ifnet *ifp) +in_lifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, int privileged) { struct if_laddrreq *iflr = (struct if_laddrreq *)data; struct ifaddr *ifa; @@ -481,7 +492,7 @@ in_lifaddr_ioctl(struct socket *so, u_lo ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in); in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen); - return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp); + return in_ioctl(SIOCAIFADDR, (caddr_t)&ifra, ifp, privileged); } case SIOCGLIFADDR: case SIOCDLIFADDR: @@ -566,7 +577,8 @@ in_lifaddr_ioctl(struct socket *so, u_lo memcpy(&ifra.ifra_dstaddr, &ia->ia_sockmask, ia->ia_sockmask.sin_len); - return in_control(so, SIOCDIFADDR, (caddr_t)&ifra, ifp); + return in_ioctl(SIOCDIFADDR, (caddr_t)&ifra, ifp, + privileged); } } } Index: netinet6/in6.c =================================================================== RCS file: /cvs/src/sys/netinet6/in6.c,v retrieving revision 1.186 diff -u -p -r1.186 in6.c --- netinet6/in6.c 3 Mar 2016 12:57:15 -0000 1.186 +++ netinet6/in6.c 1 Jun 2016 07:54:20 -0000 @@ -118,7 +118,8 @@ const struct in6_addr in6mask64 = IN6MAS const struct in6_addr in6mask96 = IN6MASK96; const struct in6_addr in6mask128 = IN6MASK128; -int in6_lifaddr_ioctl(struct socket *, u_long, caddr_t, struct ifnet *); +int in6_lifaddr_ioctl(u_long, caddr_t, struct ifnet *, int); +int in6_ioctl(u_long, caddr_t, struct ifnet *, int); int in6_ifinit(struct ifnet *, struct in6_ifaddr *, int); void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *); @@ -165,11 +166,7 @@ in6_mask2len(struct in6_addr *mask, u_ch int in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp) { - struct in6_ifreq *ifr = (struct in6_ifreq *)data; - struct in6_ifaddr *ia6 = NULL; - struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; - struct sockaddr_in6 *sa6; - int s, privileged; + int privileged; privileged = 0; if ((so->so_state & SS_PRIV) != 0) @@ -183,6 +180,18 @@ in6_control(struct socket *so, u_long cm } #endif + return (in6_ioctl(cmd, data, ifp, privileged)); +} + +int +in6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, int privileged) +{ + struct in6_ifreq *ifr = (struct in6_ifreq *)data; + struct in6_ifaddr *ia6 = NULL; + struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; + struct sockaddr_in6 *sa6; + int s; + if (ifp == NULL) return (EOPNOTSUPP); @@ -206,7 +215,7 @@ in6_control(struct socket *so, u_long cm return (EPERM); /* FALLTHROUGH */ case SIOCGLIFADDR: - return in6_lifaddr_ioctl(so, cmd, data, ifp); + return in6_lifaddr_ioctl(cmd, data, ifp, privileged); } /* @@ -939,8 +948,7 @@ in6_unlink_ifa(struct in6_ifaddr *ia6, s * address encoding scheme. (see figure on page 8) */ int -in6_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data, - struct ifnet *ifp) +in6_lifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, int privileged) { struct if_laddrreq *iflr = (struct if_laddrreq *)data; struct ifaddr *ifa; @@ -1047,7 +1055,8 @@ in6_lifaddr_ioctl(struct socket *so, u_l in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX; - return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp); + return in6_ioctl(SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, + privileged); } case SIOCGLIFADDR: case SIOCDLIFADDR: @@ -1142,8 +1151,8 @@ in6_lifaddr_ioctl(struct socket *so, u_l ia6->ia_prefixmask.sin6_len); ifra.ifra_flags = ia6->ia6_flags; - return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, - ifp); + return in6_ioctl(SIOCDIFADDR_IN6, (caddr_t)&ifra, ifp, + privileged); } } }