diff options
author | Venkat Yekkirala <vyekkirala@TrustedCS.com> | 2006-07-25 02:32:50 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 17:53:29 -0400 |
commit | 4237c75c0a35535d7f9f2bfeeb4b4df1e068a0bf (patch) | |
tree | 02adcb6fe6c346a8b99cf161ba5233ed1e572727 /security/selinux/hooks.c | |
parent | cb969f072b6d67770b559617f14e767f47e77ece (diff) |
[MLSXFRM]: Auto-labeling of child sockets
This automatically labels the TCP, Unix stream, and dccp child sockets
as well as openreqs to be at the same MLS level as the peer. This will
result in the selection of appropriately labeled IPSec Security
Associations.
This also uses the sock's sid (as opposed to the isec sid) in SELinux
enforcement of secmark in rcv_skb and postroute_last hooks.
Signed-off-by: Venkat Yekkirala <vyekkirala@TrustedCS.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 137 |
1 files changed, 93 insertions, 44 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4e5989d584ce..1dc935f7b919 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -3328,8 +3328,9 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, | |||
3328 | /* server child socket */ | 3328 | /* server child socket */ |
3329 | ssec = newsk->sk_security; | 3329 | ssec = newsk->sk_security; |
3330 | ssec->peer_sid = isec->sid; | 3330 | ssec->peer_sid = isec->sid; |
3331 | 3331 | err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid); | |
3332 | return 0; | 3332 | |
3333 | return err; | ||
3333 | } | 3334 | } |
3334 | 3335 | ||
3335 | static int selinux_socket_unix_may_send(struct socket *sock, | 3336 | static int selinux_socket_unix_may_send(struct socket *sock, |
@@ -3355,11 +3356,29 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
3355 | } | 3356 | } |
3356 | 3357 | ||
3357 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 3358 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
3358 | struct avc_audit_data *ad, u32 sock_sid, u16 sock_class, | 3359 | struct avc_audit_data *ad, u16 family, char *addrp, int len) |
3359 | u16 family, char *addrp, int len) | ||
3360 | { | 3360 | { |
3361 | int err = 0; | 3361 | int err = 0; |
3362 | u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; | 3362 | u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; |
3363 | struct socket *sock; | ||
3364 | u16 sock_class = 0; | ||
3365 | u32 sock_sid = 0; | ||
3366 | |||
3367 | read_lock_bh(&sk->sk_callback_lock); | ||
3368 | sock = sk->sk_socket; | ||
3369 | if (sock) { | ||
3370 | struct inode *inode; | ||
3371 | inode = SOCK_INODE(sock); | ||
3372 | if (inode) { | ||
3373 | struct inode_security_struct *isec; | ||
3374 | isec = inode->i_security; | ||
3375 | sock_sid = isec->sid; | ||
3376 | sock_class = isec->sclass; | ||
3377 | } | ||
3378 | } | ||
3379 | read_unlock_bh(&sk->sk_callback_lock); | ||
3380 | if (!sock_sid) | ||
3381 | goto out; | ||
3363 | 3382 | ||
3364 | if (!skb->dev) | 3383 | if (!skb->dev) |
3365 | goto out; | 3384 | goto out; |
@@ -3419,12 +3438,10 @@ out: | |||
3419 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | 3438 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) |
3420 | { | 3439 | { |
3421 | u16 family; | 3440 | u16 family; |
3422 | u16 sock_class = 0; | ||
3423 | char *addrp; | 3441 | char *addrp; |
3424 | int len, err = 0; | 3442 | int len, err = 0; |
3425 | u32 sock_sid = 0; | ||
3426 | struct socket *sock; | ||
3427 | struct avc_audit_data ad; | 3443 | struct avc_audit_data ad; |
3444 | struct sk_security_struct *sksec = sk->sk_security; | ||
3428 | 3445 | ||
3429 | family = sk->sk_family; | 3446 | family = sk->sk_family; |
3430 | if (family != PF_INET && family != PF_INET6) | 3447 | if (family != PF_INET && family != PF_INET6) |
@@ -3434,22 +3451,6 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
3434 | if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP)) | 3451 | if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP)) |
3435 | family = PF_INET; | 3452 | family = PF_INET; |
3436 | 3453 | ||
3437 | read_lock_bh(&sk->sk_callback_lock); | ||
3438 | sock = sk->sk_socket; | ||
3439 | if (sock) { | ||
3440 | struct inode *inode; | ||
3441 | inode = SOCK_INODE(sock); | ||
3442 | if (inode) { | ||
3443 | struct inode_security_struct *isec; | ||
3444 | isec = inode->i_security; | ||
3445 | sock_sid = isec->sid; | ||
3446 | sock_class = isec->sclass; | ||
3447 | } | ||
3448 | } | ||
3449 | read_unlock_bh(&sk->sk_callback_lock); | ||
3450 | if (!sock_sid) | ||
3451 | goto out; | ||
3452 | |||
3453 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3454 | AVC_AUDIT_DATA_INIT(&ad, NET); |
3454 | ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]"; | 3455 | ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]"; |
3455 | ad.u.net.family = family; | 3456 | ad.u.net.family = family; |
@@ -3459,16 +3460,15 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
3459 | goto out; | 3460 | goto out; |
3460 | 3461 | ||
3461 | if (selinux_compat_net) | 3462 | if (selinux_compat_net) |
3462 | err = selinux_sock_rcv_skb_compat(sk, skb, &ad, sock_sid, | 3463 | err = selinux_sock_rcv_skb_compat(sk, skb, &ad, family, |
3463 | sock_class, family, | ||
3464 | addrp, len); | 3464 | addrp, len); |
3465 | else | 3465 | else |
3466 | err = avc_has_perm(sock_sid, skb->secmark, SECCLASS_PACKET, | 3466 | err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, |
3467 | PACKET__RECV, &ad); | 3467 | PACKET__RECV, &ad); |
3468 | if (err) | 3468 | if (err) |
3469 | goto out; | 3469 | goto out; |
3470 | 3470 | ||
3471 | err = selinux_xfrm_sock_rcv_skb(sock_sid, skb, &ad); | 3471 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); |
3472 | out: | 3472 | out: |
3473 | return err; | 3473 | return err; |
3474 | } | 3474 | } |
@@ -3572,6 +3572,49 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid) | |||
3572 | } | 3572 | } |
3573 | } | 3573 | } |
3574 | 3574 | ||
3575 | void selinux_sock_graft(struct sock* sk, struct socket *parent) | ||
3576 | { | ||
3577 | struct inode_security_struct *isec = SOCK_INODE(parent)->i_security; | ||
3578 | struct sk_security_struct *sksec = sk->sk_security; | ||
3579 | |||
3580 | isec->sid = sksec->sid; | ||
3581 | } | ||
3582 | |||
3583 | int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | ||
3584 | struct request_sock *req) | ||
3585 | { | ||
3586 | struct sk_security_struct *sksec = sk->sk_security; | ||
3587 | int err; | ||
3588 | u32 newsid = 0; | ||
3589 | u32 peersid; | ||
3590 | |||
3591 | err = selinux_xfrm_decode_session(skb, &peersid, 0); | ||
3592 | BUG_ON(err); | ||
3593 | |||
3594 | err = security_sid_mls_copy(sksec->sid, peersid, &newsid); | ||
3595 | if (err) | ||
3596 | return err; | ||
3597 | |||
3598 | req->secid = newsid; | ||
3599 | return 0; | ||
3600 | } | ||
3601 | |||
3602 | void selinux_inet_csk_clone(struct sock *newsk, const struct request_sock *req) | ||
3603 | { | ||
3604 | struct sk_security_struct *newsksec = newsk->sk_security; | ||
3605 | |||
3606 | newsksec->sid = req->secid; | ||
3607 | /* NOTE: Ideally, we should also get the isec->sid for the | ||
3608 | new socket in sync, but we don't have the isec available yet. | ||
3609 | So we will wait until sock_graft to do it, by which | ||
3610 | time it will have been created and available. */ | ||
3611 | } | ||
3612 | |||
3613 | void selinux_req_classify_flow(const struct request_sock *req, struct flowi *fl) | ||
3614 | { | ||
3615 | fl->secid = req->secid; | ||
3616 | } | ||
3617 | |||
3575 | static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) | 3618 | static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) |
3576 | { | 3619 | { |
3577 | int err = 0; | 3620 | int err = 0; |
@@ -3611,12 +3654,24 @@ out: | |||
3611 | #ifdef CONFIG_NETFILTER | 3654 | #ifdef CONFIG_NETFILTER |
3612 | 3655 | ||
3613 | static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev, | 3656 | static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev, |
3614 | struct inode_security_struct *isec, | ||
3615 | struct avc_audit_data *ad, | 3657 | struct avc_audit_data *ad, |
3616 | u16 family, char *addrp, int len) | 3658 | u16 family, char *addrp, int len) |
3617 | { | 3659 | { |
3618 | int err; | 3660 | int err = 0; |
3619 | u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; | 3661 | u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; |
3662 | struct socket *sock; | ||
3663 | struct inode *inode; | ||
3664 | struct inode_security_struct *isec; | ||
3665 | |||
3666 | sock = sk->sk_socket; | ||
3667 | if (!sock) | ||
3668 | goto out; | ||
3669 | |||
3670 | inode = SOCK_INODE(sock); | ||
3671 | if (!inode) | ||
3672 | goto out; | ||
3673 | |||
3674 | isec = inode->i_security; | ||
3620 | 3675 | ||
3621 | err = sel_netif_sids(dev, &if_sid, NULL); | 3676 | err = sel_netif_sids(dev, &if_sid, NULL); |
3622 | if (err) | 3677 | if (err) |
@@ -3681,26 +3736,16 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | |||
3681 | char *addrp; | 3736 | char *addrp; |
3682 | int len, err = 0; | 3737 | int len, err = 0; |
3683 | struct sock *sk; | 3738 | struct sock *sk; |
3684 | struct socket *sock; | ||
3685 | struct inode *inode; | ||
3686 | struct sk_buff *skb = *pskb; | 3739 | struct sk_buff *skb = *pskb; |
3687 | struct inode_security_struct *isec; | ||
3688 | struct avc_audit_data ad; | 3740 | struct avc_audit_data ad; |
3689 | struct net_device *dev = (struct net_device *)out; | 3741 | struct net_device *dev = (struct net_device *)out; |
3742 | struct sk_security_struct *sksec; | ||
3690 | 3743 | ||
3691 | sk = skb->sk; | 3744 | sk = skb->sk; |
3692 | if (!sk) | 3745 | if (!sk) |
3693 | goto out; | 3746 | goto out; |
3694 | 3747 | ||
3695 | sock = sk->sk_socket; | 3748 | sksec = sk->sk_security; |
3696 | if (!sock) | ||
3697 | goto out; | ||
3698 | |||
3699 | inode = SOCK_INODE(sock); | ||
3700 | if (!inode) | ||
3701 | goto out; | ||
3702 | |||
3703 | isec = inode->i_security; | ||
3704 | 3749 | ||
3705 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3750 | AVC_AUDIT_DATA_INIT(&ad, NET); |
3706 | ad.u.net.netif = dev->name; | 3751 | ad.u.net.netif = dev->name; |
@@ -3711,16 +3756,16 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | |||
3711 | goto out; | 3756 | goto out; |
3712 | 3757 | ||
3713 | if (selinux_compat_net) | 3758 | if (selinux_compat_net) |
3714 | err = selinux_ip_postroute_last_compat(sk, dev, isec, &ad, | 3759 | err = selinux_ip_postroute_last_compat(sk, dev, &ad, |
3715 | family, addrp, len); | 3760 | family, addrp, len); |
3716 | else | 3761 | else |
3717 | err = avc_has_perm(isec->sid, skb->secmark, SECCLASS_PACKET, | 3762 | err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, |
3718 | PACKET__SEND, &ad); | 3763 | PACKET__SEND, &ad); |
3719 | 3764 | ||
3720 | if (err) | 3765 | if (err) |
3721 | goto out; | 3766 | goto out; |
3722 | 3767 | ||
3723 | err = selinux_xfrm_postroute_last(isec->sid, skb, &ad); | 3768 | err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad); |
3724 | out: | 3769 | out: |
3725 | return err ? NF_DROP : NF_ACCEPT; | 3770 | return err ? NF_DROP : NF_ACCEPT; |
3726 | } | 3771 | } |
@@ -4623,6 +4668,10 @@ static struct security_operations selinux_ops = { | |||
4623 | .sk_free_security = selinux_sk_free_security, | 4668 | .sk_free_security = selinux_sk_free_security, |
4624 | .sk_clone_security = selinux_sk_clone_security, | 4669 | .sk_clone_security = selinux_sk_clone_security, |
4625 | .sk_getsecid = selinux_sk_getsecid, | 4670 | .sk_getsecid = selinux_sk_getsecid, |
4671 | .sock_graft = selinux_sock_graft, | ||
4672 | .inet_conn_request = selinux_inet_conn_request, | ||
4673 | .inet_csk_clone = selinux_inet_csk_clone, | ||
4674 | .req_classify_flow = selinux_req_classify_flow, | ||
4626 | 4675 | ||
4627 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 4676 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
4628 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, | 4677 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, |