blob: 68381ab198f8177c68ea4d449253d4cd7bfc48f3 [file] [log] [blame]
From 47ad7e3568da1ac055a20971c6eadced3426c535 Mon Sep 17 00:00:00 2001
From: Kevin Cernekee <cernekee@chromium.org>
Date: Fri, 27 Jan 2017 16:15:55 -0800
Subject: [PATCH] CHROMIUM: Implement Android permission overrides for PPTP VPN
tunnels
Android kernels override the capable() checks for CAP_NET_RAW and
CAP_NET_ADMIN globally[0], allowing processes with GIDs AID_NET_RAW
or AID_NET_ADMIN to perform privileged operations. Rather than
changing the global permission checks (which makes it harder to
reason about the extent of the risk), Chrome OS supports a limited,
well-defined subset of this functionality through the per-netns
android_paranoid sysctl.
Extend these permission overrides to cover the following cases, which
are needed to support Android's builtin PPTP VPN client:
- SIOCSIF* MTU and legacy IP configuration
- SO_BINDTODEVICE
- Opening /dev/ppp
- Creating RAW sockets (for GRE)
[0] https://android.googlesource.com/kernel/common/+/9a5e2c00592e2dcb
BUG=chromium:207904
TEST=none
Reviewed-on: https://chromium-review.googlesource.com/802777
Reviewed-by: Abhishek Bhardwaj <abhishekbh@google.com>
Signed-off-by: Hugo Benichi <hugobenichi@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1157954
Commit-Ready: Hugo Benichi <hugobenichi@google.com>
Tested-by: Hugo Benichi <hugobenichi@google.com>
Reviewed-by: Grant Grundler <grundler@chromium.org>
Conflicts:
drivers/net/ppp/ppp_generic.c
net/ipv4/af_inet.c
[rebase419(groeck): Resolve conflicts;
re-introduce call to android_ns_capable() in inet6_create()]
Signed-off-by: Guenter Roeck <groeck@chromium.org>
(cherry picked from commit f13de8e112f19e0868481ff0b955480b8f38e10e)
Signed-off-by: Taoyu Li <taoyl@google.com>
Change-Id: I6b6bb33a6e92585ceacc0020acfb88afb1157bbb
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/2213512
Reviewed-by: Guenter Roeck <groeck@chromium.org>
Commit-Queue: Taoyu Li <taoyl@chromium.org>
Tested-by: Taoyu Li <taoyl@chromium.org>
Auto-Submit: Taoyu Li <taoyl@chromium.org>
Conflicts:
net/core/dev_ioctl.c
net/core/sock.c
[rebase510(groeck): Context conflicts]
Signed-off-by: Guenter Roeck <groeck@chromium.org>
---
drivers/net/ppp/ppp_generic.c | 3 ++-
include/net/sock.h | 1 +
net/core/dev_ioctl.c | 3 ++-
net/core/sock.c | 19 ++++++++++++++++++-
net/ipv4/af_inet.c | 2 +-
net/ipv4/devinet.c | 5 +++--
net/ipv6/af_inet6.c | 2 +-
7 files changed, 28 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index a9beacd552cf825b6e391862f196141358b9eadd..b3c047ce44f66dec6251aeccb5bddefa8d975ee1 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -51,6 +51,7 @@
#include <linux/nsproxy.h>
#include <net/net_namespace.h>
+#include <net/sock.h>
#include <net/netns/generic.h>
#define PPP_VERSION "2.4.2"
@@ -388,7 +389,7 @@ static int ppp_open(struct inode *inode, struct file *file)
/*
* This could (should?) be enforced by the permissions on /dev/ppp.
*/
- if (!ns_capable(file->f_cred->user_ns, CAP_NET_ADMIN))
+ if (!android_ns_capable(current->nsproxy->net_ns, CAP_NET_ADMIN))
return -EPERM;
return 0;
}
diff --git a/include/net/sock.h b/include/net/sock.h
index efb7cf522b07baadc325e511ca242f906b22cce6..186710a12429f2293aaef1a3837d454996a71a15 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -2865,6 +2865,7 @@ bool sk_ns_capable(const struct sock *sk,
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);
+bool android_ns_capable(struct net *net, int cap);
void sk_get_meminfo(const struct sock *sk, u32 *meminfo);
diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c
index 3730945ee29489ace6424967812f062c17ac3060..15b65bfec286ae7ca28dddf2dd18d498df19f0c1 100644
--- a/net/core/dev_ioctl.c
+++ b/net/core/dev_ioctl.c
@@ -8,6 +8,7 @@
#include <linux/wireless.h>
#include <linux/if_bridge.h>
#include <net/dsa_stubs.h>
+#include <net/sock.h>
#include <net/wext.h>
#include "dev.h"
@@ -595,7 +596,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr,
case SIOCBRADDIF:
case SIOCBRDELIF:
case SIOCSHWTSTAMP:
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+ if (!android_ns_capable(net, CAP_NET_ADMIN))
return -EPERM;
fallthrough;
case SIOCBONDSLAVEINFOQUERY:
diff --git a/net/core/sock.c b/net/core/sock.c
index 651886f8985f89e105e44bc9abf9980ab5485b83..6cf37cb6406a9f61446b9250f0f892088f9cfd05 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -116,6 +116,7 @@
#include <linux/compat.h>
#include <linux/cred.h>
#include <linux/uidgid.h>
+#include <linux/android_aid.h>
#include <linux/uaccess.h>
@@ -217,6 +218,22 @@ bool inet_sk_allowed(struct net *net, gid_t gid)
}
EXPORT_SYMBOL(inet_sk_allowed);
+bool android_ns_capable(struct net *net, int cap)
+{
+ if (ns_capable(net->user_ns, cap))
+ return true;
+ if (!net->core.sysctl_android_paranoid)
+ return false;
+ if (cap == CAP_NET_RAW &&
+ in_android_group(net->user_ns, AID_NET_RAW))
+ return true;
+ if (cap == CAP_NET_ADMIN &&
+ in_android_group(net->user_ns, AID_NET_ADMIN))
+ return true;
+ return false;
+}
+EXPORT_SYMBOL(android_ns_capable);
+
/*
* Each address family might have different locking rules, so we have
* one slock key per address family and separate keys for internal and
@@ -648,7 +665,7 @@ static int sock_bindtoindex_locked(struct sock *sk, int ifindex)
/* Sorry... */
ret = -EPERM;
- if (sk->sk_bound_dev_if && !ns_capable(net->user_ns, CAP_NET_RAW))
+ if (sk->sk_bound_dev_if && !android_ns_capable(net, CAP_NET_RAW))
goto out;
ret = -EINVAL;
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 6e982ed6fbcd2e5f347754c5c28c6b032597529d..283b0887c57bb58464b9e0a397f5fcdbe18c38bb 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -308,7 +308,7 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,
err = -EPERM;
if (sock->type == SOCK_RAW && !kern &&
- !ns_capable(net->user_ns, CAP_NET_RAW))
+ !android_ns_capable(net, CAP_NET_RAW))
goto out_rcu_unlock;
sock->ops = answer->ops;
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 5deac0517ef708f92e4f0540f174931117b3f1ca..9d5c4343d8aa6ed519df4c2443050c809979b7b7 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -61,6 +61,7 @@
#include <net/rtnetlink.h>
#include <net/net_namespace.h>
#include <net/addrconf.h>
+#include <net/sock.h>
#define IPV6ONLY_FLAGS \
(IFA_F_NODAD | IFA_F_OPTIMISTIC | IFA_F_DADFAILED | \
@@ -1052,7 +1053,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
case SIOCSIFFLAGS:
ret = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+ if (!android_ns_capable(net, CAP_NET_ADMIN))
goto out;
break;
case SIOCSIFADDR: /* Set interface address (and family) */
@@ -1060,7 +1061,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
case SIOCSIFDSTADDR: /* Set the destination address */
case SIOCSIFNETMASK: /* Set the netmask for the interface */
ret = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+ if (!android_ns_capable(net, CAP_NET_ADMIN))
goto out;
ret = -EINVAL;
if (sin->sin_family != AF_INET)
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index dc4e18fc849499b4f22836a366d90cda9f424e7e..c786be073fa5e25d6b04f2723fe1e24f1b2b76fa 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -182,7 +182,7 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
err = -EPERM;
if (sock->type == SOCK_RAW && !kern &&
- !ns_capable(net->user_ns, CAP_NET_RAW))
+ !android_ns_capable(net, CAP_NET_RAW))
goto out_rcu_unlock;
sock->ops = answer->ops;
--
2.38.3