aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorPaul Moore <pmoore@redhat.com>2014-09-10 17:09:57 -0400
committerPaul Moore <pmoore@redhat.com>2014-09-10 17:09:57 -0400
commitcbe0d6e8794f1da6cac1ea3864d2cfaf0bf87c8e (patch)
tree36d99ec1ecc4fec26ede0516059e611729a5afb9 /security
parent25db6bea1ff5a78ef493eefdcbb9c1d27134e560 (diff)
selinux: make the netif cache namespace aware
While SELinux largely ignores namespaces, for good reason, there are some places where it needs to at least be aware of namespaces in order to function correctly. Network namespaces are one example. Basic awareness of network namespaces are necessary in order to match a network interface's index number to an actual network device. This patch corrects a problem with network interfaces added to a non-init namespace, and can be reproduced with the following commands: [NOTE: the NetLabel configuration is here only to active the dynamic networking controls ] # netlabelctl unlbl add default address:0.0.0.0/0 \ label:system_u:object_r:unlabeled_t:s0 # netlabelctl unlbl add default address:::/0 \ label:system_u:object_r:unlabeled_t:s0 # netlabelctl cipsov4 add pass doi:100 tags:1 # netlabelctl map add domain:lspp_test_netlabel_t \ protocol:cipsov4,100 # ip link add type veth # ip netns add myns # ip link set veth1 netns myns # ip a add dev veth0 10.250.13.100/24 # ip netns exec myns ip a add dev veth1 10.250.13.101/24 # ip l set veth0 up # ip netns exec myns ip l set veth1 up # ping -c 1 10.250.13.101 # ip netns exec myns ping -c 1 10.250.13.100 Reported-by: Jiri Jaburek <jjaburek@redhat.com> Signed-off-by: Paul Moore <pmoore@redhat.com>
Diffstat (limited to 'security')
-rw-r--r--security/selinux/hooks.c33
-rw-r--r--security/selinux/include/netif.h4
-rw-r--r--security/selinux/include/objsec.h2
-rw-r--r--security/selinux/netif.c43
4 files changed, 46 insertions, 36 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 50978d3183ea..5eb512b7ac31 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4307,15 +4307,15 @@ static int selinux_socket_unix_may_send(struct socket *sock,
4307 &ad); 4307 &ad);
4308} 4308}
4309 4309
4310static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, 4310static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
4311 u32 peer_sid, 4311 char *addrp, u16 family, u32 peer_sid,
4312 struct common_audit_data *ad) 4312 struct common_audit_data *ad)
4313{ 4313{
4314 int err; 4314 int err;
4315 u32 if_sid; 4315 u32 if_sid;
4316 u32 node_sid; 4316 u32 node_sid;
4317 4317
4318 err = sel_netif_sid(ifindex, &if_sid); 4318 err = sel_netif_sid(ns, ifindex, &if_sid);
4319 if (err) 4319 if (err)
4320 return err; 4320 return err;
4321 err = avc_has_perm(peer_sid, if_sid, 4321 err = avc_has_perm(peer_sid, if_sid,
@@ -4408,8 +4408,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4408 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); 4408 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4409 if (err) 4409 if (err)
4410 return err; 4410 return err;
4411 err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family, 4411 err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
4412 peer_sid, &ad); 4412 addrp, family, peer_sid, &ad);
4413 if (err) { 4413 if (err) {
4414 selinux_netlbl_err(skb, err, 0); 4414 selinux_netlbl_err(skb, err, 0);
4415 return err; 4415 return err;
@@ -4748,7 +4748,8 @@ out:
4748 4748
4749#ifdef CONFIG_NETFILTER 4749#ifdef CONFIG_NETFILTER
4750 4750
4751static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, 4751static unsigned int selinux_ip_forward(struct sk_buff *skb,
4752 const struct net_device *indev,
4752 u16 family) 4753 u16 family)
4753{ 4754{
4754 int err; 4755 int err;
@@ -4774,14 +4775,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4774 4775
4775 ad.type = LSM_AUDIT_DATA_NET; 4776 ad.type = LSM_AUDIT_DATA_NET;
4776 ad.u.net = &net; 4777 ad.u.net = &net;
4777 ad.u.net->netif = ifindex; 4778 ad.u.net->netif = indev->ifindex;
4778 ad.u.net->family = family; 4779 ad.u.net->family = family;
4779 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) 4780 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4780 return NF_DROP; 4781 return NF_DROP;
4781 4782
4782 if (peerlbl_active) { 4783 if (peerlbl_active) {
4783 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family, 4784 err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex,
4784 peer_sid, &ad); 4785 addrp, family, peer_sid, &ad);
4785 if (err) { 4786 if (err) {
4786 selinux_netlbl_err(skb, err, 1); 4787 selinux_netlbl_err(skb, err, 1);
4787 return NF_DROP; 4788 return NF_DROP;
@@ -4810,7 +4811,7 @@ static unsigned int selinux_ipv4_forward(const struct nf_hook_ops *ops,
4810 const struct net_device *out, 4811 const struct net_device *out,
4811 int (*okfn)(struct sk_buff *)) 4812 int (*okfn)(struct sk_buff *))
4812{ 4813{
4813 return selinux_ip_forward(skb, in->ifindex, PF_INET); 4814 return selinux_ip_forward(skb, in, PF_INET);
4814} 4815}
4815 4816
4816#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 4817#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -4820,7 +4821,7 @@ static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops,
4820 const struct net_device *out, 4821 const struct net_device *out,
4821 int (*okfn)(struct sk_buff *)) 4822 int (*okfn)(struct sk_buff *))
4822{ 4823{
4823 return selinux_ip_forward(skb, in->ifindex, PF_INET6); 4824 return selinux_ip_forward(skb, in, PF_INET6);
4824} 4825}
4825#endif /* IPV6 */ 4826#endif /* IPV6 */
4826 4827
@@ -4908,11 +4909,13 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4908 return NF_ACCEPT; 4909 return NF_ACCEPT;
4909} 4910}
4910 4911
4911static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, 4912static unsigned int selinux_ip_postroute(struct sk_buff *skb,
4913 const struct net_device *outdev,
4912 u16 family) 4914 u16 family)
4913{ 4915{
4914 u32 secmark_perm; 4916 u32 secmark_perm;
4915 u32 peer_sid; 4917 u32 peer_sid;
4918 int ifindex = outdev->ifindex;
4916 struct sock *sk; 4919 struct sock *sk;
4917 struct common_audit_data ad; 4920 struct common_audit_data ad;
4918 struct lsm_network_audit net = {0,}; 4921 struct lsm_network_audit net = {0,};
@@ -5025,7 +5028,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
5025 u32 if_sid; 5028 u32 if_sid;
5026 u32 node_sid; 5029 u32 node_sid;
5027 5030
5028 if (sel_netif_sid(ifindex, &if_sid)) 5031 if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid))
5029 return NF_DROP; 5032 return NF_DROP;
5030 if (avc_has_perm(peer_sid, if_sid, 5033 if (avc_has_perm(peer_sid, if_sid,
5031 SECCLASS_NETIF, NETIF__EGRESS, &ad)) 5034 SECCLASS_NETIF, NETIF__EGRESS, &ad))
@@ -5047,7 +5050,7 @@ static unsigned int selinux_ipv4_postroute(const struct nf_hook_ops *ops,
5047 const struct net_device *out, 5050 const struct net_device *out,
5048 int (*okfn)(struct sk_buff *)) 5051 int (*okfn)(struct sk_buff *))
5049{ 5052{
5050 return selinux_ip_postroute(skb, out->ifindex, PF_INET); 5053 return selinux_ip_postroute(skb, out, PF_INET);
5051} 5054}
5052 5055
5053#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 5056#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -5057,7 +5060,7 @@ static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops,
5057 const struct net_device *out, 5060 const struct net_device *out,
5058 int (*okfn)(struct sk_buff *)) 5061 int (*okfn)(struct sk_buff *))
5059{ 5062{
5060 return selinux_ip_postroute(skb, out->ifindex, PF_INET6); 5063 return selinux_ip_postroute(skb, out, PF_INET6);
5061} 5064}
5062#endif /* IPV6 */ 5065#endif /* IPV6 */
5063 5066
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
20void sel_netif_flush(void); 22void sel_netif_flush(void);
21 23
22int sel_netif_sid(int ifindex, u32 *sid); 24int 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
80struct netif_security_struct { 81struct 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 */
55static inline u32 sel_netif_hashfn(int ifindex) 56static 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 */
69static inline struct sel_netif *sel_netif_find(int ifindex) 71static 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 */
133static int sel_netif_sid_slow(int ifindex, u32 *sid) 136static 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 */
198int sel_netif_sid(int ifindex, u32 *sid) 203int 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 */
223static void sel_netif_kill(int ifindex) 229static 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}