blob: 81825a558b4cb8eae60925da4b82c9befa32679f [file] [log] [blame]
From 24c910207376ed21dd55d2a84971262347ee9ed6 Mon Sep 17 00:00:00 2001
From: Kevin Cernekee <cernekee@chromium.org>
Date: Mon, 16 May 2016 22:28:46 -0700
Subject: [PATCH] CHROMIUM: Introduce ANDROID_PARANOID_NETWORK as per-netns
setting
ANDROID_PARANOID_NETWORK requires creators of AF_INET/AF_INET6 sockets
to be in the AID_INET group. In our system it is problematic to enable
this globally. Change the logic so that the changes apply on a per-netns
basis. Also, interpret AID_* as gids instead of kgids.
BUG=b:27932716
TEST=`echo 1 > /proc/sys/net/core/android_paranoid`
Signed-off-by: Kevin Cernekee <cernekee@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/362671
Reviewed-by: Guenter Roeck <groeck@google.com>
Conflicts:
Documentation/android.txt (deleted locally)
include/net/sock.h
net/core/sock.c
net/core/sysctl_net_core.c
net/ipv6/af_inet6.c
security/commoncap.c
net/ipv4/af_inet.c
[rebase412(groeck): Clean version, not depending on Android
version of ANDROID_PARANOID_NETWORK]
Conflicts:
net/core/sysctl_net_core.c
net/ipv4/af_inet.c
net/ipv6/af_inet6.c
security/commoncap.c
[rebase419(groeck): Resolve various conflicts]
Signed-off-by: Guenter Roeck <groeck@google.com>
(cherry picked from commit eeff9e17e144063f761163315007ea67d42106ab)
Conflicts:
drivers/net/tun.c
net/core/sysctl_net_core.c
net/ipv4/af_inet.c
net/ipv6/af_inet6.c
security/commoncap.c
[Cherry-pick to 5.4: Resolve various conflicts]
Signed-off-by: Taoyu Li <taoyl@google.com>
Change-Id: Ie14fbfbe24d875bb103bcaebb3edd1e4528baf3b
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/2213509
Tested-by: Taoyu Li <taoyl@chromium.org>
Reviewed-by: Guenter Roeck <groeck@chromium.org>
Reviewed-by: Hugo Benichi <hugobenichi@google.com>
Commit-Queue: Taoyu Li <taoyl@chromium.org>
Conflicts: net/core/sock.c
[rebase510(groeck): Context conflicts]
Signed-off-by: Guenter Roeck <groeck@chromium.org>
---
drivers/net/tun.c | 5 +++++
include/net/netns/core.h | 1 +
include/net/sock.h | 1 +
net/core/sock.c | 20 ++++++++++++++++++++
net/core/sysctl_net_core.c | 12 ++++++++++++
net/ipv4/af_inet.c | 4 ++++
net/ipv6/af_inet6.c | 4 ++++
7 files changed, 47 insertions(+)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index fc86da7f1628..e4b0d49fa3c4 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -2936,6 +2936,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
int ret;
bool do_notify = false;
+ if (current->nsproxy->net_ns->core.sysctl_android_paranoid &&
+ cmd != TUNGETIFF && !capable(CAP_NET_ADMIN)) {
+ return -EPERM;
+ }
+
if (cmd == TUNSETIFF || cmd == TUNSETQUEUE ||
(_IOC_TYPE(cmd) == SOCK_IOC_TYPE && cmd != SIOCGSKNS)) {
if (copy_from_user(&ifr, argp, ifreq_len))
diff --git a/include/net/netns/core.h b/include/net/netns/core.h
index 36c2d998a43c..2c13b2176335 100644
--- a/include/net/netns/core.h
+++ b/include/net/netns/core.h
@@ -10,6 +10,7 @@ struct netns_core {
struct ctl_table_header *sysctl_hdr;
int sysctl_somaxconn;
+ int sysctl_android_paranoid;
#ifdef CONFIG_PROC_FS
int __percpu *sock_inuse;
diff --git a/include/net/sock.h b/include/net/sock.h
index 0b6266fd6bf6..1bc0ad8cbbcf 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -2647,6 +2647,7 @@ bool sk_ns_capable(const struct sock *sk,
struct user_namespace *user_ns, int cap);
bool sk_capable(const struct sock *sk, int cap);
bool sk_net_capable(const struct sock *sk, int cap);
+bool inet_sk_allowed(struct net *net, gid_t gid);
void sk_get_meminfo(const struct sock *sk, u32 *meminfo);
diff --git a/net/core/sock.c b/net/core/sock.c
index cc31b601ae10..466e08015d8a 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -114,6 +114,8 @@
#include <linux/memcontrol.h>
#include <linux/prefetch.h>
#include <linux/compat.h>
+#include <linux/cred.h>
+#include <linux/uidgid.h>
#include <linux/uaccess.h>
@@ -192,6 +194,24 @@ bool sk_net_capable(const struct sock *sk, int cap)
}
EXPORT_SYMBOL(sk_net_capable);
+static bool in_android_group(struct user_namespace *user, gid_t gid)
+{
+ kgid_t kgid = make_kgid(user, gid);
+
+ if (!gid_valid(kgid))
+ return false;
+ return in_egroup_p(kgid);
+}
+
+bool inet_sk_allowed(struct net *net, gid_t gid)
+{
+ if (!net->core.sysctl_android_paranoid ||
+ ns_capable(net->user_ns, CAP_NET_RAW))
+ return true;
+ return in_android_group(net->user_ns, gid);
+}
+EXPORT_SYMBOL(inet_sk_allowed);
+
/*
* Each address family might have different locking rules, so we have
* one slock key per address family and separate keys for internal and
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 4567de519603..4a6c29978a51 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -582,6 +582,15 @@ static struct ctl_table netns_core_table[] = {
.extra1 = SYSCTL_ZERO,
.proc_handler = proc_dointvec_minmax
},
+ {
+ .procname = "android_paranoid",
+ .data = &init_net.core.sysctl_android_paranoid,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
+ .proc_handler = proc_dointvec_minmax
+ },
{ }
};
@@ -602,6 +611,8 @@ static __net_init int sysctl_core_net_init(struct net *net)
{
struct ctl_table *tbl;
+ net->core.sysctl_android_paranoid = 0;
+
tbl = netns_core_table;
if (!net_eq(net, &init_net)) {
tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL);
@@ -609,6 +620,7 @@ static __net_init int sysctl_core_net_init(struct net *net)
goto err_dup;
tbl[0].data = &net->core.sysctl_somaxconn;
+ tbl[1].data = &net->core.sysctl_android_paranoid;
/* Don't export any sysctls to unprivileged users */
if (net->user_ns != &init_user_ns) {
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 1355e6c0d567..60a085be3941 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -85,6 +85,7 @@
#include <linux/netfilter_ipv4.h>
#include <linux/random.h>
#include <linux/slab.h>
+#include <linux/android_aid.h>
#include <linux/uaccess.h>
@@ -259,6 +260,9 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,
if (protocol < 0 || protocol >= IPPROTO_MAX)
return -EINVAL;
+ if (!inet_sk_allowed(net, AID_INET))
+ return -EACCES;
+
sock->state = SS_UNCONNECTED;
/* Look for the requested type/protocol pair. */
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 802f5111805a..12cbe691cd08 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -39,6 +39,7 @@
#include <linux/netdevice.h>
#include <linux/icmpv6.h>
#include <linux/netfilter_ipv6.h>
+#include <linux/android_aid.h>
#include <net/ip.h>
#include <net/ipv6.h>
@@ -122,6 +123,9 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
if (protocol < 0 || protocol >= IPPROTO_MAX)
return -EINVAL;
+ if (!inet_sk_allowed(net, AID_INET))
+ return -EACCES;
+
/* Look for the requested type/protocol pair. */
lookup_protocol:
err = -ESOCKTNOSUPPORT;
--
2.17.1