Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+46 -36
+18 -15
security/selinux/hooks.c
··· 4307 4307 &ad); 4308 4308 } 4309 4309 4310 - static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, 4311 - u32 peer_sid, 4310 + static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex, 4311 + char *addrp, u16 family, u32 peer_sid, 4312 4312 struct common_audit_data *ad) 4313 4313 { 4314 4314 int err; 4315 4315 u32 if_sid; 4316 4316 u32 node_sid; 4317 4317 4318 - err = sel_netif_sid(ifindex, &if_sid); 4318 + err = sel_netif_sid(ns, ifindex, &if_sid); 4319 4319 if (err) 4320 4320 return err; 4321 4321 err = avc_has_perm(peer_sid, if_sid, ··· 4408 4408 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); 4409 4409 if (err) 4410 4410 return err; 4411 - err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family, 4412 - peer_sid, &ad); 4411 + err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif, 4412 + addrp, family, peer_sid, &ad); 4413 4413 if (err) { 4414 4414 selinux_netlbl_err(skb, err, 0); 4415 4415 return err; ··· 4748 4748 4749 4749 #ifdef CONFIG_NETFILTER 4750 4750 4751 - static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, 4751 + static unsigned int selinux_ip_forward(struct sk_buff *skb, 4752 + const struct net_device *indev, 4752 4753 u16 family) 4753 4754 { 4754 4755 int err; ··· 4775 4774 4776 4775 ad.type = LSM_AUDIT_DATA_NET; 4777 4776 ad.u.net = &net; 4778 - ad.u.net->netif = ifindex; 4777 + ad.u.net->netif = indev->ifindex; 4779 4778 ad.u.net->family = family; 4780 4779 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) 4781 4780 return NF_DROP; 4782 4781 4783 4782 if (peerlbl_active) { 4784 - err = selinux_inet_sys_rcv_skb(ifindex, addrp, family, 4785 - peer_sid, &ad); 4783 + err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex, 4784 + addrp, family, peer_sid, &ad); 4786 4785 if (err) { 4787 4786 selinux_netlbl_err(skb, err, 1); 4788 4787 return NF_DROP; ··· 4811 4810 const struct net_device *out, 4812 4811 int (*okfn)(struct sk_buff *)) 4813 4812 { 4814 - return selinux_ip_forward(skb, in->ifindex, PF_INET); 4813 + return selinux_ip_forward(skb, in, PF_INET); 4815 4814 } 4816 4815 4817 4816 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ··· 4821 4820 const struct net_device *out, 4822 4821 int (*okfn)(struct sk_buff *)) 4823 4822 { 4824 - return selinux_ip_forward(skb, in->ifindex, PF_INET6); 4823 + return selinux_ip_forward(skb, in, PF_INET6); 4825 4824 } 4826 4825 #endif /* IPV6 */ 4827 4826 ··· 4909 4908 return NF_ACCEPT; 4910 4909 } 4911 4910 4912 - 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, 4913 4913 u16 family) 4914 4914 { 4915 4915 u32 secmark_perm; 4916 4916 u32 peer_sid; 4917 + int ifindex = outdev->ifindex; 4917 4918 struct sock *sk; 4918 4919 struct common_audit_data ad; 4919 4920 struct lsm_network_audit net = {0,}; ··· 5028 5025 u32 if_sid; 5029 5026 u32 node_sid; 5030 5027 5031 - if (sel_netif_sid(ifindex, &if_sid)) 5028 + if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid)) 5032 5029 return NF_DROP; 5033 5030 if (avc_has_perm(peer_sid, if_sid, 5034 5031 SECCLASS_NETIF, NETIF__EGRESS, &ad)) ··· 5050 5047 const struct net_device *out, 5051 5048 int (*okfn)(struct sk_buff *)) 5052 5049 { 5053 - return selinux_ip_postroute(skb, out->ifindex, PF_INET); 5050 + return selinux_ip_postroute(skb, out, PF_INET); 5054 5051 } 5055 5052 5056 5053 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ··· 5060 5057 const struct net_device *out, 5061 5058 int (*okfn)(struct sk_buff *)) 5062 5059 { 5063 - return selinux_ip_postroute(skb, out->ifindex, PF_INET6); 5060 + return selinux_ip_postroute(skb, out, PF_INET6); 5064 5061 } 5065 5062 #endif /* IPV6 */ 5066 5063
+3 -1
security/selinux/include/netif.h
··· 17 17 #ifndef _SELINUX_NETIF_H_ 18 18 #define _SELINUX_NETIF_H_ 19 19 20 + #include <net/net_namespace.h> 21 + 20 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 26 #endif /* _SELINUX_NETIF_H_ */ 25 27
+2
security/selinux/include/objsec.h
··· 24 24 #include <linux/binfmts.h> 25 25 #include <linux/in.h> 26 26 #include <linux/spinlock.h> 27 + #include <net/net_namespace.h> 27 28 #include "flask.h" 28 29 #include "avc.h" 29 30 ··· 79 78 }; 80 79 81 80 struct netif_security_struct { 81 + struct net *ns; /* network namespace */ 82 82 int ifindex; /* device index */ 83 83 u32 sid; /* SID for this interface */ 84 84 };
+23 -20
security/selinux/netif.c
··· 45 45 46 46 /** 47 47 * sel_netif_hashfn - Hashing function for the interface table 48 + * @ns: the network namespace 48 49 * @ifindex: the network interface 49 50 * 50 51 * Description: ··· 53 52 * bucket number for the given interface. 54 53 * 55 54 */ 56 - static inline u32 sel_netif_hashfn(int ifindex) 55 + static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex) 57 56 { 58 - return (ifindex & (SEL_NETIF_HASH_SIZE - 1)); 57 + return (((uintptr_t)ns + ifindex) & (SEL_NETIF_HASH_SIZE - 1)); 59 58 } 60 59 61 60 /** 62 61 * sel_netif_find - Search for an interface record 62 + * @ns: the network namespace 63 63 * @ifindex: the network interface 64 64 * 65 65 * Description: ··· 68 66 * If an entry can not be found in the table return NULL. 69 67 * 70 68 */ 71 - static inline struct sel_netif *sel_netif_find(int ifindex) 69 + static inline struct sel_netif *sel_netif_find(const struct net *ns, 70 + int ifindex) 72 71 { 73 - int idx = sel_netif_hashfn(ifindex); 72 + int idx = sel_netif_hashfn(ns, ifindex); 74 73 struct sel_netif *netif; 75 74 76 75 list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list) 77 - /* all of the devices should normally fit in the hash, so we 78 - * optimize for that case */ 79 - if (likely(netif->nsec.ifindex == ifindex)) 76 + if (net_eq(netif->nsec.ns, ns) && 77 + netif->nsec.ifindex == ifindex) 80 78 return netif; 81 79 82 80 return NULL; ··· 98 96 if (sel_netif_total >= SEL_NETIF_HASH_MAX) 99 97 return -ENOSPC; 100 98 101 - idx = sel_netif_hashfn(netif->nsec.ifindex); 99 + idx = sel_netif_hashfn(netif->nsec.ns, netif->nsec.ifindex); 102 100 list_add_rcu(&netif->list, &sel_netif_hash[idx]); 103 101 sel_netif_total++; 104 102 ··· 122 120 123 121 /** 124 122 * sel_netif_sid_slow - Lookup the SID of a network interface using the policy 123 + * @ns: the network namespace 125 124 * @ifindex: the network interface 126 125 * @sid: interface SID 127 126 * ··· 133 130 * failure. 134 131 * 135 132 */ 136 - static int sel_netif_sid_slow(int ifindex, u32 *sid) 133 + static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid) 137 134 { 138 135 int ret; 139 136 struct sel_netif *netif; ··· 143 140 /* NOTE: we always use init's network namespace since we don't 144 141 * currently support containers */ 145 142 146 - dev = dev_get_by_index(&init_net, ifindex); 143 + dev = dev_get_by_index(ns, ifindex); 147 144 if (unlikely(dev == NULL)) { 148 145 printk(KERN_WARNING 149 146 "SELinux: failure in sel_netif_sid_slow()," ··· 152 149 } 153 150 154 151 spin_lock_bh(&sel_netif_lock); 155 - netif = sel_netif_find(ifindex); 152 + netif = sel_netif_find(ns, ifindex); 156 153 if (netif != NULL) { 157 154 *sid = netif->nsec.sid; 158 155 ret = 0; ··· 166 163 ret = security_netif_sid(dev->name, &new->nsec.sid); 167 164 if (ret != 0) 168 165 goto out; 166 + new->nsec.ns = ns; 169 167 new->nsec.ifindex = ifindex; 170 168 ret = sel_netif_insert(new); 171 169 if (ret != 0) ··· 188 184 189 185 /** 190 186 * sel_netif_sid - Lookup the SID of a network interface 187 + * @ns: the network namespace 191 188 * @ifindex: the network interface 192 189 * @sid: interface SID 193 190 * ··· 200 195 * on failure. 201 196 * 202 197 */ 203 - int sel_netif_sid(int ifindex, u32 *sid) 198 + int sel_netif_sid(struct net *ns, int ifindex, u32 *sid) 204 199 { 205 200 struct sel_netif *netif; 206 201 207 202 rcu_read_lock(); 208 - netif = sel_netif_find(ifindex); 203 + netif = sel_netif_find(ns, ifindex); 209 204 if (likely(netif != NULL)) { 210 205 *sid = netif->nsec.sid; 211 206 rcu_read_unlock(); ··· 213 208 } 214 209 rcu_read_unlock(); 215 210 216 - return sel_netif_sid_slow(ifindex, sid); 211 + return sel_netif_sid_slow(ns, ifindex, sid); 217 212 } 218 213 219 214 /** 220 215 * sel_netif_kill - Remove an entry from the network interface table 216 + * @ns: the network namespace 221 217 * @ifindex: the network interface 222 218 * 223 219 * Description: ··· 226 220 * table if it exists. 227 221 * 228 222 */ 229 - static void sel_netif_kill(int ifindex) 223 + static void sel_netif_kill(const struct net *ns, int ifindex) 230 224 { 231 225 struct sel_netif *netif; 232 226 233 227 rcu_read_lock(); 234 228 spin_lock_bh(&sel_netif_lock); 235 - netif = sel_netif_find(ifindex); 229 + netif = sel_netif_find(ns, ifindex); 236 230 if (netif) 237 231 sel_netif_destroy(netif); 238 232 spin_unlock_bh(&sel_netif_lock); ··· 263 257 { 264 258 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 265 259 266 - if (dev_net(dev) != &init_net) 267 - return NOTIFY_DONE; 268 - 269 260 if (event == NETDEV_DOWN) 270 - sel_netif_kill(dev->ifindex); 261 + sel_netif_kill(dev_net(dev), dev->ifindex); 271 262 272 263 return NOTIFY_DONE; 273 264 }