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.