diff options
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, |