Hi,

Like in v4 I want to check incoming inet6 socket adresses early
with the in6_sa2sin6() function.

in6_update_ifa() needs more input validation in a later diff.

ok?

bluhm

Index: netinet6/in6.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/in6.c,v
retrieving revision 1.231
diff -u -p -r1.231 in6.c
--- netinet6/in6.c      22 Oct 2019 21:40:12 -0000      1.231
+++ netinet6/in6.c      7 Nov 2019 22:14:16 -0000
@@ -182,6 +182,18 @@ in6_nam2sin6(const struct mbuf *nam, str
 }

 int
+in6_sa2sin6(struct sockaddr *sa, struct sockaddr_in6 **sin6)
+{
+       if (sa->sa_family != AF_INET6)
+               return EAFNOSUPPORT;
+       if (sa->sa_len != sizeof(struct sockaddr_in6))
+               return EINVAL;
+       *sin6 = satosin6(sa);
+
+       return 0;
+}
+
+int
 in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp)
 {
        int privileged;
@@ -243,10 +255,10 @@ in6_ioctl(u_long cmd, caddr_t data, stru
 int
 in6_ioctl_change_ifaddr(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;
+       struct  sockaddr *sa;
+       struct  sockaddr_in6 *sa6 = NULL;
        int     error = 0, newifaddr = 0, plen;

        /*
@@ -260,21 +272,29 @@ in6_ioctl_change_ifaddr(u_long cmd, cadd
         * on a single interface, we almost always look and check the
         * presence of ifra_addr, and reject invalid ones here.
         * It also decreases duplicated code among SIOC*_IN6 operations.
+        *
+        * We always require users to specify a valid IPv6 address for
+        * the corresponding operation.
         */
        switch (cmd) {
        case SIOCAIFADDR_IN6:
-               sa6 = &ifra->ifra_addr;
+               sa = sin6tosa(&ifra->ifra_addr);
                break;
        case SIOCDIFADDR_IN6:
-               sa6 = &ifr->ifr_addr;
+               sa = sin6tosa(&((struct in6_ifreq *)data)->ifr_addr);
                break;
        default:
-               panic("unknown ioctl %lu", cmd);
+               panic("%s: invalid ioctl %lu", __func__, cmd);
+       }
+       if (sa->sa_family == AF_INET6) {
+               error = in6_sa2sin6(sa, &sa6);
+               if (error)
+                       return (error);
        }

        NET_LOCK();

-       if (sa6 && sa6->sin6_family == AF_INET6) {
+       if (sa6 != NULL) {
                error = in6_check_embed_scope(sa6, ifp->if_index);
                if (error)
                        goto err;
@@ -297,30 +317,11 @@ in6_ioctl_change_ifaddr(u_long cmd, cadd
                        error = EADDRNOTAVAIL;
                        break;
                }
-               /*
-                * We always require users to specify a valid IPv6 address for
-                * the corresponding operation.
-                */
-               if (ifra->ifra_addr.sin6_family != AF_INET6 ||
-                   ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) {
-                       error = EAFNOSUPPORT;
-                       break;
-               }
                in6_purgeaddr(&ia6->ia_ifa);
                dohooks(ifp->if_addrhooks, 0);
                break;

        case SIOCAIFADDR_IN6:
-               /*
-                * We always require users to specify a valid IPv6 address for
-                * the corresponding operation.
-                */
-               if (ifra->ifra_addr.sin6_family != AF_INET6 ||
-                   ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) {
-                       error = EAFNOSUPPORT;
-                       break;
-               }
-
                /* reject read-only flags */
                if ((ifra->ifra_flags & IN6_IFF_DUPLICATED) != 0 ||
                    (ifra->ifra_flags & IN6_IFF_DETACHED) != 0 ||
@@ -346,13 +347,15 @@ in6_ioctl_change_ifaddr(u_long cmd, cadd
                 * is no link-local yet.
                 */
                error = in6_ifattach(ifp);
-               if (error != 0)
+               if (error)
                        break;
                error = in6_update_ifa(ifp, ifra, ia6);
-               if (error != 0)
+               if (error)
                        break;

-               ia6 = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr);
+               ia6 = NULL;
+               if (sa6 != NULL)
+                       ia6 = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
                if (ia6 == NULL) {
                        /*
                         * this can happen when the user specify the 0 valid
@@ -397,14 +400,20 @@ in6_ioctl_get(u_long cmd, caddr_t data,
 {
        struct  in6_ifreq *ifr = (struct in6_ifreq *)data;
        struct  in6_ifaddr *ia6 = NULL;
-       struct sockaddr_in6 *sa6;
+       struct  sockaddr *sa;
+       struct  sockaddr_in6 *sa6 = NULL;
        int     error = 0;

-       sa6 = &ifr->ifr_addr;
+       sa = sin6tosa(&ifr->ifr_addr);
+       if (sa->sa_family == AF_INET6) {
+               error = in6_sa2sin6(sa, &sa6);
+               if (error)
+                       return (error);
+       }

        NET_RLOCK();

-       if (sa6 && sa6->sin6_family == AF_INET6) {
+       if (sa6 != NULL) {
                error = in6_check_embed_scope(sa6, ifp->if_index);
                if (error)
                        goto err;
@@ -492,7 +501,7 @@ in6_ioctl_get(u_long cmd, caddr_t data,
                break;

        default:
-               panic("invalid ioctl %lu", cmd);
+               panic("%s: invalid ioctl %lu", __func__, cmd);
        }

 err:
Index: netinet6/in6.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/in6.h,v
retrieving revision 1.104
diff -u -p -r1.104 in6.h
--- netinet6/in6.h      22 Apr 2019 22:47:49 -0000      1.104
+++ netinet6/in6.h      7 Nov 2019 17:56:01 -0000
@@ -408,8 +408,11 @@ extern const u_char inet6ctlerrmap[];
 extern const struct in6_addr zeroin6_addr;

 struct mbuf;
+struct sockaddr;
+struct sockaddr_in6;
+struct ifaddr;
+struct in6_ifaddr;
 struct ifnet;
-struct cmsghdr;

 void   ipv6_input(struct ifnet *, struct mbuf *);

@@ -420,6 +423,7 @@ int in6_addrscope(struct in6_addr *);
 struct in6_ifaddr *in6_ifawithscope(struct ifnet *, struct in6_addr *, u_int);
 int    in6_mask2len(struct in6_addr *, u_char *);
 int    in6_nam2sin6(const struct mbuf *, struct sockaddr_in6 **);
+int    in6_sa2sin6(struct sockaddr *, struct sockaddr_in6 **);

 struct inpcb;

@@ -427,11 +431,6 @@ int        in6_embedscope(struct in6_addr *, co
            struct inpcb *);
 void   in6_recoverscope(struct sockaddr_in6 *, const struct in6_addr *);
 void   in6_clearscope(struct in6_addr *);
-
-struct sockaddr;
-struct sockaddr_in6;
-struct ifaddr;
-struct in6_ifaddr;

 /*
  * Convert between address family specific and general structs.

Reply via email to