diff options
Diffstat (limited to 'security/selinux/hooks.c')
| -rw-r--r-- | security/selinux/hooks.c | 246 |
1 files changed, 137 insertions, 109 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 90b4cdc0c948..54adc9d31e92 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -80,6 +80,7 @@ | |||
| 80 | 80 | ||
| 81 | extern unsigned int policydb_loaded_version; | 81 | extern unsigned int policydb_loaded_version; |
| 82 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); | 82 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); |
| 83 | extern int selinux_compat_net; | ||
| 83 | 84 | ||
| 84 | #ifdef CONFIG_SECURITY_SELINUX_DEVELOP | 85 | #ifdef CONFIG_SECURITY_SELINUX_DEVELOP |
| 85 | int selinux_enforcing = 0; | 86 | int selinux_enforcing = 0; |
| @@ -696,6 +697,8 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc | |||
| 696 | return SECCLASS_PACKET_SOCKET; | 697 | return SECCLASS_PACKET_SOCKET; |
| 697 | case PF_KEY: | 698 | case PF_KEY: |
| 698 | return SECCLASS_KEY_SOCKET; | 699 | return SECCLASS_KEY_SOCKET; |
| 700 | case PF_APPLETALK: | ||
| 701 | return SECCLASS_APPLETALK_SOCKET; | ||
| 699 | } | 702 | } |
| 700 | 703 | ||
| 701 | return SECCLASS_SOCKET; | 704 | return SECCLASS_SOCKET; |
| @@ -3214,47 +3217,17 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
| 3214 | return 0; | 3217 | return 0; |
| 3215 | } | 3218 | } |
| 3216 | 3219 | ||
| 3217 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | 3220 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
| 3221 | struct avc_audit_data *ad, u32 sock_sid, u16 sock_class, | ||
| 3222 | u16 family, char *addrp, int len) | ||
| 3218 | { | 3223 | { |
| 3219 | u16 family; | 3224 | int err = 0; |
| 3220 | char *addrp; | ||
| 3221 | int len, err = 0; | ||
| 3222 | u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; | 3225 | u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; |
| 3223 | u32 sock_sid = 0; | ||
| 3224 | u16 sock_class = 0; | ||
| 3225 | struct socket *sock; | ||
| 3226 | struct net_device *dev; | ||
| 3227 | struct avc_audit_data ad; | ||
| 3228 | |||
| 3229 | family = sk->sk_family; | ||
| 3230 | if (family != PF_INET && family != PF_INET6) | ||
| 3231 | goto out; | ||
| 3232 | |||
| 3233 | /* Handle mapped IPv4 packets arriving via IPv6 sockets */ | ||
| 3234 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | ||
| 3235 | family = PF_INET; | ||
| 3236 | |||
| 3237 | read_lock_bh(&sk->sk_callback_lock); | ||
| 3238 | sock = sk->sk_socket; | ||
| 3239 | if (sock) { | ||
| 3240 | struct inode *inode; | ||
| 3241 | inode = SOCK_INODE(sock); | ||
| 3242 | if (inode) { | ||
| 3243 | struct inode_security_struct *isec; | ||
| 3244 | isec = inode->i_security; | ||
| 3245 | sock_sid = isec->sid; | ||
| 3246 | sock_class = isec->sclass; | ||
| 3247 | } | ||
| 3248 | } | ||
| 3249 | read_unlock_bh(&sk->sk_callback_lock); | ||
| 3250 | if (!sock_sid) | ||
| 3251 | goto out; | ||
| 3252 | 3226 | ||
| 3253 | dev = skb->dev; | 3227 | if (!skb->dev) |
| 3254 | if (!dev) | ||
| 3255 | goto out; | 3228 | goto out; |
| 3256 | 3229 | ||
| 3257 | err = sel_netif_sids(dev, &if_sid, NULL); | 3230 | err = sel_netif_sids(skb->dev, &if_sid, NULL); |
| 3258 | if (err) | 3231 | if (err) |
| 3259 | goto out; | 3232 | goto out; |
| 3260 | 3233 | ||
| @@ -3277,44 +3250,88 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 3277 | break; | 3250 | break; |
| 3278 | } | 3251 | } |
| 3279 | 3252 | ||
| 3280 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3253 | err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); |
| 3281 | ad.u.net.netif = dev->name; | ||
| 3282 | ad.u.net.family = family; | ||
| 3283 | |||
| 3284 | err = selinux_parse_skb(skb, &ad, &addrp, &len, 1); | ||
| 3285 | if (err) | ||
| 3286 | goto out; | ||
| 3287 | |||
| 3288 | err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, &ad); | ||
| 3289 | if (err) | 3254 | if (err) |
| 3290 | goto out; | 3255 | goto out; |
| 3291 | 3256 | ||
| 3292 | /* Fixme: this lookup is inefficient */ | ||
| 3293 | err = security_node_sid(family, addrp, len, &node_sid); | 3257 | err = security_node_sid(family, addrp, len, &node_sid); |
| 3294 | if (err) | 3258 | if (err) |
| 3295 | goto out; | 3259 | goto out; |
| 3296 | 3260 | ||
| 3297 | err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, &ad); | 3261 | err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, ad); |
| 3298 | if (err) | 3262 | if (err) |
| 3299 | goto out; | 3263 | goto out; |
| 3300 | 3264 | ||
| 3301 | if (recv_perm) { | 3265 | if (recv_perm) { |
| 3302 | u32 port_sid; | 3266 | u32 port_sid; |
| 3303 | 3267 | ||
| 3304 | /* Fixme: make this more efficient */ | ||
| 3305 | err = security_port_sid(sk->sk_family, sk->sk_type, | 3268 | err = security_port_sid(sk->sk_family, sk->sk_type, |
| 3306 | sk->sk_protocol, ntohs(ad.u.net.sport), | 3269 | sk->sk_protocol, ntohs(ad->u.net.sport), |
| 3307 | &port_sid); | 3270 | &port_sid); |
| 3308 | if (err) | 3271 | if (err) |
| 3309 | goto out; | 3272 | goto out; |
| 3310 | 3273 | ||
| 3311 | err = avc_has_perm(sock_sid, port_sid, | 3274 | err = avc_has_perm(sock_sid, port_sid, |
| 3312 | sock_class, recv_perm, &ad); | 3275 | sock_class, recv_perm, ad); |
| 3313 | } | 3276 | } |
| 3314 | 3277 | ||
| 3315 | if (!err) | 3278 | out: |
| 3316 | err = selinux_xfrm_sock_rcv_skb(sock_sid, skb); | 3279 | return err; |
| 3280 | } | ||
| 3281 | |||
| 3282 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | ||
| 3283 | { | ||
| 3284 | u16 family; | ||
| 3285 | u16 sock_class = 0; | ||
| 3286 | char *addrp; | ||
| 3287 | int len, err = 0; | ||
| 3288 | u32 sock_sid = 0; | ||
| 3289 | struct socket *sock; | ||
| 3290 | struct avc_audit_data ad; | ||
| 3291 | |||
| 3292 | family = sk->sk_family; | ||
| 3293 | if (family != PF_INET && family != PF_INET6) | ||
| 3294 | goto out; | ||
| 3295 | |||
| 3296 | /* Handle mapped IPv4 packets arriving via IPv6 sockets */ | ||
| 3297 | if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP)) | ||
| 3298 | family = PF_INET; | ||
| 3299 | |||
| 3300 | read_lock_bh(&sk->sk_callback_lock); | ||
| 3301 | sock = sk->sk_socket; | ||
| 3302 | if (sock) { | ||
| 3303 | struct inode *inode; | ||
| 3304 | inode = SOCK_INODE(sock); | ||
| 3305 | if (inode) { | ||
| 3306 | struct inode_security_struct *isec; | ||
| 3307 | isec = inode->i_security; | ||
| 3308 | sock_sid = isec->sid; | ||
| 3309 | sock_class = isec->sclass; | ||
| 3310 | } | ||
| 3311 | } | ||
| 3312 | read_unlock_bh(&sk->sk_callback_lock); | ||
| 3313 | if (!sock_sid) | ||
| 3314 | goto out; | ||
| 3315 | |||
| 3316 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
| 3317 | ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]"; | ||
| 3318 | ad.u.net.family = family; | ||
| 3319 | |||
| 3320 | err = selinux_parse_skb(skb, &ad, &addrp, &len, 1); | ||
| 3321 | if (err) | ||
| 3322 | goto out; | ||
| 3323 | |||
| 3324 | if (selinux_compat_net) | ||
| 3325 | err = selinux_sock_rcv_skb_compat(sk, skb, &ad, sock_sid, | ||
| 3326 | sock_class, family, | ||
| 3327 | addrp, len); | ||
| 3328 | else | ||
| 3329 | err = avc_has_perm(sock_sid, skb->secmark, SECCLASS_PACKET, | ||
| 3330 | PACKET__RECV, &ad); | ||
| 3331 | if (err) | ||
| 3332 | goto out; | ||
| 3317 | 3333 | ||
| 3334 | err = selinux_xfrm_sock_rcv_skb(sock_sid, skb); | ||
| 3318 | out: | 3335 | out: |
| 3319 | return err; | 3336 | return err; |
| 3320 | } | 3337 | } |
| @@ -3454,42 +3471,18 @@ out: | |||
| 3454 | 3471 | ||
| 3455 | #ifdef CONFIG_NETFILTER | 3472 | #ifdef CONFIG_NETFILTER |
| 3456 | 3473 | ||
| 3457 | static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | 3474 | static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev, |
| 3458 | struct sk_buff **pskb, | 3475 | struct inode_security_struct *isec, |
| 3459 | const struct net_device *in, | 3476 | struct avc_audit_data *ad, |
| 3460 | const struct net_device *out, | 3477 | u16 family, char *addrp, int len) |
| 3461 | int (*okfn)(struct sk_buff *), | ||
| 3462 | u16 family) | ||
| 3463 | { | 3478 | { |
| 3464 | char *addrp; | 3479 | int err; |
| 3465 | int len, err = NF_ACCEPT; | ||
| 3466 | u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; | 3480 | u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; |
| 3467 | struct sock *sk; | ||
| 3468 | struct socket *sock; | ||
| 3469 | struct inode *inode; | ||
| 3470 | struct sk_buff *skb = *pskb; | ||
| 3471 | struct inode_security_struct *isec; | ||
| 3472 | struct avc_audit_data ad; | ||
| 3473 | struct net_device *dev = (struct net_device *)out; | ||
| 3474 | 3481 | ||
| 3475 | sk = skb->sk; | ||
| 3476 | if (!sk) | ||
| 3477 | goto out; | ||
| 3478 | |||
| 3479 | sock = sk->sk_socket; | ||
| 3480 | if (!sock) | ||
| 3481 | goto out; | ||
| 3482 | |||
| 3483 | inode = SOCK_INODE(sock); | ||
| 3484 | if (!inode) | ||
| 3485 | goto out; | ||
| 3486 | |||
| 3487 | err = sel_netif_sids(dev, &if_sid, NULL); | 3482 | err = sel_netif_sids(dev, &if_sid, NULL); |
| 3488 | if (err) | 3483 | if (err) |
| 3489 | goto out; | 3484 | goto out; |
| 3490 | 3485 | ||
| 3491 | isec = inode->i_security; | ||
| 3492 | |||
| 3493 | switch (isec->sclass) { | 3486 | switch (isec->sclass) { |
| 3494 | case SECCLASS_UDP_SOCKET: | 3487 | case SECCLASS_UDP_SOCKET: |
| 3495 | netif_perm = NETIF__UDP_SEND; | 3488 | netif_perm = NETIF__UDP_SEND; |
| @@ -3509,55 +3502,88 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | |||
| 3509 | break; | 3502 | break; |
| 3510 | } | 3503 | } |
| 3511 | 3504 | ||
| 3512 | 3505 | err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | |
| 3513 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3506 | if (err) |
| 3514 | ad.u.net.netif = dev->name; | ||
| 3515 | ad.u.net.family = family; | ||
| 3516 | |||
| 3517 | err = selinux_parse_skb(skb, &ad, &addrp, | ||
| 3518 | &len, 0) ? NF_DROP : NF_ACCEPT; | ||
| 3519 | if (err != NF_ACCEPT) | ||
| 3520 | goto out; | ||
| 3521 | |||
| 3522 | err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, | ||
| 3523 | netif_perm, &ad) ? NF_DROP : NF_ACCEPT; | ||
| 3524 | if (err != NF_ACCEPT) | ||
| 3525 | goto out; | 3507 | goto out; |
| 3526 | 3508 | ||
| 3527 | /* Fixme: this lookup is inefficient */ | 3509 | err = security_node_sid(family, addrp, len, &node_sid); |
| 3528 | err = security_node_sid(family, addrp, len, | 3510 | if (err) |
| 3529 | &node_sid) ? NF_DROP : NF_ACCEPT; | ||
| 3530 | if (err != NF_ACCEPT) | ||
| 3531 | goto out; | 3511 | goto out; |
| 3532 | 3512 | ||
| 3533 | err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, | 3513 | err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, ad); |
| 3534 | node_perm, &ad) ? NF_DROP : NF_ACCEPT; | 3514 | if (err) |
| 3535 | if (err != NF_ACCEPT) | ||
| 3536 | goto out; | 3515 | goto out; |
| 3537 | 3516 | ||
| 3538 | if (send_perm) { | 3517 | if (send_perm) { |
| 3539 | u32 port_sid; | 3518 | u32 port_sid; |
| 3540 | 3519 | ||
| 3541 | /* Fixme: make this more efficient */ | ||
| 3542 | err = security_port_sid(sk->sk_family, | 3520 | err = security_port_sid(sk->sk_family, |
| 3543 | sk->sk_type, | 3521 | sk->sk_type, |
| 3544 | sk->sk_protocol, | 3522 | sk->sk_protocol, |
| 3545 | ntohs(ad.u.net.dport), | 3523 | ntohs(ad->u.net.dport), |
| 3546 | &port_sid) ? NF_DROP : NF_ACCEPT; | 3524 | &port_sid); |
| 3547 | if (err != NF_ACCEPT) | 3525 | if (err) |
| 3548 | goto out; | 3526 | goto out; |
| 3549 | 3527 | ||
| 3550 | err = avc_has_perm(isec->sid, port_sid, isec->sclass, | 3528 | err = avc_has_perm(isec->sid, port_sid, isec->sclass, |
| 3551 | send_perm, &ad) ? NF_DROP : NF_ACCEPT; | 3529 | send_perm, ad); |
| 3552 | } | 3530 | } |
| 3531 | out: | ||
| 3532 | return err; | ||
| 3533 | } | ||
| 3534 | |||
| 3535 | static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | ||
| 3536 | struct sk_buff **pskb, | ||
| 3537 | const struct net_device *in, | ||
| 3538 | const struct net_device *out, | ||
| 3539 | int (*okfn)(struct sk_buff *), | ||
| 3540 | u16 family) | ||
| 3541 | { | ||
| 3542 | char *addrp; | ||
| 3543 | int len, err = 0; | ||
| 3544 | struct sock *sk; | ||
| 3545 | struct socket *sock; | ||
| 3546 | struct inode *inode; | ||
| 3547 | struct sk_buff *skb = *pskb; | ||
| 3548 | struct inode_security_struct *isec; | ||
| 3549 | struct avc_audit_data ad; | ||
| 3550 | struct net_device *dev = (struct net_device *)out; | ||
| 3553 | 3551 | ||
| 3554 | if (err != NF_ACCEPT) | 3552 | sk = skb->sk; |
| 3553 | if (!sk) | ||
| 3555 | goto out; | 3554 | goto out; |
| 3556 | 3555 | ||
| 3557 | err = selinux_xfrm_postroute_last(isec->sid, skb); | 3556 | sock = sk->sk_socket; |
| 3557 | if (!sock) | ||
| 3558 | goto out; | ||
| 3559 | |||
| 3560 | inode = SOCK_INODE(sock); | ||
| 3561 | if (!inode) | ||
| 3562 | goto out; | ||
| 3563 | |||
| 3564 | isec = inode->i_security; | ||
| 3565 | |||
| 3566 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
| 3567 | ad.u.net.netif = dev->name; | ||
| 3568 | ad.u.net.family = family; | ||
| 3569 | |||
| 3570 | err = selinux_parse_skb(skb, &ad, &addrp, &len, 0); | ||
| 3571 | if (err) | ||
| 3572 | goto out; | ||
| 3573 | |||
| 3574 | if (selinux_compat_net) | ||
| 3575 | err = selinux_ip_postroute_last_compat(sk, dev, isec, &ad, | ||
| 3576 | family, addrp, len); | ||
| 3577 | else | ||
| 3578 | err = avc_has_perm(isec->sid, skb->secmark, SECCLASS_PACKET, | ||
| 3579 | PACKET__SEND, &ad); | ||
| 3558 | 3580 | ||
| 3581 | if (err) | ||
| 3582 | goto out; | ||
| 3583 | |||
| 3584 | err = selinux_xfrm_postroute_last(isec->sid, skb); | ||
| 3559 | out: | 3585 | out: |
| 3560 | return err; | 3586 | return err ? NF_DROP : NF_ACCEPT; |
| 3561 | } | 3587 | } |
| 3562 | 3588 | ||
| 3563 | static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum, | 3589 | static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum, |
| @@ -4374,8 +4400,10 @@ static struct security_operations selinux_ops = { | |||
| 4374 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, | 4400 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, |
| 4375 | .xfrm_policy_clone_security = selinux_xfrm_policy_clone, | 4401 | .xfrm_policy_clone_security = selinux_xfrm_policy_clone, |
| 4376 | .xfrm_policy_free_security = selinux_xfrm_policy_free, | 4402 | .xfrm_policy_free_security = selinux_xfrm_policy_free, |
| 4403 | .xfrm_policy_delete_security = selinux_xfrm_policy_delete, | ||
| 4377 | .xfrm_state_alloc_security = selinux_xfrm_state_alloc, | 4404 | .xfrm_state_alloc_security = selinux_xfrm_state_alloc, |
| 4378 | .xfrm_state_free_security = selinux_xfrm_state_free, | 4405 | .xfrm_state_free_security = selinux_xfrm_state_free, |
| 4406 | .xfrm_state_delete_security = selinux_xfrm_state_delete, | ||
| 4379 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, | 4407 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, |
| 4380 | #endif | 4408 | #endif |
| 4381 | }; | 4409 | }; |
