smack: Check address length before reading address family
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Fri, 12 Apr 2019 10:59:35 +0000 (19:59 +0900)
committerCasey Schaufler <casey@schaufler-ca.com>
Tue, 30 Apr 2019 00:32:27 +0000 (17:32 -0700)
KMSAN will complain if valid address length passed to bind()/connect()/
sendmsg() is shorter than sizeof("struct sockaddr"->sa_family) bytes.

Also, since smk_ipv6_port_label()/smack_netlabel_send()/
smack_ipv6host_label()/smk_ipv6_check()/smk_ipv6_port_check() are not
checking valid address length and/or address family, make sure we check
both. The minimal valid length in smack_socket_connect() is changed from
sizeof(struct sockaddr_in6) bytes to SIN6_LEN_RFC2133 bytes, for it seems
that Smack is not using "struct sockaddr_in6"->sin6_scope_id field.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
security/smack/smack_lsm.c

index b9abcdb36a7337fc4cd38391256837ab37fda9a8..b5b333d726377608e4d7342a3adcc0701a7b3c70 100644 (file)
@@ -2806,13 +2806,17 @@ static int smack_socket_socketpair(struct socket *socka,
  *
  * Records the label bound to a port.
  *
- * Returns 0
+ * Returns 0 on success, and error code otherwise
  */
 static int smack_socket_bind(struct socket *sock, struct sockaddr *address,
                                int addrlen)
 {
-       if (sock->sk != NULL && sock->sk->sk_family == PF_INET6)
+       if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) {
+               if (addrlen < SIN6_LEN_RFC2133 ||
+                   address->sa_family != AF_INET6)
+                       return -EINVAL;
                smk_ipv6_port_label(sock, address);
+       }
        return 0;
 }
 #endif /* SMACK_IPV6_PORT_LABELING */
@@ -2848,12 +2852,13 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
 
        switch (sock->sk->sk_family) {
        case PF_INET:
-               if (addrlen < sizeof(struct sockaddr_in))
+               if (addrlen < sizeof(struct sockaddr_in) ||
+                   sap->sa_family != AF_INET)
                        return -EINVAL;
                rc = smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap);
                break;
        case PF_INET6:
-               if (addrlen < sizeof(struct sockaddr_in6))
+               if (addrlen < SIN6_LEN_RFC2133 || sap->sa_family != AF_INET6)
                        return -EINVAL;
 #ifdef SMACK_IPV6_SECMARK_LABELING
                rsp = smack_ipv6host_label(sip);
@@ -3683,9 +3688,15 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
 
        switch (sock->sk->sk_family) {
        case AF_INET:
+               if (msg->msg_namelen < sizeof(struct sockaddr_in) ||
+                   sip->sin_family != AF_INET)
+                       return -EINVAL;
                rc = smack_netlabel_send(sock->sk, sip);
                break;
        case AF_INET6:
+               if (msg->msg_namelen < SIN6_LEN_RFC2133 ||
+                   sap->sin6_family != AF_INET6)
+                       return -EINVAL;
 #ifdef SMACK_IPV6_SECMARK_LABELING
                rsp = smack_ipv6host_label(sap);
                if (rsp != NULL)