diff mbox

[RFC,v1,1/2] lsm: Add hooks to the TUN driver

Message ID 20090804212158.10798.34592.stgit@flek.lan
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

Paul Moore Aug. 4, 2009, 9:21 p.m. UTC
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

Comments

Eric Paris Aug. 5, 2009, 1:03 p.m. UTC | #1
On Tue, Aug 4, 2009 at 5:21 PM, Paul Moore<paul.moore@hp.com> wrote:
> 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:
>

> 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

You also must add cap_tun_dev_post_create in security/capability.c and
you need to call set_to_cap_if_null() for all 3 of these new
functions.  I believe you'll see a wonderful null pointer panic if you
tried with selinux=0.....

-Eric
--
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
Serge E. Hallyn Aug. 5, 2009, 2:13 p.m. UTC | #2
Quoting Paul Moore (paul.moore@hp.com):
...
>  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;
...

> @@ -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;
> +

...

> +/**
> + * 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;
> +}

The checks before and after this patch are not equivalent.  Post-patch,
one must always have CAP_NET_ADMIN to do the attach, whereas pre-patch
you only needed those if current_cred() did not own the tun device.  Is
that intentional?

Also as Eric said this patch needs to set the cap_ hooks.  This patch
isn't yet introducing the selinux hooks, so iiuc actually this patch should
always oops if CONFIG_SECURITY=y.

-serge
--
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
Paul Moore Aug. 5, 2009, 9:58 p.m. UTC | #3
On Wednesday 05 August 2009 10:13:50 am Serge E. Hallyn wrote:
> Quoting Paul Moore (paul.moore@hp.com):

[NOTE: my email has been out all day due to some mysterious FS issue so my 
apologies for not replying sooner]

...

> The checks before and after this patch are not equivalent.  Post-patch,
> one must always have CAP_NET_ADMIN to do the attach, whereas pre-patch
> you only needed those if current_cred() did not own the tun device.  Is
> that intentional?

Nope, just a goof on my part; I misread the booleans and haven't fully tested 
the patch yet so it slipped out, thanks for catching it.  This brings up a 
good point, would we rather move the TUN owner/group checks into the cap_tun_* 
functions or move the capable() call back into the TUN driver?  The answer 
wasn't clear to me when I was looking at the code before and the uniqueness of 
the TUN driver doesn't help much in this regard.

> Also as Eric said this patch needs to set the cap_ hooks.  This patch
> isn't yet introducing the selinux hooks, so iiuc actually this patch should
> always oops if CONFIG_SECURITY=y.

Yep, another symptom of not enough testing as I mentioned out in the original 
posting, thanks to both of you for pointing this out ... now somebody just 
needs to fix Rawhide so I can actually get a KVM instance running :)
Serge E. Hallyn Aug. 6, 2009, 2:15 a.m. UTC | #4
Quoting Paul Moore (paul.moore@hp.com):
> On Wednesday 05 August 2009 10:13:50 am Serge E. Hallyn wrote:
> > Quoting Paul Moore (paul.moore@hp.com):
> 
> [NOTE: my email has been out all day due to some mysterious FS issue so my 
> apologies for not replying sooner]
> 
> ...
> 
> > The checks before and after this patch are not equivalent.  Post-patch,
> > one must always have CAP_NET_ADMIN to do the attach, whereas pre-patch
> > you only needed those if current_cred() did not own the tun device.  Is
> > that intentional?
> 
> Nope, just a goof on my part; I misread the booleans and haven't fully tested 
> the patch yet so it slipped out, thanks for catching it.  This brings up a 
> good point, would we rather move the TUN owner/group checks into the cap_tun_* 
> functions or move the capable() call back into the TUN driver?  The answer 
> wasn't clear to me when I was looking at the code before and the uniqueness of 
> the TUN driver doesn't help much in this regard.

I see the question being asked as:  Does this device belong to
the caller and, if not, is the caller privileged to act
anyway?'  So I think the capable call should be moved back
into the tun driver, followed by a separate security_tun_dev_attach()
check, since that is a separate, restrictive question.

thanks,
-serge
--
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
Paul Moore Aug. 6, 2009, 2:24 p.m. UTC | #5
On Wednesday 05 August 2009 10:15:58 pm Serge E. Hallyn wrote:
> Quoting Paul Moore (paul.moore@hp.com):
> > On Wednesday 05 August 2009 10:13:50 am Serge E. Hallyn wrote:
> > > Quoting Paul Moore (paul.moore@hp.com):
> >
> > [NOTE: my email has been out all day due to some mysterious FS issue so
> > my apologies for not replying sooner]
> >
> > ...
> >
> > > The checks before and after this patch are not equivalent.  Post-patch,
> > > one must always have CAP_NET_ADMIN to do the attach, whereas pre-patch
> > > you only needed those if current_cred() did not own the tun device.  Is
> > > that intentional?
> >
> > Nope, just a goof on my part; I misread the booleans and haven't fully
> > tested the patch yet so it slipped out, thanks for catching it.  This
> > brings up a good point, would we rather move the TUN owner/group checks
> > into the cap_tun_* functions or move the capable() call back into the TUN
> > driver?  The answer wasn't clear to me when I was looking at the code
> > before and the uniqueness of the TUN driver doesn't help much in this
> > regard.
>
> I see the question being asked as:  Does this device belong to
> the caller and, if not, is the caller privileged to act
> anyway?'  So I think the capable call should be moved back
> into the tun driver, followed by a separate security_tun_dev_attach()
> check, since that is a separate, restrictive question.

Works for me, I'll make the change.

BTW, the main reason for posting the patches in such an early state was to 
solicit feedback on the location and types of hooks added; I've read lots of 
good feedback but nothing regarding the fundamental aspects of the hooks ... 
any comments before I push out v2?
Serge E. Hallyn Aug. 6, 2009, 3:52 p.m. UTC | #6
Quoting Paul Moore (paul.moore@hp.com):
> On Wednesday 05 August 2009 10:15:58 pm Serge E. Hallyn wrote:
> > Quoting Paul Moore (paul.moore@hp.com):
> > > On Wednesday 05 August 2009 10:13:50 am Serge E. Hallyn wrote:
> > > > Quoting Paul Moore (paul.moore@hp.com):
> > >
> > > [NOTE: my email has been out all day due to some mysterious FS issue so
> > > my apologies for not replying sooner]
> > >
> > > ...
> > >
> > > > The checks before and after this patch are not equivalent.  Post-patch,
> > > > one must always have CAP_NET_ADMIN to do the attach, whereas pre-patch
> > > > you only needed those if current_cred() did not own the tun device.  Is
> > > > that intentional?
> > >
> > > Nope, just a goof on my part; I misread the booleans and haven't fully
> > > tested the patch yet so it slipped out, thanks for catching it.  This
> > > brings up a good point, would we rather move the TUN owner/group checks
> > > into the cap_tun_* functions or move the capable() call back into the TUN
> > > driver?  The answer wasn't clear to me when I was looking at the code
> > > before and the uniqueness of the TUN driver doesn't help much in this
> > > regard.
> >
> > I see the question being asked as:  Does this device belong to
> > the caller and, if not, is the caller privileged to act
> > anyway?'  So I think the capable call should be moved back
> > into the tun driver, followed by a separate security_tun_dev_attach()
> > check, since that is a separate, restrictive question.
> 
> Works for me, I'll make the change.
> 
> BTW, the main reason for posting the patches in such an early state was to 
> solicit feedback on the location and types of hooks added; I've read lots of 
> good feedback but nothing regarding the fundamental aspects of the hooks ... 
> any comments before I push out v2?

Oh now that you mention it, yes - I think the security_tun_dev_attach()
should be called again separately after the post_create() hook.

As for more general comments on whether or which tuntap-specific hooks
need to exist, two things.  First, if you have specific requirements
in mind please do share those, otherwise I'm working based on what I
see in Documentation/networking/tuntap.txt and drivers/net/tun.c.  Second,
based on my understanding i think the hooks you have make sense,
but is there any way to relabel a tun socket?  Since they are always
labeled with current_sid(), that seems restrictive...  I see that you
don't want to use sockcreate_sid, but (to use a made-up example not
reflecting reality) a kvm_setup_t task couldn't create a tun sock for
a kvm_run_t task to use, right?

-serge
--
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
Paul Moore Aug. 6, 2009, 4:25 p.m. UTC | #7
On Thursday 06 August 2009 11:52:58 am Serge E. Hallyn wrote:
> Quoting Paul Moore (paul.moore@hp.com):
> > BTW, the main reason for posting the patches in such an early state was
> > to solicit feedback on the location and types of hooks added; I've read
> > lots of good feedback but nothing regarding the fundamental aspects of
> > the hooks ... any comments before I push out v2?
>
> Oh now that you mention it, yes - I think the security_tun_dev_attach()
> should be called again separately after the post_create() hook.

Why?  Granted the TUN driver calls tun_attach() in both cases but that doesn't 
necessarily mean the operation from a security point of view is the same.  
Using the SELinux hooks as an example, attaching to an existing TUN device is 
currently treated as a relabel operation; the calling task relabels the 
persistent TUN device to match its own label so that traffic sent over the TUN 
device is labeled using the newly attached calling task's label.  Creating a 
new TUN device is like creating any other object (yes, there are exceptions to 
this but I'm speaking generally here), it inherits the label of the task which 
creates it, performing access control for a relabel operation here just 
doesn't make sense.

Or are you expecting some other form of access control for the attach hook 
which would change this argument?

> As for more general comments on whether or which tuntap-specific hooks
> need to exist, two things.  First, if you have specific requirements
> in mind please do share those, otherwise I'm working based on what I
> see in Documentation/networking/tuntap.txt and drivers/net/tun.c.

Not that haven't already been mentioned.  If something doesn't make sense, let 
me know.

> Second, based on my understanding i think the hooks you have make sense,
> but is there any way to relabel a tun socket?  Since they are always labeled
> with current_sid(), that seems restrictive... 

Not at present, the TUN driver only supports changing the user/group IDs.  I 
am debating adding support to change/view the label of the device/socket 
(TUN{SET,GET}SECCTX perhaps?) but that can happen later and is in no way 
prevented by these patches.  My thinking is that these patches are a 
requirement for us to apply the existing LSM network access controls to 
traffic originating from the TUN driver; depending on how use cases evolve 
with the TUN driver we may want to add additional functionality but this 
should serve as a good base.

> I see that you don't want to use sockcreate_sid, but (to use a made-up
> example not reflecting reality) a kvm_setup_t task couldn't create a tun
> sock for a kvm_run_t task to use, right?

Well, the only time this will really be an issue is when you have one task 
create a new, persistent TUN device and a second task that attaches to the 
existing TUN device and uses it to send traffic.  Sticking with your example, 
if the first task is labeled kvm_setup_t and the second task is labeled 
kvm_run_t then the policy would look something like this:

	# allow kvm_setup_t to create a new TUN device
	allow kvm_setup_t self:tun_socket { create };

	# allow kvm_run_t to use TUN devices created by kvm_setup_t
	allow kvm_run_t kvm_setup_t:tun_socket { relabelfrom };
	allow kvm_run_t self:tun_socket { relabelto };

The policy above has the nice effect of only allowing kvm_run_t to attach to 
existing TUN devices created by kvm_setup_t; it can not create a new TUN 
device or use persistent TUN devices created by other domains.  This should 
also help explain why I think calling the attach() hook after the 
post_create() hook makes little sense given the access controls currently 
proposed.
Serge E. Hallyn Aug. 6, 2009, 6:38 p.m. UTC | #8
Quoting Paul Moore (paul.moore@hp.com):
> On Thursday 06 August 2009 11:52:58 am Serge E. Hallyn wrote:
> > Quoting Paul Moore (paul.moore@hp.com):
> > > BTW, the main reason for posting the patches in such an early state was
> > > to solicit feedback on the location and types of hooks added; I've read
> > > lots of good feedback but nothing regarding the fundamental aspects of
> > > the hooks ... any comments before I push out v2?
> >
> > Oh now that you mention it, yes - I think the security_tun_dev_attach()
> > should be called again separately after the post_create() hook.
> 
> Why?  Granted the TUN driver calls tun_attach() in both cases but that doesn't 
> necessarily mean the operation from a security point of view is the same.  
> Using the SELinux hooks as an example, attaching to an existing TUN device is 
> currently treated as a relabel operation; the calling task relabels the 
> persistent TUN device to match its own label so that traffic sent over the TUN 
> device is labeled using the newly attached calling task's label.  Creating a 
> new TUN device is like creating any other object (yes, there are exceptions to 
> this but I'm speaking generally here), it inherits the label of the task which 
> creates it, performing access control for a relabel operation here just 
> doesn't make sense.
> 
> Or are you expecting some other form of access control for the attach hook 
> which would change this argument?

You're right, since there is no way to create without attaching that doesn't
make sense, regardless of the LSM or policy :)  Nm.

> > As for more general comments on whether or which tuntap-specific hooks
> > need to exist, two things.  First, if you have specific requirements
> > in mind please do share those, otherwise I'm working based on what I
> > see in Documentation/networking/tuntap.txt and drivers/net/tun.c.
> 
> Not that haven't already been mentioned.  If something doesn't make sense, let 
> me know.
> 
> > Second, based on my understanding i think the hooks you have make sense,
> > but is there any way to relabel a tun socket?  Since they are always labeled
> > with current_sid(), that seems restrictive... 
> 
> Not at present, the TUN driver only supports changing the user/group IDs.  I 
> am debating adding support to change/view the label of the device/socket 
> (TUN{SET,GET}SECCTX perhaps?) but that can happen later and is in no way 
> prevented by these patches.  My thinking is that these patches are a 
> requirement for us to apply the existing LSM network access controls to 
> traffic originating from the TUN driver; depending on how use cases evolve 
> with the TUN driver we may want to add additional functionality but this 
> should serve as a good base.
> 
> > I see that you don't want to use sockcreate_sid, but (to use a made-up
> > example not reflecting reality) a kvm_setup_t task couldn't create a tun
> > sock for a kvm_run_t task to use, right?
> 
> Well, the only time this will really be an issue is when you have one task 
> create a new, persistent TUN device and a second task that attaches to the 
> existing TUN device and uses it to send traffic.  Sticking with your example, 
> if the first task is labeled kvm_setup_t and the second task is labeled 
> kvm_run_t then the policy would look something like this:
> 
> 	# allow kvm_setup_t to create a new TUN device
> 	allow kvm_setup_t self:tun_socket { create };
> 
> 	# allow kvm_run_t to use TUN devices created by kvm_setup_t
> 	allow kvm_run_t kvm_setup_t:tun_socket { relabelfrom };
> 	allow kvm_run_t self:tun_socket { relabelto };
> 
> The policy above has the nice effect of only allowing kvm_run_t to attach to 
> existing TUN devices created by kvm_setup_t; it can not create a new TUN 
> device or use persistent TUN devices created by other domains.  This should 
> also help explain why I think calling the attach() hook after the 
> post_create() hook makes little sense given the access controls currently 
> proposed.

And really allowing flexibility in the default label can always be done
without affecting the tun code so never mind.

So I think your hooks make sense as is, given the TUN usage model described
in the docs.

thanks,
-serge
--
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 mbox

Patch

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