From patchwork Tue Aug 4 21:21:58 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Moore X-Patchwork-Id: 30746 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@bilbo.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from ozlabs.org (ozlabs.org [203.10.76.45]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "mx.ozlabs.org", Issuer "CA Cert Signing Authority" (verified OK)) by bilbo.ozlabs.org (Postfix) with ESMTPS id 15D24B6F1F for ; Wed, 5 Aug 2009 07:23:05 +1000 (EST) Received: by ozlabs.org (Postfix) id 04469DDDA0; Wed, 5 Aug 2009 07:23:05 +1000 (EST) Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by ozlabs.org (Postfix) with ESMTP id 76332DDD01 for ; Wed, 5 Aug 2009 07:23:04 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932908AbZHDVW5 (ORCPT ); Tue, 4 Aug 2009 17:22:57 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S932909AbZHDVWz (ORCPT ); Tue, 4 Aug 2009 17:22:55 -0400 Received: from g4t0017.houston.hp.com ([15.201.24.20]:28380 "EHLO g4t0017.houston.hp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932878AbZHDVWx (ORCPT ); Tue, 4 Aug 2009 17:22:53 -0400 Received: from g1t0038.austin.hp.com (g1t0038.austin.hp.com [16.236.32.44]) by g4t0017.houston.hp.com (Postfix) with ESMTP id 79C6F38645; Tue, 4 Aug 2009 21:22:54 +0000 (UTC) Received: from ldl (ldl.fc.hp.com [15.11.146.30]) by g1t0038.austin.hp.com (Postfix) with ESMTP id B812830203; Tue, 4 Aug 2009 21:21:59 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by ldl (Postfix) with ESMTP id AB174CF0021; Tue, 4 Aug 2009 15:21:59 -0600 (MDT) Received: from ldl ([127.0.0.1]) by localhost (ldl.fc.hp.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zlu0JgEAiVH7; Tue, 4 Aug 2009 15:21:59 -0600 (MDT) Received: from flek.lan (squirrel.fc.hp.com [15.11.146.57]) by ldl (Postfix) with ESMTP id EDAF1CF000D; Tue, 4 Aug 2009 15:21:58 -0600 (MDT) From: Paul Moore Subject: [RFC PATCH v1 1/2] lsm: Add hooks to the TUN driver To: netdev@vger.kernel.org, linux-security-module@vger.kernel.org, selinux@tycho.nsa.gov Date: Tue, 04 Aug 2009 17:21:58 -0400 Message-ID: <20090804212158.10798.34592.stgit@flek.lan> In-Reply-To: <20090804211304.10798.65601.stgit@flek.lan> References: <20090804211304.10798.65601.stgit@flek.lan> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The TUN driver lacks any LSM hooks which makes it difficult for LSM modules, such as SELinux, to enforce access controls on network traffic generated by TUN users; this is particularly problematic for virtualization apps such as QEMU and KVM. This patch adds three new LSM hooks designed to control the creation and attachment of TUN devices, the hooks are: * security_tun_dev_create() Provides access control for the creation of new TUN devices * security_tun_dev_post_create() Provides the ability to create the necessary socket LSM state for newly created TUN devices * security_tun_dev_attach() Provides access control for attaching to existing, persistent TUN devices and the ability to update the TUN device's socket LSM state as necessary --- drivers/net/tun.c | 41 +++++++++++++++++++++++------------------ include/linux/security.h | 34 ++++++++++++++++++++++++++++++++++ security/commoncap.c | 26 ++++++++++++++++++++++++++ security/security.c | 18 ++++++++++++++++++ 4 files changed, 101 insertions(+), 18 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 027f7ab..f26c1fe 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -130,28 +130,22 @@ static inline struct tun_sock *tun_sk(struct sock *sk) static int tun_attach(struct tun_struct *tun, struct file *file) { struct tun_file *tfile = file->private_data; - const struct cred *cred = current_cred(); - int err; + int err = 0; ASSERT_RTNL(); - /* Check permissions */ - if (((tun->owner != -1 && cred->euid != tun->owner) || - (tun->group != -1 && !in_egroup_p(tun->group))) && - !capable(CAP_NET_ADMIN)) - return -EPERM; - netif_tx_lock_bh(tun->dev); - err = -EINVAL; - if (tfile->tun) + if (tfile->tun) { + err = -EINVAL; goto out; + } - err = -EBUSY; - if (tun->tfile) + if (tun->tfile) { + err = -EBUSY; goto out; + } - err = 0; tfile->tun = tun; tun->tfile = tfile; dev_hold(tun->dev); @@ -922,6 +916,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) struct sock *sk; struct tun_struct *tun; struct net_device *dev; + const struct cred *cred = current_cred(); int err; dev = __dev_get_by_name(net, ifr->ifr_name); @@ -935,6 +930,13 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) else return -EINVAL; + if ((tun->owner != -1 && cred->euid != tun->owner) || + (tun->group != -1 && !in_egroup_p(tun->group))) + return -EPERM; + err = security_tun_dev_attach(tun->sk); + if (err < 0) + return err; + err = tun_attach(tun, file); if (err < 0) return err; @@ -943,10 +945,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) char *name; unsigned long flags = 0; - err = -EINVAL; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + err = security_tun_dev_create(); + if (err < 0) + return err; /* Set dev type */ if (ifr->ifr_flags & IFF_TUN) { @@ -957,8 +958,10 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) /* TAP device */ flags |= TUN_TAP_DEV; name = "tap%d"; - } else + } else { + err = -EINVAL; goto failed; + } if (*ifr->ifr_name) name = ifr->ifr_name; @@ -989,6 +992,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) tun->sk = sk; container_of(sk, struct tun_sock, sk)->tun = tun; + security_tun_dev_post_create(sk); + tun_net_init(dev); if (strchr(dev->name, '%')) { diff --git a/include/linux/security.h b/include/linux/security.h index 5eff459..67f5d91 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -91,6 +91,9 @@ struct seq_file; extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); extern int cap_netlink_recv(struct sk_buff *skb, int cap); +extern int cap_tun_dev_create(void); +extern int cap_tun_dev_attach(void); + extern unsigned long mmap_min_addr; /* * Values used in the task_security_ops calls @@ -974,6 +977,17 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * Sets the connection's peersid to the secmark on skb. * @req_classify_flow: * Sets the flow's sid to the openreq sid. + * @tun_dev_create: + * Check permissions prior to creating a new TUN device. + * @tun_dev_post_create: + * This hook allows a module to update or allocate a per-socket security + * structure. + * @tun_sk contains the newly created sock structure. + * @tun_dev_attach: + * Check permissions prior to attaching to a persistent TUN device. This + * hook can also be used by the module to update any security state + * associated with the TUN device's sock structure. + * @tun_sk contains the existing sock structure. * * Security hooks for XFRM operations. * @@ -1572,6 +1586,9 @@ struct security_operations { void (*inet_csk_clone) (struct sock *newsk, const struct request_sock *req); void (*inet_conn_established) (struct sock *sk, struct sk_buff *skb); void (*req_classify_flow) (const struct request_sock *req, struct flowi *fl); + int (*tun_dev_create)(void); + void (*tun_dev_post_create)(struct sock *tun_sk); + int (*tun_dev_attach)(struct sock *tun_sk); #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM @@ -2557,6 +2574,9 @@ void security_inet_csk_clone(struct sock *newsk, const struct request_sock *req); void security_inet_conn_established(struct sock *sk, struct sk_buff *skb); +int security_tun_dev_create(void); +void security_tun_dev_post_create(struct sock *tun_sk); +int security_tun_dev_attach(struct sock *tun_sk); #else /* CONFIG_SECURITY_NETWORK */ static inline int security_unix_stream_connect(struct socket *sock, @@ -2707,6 +2727,20 @@ static inline void security_inet_conn_established(struct sock *sk, struct sk_buff *skb) { } + +static inline int security_tun_dev_create(void) +{ + return cap_tun_dev_create(); +} + +static inline void security_tun_dev_post_create(struct sock *tun_sk) +{ +} + +static inline int security_tun_dev_attach(struct sock *tun_sk) +{ + return cap_tun_dev_attach(); +} #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM diff --git a/security/commoncap.c b/security/commoncap.c index 48b7e02..07125a6 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -984,3 +984,29 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) cap_sys_admin = 1; return __vm_enough_memory(mm, pages, cap_sys_admin); } + +/** + * cap_tun_dev_create - Determine if creation of a new TUN device is allowed + * + * Determine if the user is allowed to create a new TUN device, historically + * this has always required the CAP_NET_ADMIN permission. + */ +int cap_tun_dev_create(void) +{ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + return 0; +} + +/** + * cap_tun_dev_attach - Determine if attaching to an TUN device is allowed + * + * Determine if the user is allowed to attach to an existing persistent TUN + * device, historically this has always required the CAP_NET_ADMIN permission. + */ +int cap_tun_dev_attach(void) +{ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + return 0; +} diff --git a/security/security.c b/security/security.c index dc7674f..14ebf82 100644 --- a/security/security.c +++ b/security/security.c @@ -1112,6 +1112,24 @@ void security_inet_conn_established(struct sock *sk, security_ops->inet_conn_established(sk, skb); } +int security_tun_dev_create(void) +{ + return security_ops->tun_dev_create(); +} +EXPORT_SYMBOL(security_tun_dev_create); + +void security_tun_dev_post_create(struct sock *tun_sk) +{ + return security_ops->tun_dev_post_create(tun_sk); +} +EXPORT_SYMBOL(security_tun_dev_post_create); + +int security_tun_dev_attach(struct sock *tun_sk) +{ + return security_ops->tun_dev_attach(tun_sk); +} +EXPORT_SYMBOL(security_tun_dev_attach); + #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM