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.