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.c242
1 files changed, 133 insertions, 109 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 41b6f5d31945..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;
@@ -3216,47 +3217,17 @@ static int selinux_socket_unix_may_send(struct socket *sock,
3216 return 0; 3217 return 0;
3217} 3218}
3218 3219
3219static 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)
3220{ 3223{
3221 u16 family; 3224 int err = 0;
3222 char *addrp;
3223 int len, err = 0;
3224 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;
3225 u32 sock_sid = 0;
3226 u16 sock_class = 0;
3227 struct socket *sock;
3228 struct net_device *dev;
3229 struct avc_audit_data ad;
3230
3231 family = sk->sk_family;
3232 if (family != PF_INET && family != PF_INET6)
3233 goto out;
3234
3235 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
3236 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
3237 family = PF_INET;
3238
3239 read_lock_bh(&sk->sk_callback_lock);
3240 sock = sk->sk_socket;
3241 if (sock) {
3242 struct inode *inode;
3243 inode = SOCK_INODE(sock);
3244 if (inode) {
3245 struct inode_security_struct *isec;
3246 isec = inode->i_security;
3247 sock_sid = isec->sid;
3248 sock_class = isec->sclass;
3249 }
3250 }
3251 read_unlock_bh(&sk->sk_callback_lock);
3252 if (!sock_sid)
3253 goto out;
3254 3226
3255 dev = skb->dev; 3227 if (!skb->dev)
3256 if (!dev)
3257 goto out; 3228 goto out;
3258 3229
3259 err = sel_netif_sids(dev, &if_sid, NULL); 3230 err = sel_netif_sids(skb->dev, &if_sid, NULL);
3260 if (err) 3231 if (err)
3261 goto out; 3232 goto out;
3262 3233
@@ -3279,44 +3250,88 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
3279 break; 3250 break;
3280 } 3251 }
3281 3252
3282 AVC_AUDIT_DATA_INIT(&ad, NET); 3253 err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
3283 ad.u.net.netif = dev->name;
3284 ad.u.net.family = family;
3285
3286 err = selinux_parse_skb(skb, &ad, &addrp, &len, 1);
3287 if (err)
3288 goto out;
3289
3290 err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, &ad);
3291 if (err) 3254 if (err)
3292 goto out; 3255 goto out;
3293 3256
3294 /* Fixme: this lookup is inefficient */
3295 err = security_node_sid(family, addrp, len, &node_sid); 3257 err = security_node_sid(family, addrp, len, &node_sid);
3296 if (err) 3258 if (err)
3297 goto out; 3259 goto out;
3298 3260
3299 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);
3300 if (err) 3262 if (err)
3301 goto out; 3263 goto out;
3302 3264
3303 if (recv_perm) { 3265 if (recv_perm) {
3304 u32 port_sid; 3266 u32 port_sid;
3305 3267
3306 /* Fixme: make this more efficient */
3307 err = security_port_sid(sk->sk_family, sk->sk_type, 3268 err = security_port_sid(sk->sk_family, sk->sk_type,
3308 sk->sk_protocol, ntohs(ad.u.net.sport), 3269 sk->sk_protocol, ntohs(ad->u.net.sport),
3309 &port_sid); 3270 &port_sid);
3310 if (err) 3271 if (err)
3311 goto out; 3272 goto out;
3312 3273
3313 err = avc_has_perm(sock_sid, port_sid, 3274 err = avc_has_perm(sock_sid, port_sid,
3314 sock_class, recv_perm, &ad); 3275 sock_class, recv_perm, ad);
3315 } 3276 }
3316 3277
3317 if (!err) 3278out:
3318 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;
3319 3333
3334 err = selinux_xfrm_sock_rcv_skb(sock_sid, skb);
3320out: 3335out:
3321 return err; 3336 return err;
3322} 3337}
@@ -3456,42 +3471,18 @@ out:
3456 3471
3457#ifdef CONFIG_NETFILTER 3472#ifdef CONFIG_NETFILTER
3458 3473
3459static unsigned int selinux_ip_postroute_last(unsigned int hooknum, 3474static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev,
3460 struct sk_buff **pskb, 3475 struct inode_security_struct *isec,
3461 const struct net_device *in, 3476 struct avc_audit_data *ad,
3462 const struct net_device *out, 3477 u16 family, char *addrp, int len)
3463 int (*okfn)(struct sk_buff *),
3464 u16 family)
3465{ 3478{
3466 char *addrp; 3479 int err;
3467 int len, err = NF_ACCEPT;
3468 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;
3469 struct sock *sk;
3470 struct socket *sock;
3471 struct inode *inode;
3472 struct sk_buff *skb = *pskb;
3473 struct inode_security_struct *isec;
3474 struct avc_audit_data ad;
3475 struct net_device *dev = (struct net_device *)out;
3476 3481
3477 sk = skb->sk;
3478 if (!sk)
3479 goto out;
3480
3481 sock = sk->sk_socket;
3482 if (!sock)
3483 goto out;
3484
3485 inode = SOCK_INODE(sock);
3486 if (!inode)
3487 goto out;
3488
3489 err = sel_netif_sids(dev, &if_sid, NULL); 3482 err = sel_netif_sids(dev, &if_sid, NULL);
3490 if (err) 3483 if (err)
3491 goto out; 3484 goto out;
3492 3485
3493 isec = inode->i_security;
3494
3495 switch (isec->sclass) { 3486 switch (isec->sclass) {
3496 case SECCLASS_UDP_SOCKET: 3487 case SECCLASS_UDP_SOCKET:
3497 netif_perm = NETIF__UDP_SEND; 3488 netif_perm = NETIF__UDP_SEND;
@@ -3511,55 +3502,88 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
3511 break; 3502 break;
3512 } 3503 }
3513 3504
3514 3505 err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
3515 AVC_AUDIT_DATA_INIT(&ad, NET); 3506 if (err)
3516 ad.u.net.netif = dev->name;
3517 ad.u.net.family = family;
3518
3519 err = selinux_parse_skb(skb, &ad, &addrp,
3520 &len, 0) ? NF_DROP : NF_ACCEPT;
3521 if (err != NF_ACCEPT)
3522 goto out;
3523
3524 err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF,
3525 netif_perm, &ad) ? NF_DROP : NF_ACCEPT;
3526 if (err != NF_ACCEPT)
3527 goto out; 3507 goto out;
3528 3508
3529 /* Fixme: this lookup is inefficient */ 3509 err = security_node_sid(family, addrp, len, &node_sid);
3530 err = security_node_sid(family, addrp, len, 3510 if (err)
3531 &node_sid) ? NF_DROP : NF_ACCEPT;
3532 if (err != NF_ACCEPT)
3533 goto out; 3511 goto out;
3534 3512
3535 err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, 3513 err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, ad);
3536 node_perm, &ad) ? NF_DROP : NF_ACCEPT; 3514 if (err)
3537 if (err != NF_ACCEPT)
3538 goto out; 3515 goto out;
3539 3516
3540 if (send_perm) { 3517 if (send_perm) {
3541 u32 port_sid; 3518 u32 port_sid;
3542 3519
3543 /* Fixme: make this more efficient */
3544 err = security_port_sid(sk->sk_family, 3520 err = security_port_sid(sk->sk_family,
3545 sk->sk_type, 3521 sk->sk_type,
3546 sk->sk_protocol, 3522 sk->sk_protocol,
3547 ntohs(ad.u.net.dport), 3523 ntohs(ad->u.net.dport),
3548 &port_sid) ? NF_DROP : NF_ACCEPT; 3524 &port_sid);
3549 if (err != NF_ACCEPT) 3525 if (err)
3550 goto out; 3526 goto out;
3551 3527
3552 err = avc_has_perm(isec->sid, port_sid, isec->sclass, 3528 err = avc_has_perm(isec->sid, port_sid, isec->sclass,
3553 send_perm, &ad) ? NF_DROP : NF_ACCEPT; 3529 send_perm, ad);
3554 } 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;
3555 3551
3556 if (err != NF_ACCEPT) 3552 sk = skb->sk;
3553 if (!sk)
3557 goto out; 3554 goto out;
3558 3555
3559 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);
3560 3580
3581 if (err)
3582 goto out;
3583
3584 err = selinux_xfrm_postroute_last(isec->sid, skb);
3561out: 3585out:
3562 return err; 3586 return err ? NF_DROP : NF_ACCEPT;
3563} 3587}
3564 3588
3565static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum, 3589static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum,