aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/hooks.c
diff options
context:
space:
mode:
authorJames Morris <jmorris@namei.org>2006-06-09 03:33:33 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-06-18 00:30:05 -0400
commit4e5ab4cb85683cf77b507ba0c4d48871e1562305 (patch)
treeaef7ba8b6050fcaccbaf0d05f8e5ba860a143eaf /security/selinux/hooks.c
parent100468e9c05c10fb6872751c1af523b996d6afa9 (diff)
[SECMARK]: Add new packet controls to SELinux
Add new per-packet access controls to SELinux, replacing the old packet controls. Packets are labeled with the iptables SECMARK and CONNSECMARK targets, then security policy for the packets is enforced with these controls. To allow for a smooth transition to the new controls, the old code is still present, but not active by default. To restore previous behavior, the old controls may be activated at runtime by writing a '1' to /selinux/compat_net, and also via the kernel boot parameter selinux_compat_net. Switching between the network control models requires the security load_policy permission. The old controls will probably eventually be removed and any continued use is discouraged. With this patch, the new secmark controls for SElinux are disabled by default, so existing behavior is entirely preserved, and the user is not affected at all. It also provides a config option to enable the secmark controls by default (which can always be overridden at boot and runtime). It is also noted in the kconfig help that the user will need updated userspace if enabling secmark controls for SELinux and that they'll probably need the SECMARK and CONNMARK targets, and conntrack protocol helpers, although such decisions are beyond the scope of kernel configuration. Signed-off-by: James Morris <jmorris@namei.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: David S. Miller <davem@davemloft.net>
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,