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