Merge tag 'v3.10.95' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / ipv6 / af_inet6.c
index a944f1313c5fd6c04d4962c9ed59d4d29bb82db8..72aa1a1350e85f4e65e2ff795bac0aea1b30c1fe 100644 (file)
@@ -49,6 +49,7 @@
 #include <net/udp.h>
 #include <net/udplite.h>
 #include <net/tcp.h>
 #include <net/udp.h>
 #include <net/udplite.h>
 #include <net/tcp.h>
+#include <net/ping.h>
 #include <net/protocol.h>
 #include <net/inet_common.h>
 #include <net/route.h>
 #include <net/protocol.h>
 #include <net/inet_common.h>
 #include <net/route.h>
 #include <asm/uaccess.h>
 #include <linux/mroute6.h>
 
 #include <asm/uaccess.h>
 #include <linux/mroute6.h>
 
+#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+#include <linux/android_aid.h>
+
+static inline int current_has_network(void)
+{
+       return in_egroup_p(AID_INET) || capable(CAP_NET_RAW);
+}
+#else
+static inline int current_has_network(void)
+{
+       return 1;
+}
+#endif
+
 MODULE_AUTHOR("Cast of dozens");
 MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Cast of dozens");
 MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
 MODULE_LICENSE("GPL");
@@ -108,6 +123,9 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
        int try_loading_module = 0;
        int err;
 
        int try_loading_module = 0;
        int err;
 
+       if (!current_has_network())
+               return -EACCES;
+
        if (sock->type != SOCK_RAW &&
            sock->type != SOCK_DGRAM &&
            !inet_ehash_secret)
        if (sock->type != SOCK_RAW &&
            sock->type != SOCK_DGRAM &&
            !inet_ehash_secret)
@@ -162,8 +180,7 @@ lookup_protocol:
        }
 
        err = -EPERM;
        }
 
        err = -EPERM;
-       if (sock->type == SOCK_RAW && !kern &&
-           !ns_capable(net->user_ns, CAP_NET_RAW))
+       if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
                goto out_rcu_unlock;
 
        sock->ops = answer->ops;
                goto out_rcu_unlock;
 
        sock->ops = answer->ops;
@@ -480,6 +497,21 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
 }
 EXPORT_SYMBOL(inet6_getname);
 
 }
 EXPORT_SYMBOL(inet6_getname);
 
+int inet6_killaddr_ioctl(struct net *net, void __user *arg) {
+       struct in6_ifreq ireq;
+       struct sockaddr_in6 sin6;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EACCES;
+
+       if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
+               return -EFAULT;
+
+       sin6.sin6_family = AF_INET6;
+       sin6.sin6_addr = ireq.ifr6_addr;
+       return tcp_nuke_addr(net, (struct sockaddr *) &sin6);
+}
+
 int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        struct sock *sk = sock->sk;
 int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        struct sock *sk = sock->sk;
@@ -503,6 +535,8 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                return addrconf_del_ifaddr(net, (void __user *) arg);
        case SIOCSIFDSTADDR:
                return addrconf_set_dstaddr(net, (void __user *) arg);
                return addrconf_del_ifaddr(net, (void __user *) arg);
        case SIOCSIFDSTADDR:
                return addrconf_set_dstaddr(net, (void __user *) arg);
+       case SIOCKILLADDR:
+               return inet6_killaddr_ioctl(net, (void __user *) arg);
        default:
                if (!sk->sk_prot->ioctl)
                        return -ENOIOCTLCMD;
        default:
                if (!sk->sk_prot->ioctl)
                        return -ENOIOCTLCMD;
@@ -663,6 +697,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
                fl6.flowi6_mark = sk->sk_mark;
                fl6.fl6_dport = inet->inet_dport;
                fl6.fl6_sport = inet->inet_sport;
                fl6.flowi6_mark = sk->sk_mark;
                fl6.fl6_dport = inet->inet_dport;
                fl6.fl6_sport = inet->inet_sport;
+               fl6.flowi6_uid = sock_i_uid(sk);
                security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
                final_p = fl6_update_dst(&fl6, np->opt, &final);
                security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
                final_p = fl6_update_dst(&fl6, np->opt, &final);
@@ -843,6 +878,9 @@ static int __init inet6_init(void)
        if (err)
                goto out_unregister_udplite_proto;
 
        if (err)
                goto out_unregister_udplite_proto;
 
+       err = proto_register(&pingv6_prot, 1);
+       if (err)
+               goto out_unregister_ping_proto;
 
        /* We MUST register RAW sockets before we create the ICMP6,
         * IGMP6, or NDISC control sockets.
 
        /* We MUST register RAW sockets before we create the ICMP6,
         * IGMP6, or NDISC control sockets.
@@ -933,6 +971,10 @@ static int __init inet6_init(void)
        if (err)
                goto ipv6_packet_fail;
 
        if (err)
                goto ipv6_packet_fail;
 
+       err = pingv6_init();
+       if (err)
+               goto pingv6_fail;
+
 #ifdef CONFIG_SYSCTL
        err = ipv6_sysctl_register();
        if (err)
 #ifdef CONFIG_SYSCTL
        err = ipv6_sysctl_register();
        if (err)
@@ -945,6 +987,8 @@ out:
 sysctl_fail:
        ipv6_packet_cleanup();
 #endif
 sysctl_fail:
        ipv6_packet_cleanup();
 #endif
+pingv6_fail:
+       pingv6_exit();
 ipv6_packet_fail:
        tcpv6_exit();
 tcpv6_fail:
 ipv6_packet_fail:
        tcpv6_exit();
 tcpv6_fail:
@@ -988,6 +1032,8 @@ register_pernet_fail:
        rtnl_unregister_all(PF_INET6);
 out_sock_register_fail:
        rawv6_exit();
        rtnl_unregister_all(PF_INET6);
 out_sock_register_fail:
        rawv6_exit();
+out_unregister_ping_proto:
+       proto_unregister(&pingv6_prot);
 out_unregister_raw_proto:
        proto_unregister(&rawv6_prot);
 out_unregister_udplite_proto:
 out_unregister_raw_proto:
        proto_unregister(&rawv6_prot);
 out_unregister_udplite_proto: