diff options
| -rw-r--r-- | security/selinux/hooks.c | 135 | ||||
| -rw-r--r-- | security/selinux/include/netif.h | 4 | ||||
| -rw-r--r-- | security/selinux/include/objsec.h | 2 | ||||
| -rw-r--r-- | security/selinux/netif.c | 43 | ||||
| -rw-r--r-- | security/selinux/ss/services.c | 14 |
5 files changed, 115 insertions, 83 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index b0e940497e23..29e64d4ca099 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -2097,6 +2097,41 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) | |||
| 2097 | 2097 | ||
| 2098 | /* binprm security operations */ | 2098 | /* binprm security operations */ |
| 2099 | 2099 | ||
| 2100 | static int check_nnp_nosuid(const struct linux_binprm *bprm, | ||
| 2101 | const struct task_security_struct *old_tsec, | ||
| 2102 | const struct task_security_struct *new_tsec) | ||
| 2103 | { | ||
| 2104 | int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS); | ||
| 2105 | int nosuid = (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID); | ||
| 2106 | int rc; | ||
| 2107 | |||
| 2108 | if (!nnp && !nosuid) | ||
| 2109 | return 0; /* neither NNP nor nosuid */ | ||
| 2110 | |||
| 2111 | if (new_tsec->sid == old_tsec->sid) | ||
| 2112 | return 0; /* No change in credentials */ | ||
| 2113 | |||
| 2114 | /* | ||
| 2115 | * The only transitions we permit under NNP or nosuid | ||
| 2116 | * are transitions to bounded SIDs, i.e. SIDs that are | ||
| 2117 | * guaranteed to only be allowed a subset of the permissions | ||
| 2118 | * of the current SID. | ||
| 2119 | */ | ||
| 2120 | rc = security_bounded_transition(old_tsec->sid, new_tsec->sid); | ||
| 2121 | if (rc) { | ||
| 2122 | /* | ||
| 2123 | * On failure, preserve the errno values for NNP vs nosuid. | ||
| 2124 | * NNP: Operation not permitted for caller. | ||
| 2125 | * nosuid: Permission denied to file. | ||
| 2126 | */ | ||
| 2127 | if (nnp) | ||
| 2128 | return -EPERM; | ||
| 2129 | else | ||
| 2130 | return -EACCES; | ||
| 2131 | } | ||
| 2132 | return 0; | ||
| 2133 | } | ||
| 2134 | |||
| 2100 | static int selinux_bprm_set_creds(struct linux_binprm *bprm) | 2135 | static int selinux_bprm_set_creds(struct linux_binprm *bprm) |
| 2101 | { | 2136 | { |
| 2102 | const struct task_security_struct *old_tsec; | 2137 | const struct task_security_struct *old_tsec; |
| @@ -2133,14 +2168,10 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
| 2133 | /* Reset exec SID on execve. */ | 2168 | /* Reset exec SID on execve. */ |
| 2134 | new_tsec->exec_sid = 0; | 2169 | new_tsec->exec_sid = 0; |
| 2135 | 2170 | ||
| 2136 | /* | 2171 | /* Fail on NNP or nosuid if not an allowed transition. */ |
| 2137 | * Minimize confusion: if no_new_privs or nosuid and a | 2172 | rc = check_nnp_nosuid(bprm, old_tsec, new_tsec); |
| 2138 | * transition is explicitly requested, then fail the exec. | 2173 | if (rc) |
| 2139 | */ | 2174 | return rc; |
| 2140 | if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) | ||
| 2141 | return -EPERM; | ||
| 2142 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) | ||
| 2143 | return -EACCES; | ||
| 2144 | } else { | 2175 | } else { |
| 2145 | /* Check for a default transition on this program. */ | 2176 | /* Check for a default transition on this program. */ |
| 2146 | rc = security_transition_sid(old_tsec->sid, isec->sid, | 2177 | rc = security_transition_sid(old_tsec->sid, isec->sid, |
| @@ -2148,15 +2179,19 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
| 2148 | &new_tsec->sid); | 2179 | &new_tsec->sid); |
| 2149 | if (rc) | 2180 | if (rc) |
| 2150 | return rc; | 2181 | return rc; |
| 2182 | |||
| 2183 | /* | ||
| 2184 | * Fallback to old SID on NNP or nosuid if not an allowed | ||
| 2185 | * transition. | ||
| 2186 | */ | ||
| 2187 | rc = check_nnp_nosuid(bprm, old_tsec, new_tsec); | ||
| 2188 | if (rc) | ||
| 2189 | new_tsec->sid = old_tsec->sid; | ||
| 2151 | } | 2190 | } |
| 2152 | 2191 | ||
| 2153 | ad.type = LSM_AUDIT_DATA_PATH; | 2192 | ad.type = LSM_AUDIT_DATA_PATH; |
| 2154 | ad.u.path = bprm->file->f_path; | 2193 | ad.u.path = bprm->file->f_path; |
| 2155 | 2194 | ||
| 2156 | if ((bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) || | ||
| 2157 | (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) | ||
| 2158 | new_tsec->sid = old_tsec->sid; | ||
| 2159 | |||
| 2160 | if (new_tsec->sid == old_tsec->sid) { | 2195 | if (new_tsec->sid == old_tsec->sid) { |
| 2161 | rc = avc_has_perm(old_tsec->sid, isec->sid, | 2196 | rc = avc_has_perm(old_tsec->sid, isec->sid, |
| 2162 | SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); | 2197 | SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); |
| @@ -4272,15 +4307,15 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
| 4272 | &ad); | 4307 | &ad); |
| 4273 | } | 4308 | } |
| 4274 | 4309 | ||
| 4275 | static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, | 4310 | static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex, |
| 4276 | u32 peer_sid, | 4311 | char *addrp, u16 family, u32 peer_sid, |
| 4277 | struct common_audit_data *ad) | 4312 | struct common_audit_data *ad) |
| 4278 | { | 4313 | { |
| 4279 | int err; | 4314 | int err; |
| 4280 | u32 if_sid; | 4315 | u32 if_sid; |
| 4281 | u32 node_sid; | 4316 | u32 node_sid; |
| 4282 | 4317 | ||
| 4283 | err = sel_netif_sid(ifindex, &if_sid); | 4318 | err = sel_netif_sid(ns, ifindex, &if_sid); |
| 4284 | if (err) | 4319 | if (err) |
| 4285 | return err; | 4320 | return err; |
| 4286 | err = avc_has_perm(peer_sid, if_sid, | 4321 | err = avc_has_perm(peer_sid, if_sid, |
| @@ -4373,8 +4408,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 4373 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); | 4408 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); |
| 4374 | if (err) | 4409 | if (err) |
| 4375 | return err; | 4410 | return err; |
| 4376 | err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family, | 4411 | err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif, |
| 4377 | peer_sid, &ad); | 4412 | addrp, family, peer_sid, &ad); |
| 4378 | if (err) { | 4413 | if (err) { |
| 4379 | selinux_netlbl_err(skb, err, 0); | 4414 | selinux_netlbl_err(skb, err, 0); |
| 4380 | return err; | 4415 | return err; |
| @@ -4692,10 +4727,9 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) | |||
| 4692 | err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm); | 4727 | err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm); |
| 4693 | if (err) { | 4728 | if (err) { |
| 4694 | if (err == -EINVAL) { | 4729 | if (err == -EINVAL) { |
| 4695 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR, | 4730 | WARN_ONCE(1, "selinux_nlmsg_perm: unrecognized netlink message:" |
| 4696 | "SELinux: unrecognized netlink message" | 4731 | " protocol=%hu nlmsg_type=%hu sclass=%hu\n", |
| 4697 | " type=%hu for sclass=%hu\n", | 4732 | sk->sk_protocol, nlh->nlmsg_type, sksec->sclass); |
| 4698 | nlh->nlmsg_type, sksec->sclass); | ||
| 4699 | if (!selinux_enforcing || security_get_allow_unknown()) | 4733 | if (!selinux_enforcing || security_get_allow_unknown()) |
| 4700 | err = 0; | 4734 | err = 0; |
| 4701 | } | 4735 | } |
| @@ -4713,7 +4747,8 @@ out: | |||
| 4713 | 4747 | ||
| 4714 | #ifdef CONFIG_NETFILTER | 4748 | #ifdef CONFIG_NETFILTER |
| 4715 | 4749 | ||
| 4716 | static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | 4750 | static unsigned int selinux_ip_forward(struct sk_buff *skb, |
| 4751 | const struct net_device *indev, | ||
| 4717 | u16 family) | 4752 | u16 family) |
| 4718 | { | 4753 | { |
| 4719 | int err; | 4754 | int err; |
| @@ -4739,14 +4774,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | |||
| 4739 | 4774 | ||
| 4740 | ad.type = LSM_AUDIT_DATA_NET; | 4775 | ad.type = LSM_AUDIT_DATA_NET; |
| 4741 | ad.u.net = &net; | 4776 | ad.u.net = &net; |
| 4742 | ad.u.net->netif = ifindex; | 4777 | ad.u.net->netif = indev->ifindex; |
| 4743 | ad.u.net->family = family; | 4778 | ad.u.net->family = family; |
| 4744 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) | 4779 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) |
| 4745 | return NF_DROP; | 4780 | return NF_DROP; |
| 4746 | 4781 | ||
| 4747 | if (peerlbl_active) { | 4782 | if (peerlbl_active) { |
| 4748 | err = selinux_inet_sys_rcv_skb(ifindex, addrp, family, | 4783 | err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex, |
| 4749 | peer_sid, &ad); | 4784 | addrp, family, peer_sid, &ad); |
| 4750 | if (err) { | 4785 | if (err) { |
| 4751 | selinux_netlbl_err(skb, err, 1); | 4786 | selinux_netlbl_err(skb, err, 1); |
| 4752 | return NF_DROP; | 4787 | return NF_DROP; |
| @@ -4775,7 +4810,7 @@ static unsigned int selinux_ipv4_forward(const struct nf_hook_ops *ops, | |||
| 4775 | const struct net_device *out, | 4810 | const struct net_device *out, |
| 4776 | int (*okfn)(struct sk_buff *)) | 4811 | int (*okfn)(struct sk_buff *)) |
| 4777 | { | 4812 | { |
| 4778 | return selinux_ip_forward(skb, in->ifindex, PF_INET); | 4813 | return selinux_ip_forward(skb, in, PF_INET); |
| 4779 | } | 4814 | } |
| 4780 | 4815 | ||
| 4781 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 4816 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| @@ -4785,7 +4820,7 @@ static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops, | |||
| 4785 | const struct net_device *out, | 4820 | const struct net_device *out, |
| 4786 | int (*okfn)(struct sk_buff *)) | 4821 | int (*okfn)(struct sk_buff *)) |
| 4787 | { | 4822 | { |
| 4788 | return selinux_ip_forward(skb, in->ifindex, PF_INET6); | 4823 | return selinux_ip_forward(skb, in, PF_INET6); |
| 4789 | } | 4824 | } |
| 4790 | #endif /* IPV6 */ | 4825 | #endif /* IPV6 */ |
| 4791 | 4826 | ||
| @@ -4873,11 +4908,13 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
| 4873 | return NF_ACCEPT; | 4908 | return NF_ACCEPT; |
| 4874 | } | 4909 | } |
| 4875 | 4910 | ||
| 4876 | static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | 4911 | static unsigned int selinux_ip_postroute(struct sk_buff *skb, |
| 4912 | const struct net_device *outdev, | ||
| 4877 | u16 family) | 4913 | u16 family) |
| 4878 | { | 4914 | { |
| 4879 | u32 secmark_perm; | 4915 | u32 secmark_perm; |
| 4880 | u32 peer_sid; | 4916 | u32 peer_sid; |
| 4917 | int ifindex = outdev->ifindex; | ||
| 4881 | struct sock *sk; | 4918 | struct sock *sk; |
| 4882 | struct common_audit_data ad; | 4919 | struct common_audit_data ad; |
| 4883 | struct lsm_network_audit net = {0,}; | 4920 | struct lsm_network_audit net = {0,}; |
| @@ -4958,6 +4995,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4958 | case PF_INET6: | 4995 | case PF_INET6: |
| 4959 | if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) | 4996 | if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) |
| 4960 | return NF_ACCEPT; | 4997 | return NF_ACCEPT; |
| 4998 | break; | ||
| 4961 | default: | 4999 | default: |
| 4962 | return NF_DROP_ERR(-ECONNREFUSED); | 5000 | return NF_DROP_ERR(-ECONNREFUSED); |
| 4963 | } | 5001 | } |
| @@ -4989,7 +5027,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4989 | u32 if_sid; | 5027 | u32 if_sid; |
| 4990 | u32 node_sid; | 5028 | u32 node_sid; |
| 4991 | 5029 | ||
| 4992 | if (sel_netif_sid(ifindex, &if_sid)) | 5030 | if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid)) |
| 4993 | return NF_DROP; | 5031 | return NF_DROP; |
| 4994 | if (avc_has_perm(peer_sid, if_sid, | 5032 | if (avc_has_perm(peer_sid, if_sid, |
| 4995 | SECCLASS_NETIF, NETIF__EGRESS, &ad)) | 5033 | SECCLASS_NETIF, NETIF__EGRESS, &ad)) |
| @@ -5011,7 +5049,7 @@ static unsigned int selinux_ipv4_postroute(const struct nf_hook_ops *ops, | |||
| 5011 | const struct net_device *out, | 5049 | const struct net_device *out, |
| 5012 | int (*okfn)(struct sk_buff *)) | 5050 | int (*okfn)(struct sk_buff *)) |
| 5013 | { | 5051 | { |
| 5014 | return selinux_ip_postroute(skb, out->ifindex, PF_INET); | 5052 | return selinux_ip_postroute(skb, out, PF_INET); |
| 5015 | } | 5053 | } |
| 5016 | 5054 | ||
| 5017 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 5055 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| @@ -5021,7 +5059,7 @@ static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops, | |||
| 5021 | const struct net_device *out, | 5059 | const struct net_device *out, |
| 5022 | int (*okfn)(struct sk_buff *)) | 5060 | int (*okfn)(struct sk_buff *)) |
| 5023 | { | 5061 | { |
| 5024 | return selinux_ip_postroute(skb, out->ifindex, PF_INET6); | 5062 | return selinux_ip_postroute(skb, out, PF_INET6); |
| 5025 | } | 5063 | } |
| 5026 | #endif /* IPV6 */ | 5064 | #endif /* IPV6 */ |
| 5027 | 5065 | ||
| @@ -6035,7 +6073,7 @@ security_initcall(selinux_init); | |||
| 6035 | 6073 | ||
| 6036 | #if defined(CONFIG_NETFILTER) | 6074 | #if defined(CONFIG_NETFILTER) |
| 6037 | 6075 | ||
| 6038 | static struct nf_hook_ops selinux_ipv4_ops[] = { | 6076 | static struct nf_hook_ops selinux_nf_ops[] = { |
| 6039 | { | 6077 | { |
| 6040 | .hook = selinux_ipv4_postroute, | 6078 | .hook = selinux_ipv4_postroute, |
| 6041 | .owner = THIS_MODULE, | 6079 | .owner = THIS_MODULE, |
| @@ -6056,12 +6094,8 @@ static struct nf_hook_ops selinux_ipv4_ops[] = { | |||
| 6056 | .pf = NFPROTO_IPV4, | 6094 | .pf = NFPROTO_IPV4, |
| 6057 | .hooknum = NF_INET_LOCAL_OUT, | 6095 | .hooknum = NF_INET_LOCAL_OUT, |
| 6058 | .priority = NF_IP_PRI_SELINUX_FIRST, | 6096 | .priority = NF_IP_PRI_SELINUX_FIRST, |
| 6059 | } | 6097 | }, |
| 6060 | }; | ||
| 6061 | |||
| 6062 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 6098 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| 6063 | |||
| 6064 | static struct nf_hook_ops selinux_ipv6_ops[] = { | ||
| 6065 | { | 6099 | { |
| 6066 | .hook = selinux_ipv6_postroute, | 6100 | .hook = selinux_ipv6_postroute, |
| 6067 | .owner = THIS_MODULE, | 6101 | .owner = THIS_MODULE, |
| @@ -6075,32 +6109,24 @@ static struct nf_hook_ops selinux_ipv6_ops[] = { | |||
| 6075 | .pf = NFPROTO_IPV6, | 6109 | .pf = NFPROTO_IPV6, |
| 6076 | .hooknum = NF_INET_FORWARD, | 6110 | .hooknum = NF_INET_FORWARD, |
| 6077 | .priority = NF_IP6_PRI_SELINUX_FIRST, | 6111 | .priority = NF_IP6_PRI_SELINUX_FIRST, |
| 6078 | } | 6112 | }, |
| 6079 | }; | ||
| 6080 | |||
| 6081 | #endif /* IPV6 */ | 6113 | #endif /* IPV6 */ |
| 6114 | }; | ||
| 6082 | 6115 | ||
| 6083 | static int __init selinux_nf_ip_init(void) | 6116 | static int __init selinux_nf_ip_init(void) |
| 6084 | { | 6117 | { |
| 6085 | int err = 0; | 6118 | int err; |
| 6086 | 6119 | ||
| 6087 | if (!selinux_enabled) | 6120 | if (!selinux_enabled) |
| 6088 | goto out; | 6121 | return 0; |
| 6089 | 6122 | ||
| 6090 | printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); | 6123 | printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); |
| 6091 | 6124 | ||
| 6092 | err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops)); | 6125 | err = nf_register_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops)); |
| 6093 | if (err) | 6126 | if (err) |
| 6094 | panic("SELinux: nf_register_hooks for IPv4: error %d\n", err); | 6127 | panic("SELinux: nf_register_hooks: error %d\n", err); |
| 6095 | 6128 | ||
| 6096 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 6129 | return 0; |
| 6097 | err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops)); | ||
| 6098 | if (err) | ||
| 6099 | panic("SELinux: nf_register_hooks for IPv6: error %d\n", err); | ||
| 6100 | #endif /* IPV6 */ | ||
| 6101 | |||
| 6102 | out: | ||
| 6103 | return err; | ||
| 6104 | } | 6130 | } |
| 6105 | 6131 | ||
| 6106 | __initcall(selinux_nf_ip_init); | 6132 | __initcall(selinux_nf_ip_init); |
| @@ -6110,10 +6136,7 @@ static void selinux_nf_ip_exit(void) | |||
| 6110 | { | 6136 | { |
| 6111 | printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); | 6137 | printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); |
| 6112 | 6138 | ||
| 6113 | nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops)); | 6139 | nf_unregister_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops)); |
| 6114 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 6115 | nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops)); | ||
| 6116 | #endif /* IPV6 */ | ||
| 6117 | } | 6140 | } |
| 6118 | #endif | 6141 | #endif |
| 6119 | 6142 | ||
diff --git a/security/selinux/include/netif.h b/security/selinux/include/netif.h index 57c6eae81eac..c72145444090 100644 --- a/security/selinux/include/netif.h +++ b/security/selinux/include/netif.h | |||
| @@ -17,9 +17,11 @@ | |||
| 17 | #ifndef _SELINUX_NETIF_H_ | 17 | #ifndef _SELINUX_NETIF_H_ |
| 18 | #define _SELINUX_NETIF_H_ | 18 | #define _SELINUX_NETIF_H_ |
| 19 | 19 | ||
| 20 | #include <net/net_namespace.h> | ||
| 21 | |||
| 20 | void sel_netif_flush(void); | 22 | void sel_netif_flush(void); |
| 21 | 23 | ||
| 22 | int sel_netif_sid(int ifindex, u32 *sid); | 24 | int sel_netif_sid(struct net *ns, int ifindex, u32 *sid); |
| 23 | 25 | ||
| 24 | #endif /* _SELINUX_NETIF_H_ */ | 26 | #endif /* _SELINUX_NETIF_H_ */ |
| 25 | 27 | ||
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 078e553f52f2..81fa718d5cb3 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/binfmts.h> | 24 | #include <linux/binfmts.h> |
| 25 | #include <linux/in.h> | 25 | #include <linux/in.h> |
| 26 | #include <linux/spinlock.h> | 26 | #include <linux/spinlock.h> |
| 27 | #include <net/net_namespace.h> | ||
| 27 | #include "flask.h" | 28 | #include "flask.h" |
| 28 | #include "avc.h" | 29 | #include "avc.h" |
| 29 | 30 | ||
| @@ -78,6 +79,7 @@ struct ipc_security_struct { | |||
| 78 | }; | 79 | }; |
| 79 | 80 | ||
| 80 | struct netif_security_struct { | 81 | struct netif_security_struct { |
| 82 | struct net *ns; /* network namespace */ | ||
| 81 | int ifindex; /* device index */ | 83 | int ifindex; /* device index */ |
| 82 | u32 sid; /* SID for this interface */ | 84 | u32 sid; /* SID for this interface */ |
| 83 | }; | 85 | }; |
diff --git a/security/selinux/netif.c b/security/selinux/netif.c index 3c3de4ca0ebc..485524c477a4 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c | |||
| @@ -45,6 +45,7 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; | |||
| 45 | 45 | ||
| 46 | /** | 46 | /** |
| 47 | * sel_netif_hashfn - Hashing function for the interface table | 47 | * sel_netif_hashfn - Hashing function for the interface table |
| 48 | * @ns: the network namespace | ||
| 48 | * @ifindex: the network interface | 49 | * @ifindex: the network interface |
| 49 | * | 50 | * |
| 50 | * Description: | 51 | * Description: |
| @@ -52,13 +53,14 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; | |||
| 52 | * bucket number for the given interface. | 53 | * bucket number for the given interface. |
| 53 | * | 54 | * |
| 54 | */ | 55 | */ |
| 55 | static inline u32 sel_netif_hashfn(int ifindex) | 56 | static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex) |
| 56 | { | 57 | { |
| 57 | return (ifindex & (SEL_NETIF_HASH_SIZE - 1)); | 58 | return (((uintptr_t)ns + ifindex) & (SEL_NETIF_HASH_SIZE - 1)); |
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | /** | 61 | /** |
| 61 | * sel_netif_find - Search for an interface record | 62 | * sel_netif_find - Search for an interface record |
| 63 | * @ns: the network namespace | ||
| 62 | * @ifindex: the network interface | 64 | * @ifindex: the network interface |
| 63 | * | 65 | * |
| 64 | * Description: | 66 | * Description: |
| @@ -66,15 +68,15 @@ static inline u32 sel_netif_hashfn(int ifindex) | |||
| 66 | * If an entry can not be found in the table return NULL. | 68 | * If an entry can not be found in the table return NULL. |
| 67 | * | 69 | * |
| 68 | */ | 70 | */ |
| 69 | static inline struct sel_netif *sel_netif_find(int ifindex) | 71 | static inline struct sel_netif *sel_netif_find(const struct net *ns, |
| 72 | int ifindex) | ||
| 70 | { | 73 | { |
| 71 | int idx = sel_netif_hashfn(ifindex); | 74 | int idx = sel_netif_hashfn(ns, ifindex); |
| 72 | struct sel_netif *netif; | 75 | struct sel_netif *netif; |
| 73 | 76 | ||
| 74 | list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list) | 77 | list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list) |
| 75 | /* all of the devices should normally fit in the hash, so we | 78 | if (net_eq(netif->nsec.ns, ns) && |
| 76 | * optimize for that case */ | 79 | netif->nsec.ifindex == ifindex) |
| 77 | if (likely(netif->nsec.ifindex == ifindex)) | ||
| 78 | return netif; | 80 | return netif; |
| 79 | 81 | ||
| 80 | return NULL; | 82 | return NULL; |
| @@ -96,7 +98,7 @@ static int sel_netif_insert(struct sel_netif *netif) | |||
| 96 | if (sel_netif_total >= SEL_NETIF_HASH_MAX) | 98 | if (sel_netif_total >= SEL_NETIF_HASH_MAX) |
| 97 | return -ENOSPC; | 99 | return -ENOSPC; |
| 98 | 100 | ||
| 99 | idx = sel_netif_hashfn(netif->nsec.ifindex); | 101 | idx = sel_netif_hashfn(netif->nsec.ns, netif->nsec.ifindex); |
| 100 | list_add_rcu(&netif->list, &sel_netif_hash[idx]); | 102 | list_add_rcu(&netif->list, &sel_netif_hash[idx]); |
| 101 | sel_netif_total++; | 103 | sel_netif_total++; |
| 102 | 104 | ||
| @@ -120,6 +122,7 @@ static void sel_netif_destroy(struct sel_netif *netif) | |||
| 120 | 122 | ||
| 121 | /** | 123 | /** |
| 122 | * sel_netif_sid_slow - Lookup the SID of a network interface using the policy | 124 | * sel_netif_sid_slow - Lookup the SID of a network interface using the policy |
| 125 | * @ns: the network namespace | ||
| 123 | * @ifindex: the network interface | 126 | * @ifindex: the network interface |
| 124 | * @sid: interface SID | 127 | * @sid: interface SID |
| 125 | * | 128 | * |
| @@ -130,7 +133,7 @@ static void sel_netif_destroy(struct sel_netif *netif) | |||
| 130 | * failure. | 133 | * failure. |
| 131 | * | 134 | * |
| 132 | */ | 135 | */ |
| 133 | static int sel_netif_sid_slow(int ifindex, u32 *sid) | 136 | static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid) |
| 134 | { | 137 | { |
| 135 | int ret; | 138 | int ret; |
| 136 | struct sel_netif *netif; | 139 | struct sel_netif *netif; |
| @@ -140,7 +143,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid) | |||
| 140 | /* NOTE: we always use init's network namespace since we don't | 143 | /* NOTE: we always use init's network namespace since we don't |
| 141 | * currently support containers */ | 144 | * currently support containers */ |
| 142 | 145 | ||
| 143 | dev = dev_get_by_index(&init_net, ifindex); | 146 | dev = dev_get_by_index(ns, ifindex); |
| 144 | if (unlikely(dev == NULL)) { | 147 | if (unlikely(dev == NULL)) { |
| 145 | printk(KERN_WARNING | 148 | printk(KERN_WARNING |
| 146 | "SELinux: failure in sel_netif_sid_slow()," | 149 | "SELinux: failure in sel_netif_sid_slow()," |
| @@ -149,7 +152,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid) | |||
| 149 | } | 152 | } |
| 150 | 153 | ||
| 151 | spin_lock_bh(&sel_netif_lock); | 154 | spin_lock_bh(&sel_netif_lock); |
| 152 | netif = sel_netif_find(ifindex); | 155 | netif = sel_netif_find(ns, ifindex); |
| 153 | if (netif != NULL) { | 156 | if (netif != NULL) { |
| 154 | *sid = netif->nsec.sid; | 157 | *sid = netif->nsec.sid; |
| 155 | ret = 0; | 158 | ret = 0; |
| @@ -163,6 +166,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid) | |||
| 163 | ret = security_netif_sid(dev->name, &new->nsec.sid); | 166 | ret = security_netif_sid(dev->name, &new->nsec.sid); |
| 164 | if (ret != 0) | 167 | if (ret != 0) |
| 165 | goto out; | 168 | goto out; |
| 169 | new->nsec.ns = ns; | ||
| 166 | new->nsec.ifindex = ifindex; | 170 | new->nsec.ifindex = ifindex; |
| 167 | ret = sel_netif_insert(new); | 171 | ret = sel_netif_insert(new); |
| 168 | if (ret != 0) | 172 | if (ret != 0) |
| @@ -184,6 +188,7 @@ out: | |||
| 184 | 188 | ||
| 185 | /** | 189 | /** |
| 186 | * sel_netif_sid - Lookup the SID of a network interface | 190 | * sel_netif_sid - Lookup the SID of a network interface |
| 191 | * @ns: the network namespace | ||
| 187 | * @ifindex: the network interface | 192 | * @ifindex: the network interface |
| 188 | * @sid: interface SID | 193 | * @sid: interface SID |
| 189 | * | 194 | * |
| @@ -195,12 +200,12 @@ out: | |||
| 195 | * on failure. | 200 | * on failure. |
| 196 | * | 201 | * |
| 197 | */ | 202 | */ |
| 198 | int sel_netif_sid(int ifindex, u32 *sid) | 203 | int sel_netif_sid(struct net *ns, int ifindex, u32 *sid) |
| 199 | { | 204 | { |
| 200 | struct sel_netif *netif; | 205 | struct sel_netif *netif; |
| 201 | 206 | ||
| 202 | rcu_read_lock(); | 207 | rcu_read_lock(); |
| 203 | netif = sel_netif_find(ifindex); | 208 | netif = sel_netif_find(ns, ifindex); |
| 204 | if (likely(netif != NULL)) { | 209 | if (likely(netif != NULL)) { |
| 205 | *sid = netif->nsec.sid; | 210 | *sid = netif->nsec.sid; |
| 206 | rcu_read_unlock(); | 211 | rcu_read_unlock(); |
| @@ -208,11 +213,12 @@ int sel_netif_sid(int ifindex, u32 *sid) | |||
| 208 | } | 213 | } |
| 209 | rcu_read_unlock(); | 214 | rcu_read_unlock(); |
| 210 | 215 | ||
| 211 | return sel_netif_sid_slow(ifindex, sid); | 216 | return sel_netif_sid_slow(ns, ifindex, sid); |
| 212 | } | 217 | } |
| 213 | 218 | ||
| 214 | /** | 219 | /** |
| 215 | * sel_netif_kill - Remove an entry from the network interface table | 220 | * sel_netif_kill - Remove an entry from the network interface table |
| 221 | * @ns: the network namespace | ||
| 216 | * @ifindex: the network interface | 222 | * @ifindex: the network interface |
| 217 | * | 223 | * |
| 218 | * Description: | 224 | * Description: |
| @@ -220,13 +226,13 @@ int sel_netif_sid(int ifindex, u32 *sid) | |||
| 220 | * table if it exists. | 226 | * table if it exists. |
| 221 | * | 227 | * |
| 222 | */ | 228 | */ |
| 223 | static void sel_netif_kill(int ifindex) | 229 | static void sel_netif_kill(const struct net *ns, int ifindex) |
| 224 | { | 230 | { |
| 225 | struct sel_netif *netif; | 231 | struct sel_netif *netif; |
| 226 | 232 | ||
| 227 | rcu_read_lock(); | 233 | rcu_read_lock(); |
| 228 | spin_lock_bh(&sel_netif_lock); | 234 | spin_lock_bh(&sel_netif_lock); |
| 229 | netif = sel_netif_find(ifindex); | 235 | netif = sel_netif_find(ns, ifindex); |
| 230 | if (netif) | 236 | if (netif) |
| 231 | sel_netif_destroy(netif); | 237 | sel_netif_destroy(netif); |
| 232 | spin_unlock_bh(&sel_netif_lock); | 238 | spin_unlock_bh(&sel_netif_lock); |
| @@ -257,11 +263,8 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this, | |||
| 257 | { | 263 | { |
| 258 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | 264 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
| 259 | 265 | ||
| 260 | if (dev_net(dev) != &init_net) | ||
| 261 | return NOTIFY_DONE; | ||
| 262 | |||
| 263 | if (event == NETDEV_DOWN) | 266 | if (event == NETDEV_DOWN) |
| 264 | sel_netif_kill(dev->ifindex); | 267 | sel_netif_kill(dev_net(dev), dev->ifindex); |
| 265 | 268 | ||
| 266 | return NOTIFY_DONE; | 269 | return NOTIFY_DONE; |
| 267 | } | 270 | } |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 2aa9d172dc7e..a1d3944751b9 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -728,7 +728,7 @@ static int security_validtrans_handle_fail(struct context *ocontext, | |||
| 728 | if (context_struct_to_string(tcontext, &t, &tlen)) | 728 | if (context_struct_to_string(tcontext, &t, &tlen)) |
| 729 | goto out; | 729 | goto out; |
| 730 | audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, | 730 | audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, |
| 731 | "security_validate_transition: denied for" | 731 | "op=security_validate_transition seresult=denied" |
| 732 | " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", | 732 | " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", |
| 733 | o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); | 733 | o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); |
| 734 | out: | 734 | out: |
| @@ -877,7 +877,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) | |||
| 877 | audit_log(current->audit_context, | 877 | audit_log(current->audit_context, |
| 878 | GFP_ATOMIC, AUDIT_SELINUX_ERR, | 878 | GFP_ATOMIC, AUDIT_SELINUX_ERR, |
| 879 | "op=security_bounded_transition " | 879 | "op=security_bounded_transition " |
| 880 | "result=denied " | 880 | "seresult=denied " |
| 881 | "oldcontext=%s newcontext=%s", | 881 | "oldcontext=%s newcontext=%s", |
| 882 | old_name, new_name); | 882 | old_name, new_name); |
| 883 | } | 883 | } |
| @@ -1351,8 +1351,8 @@ static int compute_sid_handle_invalid_context( | |||
| 1351 | if (context_struct_to_string(newcontext, &n, &nlen)) | 1351 | if (context_struct_to_string(newcontext, &n, &nlen)) |
| 1352 | goto out; | 1352 | goto out; |
| 1353 | audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, | 1353 | audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, |
| 1354 | "security_compute_sid: invalid context %s" | 1354 | "op=security_compute_sid invalid_context=%s" |
| 1355 | " for scontext=%s" | 1355 | " scontext=%s" |
| 1356 | " tcontext=%s" | 1356 | " tcontext=%s" |
| 1357 | " tclass=%s", | 1357 | " tclass=%s", |
| 1358 | n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); | 1358 | n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); |
| @@ -2607,8 +2607,10 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) | |||
| 2607 | rc = convert_context_handle_invalid_context(&newcon); | 2607 | rc = convert_context_handle_invalid_context(&newcon); |
| 2608 | if (rc) { | 2608 | if (rc) { |
| 2609 | if (!context_struct_to_string(&newcon, &s, &len)) { | 2609 | if (!context_struct_to_string(&newcon, &s, &len)) { |
| 2610 | audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, | 2610 | audit_log(current->audit_context, |
| 2611 | "security_sid_mls_copy: invalid context %s", s); | 2611 | GFP_ATOMIC, AUDIT_SELINUX_ERR, |
| 2612 | "op=security_sid_mls_copy " | ||
| 2613 | "invalid_context=%s", s); | ||
| 2612 | kfree(s); | 2614 | kfree(s); |
| 2613 | } | 2615 | } |
| 2614 | goto out_unlock; | 2616 | goto out_unlock; |
