diff options
author | Paul Moore <paul.moore@hp.com> | 2008-01-29 08:49:27 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-01-29 16:17:30 -0500 |
commit | effad8df44261031a882e1a895415f7186a5098e (patch) | |
tree | 42c04b3247ede13077546e13f82fe3da83ce7b90 | |
parent | 13541b3adad2dc2f56761c5193c2b88db3597f0e (diff) |
SELinux: Add network ingress and egress control permission checks
This patch implements packet ingress/egress controls for SELinux which allow
SELinux security policy to control the flow of all IPv4 and IPv6 packets into
and out of the system. Currently SELinux does not have proper control over
forwarded packets and this patch corrects this problem.
Special thanks to Venkat Yekkirala <vyekkirala@trustedcs.com> whose earlier
work on this topic eventually led to this patch.
Signed-off-by: Paul Moore <paul.moore@hp.com>
Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r-- | security/selinux/hooks.c | 402 |
1 files changed, 280 insertions, 122 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c90e865a8603..b3c064744d32 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -12,8 +12,8 @@ | |||
12 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> | 12 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> |
13 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. | 13 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. |
14 | * <dgoeddel@trustedcs.com> | 14 | * <dgoeddel@trustedcs.com> |
15 | * Copyright (C) 2006 Hewlett-Packard Development Company, L.P. | 15 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. |
16 | * Paul Moore, <paul.moore@hp.com> | 16 | * Paul Moore <paul.moore@hp.com> |
17 | * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. | 17 | * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. |
18 | * Yuichi Nakamura <ynakam@hitachisoft.jp> | 18 | * Yuichi Nakamura <ynakam@hitachisoft.jp> |
19 | * | 19 | * |
@@ -3845,6 +3845,29 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
3845 | return 0; | 3845 | return 0; |
3846 | } | 3846 | } |
3847 | 3847 | ||
3848 | static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, | ||
3849 | u32 peer_sid, | ||
3850 | struct avc_audit_data *ad) | ||
3851 | { | ||
3852 | int err; | ||
3853 | u32 if_sid; | ||
3854 | u32 node_sid; | ||
3855 | |||
3856 | err = sel_netif_sid(ifindex, &if_sid); | ||
3857 | if (err) | ||
3858 | return err; | ||
3859 | err = avc_has_perm(peer_sid, if_sid, | ||
3860 | SECCLASS_NETIF, NETIF__INGRESS, ad); | ||
3861 | if (err) | ||
3862 | return err; | ||
3863 | |||
3864 | err = sel_netnode_sid(addrp, family, &node_sid); | ||
3865 | if (err) | ||
3866 | return err; | ||
3867 | return avc_has_perm(peer_sid, node_sid, | ||
3868 | SECCLASS_NODE, NODE__RECVFROM, ad); | ||
3869 | } | ||
3870 | |||
3848 | static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, | 3871 | static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, |
3849 | struct sk_buff *skb, | 3872 | struct sk_buff *skb, |
3850 | struct avc_audit_data *ad, | 3873 | struct avc_audit_data *ad, |
@@ -3972,23 +3995,27 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
3972 | return selinux_sock_rcv_skb_compat(sk, skb, &ad, | 3995 | return selinux_sock_rcv_skb_compat(sk, skb, &ad, |
3973 | family, addrp); | 3996 | family, addrp); |
3974 | 3997 | ||
3975 | if (selinux_secmark_enabled()) { | ||
3976 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | ||
3977 | PACKET__RECV, &ad); | ||
3978 | if (err) | ||
3979 | return err; | ||
3980 | } | ||
3981 | |||
3982 | if (netlbl_enabled() || selinux_xfrm_enabled()) { | 3998 | if (netlbl_enabled() || selinux_xfrm_enabled()) { |
3983 | u32 peer_sid; | 3999 | u32 peer_sid; |
3984 | 4000 | ||
3985 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); | 4001 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); |
3986 | if (err) | 4002 | if (err) |
3987 | return err; | 4003 | return err; |
4004 | err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family, | ||
4005 | peer_sid, &ad); | ||
4006 | if (err) | ||
4007 | return err; | ||
3988 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, | 4008 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, |
3989 | PEER__RECV, &ad); | 4009 | PEER__RECV, &ad); |
3990 | } | 4010 | } |
3991 | 4011 | ||
4012 | if (selinux_secmark_enabled()) { | ||
4013 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | ||
4014 | PACKET__RECV, &ad); | ||
4015 | if (err) | ||
4016 | return err; | ||
4017 | } | ||
4018 | |||
3992 | return err; | 4019 | return err; |
3993 | } | 4020 | } |
3994 | 4021 | ||
@@ -4201,151 +4228,255 @@ out: | |||
4201 | 4228 | ||
4202 | #ifdef CONFIG_NETFILTER | 4229 | #ifdef CONFIG_NETFILTER |
4203 | 4230 | ||
4204 | static int selinux_ip_postroute_last_compat(struct sock *sk, | 4231 | static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, |
4205 | struct net_device *dev, | 4232 | u16 family) |
4206 | struct avc_audit_data *ad, | ||
4207 | u16 family, | ||
4208 | char *addrp) | ||
4209 | { | 4233 | { |
4210 | int err = 0; | 4234 | char *addrp; |
4211 | u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; | 4235 | u32 peer_sid; |
4212 | struct socket *sock; | 4236 | struct avc_audit_data ad; |
4213 | struct inode *inode; | 4237 | u8 secmark_active; |
4214 | struct inode_security_struct *isec; | 4238 | u8 peerlbl_active; |
4215 | 4239 | ||
4216 | sock = sk->sk_socket; | 4240 | if (!selinux_policycap_netpeer) |
4217 | if (!sock) | 4241 | return NF_ACCEPT; |
4218 | goto out; | ||
4219 | 4242 | ||
4220 | inode = SOCK_INODE(sock); | 4243 | secmark_active = selinux_secmark_enabled(); |
4221 | if (!inode) | 4244 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); |
4222 | goto out; | 4245 | if (!secmark_active && !peerlbl_active) |
4246 | return NF_ACCEPT; | ||
4223 | 4247 | ||
4224 | isec = inode->i_security; | 4248 | AVC_AUDIT_DATA_INIT(&ad, NET); |
4225 | 4249 | ad.u.net.netif = ifindex; | |
4226 | err = sel_netif_sid(dev->ifindex, &if_sid); | 4250 | ad.u.net.family = family; |
4227 | if (err) | 4251 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) |
4228 | goto out; | 4252 | return NF_DROP; |
4253 | |||
4254 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | ||
4255 | return NF_DROP; | ||
4256 | |||
4257 | if (peerlbl_active) | ||
4258 | if (selinux_inet_sys_rcv_skb(ifindex, addrp, family, | ||
4259 | peer_sid, &ad) != 0) | ||
4260 | return NF_DROP; | ||
4261 | |||
4262 | if (secmark_active) | ||
4263 | if (avc_has_perm(peer_sid, skb->secmark, | ||
4264 | SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) | ||
4265 | return NF_DROP; | ||
4266 | |||
4267 | return NF_ACCEPT; | ||
4268 | } | ||
4269 | |||
4270 | static unsigned int selinux_ipv4_forward(unsigned int hooknum, | ||
4271 | struct sk_buff *skb, | ||
4272 | const struct net_device *in, | ||
4273 | const struct net_device *out, | ||
4274 | int (*okfn)(struct sk_buff *)) | ||
4275 | { | ||
4276 | return selinux_ip_forward(skb, in->ifindex, PF_INET); | ||
4277 | } | ||
4278 | |||
4279 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
4280 | static unsigned int selinux_ipv6_forward(unsigned int hooknum, | ||
4281 | struct sk_buff *skb, | ||
4282 | const struct net_device *in, | ||
4283 | const struct net_device *out, | ||
4284 | int (*okfn)(struct sk_buff *)) | ||
4285 | { | ||
4286 | return selinux_ip_forward(skb, in->ifindex, PF_INET6); | ||
4287 | } | ||
4288 | #endif /* IPV6 */ | ||
4289 | |||
4290 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, | ||
4291 | int ifindex, | ||
4292 | struct avc_audit_data *ad, | ||
4293 | u16 family, char *addrp) | ||
4294 | { | ||
4295 | int err; | ||
4296 | struct sk_security_struct *sksec = sk->sk_security; | ||
4297 | u16 sk_class; | ||
4298 | u32 netif_perm, node_perm, send_perm; | ||
4299 | u32 port_sid, node_sid, if_sid, sk_sid; | ||
4300 | |||
4301 | sk_sid = sksec->sid; | ||
4302 | sk_class = sksec->sclass; | ||
4229 | 4303 | ||
4230 | switch (isec->sclass) { | 4304 | switch (sk_class) { |
4231 | case SECCLASS_UDP_SOCKET: | 4305 | case SECCLASS_UDP_SOCKET: |
4232 | netif_perm = NETIF__UDP_SEND; | 4306 | netif_perm = NETIF__UDP_SEND; |
4233 | node_perm = NODE__UDP_SEND; | 4307 | node_perm = NODE__UDP_SEND; |
4234 | send_perm = UDP_SOCKET__SEND_MSG; | 4308 | send_perm = UDP_SOCKET__SEND_MSG; |
4235 | break; | 4309 | break; |
4236 | |||
4237 | case SECCLASS_TCP_SOCKET: | 4310 | case SECCLASS_TCP_SOCKET: |
4238 | netif_perm = NETIF__TCP_SEND; | 4311 | netif_perm = NETIF__TCP_SEND; |
4239 | node_perm = NODE__TCP_SEND; | 4312 | node_perm = NODE__TCP_SEND; |
4240 | send_perm = TCP_SOCKET__SEND_MSG; | 4313 | send_perm = TCP_SOCKET__SEND_MSG; |
4241 | break; | 4314 | break; |
4242 | |||
4243 | case SECCLASS_DCCP_SOCKET: | 4315 | case SECCLASS_DCCP_SOCKET: |
4244 | netif_perm = NETIF__DCCP_SEND; | 4316 | netif_perm = NETIF__DCCP_SEND; |
4245 | node_perm = NODE__DCCP_SEND; | 4317 | node_perm = NODE__DCCP_SEND; |
4246 | send_perm = DCCP_SOCKET__SEND_MSG; | 4318 | send_perm = DCCP_SOCKET__SEND_MSG; |
4247 | break; | 4319 | break; |
4248 | |||
4249 | default: | 4320 | default: |
4250 | netif_perm = NETIF__RAWIP_SEND; | 4321 | netif_perm = NETIF__RAWIP_SEND; |
4251 | node_perm = NODE__RAWIP_SEND; | 4322 | node_perm = NODE__RAWIP_SEND; |
4323 | send_perm = 0; | ||
4252 | break; | 4324 | break; |
4253 | } | 4325 | } |
4254 | 4326 | ||
4255 | err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | 4327 | err = sel_netif_sid(ifindex, &if_sid); |
4256 | if (err) | 4328 | if (err) |
4257 | goto out; | 4329 | return err; |
4330 | err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | ||
4331 | return err; | ||
4258 | 4332 | ||
4259 | err = sel_netnode_sid(addrp, family, &node_sid); | 4333 | err = sel_netnode_sid(addrp, family, &node_sid); |
4260 | if (err) | 4334 | if (err) |
4261 | goto out; | 4335 | return err; |
4262 | 4336 | err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad); | |
4263 | err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, ad); | ||
4264 | if (err) | 4337 | if (err) |
4265 | goto out; | 4338 | return err; |
4266 | 4339 | ||
4267 | if (send_perm) { | 4340 | if (send_perm != 0) |
4268 | u32 port_sid; | 4341 | return 0; |
4269 | 4342 | ||
4270 | err = security_port_sid(sk->sk_family, | 4343 | err = security_port_sid(sk->sk_family, sk->sk_type, |
4271 | sk->sk_type, | 4344 | sk->sk_protocol, ntohs(ad->u.net.dport), |
4272 | sk->sk_protocol, | 4345 | &port_sid); |
4273 | ntohs(ad->u.net.dport), | 4346 | if (err) |
4274 | &port_sid); | 4347 | return err; |
4275 | if (err) | 4348 | return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad); |
4276 | goto out; | 4349 | } |
4350 | |||
4351 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | ||
4352 | int ifindex, | ||
4353 | struct avc_audit_data *ad, | ||
4354 | u16 family, | ||
4355 | char *addrp, | ||
4356 | u8 proto) | ||
4357 | { | ||
4358 | struct sock *sk = skb->sk; | ||
4359 | struct sk_security_struct *sksec; | ||
4277 | 4360 | ||
4278 | err = avc_has_perm(isec->sid, port_sid, isec->sclass, | 4361 | if (sk == NULL) |
4279 | send_perm, ad); | 4362 | return NF_ACCEPT; |
4363 | sksec = sk->sk_security; | ||
4364 | |||
4365 | if (selinux_compat_net) { | ||
4366 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, | ||
4367 | ad, family, addrp)) | ||
4368 | return NF_DROP; | ||
4369 | } else { | ||
4370 | if (avc_has_perm(sksec->sid, skb->secmark, | ||
4371 | SECCLASS_PACKET, PACKET__SEND, ad)) | ||
4372 | return NF_DROP; | ||
4280 | } | 4373 | } |
4281 | out: | 4374 | |
4282 | return err; | 4375 | if (selinux_policycap_netpeer) |
4376 | if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto)) | ||
4377 | return NF_DROP; | ||
4378 | |||
4379 | return NF_ACCEPT; | ||
4283 | } | 4380 | } |
4284 | 4381 | ||
4285 | static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | 4382 | static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, |
4286 | struct sk_buff *skb, | 4383 | u16 family) |
4287 | const struct net_device *in, | ||
4288 | const struct net_device *out, | ||
4289 | int (*okfn)(struct sk_buff *), | ||
4290 | u16 family) | ||
4291 | { | 4384 | { |
4292 | char *addrp; | 4385 | u32 secmark_perm; |
4293 | int err = 0; | 4386 | u32 peer_sid; |
4294 | struct sock *sk; | 4387 | struct sock *sk; |
4295 | struct avc_audit_data ad; | 4388 | struct avc_audit_data ad; |
4296 | struct net_device *dev = (struct net_device *)out; | 4389 | char *addrp; |
4297 | struct sk_security_struct *sksec; | ||
4298 | u8 proto; | 4390 | u8 proto; |
4299 | 4391 | u8 secmark_active; | |
4300 | sk = skb->sk; | 4392 | u8 peerlbl_active; |
4301 | if (!sk) | ||
4302 | goto out; | ||
4303 | |||
4304 | sksec = sk->sk_security; | ||
4305 | 4393 | ||
4306 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4394 | AVC_AUDIT_DATA_INIT(&ad, NET); |
4307 | ad.u.net.netif = dev->ifindex; | 4395 | ad.u.net.netif = ifindex; |
4308 | ad.u.net.family = family; | 4396 | ad.u.net.family = family; |
4397 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | ||
4398 | return NF_DROP; | ||
4309 | 4399 | ||
4310 | err = selinux_parse_skb(skb, &ad, &addrp, 0, &proto); | 4400 | /* If any sort of compatibility mode is enabled then handoff processing |
4311 | if (err) | 4401 | * to the selinux_ip_postroute_compat() function to deal with the |
4312 | goto out; | 4402 | * special handling. We do this in an attempt to keep this function |
4313 | 4403 | * as fast and as clean as possible. */ | |
4314 | if (selinux_compat_net) | 4404 | if (selinux_compat_net || !selinux_policycap_netpeer) |
4315 | err = selinux_ip_postroute_last_compat(sk, dev, &ad, | 4405 | return selinux_ip_postroute_compat(skb, ifindex, &ad, |
4316 | family, addrp); | 4406 | family, addrp, proto); |
4317 | else | 4407 | |
4318 | err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, | 4408 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec |
4319 | PACKET__SEND, &ad); | 4409 | * packet transformation so allow the packet to pass without any checks |
4410 | * since we'll have another chance to perform access control checks | ||
4411 | * when the packet is on it's final way out. | ||
4412 | * NOTE: there appear to be some IPv6 multicast cases where skb->dst | ||
4413 | * is NULL, in this case go ahead and apply access control. */ | ||
4414 | if (skb->dst != NULL && skb->dst->xfrm != NULL) | ||
4415 | return NF_ACCEPT; | ||
4416 | |||
4417 | secmark_active = selinux_secmark_enabled(); | ||
4418 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | ||
4419 | if (!secmark_active && !peerlbl_active) | ||
4420 | return NF_ACCEPT; | ||
4421 | |||
4422 | /* if the packet is locally generated (skb->sk != NULL) then use the | ||
4423 | * socket's label as the peer label, otherwise the packet is being | ||
4424 | * forwarded through this system and we need to fetch the peer label | ||
4425 | * directly from the packet */ | ||
4426 | sk = skb->sk; | ||
4427 | if (sk) { | ||
4428 | struct sk_security_struct *sksec = sk->sk_security; | ||
4429 | peer_sid = sksec->sid; | ||
4430 | secmark_perm = PACKET__SEND; | ||
4431 | } else { | ||
4432 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | ||
4433 | return NF_DROP; | ||
4434 | secmark_perm = PACKET__FORWARD_OUT; | ||
4435 | } | ||
4320 | 4436 | ||
4321 | if (err) | 4437 | if (secmark_active) |
4322 | goto out; | 4438 | if (avc_has_perm(peer_sid, skb->secmark, |
4439 | SECCLASS_PACKET, secmark_perm, &ad)) | ||
4440 | return NF_DROP; | ||
4441 | |||
4442 | if (peerlbl_active) { | ||
4443 | u32 if_sid; | ||
4444 | u32 node_sid; | ||
4445 | |||
4446 | if (sel_netif_sid(ifindex, &if_sid)) | ||
4447 | return NF_DROP; | ||
4448 | if (avc_has_perm(peer_sid, if_sid, | ||
4449 | SECCLASS_NETIF, NETIF__EGRESS, &ad)) | ||
4450 | return NF_DROP; | ||
4451 | |||
4452 | if (sel_netnode_sid(addrp, family, &node_sid)) | ||
4453 | return NF_DROP; | ||
4454 | if (avc_has_perm(peer_sid, node_sid, | ||
4455 | SECCLASS_NODE, NODE__SENDTO, &ad)) | ||
4456 | return NF_DROP; | ||
4457 | } | ||
4323 | 4458 | ||
4324 | err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto); | 4459 | return NF_ACCEPT; |
4325 | out: | ||
4326 | return err ? NF_DROP : NF_ACCEPT; | ||
4327 | } | 4460 | } |
4328 | 4461 | ||
4329 | static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum, | 4462 | static unsigned int selinux_ipv4_postroute(unsigned int hooknum, |
4330 | struct sk_buff *skb, | 4463 | struct sk_buff *skb, |
4331 | const struct net_device *in, | 4464 | const struct net_device *in, |
4332 | const struct net_device *out, | 4465 | const struct net_device *out, |
4333 | int (*okfn)(struct sk_buff *)) | 4466 | int (*okfn)(struct sk_buff *)) |
4334 | { | 4467 | { |
4335 | return selinux_ip_postroute_last(hooknum, skb, in, out, okfn, PF_INET); | 4468 | return selinux_ip_postroute(skb, out->ifindex, PF_INET); |
4336 | } | 4469 | } |
4337 | 4470 | ||
4338 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 4471 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
4339 | 4472 | static unsigned int selinux_ipv6_postroute(unsigned int hooknum, | |
4340 | static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum, | 4473 | struct sk_buff *skb, |
4341 | struct sk_buff *skb, | 4474 | const struct net_device *in, |
4342 | const struct net_device *in, | 4475 | const struct net_device *out, |
4343 | const struct net_device *out, | 4476 | int (*okfn)(struct sk_buff *)) |
4344 | int (*okfn)(struct sk_buff *)) | ||
4345 | { | 4477 | { |
4346 | return selinux_ip_postroute_last(hooknum, skb, in, out, okfn, PF_INET6); | 4478 | return selinux_ip_postroute(skb, out->ifindex, PF_INET6); |
4347 | } | 4479 | } |
4348 | |||
4349 | #endif /* IPV6 */ | 4480 | #endif /* IPV6 */ |
4350 | 4481 | ||
4351 | #endif /* CONFIG_NETFILTER */ | 4482 | #endif /* CONFIG_NETFILTER */ |
@@ -5333,22 +5464,40 @@ security_initcall(selinux_init); | |||
5333 | 5464 | ||
5334 | #if defined(CONFIG_NETFILTER) | 5465 | #if defined(CONFIG_NETFILTER) |
5335 | 5466 | ||
5336 | static struct nf_hook_ops selinux_ipv4_op = { | 5467 | static struct nf_hook_ops selinux_ipv4_ops[] = { |
5337 | .hook = selinux_ipv4_postroute_last, | 5468 | { |
5338 | .owner = THIS_MODULE, | 5469 | .hook = selinux_ipv4_postroute, |
5339 | .pf = PF_INET, | 5470 | .owner = THIS_MODULE, |
5340 | .hooknum = NF_INET_POST_ROUTING, | 5471 | .pf = PF_INET, |
5341 | .priority = NF_IP_PRI_SELINUX_LAST, | 5472 | .hooknum = NF_INET_POST_ROUTING, |
5473 | .priority = NF_IP_PRI_SELINUX_LAST, | ||
5474 | }, | ||
5475 | { | ||
5476 | .hook = selinux_ipv4_forward, | ||
5477 | .owner = THIS_MODULE, | ||
5478 | .pf = PF_INET, | ||
5479 | .hooknum = NF_INET_FORWARD, | ||
5480 | .priority = NF_IP_PRI_SELINUX_FIRST, | ||
5481 | } | ||
5342 | }; | 5482 | }; |
5343 | 5483 | ||
5344 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 5484 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
5345 | 5485 | ||
5346 | static struct nf_hook_ops selinux_ipv6_op = { | 5486 | static struct nf_hook_ops selinux_ipv6_ops[] = { |
5347 | .hook = selinux_ipv6_postroute_last, | 5487 | { |
5348 | .owner = THIS_MODULE, | 5488 | .hook = selinux_ipv6_postroute, |
5349 | .pf = PF_INET6, | 5489 | .owner = THIS_MODULE, |
5350 | .hooknum = NF_INET_POST_ROUTING, | 5490 | .pf = PF_INET6, |
5351 | .priority = NF_IP6_PRI_SELINUX_LAST, | 5491 | .hooknum = NF_INET_POST_ROUTING, |
5492 | .priority = NF_IP6_PRI_SELINUX_LAST, | ||
5493 | }, | ||
5494 | { | ||
5495 | .hook = selinux_ipv6_forward, | ||
5496 | .owner = THIS_MODULE, | ||
5497 | .pf = PF_INET6, | ||
5498 | .hooknum = NF_INET_FORWARD, | ||
5499 | .priority = NF_IP6_PRI_SELINUX_FIRST, | ||
5500 | } | ||
5352 | }; | 5501 | }; |
5353 | 5502 | ||
5354 | #endif /* IPV6 */ | 5503 | #endif /* IPV6 */ |
@@ -5356,22 +5505,27 @@ static struct nf_hook_ops selinux_ipv6_op = { | |||
5356 | static int __init selinux_nf_ip_init(void) | 5505 | static int __init selinux_nf_ip_init(void) |
5357 | { | 5506 | { |
5358 | int err = 0; | 5507 | int err = 0; |
5508 | u32 iter; | ||
5359 | 5509 | ||
5360 | if (!selinux_enabled) | 5510 | if (!selinux_enabled) |
5361 | goto out; | 5511 | goto out; |
5362 | 5512 | ||
5363 | printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); | 5513 | printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); |
5364 | 5514 | ||
5365 | err = nf_register_hook(&selinux_ipv4_op); | 5515 | for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) { |
5366 | if (err) | 5516 | err = nf_register_hook(&selinux_ipv4_ops[iter]); |
5367 | panic("SELinux: nf_register_hook for IPv4: error %d\n", err); | 5517 | if (err) |
5518 | panic("SELinux: nf_register_hook for IPv4: error %d\n", | ||
5519 | err); | ||
5520 | } | ||
5368 | 5521 | ||
5369 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 5522 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
5370 | 5523 | for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) { | |
5371 | err = nf_register_hook(&selinux_ipv6_op); | 5524 | err = nf_register_hook(&selinux_ipv6_ops[iter]); |
5372 | if (err) | 5525 | if (err) |
5373 | panic("SELinux: nf_register_hook for IPv6: error %d\n", err); | 5526 | panic("SELinux: nf_register_hook for IPv6: error %d\n", |
5374 | 5527 | err); | |
5528 | } | ||
5375 | #endif /* IPV6 */ | 5529 | #endif /* IPV6 */ |
5376 | 5530 | ||
5377 | out: | 5531 | out: |
@@ -5383,11 +5537,15 @@ __initcall(selinux_nf_ip_init); | |||
5383 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 5537 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
5384 | static void selinux_nf_ip_exit(void) | 5538 | static void selinux_nf_ip_exit(void) |
5385 | { | 5539 | { |
5540 | u32 iter; | ||
5541 | |||
5386 | printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); | 5542 | printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); |
5387 | 5543 | ||
5388 | nf_unregister_hook(&selinux_ipv4_op); | 5544 | for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) |
5545 | nf_unregister_hook(&selinux_ipv4_ops[iter]); | ||
5389 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 5546 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
5390 | nf_unregister_hook(&selinux_ipv6_op); | 5547 | for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) |
5548 | nf_unregister_hook(&selinux_ipv6_ops[iter]); | ||
5391 | #endif /* IPV6 */ | 5549 | #endif /* IPV6 */ |
5392 | } | 5550 | } |
5393 | #endif | 5551 | #endif |