diff options
author | James Morris <jmorris@namei.org> | 2008-10-10 18:26:14 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-10-10 18:26:14 -0400 |
commit | 0da939b0058742ad2d8580b7db6b966d0fc72252 (patch) | |
tree | 47cb109fdf97135191bff5db4e3bfc905136bf8b /security/selinux | |
parent | 4bdec11f560b8f405a011288a50e65b1a81b3654 (diff) | |
parent | d91d40799165b0c84c97e7c71fb8039494ff07dc (diff) |
Merge branch 'master' of git://git.infradead.org/users/pcmoore/lblnet-2.6_next into next
Diffstat (limited to 'security/selinux')
-rw-r--r-- | security/selinux/hooks.c | 229 | ||||
-rw-r--r-- | security/selinux/include/netlabel.h | 44 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 9 | ||||
-rw-r--r-- | security/selinux/netlabel.c | 280 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 13 |
5 files changed, 465 insertions, 110 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 | ||
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index 487a7d81fe20..b913c8d06038 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
@@ -39,6 +39,9 @@ | |||
39 | #ifdef CONFIG_NETLABEL | 39 | #ifdef CONFIG_NETLABEL |
40 | void selinux_netlbl_cache_invalidate(void); | 40 | void selinux_netlbl_cache_invalidate(void); |
41 | 41 | ||
42 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); | ||
43 | |||
44 | void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec); | ||
42 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, | 45 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, |
43 | int family); | 46 | int family); |
44 | 47 | ||
@@ -46,8 +49,11 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
46 | u16 family, | 49 | u16 family, |
47 | u32 *type, | 50 | u32 *type, |
48 | u32 *sid); | 51 | u32 *sid); |
52 | int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
53 | u16 family, | ||
54 | u32 sid); | ||
49 | 55 | ||
50 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); | 56 | void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family); |
51 | int selinux_netlbl_socket_post_create(struct socket *sock); | 57 | int selinux_netlbl_socket_post_create(struct socket *sock); |
52 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); | 58 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); |
53 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | 59 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, |
@@ -57,12 +63,27 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | |||
57 | int selinux_netlbl_socket_setsockopt(struct socket *sock, | 63 | int selinux_netlbl_socket_setsockopt(struct socket *sock, |
58 | int level, | 64 | int level, |
59 | int optname); | 65 | int optname); |
66 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr); | ||
67 | |||
60 | #else | 68 | #else |
61 | static inline void selinux_netlbl_cache_invalidate(void) | 69 | static inline void selinux_netlbl_cache_invalidate(void) |
62 | { | 70 | { |
63 | return; | 71 | return; |
64 | } | 72 | } |
65 | 73 | ||
74 | static inline void selinux_netlbl_err(struct sk_buff *skb, | ||
75 | int error, | ||
76 | int gateway) | ||
77 | { | ||
78 | return; | ||
79 | } | ||
80 | |||
81 | static inline void selinux_netlbl_sk_security_free( | ||
82 | struct sk_security_struct *ssec) | ||
83 | { | ||
84 | return; | ||
85 | } | ||
86 | |||
66 | static inline void selinux_netlbl_sk_security_reset( | 87 | static inline void selinux_netlbl_sk_security_reset( |
67 | struct sk_security_struct *ssec, | 88 | struct sk_security_struct *ssec, |
68 | int family) | 89 | int family) |
@@ -79,9 +100,21 @@ static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
79 | *sid = SECSID_NULL; | 100 | *sid = SECSID_NULL; |
80 | return 0; | 101 | return 0; |
81 | } | 102 | } |
103 | static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
104 | u16 family, | ||
105 | u32 sid) | ||
106 | { | ||
107 | return 0; | ||
108 | } | ||
82 | 109 | ||
83 | static inline void selinux_netlbl_sock_graft(struct sock *sk, | 110 | static inline int selinux_netlbl_conn_setsid(struct sock *sk, |
84 | struct socket *sock) | 111 | struct sockaddr *addr) |
112 | { | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static inline void selinux_netlbl_inet_conn_established(struct sock *sk, | ||
117 | u16 family) | ||
85 | { | 118 | { |
86 | return; | 119 | return; |
87 | } | 120 | } |
@@ -107,6 +140,11 @@ static inline int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
107 | { | 140 | { |
108 | return 0; | 141 | return 0; |
109 | } | 142 | } |
143 | static inline int selinux_netlbl_socket_connect(struct sock *sk, | ||
144 | struct sockaddr *addr) | ||
145 | { | ||
146 | return 0; | ||
147 | } | ||
110 | #endif /* CONFIG_NETLABEL */ | 148 | #endif /* CONFIG_NETLABEL */ |
111 | 149 | ||
112 | #endif | 150 | #endif |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 91070ab874ce..f8be8d7fa26d 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -109,16 +109,19 @@ struct netport_security_struct { | |||
109 | }; | 109 | }; |
110 | 110 | ||
111 | struct sk_security_struct { | 111 | struct sk_security_struct { |
112 | u32 sid; /* SID of this object */ | ||
113 | u32 peer_sid; /* SID of peer */ | ||
114 | u16 sclass; /* sock security class */ | ||
115 | #ifdef CONFIG_NETLABEL | 112 | #ifdef CONFIG_NETLABEL |
116 | enum { /* NetLabel state */ | 113 | enum { /* NetLabel state */ |
117 | NLBL_UNSET = 0, | 114 | NLBL_UNSET = 0, |
118 | NLBL_REQUIRE, | 115 | NLBL_REQUIRE, |
119 | NLBL_LABELED, | 116 | NLBL_LABELED, |
117 | NLBL_REQSKB, | ||
118 | NLBL_CONNLABELED, | ||
120 | } nlbl_state; | 119 | } nlbl_state; |
120 | struct netlbl_lsm_secattr *nlbl_secattr; /* NetLabel sec attributes */ | ||
121 | #endif | 121 | #endif |
122 | u32 sid; /* SID of this object */ | ||
123 | u32 peer_sid; /* SID of peer */ | ||
124 | u16 sclass; /* sock security class */ | ||
122 | }; | 125 | }; |
123 | 126 | ||
124 | struct key_security_struct { | 127 | struct key_security_struct { |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 89b418392f11..f58701a7b728 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
@@ -9,7 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | /* | 11 | /* |
12 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2007 | 12 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008 |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
@@ -29,8 +29,12 @@ | |||
29 | 29 | ||
30 | #include <linux/spinlock.h> | 30 | #include <linux/spinlock.h> |
31 | #include <linux/rcupdate.h> | 31 | #include <linux/rcupdate.h> |
32 | #include <linux/ip.h> | ||
33 | #include <linux/ipv6.h> | ||
32 | #include <net/sock.h> | 34 | #include <net/sock.h> |
33 | #include <net/netlabel.h> | 35 | #include <net/netlabel.h> |
36 | #include <net/ip.h> | ||
37 | #include <net/ipv6.h> | ||
34 | 38 | ||
35 | #include "objsec.h" | 39 | #include "objsec.h" |
36 | #include "security.h" | 40 | #include "security.h" |
@@ -64,32 +68,69 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, | |||
64 | } | 68 | } |
65 | 69 | ||
66 | /** | 70 | /** |
71 | * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr | ||
72 | * @sk: the socket | ||
73 | * | ||
74 | * Description: | ||
75 | * Generate the NetLabel security attributes for a socket, making full use of | ||
76 | * the socket's attribute cache. Returns a pointer to the security attributes | ||
77 | * on success, NULL on failure. | ||
78 | * | ||
79 | */ | ||
80 | static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) | ||
81 | { | ||
82 | int rc; | ||
83 | struct sk_security_struct *sksec = sk->sk_security; | ||
84 | struct netlbl_lsm_secattr *secattr; | ||
85 | |||
86 | if (sksec->nlbl_secattr != NULL) | ||
87 | return sksec->nlbl_secattr; | ||
88 | |||
89 | secattr = netlbl_secattr_alloc(GFP_ATOMIC); | ||
90 | if (secattr == NULL) | ||
91 | return NULL; | ||
92 | rc = security_netlbl_sid_to_secattr(sksec->sid, secattr); | ||
93 | if (rc != 0) { | ||
94 | netlbl_secattr_free(secattr); | ||
95 | return NULL; | ||
96 | } | ||
97 | sksec->nlbl_secattr = secattr; | ||
98 | |||
99 | return secattr; | ||
100 | } | ||
101 | |||
102 | /** | ||
67 | * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism | 103 | * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism |
68 | * @sk: the socket to label | 104 | * @sk: the socket to label |
69 | * @sid: the SID to use | ||
70 | * | 105 | * |
71 | * Description: | 106 | * Description: |
72 | * Attempt to label a socket using the NetLabel mechanism using the given | 107 | * Attempt to label a socket using the NetLabel mechanism. Returns zero values |
73 | * SID. Returns zero values on success, negative values on failure. | 108 | * on success, negative values on failure. |
74 | * | 109 | * |
75 | */ | 110 | */ |
76 | static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid) | 111 | static int selinux_netlbl_sock_setsid(struct sock *sk) |
77 | { | 112 | { |
78 | int rc; | 113 | int rc; |
79 | struct sk_security_struct *sksec = sk->sk_security; | 114 | struct sk_security_struct *sksec = sk->sk_security; |
80 | struct netlbl_lsm_secattr secattr; | 115 | struct netlbl_lsm_secattr *secattr; |
81 | 116 | ||
82 | netlbl_secattr_init(&secattr); | 117 | if (sksec->nlbl_state != NLBL_REQUIRE) |
118 | return 0; | ||
83 | 119 | ||
84 | rc = security_netlbl_sid_to_secattr(sid, &secattr); | 120 | secattr = selinux_netlbl_sock_genattr(sk); |
85 | if (rc != 0) | 121 | if (secattr == NULL) |
86 | goto sock_setsid_return; | 122 | return -ENOMEM; |
87 | rc = netlbl_sock_setattr(sk, &secattr); | 123 | rc = netlbl_sock_setattr(sk, secattr); |
88 | if (rc == 0) | 124 | switch (rc) { |
125 | case 0: | ||
89 | sksec->nlbl_state = NLBL_LABELED; | 126 | sksec->nlbl_state = NLBL_LABELED; |
127 | break; | ||
128 | case -EDESTADDRREQ: | ||
129 | sksec->nlbl_state = NLBL_REQSKB; | ||
130 | rc = 0; | ||
131 | break; | ||
132 | } | ||
90 | 133 | ||
91 | sock_setsid_return: | ||
92 | netlbl_secattr_destroy(&secattr); | ||
93 | return rc; | 134 | return rc; |
94 | } | 135 | } |
95 | 136 | ||
@@ -106,6 +147,38 @@ void selinux_netlbl_cache_invalidate(void) | |||
106 | } | 147 | } |
107 | 148 | ||
108 | /** | 149 | /** |
150 | * selinux_netlbl_err - Handle a NetLabel packet error | ||
151 | * @skb: the packet | ||
152 | * @error: the error code | ||
153 | * @gateway: true if host is acting as a gateway, false otherwise | ||
154 | * | ||
155 | * Description: | ||
156 | * When a packet is dropped due to a call to avc_has_perm() pass the error | ||
157 | * code to the NetLabel subsystem so any protocol specific processing can be | ||
158 | * done. This is safe to call even if you are unsure if NetLabel labeling is | ||
159 | * present on the packet, NetLabel is smart enough to only act when it should. | ||
160 | * | ||
161 | */ | ||
162 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway) | ||
163 | { | ||
164 | netlbl_skbuff_err(skb, error, gateway); | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * selinux_netlbl_sk_security_free - Free the NetLabel fields | ||
169 | * @sssec: the sk_security_struct | ||
170 | * | ||
171 | * Description: | ||
172 | * Free all of the memory in the NetLabel fields of a sk_security_struct. | ||
173 | * | ||
174 | */ | ||
175 | void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec) | ||
176 | { | ||
177 | if (ssec->nlbl_secattr != NULL) | ||
178 | netlbl_secattr_free(ssec->nlbl_secattr); | ||
179 | } | ||
180 | |||
181 | /** | ||
109 | * selinux_netlbl_sk_security_reset - Reset the NetLabel fields | 182 | * selinux_netlbl_sk_security_reset - Reset the NetLabel fields |
110 | * @ssec: the sk_security_struct | 183 | * @ssec: the sk_security_struct |
111 | * @family: the socket family | 184 | * @family: the socket family |
@@ -163,35 +236,118 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
163 | } | 236 | } |
164 | 237 | ||
165 | /** | 238 | /** |
166 | * selinux_netlbl_sock_graft - Netlabel the new socket | 239 | * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid |
240 | * @skb: the packet | ||
241 | * @family: protocol family | ||
242 | * @sid: the SID | ||
243 | * | ||
244 | * Description | ||
245 | * Call the NetLabel mechanism to set the label of a packet using @sid. | ||
246 | * Returns zero on auccess, negative values on failure. | ||
247 | * | ||
248 | */ | ||
249 | int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
250 | u16 family, | ||
251 | u32 sid) | ||
252 | { | ||
253 | int rc; | ||
254 | struct netlbl_lsm_secattr secattr_storage; | ||
255 | struct netlbl_lsm_secattr *secattr = NULL; | ||
256 | struct sock *sk; | ||
257 | |||
258 | /* if this is a locally generated packet check to see if it is already | ||
259 | * being labeled by it's parent socket, if it is just exit */ | ||
260 | sk = skb->sk; | ||
261 | if (sk != NULL) { | ||
262 | struct sk_security_struct *sksec = sk->sk_security; | ||
263 | if (sksec->nlbl_state != NLBL_REQSKB) | ||
264 | return 0; | ||
265 | secattr = sksec->nlbl_secattr; | ||
266 | } | ||
267 | if (secattr == NULL) { | ||
268 | secattr = &secattr_storage; | ||
269 | netlbl_secattr_init(secattr); | ||
270 | rc = security_netlbl_sid_to_secattr(sid, secattr); | ||
271 | if (rc != 0) | ||
272 | goto skbuff_setsid_return; | ||
273 | } | ||
274 | |||
275 | rc = netlbl_skbuff_setattr(skb, family, secattr); | ||
276 | |||
277 | skbuff_setsid_return: | ||
278 | if (secattr == &secattr_storage) | ||
279 | netlbl_secattr_destroy(secattr); | ||
280 | return rc; | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection | ||
167 | * @sk: the new connection | 285 | * @sk: the new connection |
168 | * @sock: the new socket | ||
169 | * | 286 | * |
170 | * Description: | 287 | * Description: |
171 | * The connection represented by @sk is being grafted onto @sock so set the | 288 | * A new connection has been established on @sk so make sure it is labeled |
172 | * socket's NetLabel to match the SID of @sk. | 289 | * correctly with the NetLabel susbsystem. |
173 | * | 290 | * |
174 | */ | 291 | */ |
175 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) | 292 | void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) |
176 | { | 293 | { |
294 | int rc; | ||
177 | struct sk_security_struct *sksec = sk->sk_security; | 295 | struct sk_security_struct *sksec = sk->sk_security; |
178 | struct netlbl_lsm_secattr secattr; | 296 | struct netlbl_lsm_secattr *secattr; |
179 | u32 nlbl_peer_sid; | 297 | struct inet_sock *sk_inet = inet_sk(sk); |
298 | struct sockaddr_in addr; | ||
180 | 299 | ||
181 | if (sksec->nlbl_state != NLBL_REQUIRE) | 300 | if (sksec->nlbl_state != NLBL_REQUIRE) |
182 | return; | 301 | return; |
183 | 302 | ||
184 | netlbl_secattr_init(&secattr); | 303 | secattr = selinux_netlbl_sock_genattr(sk); |
185 | if (netlbl_sock_getattr(sk, &secattr) == 0 && | 304 | if (secattr == NULL) |
186 | secattr.flags != NETLBL_SECATTR_NONE && | 305 | return; |
187 | security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0) | ||
188 | sksec->peer_sid = nlbl_peer_sid; | ||
189 | netlbl_secattr_destroy(&secattr); | ||
190 | 306 | ||
191 | /* Try to set the NetLabel on the socket to save time later, if we fail | 307 | rc = netlbl_sock_setattr(sk, secattr); |
192 | * here we will pick up the pieces in later calls to | 308 | switch (rc) { |
193 | * selinux_netlbl_inode_permission(). */ | 309 | case 0: |
194 | selinux_netlbl_sock_setsid(sk, sksec->sid); | 310 | sksec->nlbl_state = NLBL_LABELED; |
311 | break; | ||
312 | case -EDESTADDRREQ: | ||
313 | /* no PF_INET6 support yet because we don't support any IPv6 | ||
314 | * labeling protocols */ | ||
315 | if (family != PF_INET) { | ||
316 | sksec->nlbl_state = NLBL_UNSET; | ||
317 | return; | ||
318 | } | ||
319 | |||
320 | addr.sin_family = family; | ||
321 | addr.sin_addr.s_addr = sk_inet->daddr; | ||
322 | if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr, | ||
323 | secattr) != 0) { | ||
324 | /* we failed to label the connected socket (could be | ||
325 | * for a variety of reasons, the actual "why" isn't | ||
326 | * important here) so we have to go to our backup plan, | ||
327 | * labeling the packets individually in the netfilter | ||
328 | * local output hook. this is okay but we need to | ||
329 | * adjust the MSS of the connection to take into | ||
330 | * account any labeling overhead, since we don't know | ||
331 | * the exact overhead at this point we'll use the worst | ||
332 | * case value which is 40 bytes for IPv4 */ | ||
333 | struct inet_connection_sock *sk_conn = inet_csk(sk); | ||
334 | sk_conn->icsk_ext_hdr_len += 40 - | ||
335 | (sk_inet->opt ? sk_inet->opt->optlen : 0); | ||
336 | sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); | ||
337 | |||
338 | sksec->nlbl_state = NLBL_REQSKB; | ||
339 | } else | ||
340 | sksec->nlbl_state = NLBL_CONNLABELED; | ||
341 | break; | ||
342 | default: | ||
343 | /* note that we are failing to label the socket which could be | ||
344 | * a bad thing since it means traffic could leave the system | ||
345 | * without the desired labeling, however, all is not lost as | ||
346 | * we have a check in selinux_netlbl_inode_permission() to | ||
347 | * pick up the pieces that we might drop here because we can't | ||
348 | * return an error code */ | ||
349 | break; | ||
350 | } | ||
195 | } | 351 | } |
196 | 352 | ||
197 | /** | 353 | /** |
@@ -205,13 +361,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) | |||
205 | */ | 361 | */ |
206 | int selinux_netlbl_socket_post_create(struct socket *sock) | 362 | int selinux_netlbl_socket_post_create(struct socket *sock) |
207 | { | 363 | { |
208 | struct sock *sk = sock->sk; | 364 | return selinux_netlbl_sock_setsid(sock->sk); |
209 | struct sk_security_struct *sksec = sk->sk_security; | ||
210 | |||
211 | if (sksec->nlbl_state != NLBL_REQUIRE) | ||
212 | return 0; | ||
213 | |||
214 | return selinux_netlbl_sock_setsid(sk, sksec->sid); | ||
215 | } | 365 | } |
216 | 366 | ||
217 | /** | 367 | /** |
@@ -246,7 +396,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask) | |||
246 | local_bh_disable(); | 396 | local_bh_disable(); |
247 | bh_lock_sock_nested(sk); | 397 | bh_lock_sock_nested(sk); |
248 | if (likely(sksec->nlbl_state == NLBL_REQUIRE)) | 398 | if (likely(sksec->nlbl_state == NLBL_REQUIRE)) |
249 | rc = selinux_netlbl_sock_setsid(sk, sksec->sid); | 399 | rc = selinux_netlbl_sock_setsid(sk); |
250 | else | 400 | else |
251 | rc = 0; | 401 | rc = 0; |
252 | bh_unlock_sock(sk); | 402 | bh_unlock_sock(sk); |
@@ -307,7 +457,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | |||
307 | return 0; | 457 | return 0; |
308 | 458 | ||
309 | if (nlbl_sid != SECINITSID_UNLABELED) | 459 | if (nlbl_sid != SECINITSID_UNLABELED) |
310 | netlbl_skbuff_err(skb, rc); | 460 | netlbl_skbuff_err(skb, rc, 0); |
311 | return rc; | 461 | return rc; |
312 | } | 462 | } |
313 | 463 | ||
@@ -334,7 +484,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
334 | struct netlbl_lsm_secattr secattr; | 484 | struct netlbl_lsm_secattr secattr; |
335 | 485 | ||
336 | if (level == IPPROTO_IP && optname == IP_OPTIONS && | 486 | if (level == IPPROTO_IP && optname == IP_OPTIONS && |
337 | sksec->nlbl_state == NLBL_LABELED) { | 487 | (sksec->nlbl_state == NLBL_LABELED || |
488 | sksec->nlbl_state == NLBL_CONNLABELED)) { | ||
338 | netlbl_secattr_init(&secattr); | 489 | netlbl_secattr_init(&secattr); |
339 | lock_sock(sk); | 490 | lock_sock(sk); |
340 | rc = netlbl_sock_getattr(sk, &secattr); | 491 | rc = netlbl_sock_getattr(sk, &secattr); |
@@ -346,3 +497,50 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
346 | 497 | ||
347 | return rc; | 498 | return rc; |
348 | } | 499 | } |
500 | |||
501 | /** | ||
502 | * selinux_netlbl_socket_connect - Label a client-side socket on connect | ||
503 | * @sk: the socket to label | ||
504 | * @addr: the destination address | ||
505 | * | ||
506 | * Description: | ||
507 | * Attempt to label a connected socket with NetLabel using the given address. | ||
508 | * Returns zero values on success, negative values on failure. | ||
509 | * | ||
510 | */ | ||
511 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | ||
512 | { | ||
513 | int rc; | ||
514 | struct sk_security_struct *sksec = sk->sk_security; | ||
515 | struct netlbl_lsm_secattr *secattr; | ||
516 | |||
517 | if (sksec->nlbl_state != NLBL_REQSKB && | ||
518 | sksec->nlbl_state != NLBL_CONNLABELED) | ||
519 | return 0; | ||
520 | |||
521 | local_bh_disable(); | ||
522 | bh_lock_sock_nested(sk); | ||
523 | |||
524 | /* connected sockets are allowed to disconnect when the address family | ||
525 | * is set to AF_UNSPEC, if that is what is happening we want to reset | ||
526 | * the socket */ | ||
527 | if (addr->sa_family == AF_UNSPEC) { | ||
528 | netlbl_sock_delattr(sk); | ||
529 | sksec->nlbl_state = NLBL_REQSKB; | ||
530 | rc = 0; | ||
531 | goto socket_connect_return; | ||
532 | } | ||
533 | secattr = selinux_netlbl_sock_genattr(sk); | ||
534 | if (secattr == NULL) { | ||
535 | rc = -ENOMEM; | ||
536 | goto socket_connect_return; | ||
537 | } | ||
538 | rc = netlbl_conn_setattr(sk, addr, secattr); | ||
539 | if (rc == 0) | ||
540 | sksec->nlbl_state = NLBL_CONNLABELED; | ||
541 | |||
542 | socket_connect_return: | ||
543 | bh_unlock_sock(sk); | ||
544 | local_bh_enable(); | ||
545 | return rc; | ||
546 | } | ||
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index ab0cc0c7b944..343c8ab14af0 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -2955,7 +2955,7 @@ netlbl_secattr_to_sid_return_cleanup: | |||
2955 | */ | 2955 | */ |
2956 | int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) | 2956 | int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) |
2957 | { | 2957 | { |
2958 | int rc = -ENOENT; | 2958 | int rc; |
2959 | struct context *ctx; | 2959 | struct context *ctx; |
2960 | 2960 | ||
2961 | if (!ss_initialized) | 2961 | if (!ss_initialized) |
@@ -2963,11 +2963,18 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) | |||
2963 | 2963 | ||
2964 | read_lock(&policy_rwlock); | 2964 | read_lock(&policy_rwlock); |
2965 | ctx = sidtab_search(&sidtab, sid); | 2965 | ctx = sidtab_search(&sidtab, sid); |
2966 | if (ctx == NULL) | 2966 | if (ctx == NULL) { |
2967 | rc = -ENOENT; | ||
2967 | goto netlbl_sid_to_secattr_failure; | 2968 | goto netlbl_sid_to_secattr_failure; |
2969 | } | ||
2968 | secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], | 2970 | secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], |
2969 | GFP_ATOMIC); | 2971 | GFP_ATOMIC); |
2970 | secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY; | 2972 | if (secattr->domain == NULL) { |
2973 | rc = -ENOMEM; | ||
2974 | goto netlbl_sid_to_secattr_failure; | ||
2975 | } | ||
2976 | secattr->attr.secid = sid; | ||
2977 | secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID; | ||
2971 | mls_export_netlbl_lvl(ctx, secattr); | 2978 | mls_export_netlbl_lvl(ctx, secattr); |
2972 | rc = mls_export_netlbl_cat(ctx, secattr); | 2979 | rc = mls_export_netlbl_cat(ctx, secattr); |
2973 | if (rc != 0) | 2980 | if (rc != 0) |