diff options
Diffstat (limited to 'security/selinux/hooks.c')
| -rw-r--r-- | security/selinux/hooks.c | 229 |
1 files changed, 169 insertions, 60 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4a7374c12d9c..c679ba653e1d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -291,6 +291,7 @@ static void sk_free_security(struct sock *sk) | |||
| 291 | struct sk_security_struct *ssec = sk->sk_security; | 291 | struct sk_security_struct *ssec = sk->sk_security; |
| 292 | 292 | ||
| 293 | sk->sk_security = NULL; | 293 | sk->sk_security = NULL; |
| 294 | selinux_netlbl_sk_security_free(ssec); | ||
| 294 | kfree(ssec); | 295 | kfree(ssec); |
| 295 | } | 296 | } |
| 296 | 297 | ||
| @@ -3801,6 +3802,7 @@ out: | |||
| 3801 | 3802 | ||
| 3802 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) | 3803 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) |
| 3803 | { | 3804 | { |
| 3805 | struct sock *sk = sock->sk; | ||
| 3804 | struct inode_security_struct *isec; | 3806 | struct inode_security_struct *isec; |
| 3805 | int err; | 3807 | int err; |
| 3806 | 3808 | ||
| @@ -3814,7 +3816,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
| 3814 | isec = SOCK_INODE(sock)->i_security; | 3816 | isec = SOCK_INODE(sock)->i_security; |
| 3815 | if (isec->sclass == SECCLASS_TCP_SOCKET || | 3817 | if (isec->sclass == SECCLASS_TCP_SOCKET || |
| 3816 | isec->sclass == SECCLASS_DCCP_SOCKET) { | 3818 | isec->sclass == SECCLASS_DCCP_SOCKET) { |
| 3817 | struct sock *sk = sock->sk; | ||
| 3818 | struct avc_audit_data ad; | 3819 | struct avc_audit_data ad; |
| 3819 | struct sockaddr_in *addr4 = NULL; | 3820 | struct sockaddr_in *addr4 = NULL; |
| 3820 | struct sockaddr_in6 *addr6 = NULL; | 3821 | struct sockaddr_in6 *addr6 = NULL; |
| @@ -3848,6 +3849,8 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
| 3848 | goto out; | 3849 | goto out; |
| 3849 | } | 3850 | } |
| 3850 | 3851 | ||
| 3852 | err = selinux_netlbl_socket_connect(sk, address); | ||
| 3853 | |||
| 3851 | out: | 3854 | out: |
| 3852 | return err; | 3855 | return err; |
| 3853 | } | 3856 | } |
| @@ -4077,20 +4080,28 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, | |||
| 4077 | } | 4080 | } |
| 4078 | 4081 | ||
| 4079 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 4082 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
| 4080 | struct avc_audit_data *ad, | 4083 | u16 family) |
| 4081 | u16 family, char *addrp) | ||
| 4082 | { | 4084 | { |
| 4083 | int err; | 4085 | int err; |
| 4084 | struct sk_security_struct *sksec = sk->sk_security; | 4086 | struct sk_security_struct *sksec = sk->sk_security; |
| 4085 | u32 peer_sid; | 4087 | u32 peer_sid; |
| 4086 | u32 sk_sid = sksec->sid; | 4088 | u32 sk_sid = sksec->sid; |
| 4089 | struct avc_audit_data ad; | ||
| 4090 | char *addrp; | ||
| 4091 | |||
| 4092 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
| 4093 | ad.u.net.netif = skb->iif; | ||
| 4094 | ad.u.net.family = family; | ||
| 4095 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); | ||
| 4096 | if (err) | ||
| 4097 | return err; | ||
| 4087 | 4098 | ||
| 4088 | if (selinux_compat_net) | 4099 | if (selinux_compat_net) |
| 4089 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad, | 4100 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad, |
| 4090 | family, addrp); | 4101 | family, addrp); |
| 4091 | else | 4102 | else |
| 4092 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | 4103 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
| 4093 | PACKET__RECV, ad); | 4104 | PACKET__RECV, &ad); |
| 4094 | if (err) | 4105 | if (err) |
| 4095 | return err; | 4106 | return err; |
| 4096 | 4107 | ||
| @@ -4099,12 +4110,14 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
| 4099 | if (err) | 4110 | if (err) |
| 4100 | return err; | 4111 | return err; |
| 4101 | err = avc_has_perm(sk_sid, peer_sid, | 4112 | err = avc_has_perm(sk_sid, peer_sid, |
| 4102 | SECCLASS_PEER, PEER__RECV, ad); | 4113 | SECCLASS_PEER, PEER__RECV, &ad); |
| 4114 | if (err) | ||
| 4115 | selinux_netlbl_err(skb, err, 0); | ||
| 4103 | } else { | 4116 | } else { |
| 4104 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad); | 4117 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); |
| 4105 | if (err) | 4118 | if (err) |
| 4106 | return err; | 4119 | return err; |
| 4107 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad); | 4120 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); |
| 4108 | } | 4121 | } |
| 4109 | 4122 | ||
| 4110 | return err; | 4123 | return err; |
| @@ -4118,6 +4131,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 4118 | u32 sk_sid = sksec->sid; | 4131 | u32 sk_sid = sksec->sid; |
| 4119 | struct avc_audit_data ad; | 4132 | struct avc_audit_data ad; |
| 4120 | char *addrp; | 4133 | char *addrp; |
| 4134 | u8 secmark_active; | ||
| 4135 | u8 peerlbl_active; | ||
| 4121 | 4136 | ||
| 4122 | if (family != PF_INET && family != PF_INET6) | 4137 | if (family != PF_INET && family != PF_INET6) |
| 4123 | return 0; | 4138 | return 0; |
| @@ -4126,6 +4141,18 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 4126 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | 4141 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) |
| 4127 | family = PF_INET; | 4142 | family = PF_INET; |
| 4128 | 4143 | ||
| 4144 | /* If any sort of compatibility mode is enabled then handoff processing | ||
| 4145 | * to the selinux_sock_rcv_skb_compat() function to deal with the | ||
| 4146 | * special handling. We do this in an attempt to keep this function | ||
| 4147 | * as fast and as clean as possible. */ | ||
| 4148 | if (selinux_compat_net || !selinux_policycap_netpeer) | ||
| 4149 | return selinux_sock_rcv_skb_compat(sk, skb, family); | ||
| 4150 | |||
| 4151 | secmark_active = selinux_secmark_enabled(); | ||
| 4152 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | ||
| 4153 | if (!secmark_active && !peerlbl_active) | ||
| 4154 | return 0; | ||
| 4155 | |||
| 4129 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4156 | AVC_AUDIT_DATA_INIT(&ad, NET); |
| 4130 | ad.u.net.netif = skb->iif; | 4157 | ad.u.net.netif = skb->iif; |
| 4131 | ad.u.net.family = family; | 4158 | ad.u.net.family = family; |
| @@ -4133,15 +4160,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 4133 | if (err) | 4160 | if (err) |
| 4134 | return err; | 4161 | return err; |
| 4135 | 4162 | ||
| 4136 | /* If any sort of compatibility mode is enabled then handoff processing | 4163 | if (peerlbl_active) { |
| 4137 | * to the selinux_sock_rcv_skb_compat() function to deal with the | ||
| 4138 | * special handling. We do this in an attempt to keep this function | ||
| 4139 | * as fast and as clean as possible. */ | ||
| 4140 | if (selinux_compat_net || !selinux_policycap_netpeer) | ||
| 4141 | return selinux_sock_rcv_skb_compat(sk, skb, &ad, | ||
| 4142 | family, addrp); | ||
| 4143 | |||
| 4144 | if (netlbl_enabled() || selinux_xfrm_enabled()) { | ||
| 4145 | u32 peer_sid; | 4164 | u32 peer_sid; |
| 4146 | 4165 | ||
| 4147 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); | 4166 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); |
| @@ -4149,13 +4168,17 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 4149 | return err; | 4168 | return err; |
| 4150 | err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family, | 4169 | err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family, |
| 4151 | peer_sid, &ad); | 4170 | peer_sid, &ad); |
| 4152 | if (err) | 4171 | if (err) { |
| 4172 | selinux_netlbl_err(skb, err, 0); | ||
| 4153 | return err; | 4173 | return err; |
| 4174 | } | ||
| 4154 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, | 4175 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, |
| 4155 | PEER__RECV, &ad); | 4176 | PEER__RECV, &ad); |
| 4177 | if (err) | ||
| 4178 | selinux_netlbl_err(skb, err, 0); | ||
| 4156 | } | 4179 | } |
| 4157 | 4180 | ||
| 4158 | if (selinux_secmark_enabled()) { | 4181 | if (secmark_active) { |
| 4159 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | 4182 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
| 4160 | PACKET__RECV, &ad); | 4183 | PACKET__RECV, &ad); |
| 4161 | if (err) | 4184 | if (err) |
| @@ -4214,10 +4237,12 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff * | |||
| 4214 | u32 peer_secid = SECSID_NULL; | 4237 | u32 peer_secid = SECSID_NULL; |
| 4215 | u16 family; | 4238 | u16 family; |
| 4216 | 4239 | ||
| 4217 | if (sock) | 4240 | if (skb && skb->protocol == htons(ETH_P_IP)) |
| 4241 | family = PF_INET; | ||
| 4242 | else if (skb && skb->protocol == htons(ETH_P_IPV6)) | ||
| 4243 | family = PF_INET6; | ||
| 4244 | else if (sock) | ||
| 4218 | family = sock->sk->sk_family; | 4245 | family = sock->sk->sk_family; |
| 4219 | else if (skb && skb->sk) | ||
| 4220 | family = skb->sk->sk_family; | ||
| 4221 | else | 4246 | else |
| 4222 | goto out; | 4247 | goto out; |
| 4223 | 4248 | ||
| @@ -4275,8 +4300,6 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent) | |||
| 4275 | sk->sk_family == PF_UNIX) | 4300 | sk->sk_family == PF_UNIX) |
| 4276 | isec->sid = sksec->sid; | 4301 | isec->sid = sksec->sid; |
| 4277 | sksec->sclass = isec->sclass; | 4302 | sksec->sclass = isec->sclass; |
| 4278 | |||
| 4279 | selinux_netlbl_sock_graft(sk, parent); | ||
| 4280 | } | 4303 | } |
| 4281 | 4304 | ||
| 4282 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | 4305 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, |
| @@ -4284,10 +4307,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
| 4284 | { | 4307 | { |
| 4285 | struct sk_security_struct *sksec = sk->sk_security; | 4308 | struct sk_security_struct *sksec = sk->sk_security; |
| 4286 | int err; | 4309 | int err; |
| 4310 | u16 family = sk->sk_family; | ||
| 4287 | u32 newsid; | 4311 | u32 newsid; |
| 4288 | u32 peersid; | 4312 | u32 peersid; |
| 4289 | 4313 | ||
| 4290 | err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid); | 4314 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ |
| 4315 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | ||
| 4316 | family = PF_INET; | ||
| 4317 | |||
| 4318 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); | ||
| 4291 | if (err) | 4319 | if (err) |
| 4292 | return err; | 4320 | return err; |
| 4293 | if (peersid == SECSID_NULL) { | 4321 | if (peersid == SECSID_NULL) { |
| @@ -4322,12 +4350,18 @@ static void selinux_inet_csk_clone(struct sock *newsk, | |||
| 4322 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); | 4350 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); |
| 4323 | } | 4351 | } |
| 4324 | 4352 | ||
| 4325 | static void selinux_inet_conn_established(struct sock *sk, | 4353 | static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) |
| 4326 | struct sk_buff *skb) | ||
| 4327 | { | 4354 | { |
| 4355 | u16 family = sk->sk_family; | ||
| 4328 | struct sk_security_struct *sksec = sk->sk_security; | 4356 | struct sk_security_struct *sksec = sk->sk_security; |
| 4329 | 4357 | ||
| 4330 | selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid); | 4358 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ |
| 4359 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | ||
| 4360 | family = PF_INET; | ||
| 4361 | |||
| 4362 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); | ||
| 4363 | |||
| 4364 | selinux_netlbl_inet_conn_established(sk, family); | ||
| 4331 | } | 4365 | } |
| 4332 | 4366 | ||
| 4333 | static void selinux_req_classify_flow(const struct request_sock *req, | 4367 | static void selinux_req_classify_flow(const struct request_sock *req, |
| @@ -4377,39 +4411,54 @@ out: | |||
| 4377 | static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | 4411 | static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, |
| 4378 | u16 family) | 4412 | u16 family) |
| 4379 | { | 4413 | { |
| 4414 | int err; | ||
| 4380 | char *addrp; | 4415 | char *addrp; |
| 4381 | u32 peer_sid; | 4416 | u32 peer_sid; |
| 4382 | struct avc_audit_data ad; | 4417 | struct avc_audit_data ad; |
| 4383 | u8 secmark_active; | 4418 | u8 secmark_active; |
| 4419 | u8 netlbl_active; | ||
| 4384 | u8 peerlbl_active; | 4420 | u8 peerlbl_active; |
| 4385 | 4421 | ||
| 4386 | if (!selinux_policycap_netpeer) | 4422 | if (!selinux_policycap_netpeer) |
| 4387 | return NF_ACCEPT; | 4423 | return NF_ACCEPT; |
| 4388 | 4424 | ||
| 4389 | secmark_active = selinux_secmark_enabled(); | 4425 | secmark_active = selinux_secmark_enabled(); |
| 4390 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | 4426 | netlbl_active = netlbl_enabled(); |
| 4427 | peerlbl_active = netlbl_active || selinux_xfrm_enabled(); | ||
| 4391 | if (!secmark_active && !peerlbl_active) | 4428 | if (!secmark_active && !peerlbl_active) |
| 4392 | return NF_ACCEPT; | 4429 | return NF_ACCEPT; |
| 4393 | 4430 | ||
| 4431 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | ||
| 4432 | return NF_DROP; | ||
| 4433 | |||
| 4394 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4434 | AVC_AUDIT_DATA_INIT(&ad, NET); |
| 4395 | ad.u.net.netif = ifindex; | 4435 | ad.u.net.netif = ifindex; |
| 4396 | ad.u.net.family = family; | 4436 | ad.u.net.family = family; |
| 4397 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) | 4437 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) |
| 4398 | return NF_DROP; | 4438 | return NF_DROP; |
| 4399 | 4439 | ||
| 4400 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | 4440 | if (peerlbl_active) { |
| 4401 | return NF_DROP; | 4441 | err = selinux_inet_sys_rcv_skb(ifindex, addrp, family, |
| 4402 | 4442 | peer_sid, &ad); | |
| 4403 | if (peerlbl_active) | 4443 | if (err) { |
| 4404 | if (selinux_inet_sys_rcv_skb(ifindex, addrp, family, | 4444 | selinux_netlbl_err(skb, err, 1); |
| 4405 | peer_sid, &ad) != 0) | ||
| 4406 | return NF_DROP; | 4445 | return NF_DROP; |
| 4446 | } | ||
| 4447 | } | ||
| 4407 | 4448 | ||
| 4408 | if (secmark_active) | 4449 | if (secmark_active) |
| 4409 | if (avc_has_perm(peer_sid, skb->secmark, | 4450 | if (avc_has_perm(peer_sid, skb->secmark, |
| 4410 | SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) | 4451 | SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) |
| 4411 | return NF_DROP; | 4452 | return NF_DROP; |
| 4412 | 4453 | ||
| 4454 | if (netlbl_active) | ||
| 4455 | /* we do this in the FORWARD path and not the POST_ROUTING | ||
| 4456 | * path because we want to make sure we apply the necessary | ||
| 4457 | * labeling before IPsec is applied so we can leverage AH | ||
| 4458 | * protection */ | ||
| 4459 | if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0) | ||
| 4460 | return NF_DROP; | ||
| 4461 | |||
| 4413 | return NF_ACCEPT; | 4462 | return NF_ACCEPT; |
| 4414 | } | 4463 | } |
| 4415 | 4464 | ||
| @@ -4433,6 +4482,37 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum, | |||
| 4433 | } | 4482 | } |
| 4434 | #endif /* IPV6 */ | 4483 | #endif /* IPV6 */ |
| 4435 | 4484 | ||
| 4485 | static unsigned int selinux_ip_output(struct sk_buff *skb, | ||
| 4486 | u16 family) | ||
| 4487 | { | ||
| 4488 | u32 sid; | ||
| 4489 | |||
| 4490 | if (!netlbl_enabled()) | ||
| 4491 | return NF_ACCEPT; | ||
| 4492 | |||
| 4493 | /* we do this in the LOCAL_OUT path and not the POST_ROUTING path | ||
| 4494 | * because we want to make sure we apply the necessary labeling | ||
| 4495 | * before IPsec is applied so we can leverage AH protection */ | ||
| 4496 | if (skb->sk) { | ||
| 4497 | struct sk_security_struct *sksec = skb->sk->sk_security; | ||
| 4498 | sid = sksec->sid; | ||
| 4499 | } else | ||
| 4500 | sid = SECINITSID_KERNEL; | ||
| 4501 | if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0) | ||
| 4502 | return NF_DROP; | ||
| 4503 | |||
| 4504 | return NF_ACCEPT; | ||
| 4505 | } | ||
| 4506 | |||
| 4507 | static unsigned int selinux_ipv4_output(unsigned int hooknum, | ||
| 4508 | struct sk_buff *skb, | ||
| 4509 | const struct net_device *in, | ||
| 4510 | const struct net_device *out, | ||
| 4511 | int (*okfn)(struct sk_buff *)) | ||
| 4512 | { | ||
| 4513 | return selinux_ip_output(skb, PF_INET); | ||
| 4514 | } | ||
| 4515 | |||
| 4436 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, | 4516 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, |
| 4437 | int ifindex, | 4517 | int ifindex, |
| 4438 | struct avc_audit_data *ad, | 4518 | struct avc_audit_data *ad, |
| @@ -4500,30 +4580,36 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk, | |||
| 4500 | 4580 | ||
| 4501 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | 4581 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, |
| 4502 | int ifindex, | 4582 | int ifindex, |
| 4503 | struct avc_audit_data *ad, | 4583 | u16 family) |
| 4504 | u16 family, | ||
| 4505 | char *addrp, | ||
| 4506 | u8 proto) | ||
| 4507 | { | 4584 | { |
| 4508 | struct sock *sk = skb->sk; | 4585 | struct sock *sk = skb->sk; |
| 4509 | struct sk_security_struct *sksec; | 4586 | struct sk_security_struct *sksec; |
| 4587 | struct avc_audit_data ad; | ||
| 4588 | char *addrp; | ||
| 4589 | u8 proto; | ||
| 4510 | 4590 | ||
| 4511 | if (sk == NULL) | 4591 | if (sk == NULL) |
| 4512 | return NF_ACCEPT; | 4592 | return NF_ACCEPT; |
| 4513 | sksec = sk->sk_security; | 4593 | sksec = sk->sk_security; |
| 4514 | 4594 | ||
| 4595 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
| 4596 | ad.u.net.netif = ifindex; | ||
| 4597 | ad.u.net.family = family; | ||
| 4598 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | ||
| 4599 | return NF_DROP; | ||
| 4600 | |||
| 4515 | if (selinux_compat_net) { | 4601 | if (selinux_compat_net) { |
| 4516 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, | 4602 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, |
| 4517 | ad, family, addrp)) | 4603 | &ad, family, addrp)) |
| 4518 | return NF_DROP; | 4604 | return NF_DROP; |
| 4519 | } else { | 4605 | } else { |
| 4520 | if (avc_has_perm(sksec->sid, skb->secmark, | 4606 | if (avc_has_perm(sksec->sid, skb->secmark, |
| 4521 | SECCLASS_PACKET, PACKET__SEND, ad)) | 4607 | SECCLASS_PACKET, PACKET__SEND, &ad)) |
| 4522 | return NF_DROP; | 4608 | return NF_DROP; |
| 4523 | } | 4609 | } |
| 4524 | 4610 | ||
| 4525 | if (selinux_policycap_netpeer) | 4611 | if (selinux_policycap_netpeer) |
| 4526 | if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto)) | 4612 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) |
| 4527 | return NF_DROP; | 4613 | return NF_DROP; |
| 4528 | 4614 | ||
| 4529 | return NF_ACCEPT; | 4615 | return NF_ACCEPT; |
| @@ -4537,23 +4623,15 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4537 | struct sock *sk; | 4623 | struct sock *sk; |
| 4538 | struct avc_audit_data ad; | 4624 | struct avc_audit_data ad; |
| 4539 | char *addrp; | 4625 | char *addrp; |
| 4540 | u8 proto; | ||
| 4541 | u8 secmark_active; | 4626 | u8 secmark_active; |
| 4542 | u8 peerlbl_active; | 4627 | u8 peerlbl_active; |
| 4543 | 4628 | ||
| 4544 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
| 4545 | ad.u.net.netif = ifindex; | ||
| 4546 | ad.u.net.family = family; | ||
| 4547 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | ||
| 4548 | return NF_DROP; | ||
| 4549 | |||
| 4550 | /* If any sort of compatibility mode is enabled then handoff processing | 4629 | /* If any sort of compatibility mode is enabled then handoff processing |
| 4551 | * to the selinux_ip_postroute_compat() function to deal with the | 4630 | * to the selinux_ip_postroute_compat() function to deal with the |
| 4552 | * special handling. We do this in an attempt to keep this function | 4631 | * special handling. We do this in an attempt to keep this function |
| 4553 | * as fast and as clean as possible. */ | 4632 | * as fast and as clean as possible. */ |
| 4554 | if (selinux_compat_net || !selinux_policycap_netpeer) | 4633 | if (selinux_compat_net || !selinux_policycap_netpeer) |
| 4555 | return selinux_ip_postroute_compat(skb, ifindex, &ad, | 4634 | return selinux_ip_postroute_compat(skb, ifindex, family); |
| 4556 | family, addrp, proto); | ||
| 4557 | 4635 | ||
| 4558 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec | 4636 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec |
| 4559 | * packet transformation so allow the packet to pass without any checks | 4637 | * packet transformation so allow the packet to pass without any checks |
| @@ -4569,21 +4647,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4569 | if (!secmark_active && !peerlbl_active) | 4647 | if (!secmark_active && !peerlbl_active) |
| 4570 | return NF_ACCEPT; | 4648 | return NF_ACCEPT; |
| 4571 | 4649 | ||
| 4572 | /* if the packet is locally generated (skb->sk != NULL) then use the | 4650 | /* if the packet is being forwarded then get the peer label from the |
| 4573 | * socket's label as the peer label, otherwise the packet is being | 4651 | * packet itself; otherwise check to see if it is from a local |
| 4574 | * forwarded through this system and we need to fetch the peer label | 4652 | * application or the kernel, if from an application get the peer label |
| 4575 | * directly from the packet */ | 4653 | * from the sending socket, otherwise use the kernel's sid */ |
| 4576 | sk = skb->sk; | 4654 | sk = skb->sk; |
| 4577 | if (sk) { | 4655 | if (sk == NULL) { |
| 4656 | switch (family) { | ||
| 4657 | case PF_INET: | ||
| 4658 | if (IPCB(skb)->flags & IPSKB_FORWARDED) | ||
| 4659 | secmark_perm = PACKET__FORWARD_OUT; | ||
| 4660 | else | ||
| 4661 | secmark_perm = PACKET__SEND; | ||
| 4662 | break; | ||
| 4663 | case PF_INET6: | ||
| 4664 | if (IP6CB(skb)->flags & IP6SKB_FORWARDED) | ||
| 4665 | secmark_perm = PACKET__FORWARD_OUT; | ||
| 4666 | else | ||
| 4667 | secmark_perm = PACKET__SEND; | ||
| 4668 | break; | ||
| 4669 | default: | ||
| 4670 | return NF_DROP; | ||
| 4671 | } | ||
| 4672 | if (secmark_perm == PACKET__FORWARD_OUT) { | ||
| 4673 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | ||
| 4674 | return NF_DROP; | ||
| 4675 | } else | ||
| 4676 | peer_sid = SECINITSID_KERNEL; | ||
| 4677 | } else { | ||
| 4578 | struct sk_security_struct *sksec = sk->sk_security; | 4678 | struct sk_security_struct *sksec = sk->sk_security; |
| 4579 | peer_sid = sksec->sid; | 4679 | peer_sid = sksec->sid; |
| 4580 | secmark_perm = PACKET__SEND; | 4680 | secmark_perm = PACKET__SEND; |
| 4581 | } else { | ||
| 4582 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | ||
| 4583 | return NF_DROP; | ||
| 4584 | secmark_perm = PACKET__FORWARD_OUT; | ||
| 4585 | } | 4681 | } |
| 4586 | 4682 | ||
| 4683 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
| 4684 | ad.u.net.netif = ifindex; | ||
| 4685 | ad.u.net.family = family; | ||
| 4686 | if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) | ||
| 4687 | return NF_DROP; | ||
| 4688 | |||
| 4587 | if (secmark_active) | 4689 | if (secmark_active) |
| 4588 | if (avc_has_perm(peer_sid, skb->secmark, | 4690 | if (avc_has_perm(peer_sid, skb->secmark, |
| 4589 | SECCLASS_PACKET, secmark_perm, &ad)) | 4691 | SECCLASS_PACKET, secmark_perm, &ad)) |
| @@ -5657,6 +5759,13 @@ static struct nf_hook_ops selinux_ipv4_ops[] = { | |||
| 5657 | .pf = PF_INET, | 5759 | .pf = PF_INET, |
| 5658 | .hooknum = NF_INET_FORWARD, | 5760 | .hooknum = NF_INET_FORWARD, |
| 5659 | .priority = NF_IP_PRI_SELINUX_FIRST, | 5761 | .priority = NF_IP_PRI_SELINUX_FIRST, |
| 5762 | }, | ||
| 5763 | { | ||
| 5764 | .hook = selinux_ipv4_output, | ||
| 5765 | .owner = THIS_MODULE, | ||
| 5766 | .pf = PF_INET, | ||
| 5767 | .hooknum = NF_INET_LOCAL_OUT, | ||
| 5768 | .priority = NF_IP_PRI_SELINUX_FIRST, | ||
| 5660 | } | 5769 | } |
| 5661 | }; | 5770 | }; |
| 5662 | 5771 | ||
