| 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 |
| |