diff options
author | Paul Moore <pmoore@redhat.com> | 2013-01-14 02:12:19 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-01-14 18:16:59 -0500 |
commit | 5dbbaf2de89613d19a9286d4db0a535ca2735d26 (patch) | |
tree | 1eaa64968a8ecf83aee4d2f6792840abde6c4916 /security/selinux/hooks.c | |
parent | 6f96c142f77c96a34ac377a3616ee7abcd77fb4d (diff) |
tun: fix LSM/SELinux labeling of tun/tap devices
This patch corrects some problems with LSM/SELinux that were introduced
with the multiqueue patchset. The problem stems from the fact that the
multiqueue work changed the relationship between the tun device and its
associated socket; before the socket persisted for the life of the
device, however after the multiqueue changes the socket only persisted
for the life of the userspace connection (fd open). For non-persistent
devices this is not an issue, but for persistent devices this can cause
the tun device to lose its SELinux label.
We correct this problem by adding an opaque LSM security blob to the
tun device struct which allows us to have the LSM security state, e.g.
SELinux labeling information, persist for the lifetime of the tun
device. In the process we tweak the LSM hooks to work with this new
approach to TUN device/socket labeling and introduce a new LSM hook,
security_tun_dev_attach_queue(), to approve requests to attach to a
TUN queue via TUNSETQUEUE.
The SELinux code has been adjusted to match the new LSM hooks, the
other LSMs do not make use of the LSM TUN controls. This patch makes
use of the recently added "tun_socket:attach_queue" permission to
restrict access to the TUNSETQUEUE operation. On older SELinux
policies which do not define the "tun_socket:attach_queue" permission
the access control decision for TUNSETQUEUE will be handled according
to the SELinux policy's unknown permission setting.
Signed-off-by: Paul Moore <pmoore@redhat.com>
Acked-by: Eric Paris <eparis@parisplace.org>
Tested-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 61a53367d029..ef26e9611ffb 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -4399,6 +4399,24 @@ static void selinux_req_classify_flow(const struct request_sock *req, | |||
4399 | fl->flowi_secid = req->secid; | 4399 | fl->flowi_secid = req->secid; |
4400 | } | 4400 | } |
4401 | 4401 | ||
4402 | static int selinux_tun_dev_alloc_security(void **security) | ||
4403 | { | ||
4404 | struct tun_security_struct *tunsec; | ||
4405 | |||
4406 | tunsec = kzalloc(sizeof(*tunsec), GFP_KERNEL); | ||
4407 | if (!tunsec) | ||
4408 | return -ENOMEM; | ||
4409 | tunsec->sid = current_sid(); | ||
4410 | |||
4411 | *security = tunsec; | ||
4412 | return 0; | ||
4413 | } | ||
4414 | |||
4415 | static void selinux_tun_dev_free_security(void *security) | ||
4416 | { | ||
4417 | kfree(security); | ||
4418 | } | ||
4419 | |||
4402 | static int selinux_tun_dev_create(void) | 4420 | static int selinux_tun_dev_create(void) |
4403 | { | 4421 | { |
4404 | u32 sid = current_sid(); | 4422 | u32 sid = current_sid(); |
@@ -4414,8 +4432,17 @@ static int selinux_tun_dev_create(void) | |||
4414 | NULL); | 4432 | NULL); |
4415 | } | 4433 | } |
4416 | 4434 | ||
4417 | static void selinux_tun_dev_post_create(struct sock *sk) | 4435 | static int selinux_tun_dev_attach_queue(void *security) |
4418 | { | 4436 | { |
4437 | struct tun_security_struct *tunsec = security; | ||
4438 | |||
4439 | return avc_has_perm(current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET, | ||
4440 | TUN_SOCKET__ATTACH_QUEUE, NULL); | ||
4441 | } | ||
4442 | |||
4443 | static int selinux_tun_dev_attach(struct sock *sk, void *security) | ||
4444 | { | ||
4445 | struct tun_security_struct *tunsec = security; | ||
4419 | struct sk_security_struct *sksec = sk->sk_security; | 4446 | struct sk_security_struct *sksec = sk->sk_security; |
4420 | 4447 | ||
4421 | /* we don't currently perform any NetLabel based labeling here and it | 4448 | /* we don't currently perform any NetLabel based labeling here and it |
@@ -4425,20 +4452,19 @@ static void selinux_tun_dev_post_create(struct sock *sk) | |||
4425 | * cause confusion to the TUN user that had no idea network labeling | 4452 | * cause confusion to the TUN user that had no idea network labeling |
4426 | * protocols were being used */ | 4453 | * protocols were being used */ |
4427 | 4454 | ||
4428 | /* see the comments in selinux_tun_dev_create() about why we don't use | 4455 | sksec->sid = tunsec->sid; |
4429 | * the sockcreate SID here */ | ||
4430 | |||
4431 | sksec->sid = current_sid(); | ||
4432 | sksec->sclass = SECCLASS_TUN_SOCKET; | 4456 | sksec->sclass = SECCLASS_TUN_SOCKET; |
4457 | |||
4458 | return 0; | ||
4433 | } | 4459 | } |
4434 | 4460 | ||
4435 | static int selinux_tun_dev_attach(struct sock *sk) | 4461 | static int selinux_tun_dev_open(void *security) |
4436 | { | 4462 | { |
4437 | struct sk_security_struct *sksec = sk->sk_security; | 4463 | struct tun_security_struct *tunsec = security; |
4438 | u32 sid = current_sid(); | 4464 | u32 sid = current_sid(); |
4439 | int err; | 4465 | int err; |
4440 | 4466 | ||
4441 | err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET, | 4467 | err = avc_has_perm(sid, tunsec->sid, SECCLASS_TUN_SOCKET, |
4442 | TUN_SOCKET__RELABELFROM, NULL); | 4468 | TUN_SOCKET__RELABELFROM, NULL); |
4443 | if (err) | 4469 | if (err) |
4444 | return err; | 4470 | return err; |
@@ -4446,8 +4472,7 @@ static int selinux_tun_dev_attach(struct sock *sk) | |||
4446 | TUN_SOCKET__RELABELTO, NULL); | 4472 | TUN_SOCKET__RELABELTO, NULL); |
4447 | if (err) | 4473 | if (err) |
4448 | return err; | 4474 | return err; |
4449 | 4475 | tunsec->sid = sid; | |
4450 | sksec->sid = sid; | ||
4451 | 4476 | ||
4452 | return 0; | 4477 | return 0; |
4453 | } | 4478 | } |
@@ -5642,9 +5667,12 @@ static struct security_operations selinux_ops = { | |||
5642 | .secmark_refcount_inc = selinux_secmark_refcount_inc, | 5667 | .secmark_refcount_inc = selinux_secmark_refcount_inc, |
5643 | .secmark_refcount_dec = selinux_secmark_refcount_dec, | 5668 | .secmark_refcount_dec = selinux_secmark_refcount_dec, |
5644 | .req_classify_flow = selinux_req_classify_flow, | 5669 | .req_classify_flow = selinux_req_classify_flow, |
5670 | .tun_dev_alloc_security = selinux_tun_dev_alloc_security, | ||
5671 | .tun_dev_free_security = selinux_tun_dev_free_security, | ||
5645 | .tun_dev_create = selinux_tun_dev_create, | 5672 | .tun_dev_create = selinux_tun_dev_create, |
5646 | .tun_dev_post_create = selinux_tun_dev_post_create, | 5673 | .tun_dev_attach_queue = selinux_tun_dev_attach_queue, |
5647 | .tun_dev_attach = selinux_tun_dev_attach, | 5674 | .tun_dev_attach = selinux_tun_dev_attach, |
5675 | .tun_dev_open = selinux_tun_dev_open, | ||
5648 | 5676 | ||
5649 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 5677 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
5650 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, | 5678 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, |