aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/hooks.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r--security/selinux/hooks.c246
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
81extern unsigned int policydb_loaded_version; 81extern unsigned int policydb_loaded_version;
82extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); 82extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
83extern int selinux_compat_net;
83 84
84#ifdef CONFIG_SECURITY_SELINUX_DEVELOP 85#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
85int selinux_enforcing = 0; 86int 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
3217static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) 3220static 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) 3278out:
3316 err = selinux_xfrm_sock_rcv_skb(sock_sid, skb); 3279 return err;
3280}
3281
3282static 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);
3318out: 3335out:
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
3457static unsigned int selinux_ip_postroute_last(unsigned int hooknum, 3474static 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 }
3531out:
3532 return err;
3533}
3534
3535static 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);
3559out: 3585out:
3560 return err; 3586 return err ? NF_DROP : NF_ACCEPT;
3561} 3587}
3562 3588
3563static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum, 3589static 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};