diff options
| -rw-r--r-- | security/selinux/hooks.c | 68 |
1 files changed, 53 insertions, 15 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 877bab748c87..cc076a9b0344 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -3847,6 +3847,30 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) | |||
| 3847 | return 0; | 3847 | return 0; |
| 3848 | } | 3848 | } |
| 3849 | 3849 | ||
| 3850 | /** | ||
| 3851 | * selinux_conn_sid - Determine the child socket label for a connection | ||
| 3852 | * @sk_sid: the parent socket's SID | ||
| 3853 | * @skb_sid: the packet's SID | ||
| 3854 | * @conn_sid: the resulting connection SID | ||
| 3855 | * | ||
| 3856 | * If @skb_sid is valid then the user:role:type information from @sk_sid is | ||
| 3857 | * combined with the MLS information from @skb_sid in order to create | ||
| 3858 | * @conn_sid. If @skb_sid is not valid then then @conn_sid is simply a copy | ||
| 3859 | * of @sk_sid. Returns zero on success, negative values on failure. | ||
| 3860 | * | ||
| 3861 | */ | ||
| 3862 | static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid) | ||
| 3863 | { | ||
| 3864 | int err = 0; | ||
| 3865 | |||
| 3866 | if (skb_sid != SECSID_NULL) | ||
| 3867 | err = security_sid_mls_copy(sk_sid, skb_sid, conn_sid); | ||
| 3868 | else | ||
| 3869 | *conn_sid = sk_sid; | ||
| 3870 | |||
| 3871 | return err; | ||
| 3872 | } | ||
| 3873 | |||
| 3850 | /* socket security operations */ | 3874 | /* socket security operations */ |
| 3851 | 3875 | ||
| 3852 | static int socket_sockcreate_sid(const struct task_security_struct *tsec, | 3876 | static int socket_sockcreate_sid(const struct task_security_struct *tsec, |
| @@ -4453,7 +4477,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
| 4453 | struct sk_security_struct *sksec = sk->sk_security; | 4477 | struct sk_security_struct *sksec = sk->sk_security; |
| 4454 | int err; | 4478 | int err; |
| 4455 | u16 family = sk->sk_family; | 4479 | u16 family = sk->sk_family; |
| 4456 | u32 newsid; | 4480 | u32 connsid; |
| 4457 | u32 peersid; | 4481 | u32 peersid; |
| 4458 | 4482 | ||
| 4459 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ | 4483 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ |
| @@ -4463,16 +4487,11 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
| 4463 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); | 4487 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); |
| 4464 | if (err) | 4488 | if (err) |
| 4465 | return err; | 4489 | return err; |
| 4466 | if (peersid == SECSID_NULL) { | 4490 | err = selinux_conn_sid(sksec->sid, peersid, &connsid); |
| 4467 | req->secid = sksec->sid; | 4491 | if (err) |
| 4468 | req->peer_secid = SECSID_NULL; | 4492 | return err; |
| 4469 | } else { | 4493 | req->secid = connsid; |
| 4470 | err = security_sid_mls_copy(sksec->sid, peersid, &newsid); | 4494 | req->peer_secid = peersid; |
| 4471 | if (err) | ||
| 4472 | return err; | ||
| 4473 | req->secid = newsid; | ||
| 4474 | req->peer_secid = peersid; | ||
| 4475 | } | ||
| 4476 | 4495 | ||
| 4477 | return selinux_netlbl_inet_conn_request(req, family); | 4496 | return selinux_netlbl_inet_conn_request(req, family); |
| 4478 | } | 4497 | } |
| @@ -4846,12 +4865,12 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4846 | if (!secmark_active && !peerlbl_active) | 4865 | if (!secmark_active && !peerlbl_active) |
| 4847 | return NF_ACCEPT; | 4866 | return NF_ACCEPT; |
| 4848 | 4867 | ||
| 4849 | /* if the packet is being forwarded then get the peer label from the | ||
| 4850 | * packet itself; otherwise check to see if it is from a local | ||
| 4851 | * application or the kernel, if from an application get the peer label | ||
| 4852 | * from the sending socket, otherwise use the kernel's sid */ | ||
| 4853 | sk = skb->sk; | 4868 | sk = skb->sk; |
| 4854 | if (sk == NULL) { | 4869 | if (sk == NULL) { |
| 4870 | /* Without an associated socket the packet is either coming | ||
| 4871 | * from the kernel or it is being forwarded; check the packet | ||
| 4872 | * to determine which and if the packet is being forwarded | ||
| 4873 | * query the packet directly to determine the security label. */ | ||
| 4855 | if (skb->skb_iif) { | 4874 | if (skb->skb_iif) { |
| 4856 | secmark_perm = PACKET__FORWARD_OUT; | 4875 | secmark_perm = PACKET__FORWARD_OUT; |
| 4857 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | 4876 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) |
| @@ -4860,7 +4879,26 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4860 | secmark_perm = PACKET__SEND; | 4879 | secmark_perm = PACKET__SEND; |
| 4861 | peer_sid = SECINITSID_KERNEL; | 4880 | peer_sid = SECINITSID_KERNEL; |
| 4862 | } | 4881 | } |
| 4882 | } else if (sk->sk_state == TCP_LISTEN) { | ||
| 4883 | /* Locally generated packet but the associated socket is in the | ||
| 4884 | * listening state which means this is a SYN-ACK packet. In | ||
| 4885 | * this particular case the correct security label is assigned | ||
| 4886 | * to the connection/request_sock but unfortunately we can't | ||
| 4887 | * query the request_sock as it isn't queued on the parent | ||
| 4888 | * socket until after the SYN-ACK packet is sent; the only | ||
| 4889 | * viable choice is to regenerate the label like we do in | ||
| 4890 | * selinux_inet_conn_request(). See also selinux_ip_output() | ||
| 4891 | * for similar problems. */ | ||
| 4892 | u32 skb_sid; | ||
| 4893 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 4894 | if (selinux_skb_peerlbl_sid(skb, family, &skb_sid)) | ||
| 4895 | return NF_DROP; | ||
| 4896 | if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid)) | ||
| 4897 | return NF_DROP; | ||
| 4898 | secmark_perm = PACKET__SEND; | ||
| 4863 | } else { | 4899 | } else { |
| 4900 | /* Locally generated packet, fetch the security label from the | ||
| 4901 | * associated socket. */ | ||
| 4864 | struct sk_security_struct *sksec = sk->sk_security; | 4902 | struct sk_security_struct *sksec = sk->sk_security; |
| 4865 | peer_sid = sksec->sid; | 4903 | peer_sid = sksec->sid; |
| 4866 | secmark_perm = PACKET__SEND; | 4904 | secmark_perm = PACKET__SEND; |
