Commit cbe0d6e8 authored by Paul Moore's avatar Paul Moore

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: default avatarJiri Jaburek <jjaburek@redhat.com>
Signed-off-by: default avatarPaul Moore <pmoore@redhat.com>
parent 25db6bea
...@@ -4307,15 +4307,15 @@ static int selinux_socket_unix_may_send(struct socket *sock, ...@@ -4307,15 +4307,15 @@ static int selinux_socket_unix_may_send(struct socket *sock,
&ad); &ad);
} }
static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
u32 peer_sid, char *addrp, u16 family, u32 peer_sid,
struct common_audit_data *ad) struct common_audit_data *ad)
{ {
int err; int err;
u32 if_sid; u32 if_sid;
u32 node_sid; u32 node_sid;
err = sel_netif_sid(ifindex, &if_sid); err = sel_netif_sid(ns, ifindex, &if_sid);
if (err) if (err)
return err; return err;
err = avc_has_perm(peer_sid, if_sid, 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,8 +4408,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
if (err) if (err)
return err; return err;
err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family, err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
peer_sid, &ad); addrp, family, peer_sid, &ad);
if (err) { if (err) {
selinux_netlbl_err(skb, err, 0); selinux_netlbl_err(skb, err, 0);
return err; return err;
...@@ -4748,7 +4748,8 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) ...@@ -4748,7 +4748,8 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
#ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER
static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, static unsigned int selinux_ip_forward(struct sk_buff *skb,
const struct net_device *indev,
u16 family) u16 family)
{ {
int err; int err;
...@@ -4774,14 +4775,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, ...@@ -4774,14 +4775,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
ad.type = LSM_AUDIT_DATA_NET; ad.type = LSM_AUDIT_DATA_NET;
ad.u.net = &net; ad.u.net = &net;
ad.u.net->netif = ifindex; ad.u.net->netif = indev->ifindex;
ad.u.net->family = family; ad.u.net->family = family;
if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
return NF_DROP; return NF_DROP;
if (peerlbl_active) { if (peerlbl_active) {
err = selinux_inet_sys_rcv_skb(ifindex, addrp, family, err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex,
peer_sid, &ad); addrp, family, peer_sid, &ad);
if (err) { if (err) {
selinux_netlbl_err(skb, err, 1); selinux_netlbl_err(skb, err, 1);
return NF_DROP; return NF_DROP;
...@@ -4810,7 +4811,7 @@ static unsigned int selinux_ipv4_forward(const struct nf_hook_ops *ops, ...@@ -4810,7 +4811,7 @@ static unsigned int selinux_ipv4_forward(const struct nf_hook_ops *ops,
const struct net_device *out, const struct net_device *out,
int (*okfn)(struct sk_buff *)) int (*okfn)(struct sk_buff *))
{ {
return selinux_ip_forward(skb, in->ifindex, PF_INET); return selinux_ip_forward(skb, in, PF_INET);
} }
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #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,7 +4821,7 @@ static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops,
const struct net_device *out, const struct net_device *out,
int (*okfn)(struct sk_buff *)) int (*okfn)(struct sk_buff *))
{ {
return selinux_ip_forward(skb, in->ifindex, PF_INET6); return selinux_ip_forward(skb, in, PF_INET6);
} }
#endif /* IPV6 */ #endif /* IPV6 */
...@@ -4908,11 +4909,13 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, ...@@ -4908,11 +4909,13 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
return NF_ACCEPT; return NF_ACCEPT;
} }
static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, static unsigned int selinux_ip_postroute(struct sk_buff *skb,
const struct net_device *outdev,
u16 family) u16 family)
{ {
u32 secmark_perm; u32 secmark_perm;
u32 peer_sid; u32 peer_sid;
int ifindex = outdev->ifindex;
struct sock *sk; struct sock *sk;
struct common_audit_data ad; struct common_audit_data ad;
struct lsm_network_audit net = {0,}; struct lsm_network_audit net = {0,};
...@@ -5025,7 +5028,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, ...@@ -5025,7 +5028,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
u32 if_sid; u32 if_sid;
u32 node_sid; u32 node_sid;
if (sel_netif_sid(ifindex, &if_sid)) if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid))
return NF_DROP; return NF_DROP;
if (avc_has_perm(peer_sid, if_sid, if (avc_has_perm(peer_sid, if_sid,
SECCLASS_NETIF, NETIF__EGRESS, &ad)) SECCLASS_NETIF, NETIF__EGRESS, &ad))
...@@ -5047,7 +5050,7 @@ static unsigned int selinux_ipv4_postroute(const struct nf_hook_ops *ops, ...@@ -5047,7 +5050,7 @@ static unsigned int selinux_ipv4_postroute(const struct nf_hook_ops *ops,
const struct net_device *out, const struct net_device *out,
int (*okfn)(struct sk_buff *)) int (*okfn)(struct sk_buff *))
{ {
return selinux_ip_postroute(skb, out->ifindex, PF_INET); return selinux_ip_postroute(skb, out, PF_INET);
} }
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #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,7 +5060,7 @@ static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops,
const struct net_device *out, const struct net_device *out,
int (*okfn)(struct sk_buff *)) int (*okfn)(struct sk_buff *))
{ {
return selinux_ip_postroute(skb, out->ifindex, PF_INET6); return selinux_ip_postroute(skb, out, PF_INET6);
} }
#endif /* IPV6 */ #endif /* IPV6 */
......
...@@ -17,9 +17,11 @@ ...@@ -17,9 +17,11 @@
#ifndef _SELINUX_NETIF_H_ #ifndef _SELINUX_NETIF_H_
#define _SELINUX_NETIF_H_ #define _SELINUX_NETIF_H_
#include <net/net_namespace.h>
void sel_netif_flush(void); void sel_netif_flush(void);
int sel_netif_sid(int ifindex, u32 *sid); int sel_netif_sid(struct net *ns, int ifindex, u32 *sid);
#endif /* _SELINUX_NETIF_H_ */ #endif /* _SELINUX_NETIF_H_ */
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/binfmts.h> #include <linux/binfmts.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <net/net_namespace.h>
#include "flask.h" #include "flask.h"
#include "avc.h" #include "avc.h"
...@@ -78,6 +79,7 @@ struct ipc_security_struct { ...@@ -78,6 +79,7 @@ struct ipc_security_struct {
}; };
struct netif_security_struct { struct netif_security_struct {
struct net *ns; /* network namespace */
int ifindex; /* device index */ int ifindex; /* device index */
u32 sid; /* SID for this interface */ u32 sid; /* SID for this interface */
}; };
......
...@@ -45,6 +45,7 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; ...@@ -45,6 +45,7 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
/** /**
* sel_netif_hashfn - Hashing function for the interface table * sel_netif_hashfn - Hashing function for the interface table
* @ns: the network namespace
* @ifindex: the network interface * @ifindex: the network interface
* *
* Description: * Description:
...@@ -52,13 +53,14 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; ...@@ -52,13 +53,14 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
* bucket number for the given interface. * bucket number for the given interface.
* *
*/ */
static inline u32 sel_netif_hashfn(int ifindex) static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex)
{ {
return (ifindex & (SEL_NETIF_HASH_SIZE - 1)); return (((uintptr_t)ns + ifindex) & (SEL_NETIF_HASH_SIZE - 1));
} }
/** /**
* sel_netif_find - Search for an interface record * sel_netif_find - Search for an interface record
* @ns: the network namespace
* @ifindex: the network interface * @ifindex: the network interface
* *
* Description: * Description:
...@@ -66,15 +68,15 @@ static inline u32 sel_netif_hashfn(int ifindex) ...@@ -66,15 +68,15 @@ static inline u32 sel_netif_hashfn(int ifindex)
* If an entry can not be found in the table return NULL. * If an entry can not be found in the table return NULL.
* *
*/ */
static inline struct sel_netif *sel_netif_find(int ifindex) static inline struct sel_netif *sel_netif_find(const struct net *ns,
int ifindex)
{ {
int idx = sel_netif_hashfn(ifindex); int idx = sel_netif_hashfn(ns, ifindex);
struct sel_netif *netif; struct sel_netif *netif;
list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list) list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list)
/* all of the devices should normally fit in the hash, so we if (net_eq(netif->nsec.ns, ns) &&
* optimize for that case */ netif->nsec.ifindex == ifindex)
if (likely(netif->nsec.ifindex == ifindex))
return netif; return netif;
return NULL; return NULL;
...@@ -96,7 +98,7 @@ static int sel_netif_insert(struct sel_netif *netif) ...@@ -96,7 +98,7 @@ static int sel_netif_insert(struct sel_netif *netif)
if (sel_netif_total >= SEL_NETIF_HASH_MAX) if (sel_netif_total >= SEL_NETIF_HASH_MAX)
return -ENOSPC; return -ENOSPC;
idx = sel_netif_hashfn(netif->nsec.ifindex); idx = sel_netif_hashfn(netif->nsec.ns, netif->nsec.ifindex);
list_add_rcu(&netif->list, &sel_netif_hash[idx]); list_add_rcu(&netif->list, &sel_netif_hash[idx]);
sel_netif_total++; sel_netif_total++;
...@@ -120,6 +122,7 @@ static void sel_netif_destroy(struct sel_netif *netif) ...@@ -120,6 +122,7 @@ static void sel_netif_destroy(struct sel_netif *netif)
/** /**
* sel_netif_sid_slow - Lookup the SID of a network interface using the policy * sel_netif_sid_slow - Lookup the SID of a network interface using the policy
* @ns: the network namespace
* @ifindex: the network interface * @ifindex: the network interface
* @sid: interface SID * @sid: interface SID
* *
...@@ -130,7 +133,7 @@ static void sel_netif_destroy(struct sel_netif *netif) ...@@ -130,7 +133,7 @@ static void sel_netif_destroy(struct sel_netif *netif)
* failure. * failure.
* *
*/ */
static int sel_netif_sid_slow(int ifindex, u32 *sid) static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
{ {
int ret; int ret;
struct sel_netif *netif; struct sel_netif *netif;
...@@ -140,7 +143,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid) ...@@ -140,7 +143,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
/* NOTE: we always use init's network namespace since we don't /* NOTE: we always use init's network namespace since we don't
* currently support containers */ * currently support containers */
dev = dev_get_by_index(&init_net, ifindex); dev = dev_get_by_index(ns, ifindex);
if (unlikely(dev == NULL)) { if (unlikely(dev == NULL)) {
printk(KERN_WARNING printk(KERN_WARNING
"SELinux: failure in sel_netif_sid_slow()," "SELinux: failure in sel_netif_sid_slow(),"
...@@ -149,7 +152,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid) ...@@ -149,7 +152,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
} }
spin_lock_bh(&sel_netif_lock); spin_lock_bh(&sel_netif_lock);
netif = sel_netif_find(ifindex); netif = sel_netif_find(ns, ifindex);
if (netif != NULL) { if (netif != NULL) {
*sid = netif->nsec.sid; *sid = netif->nsec.sid;
ret = 0; ret = 0;
...@@ -163,6 +166,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid) ...@@ -163,6 +166,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
ret = security_netif_sid(dev->name, &new->nsec.sid); ret = security_netif_sid(dev->name, &new->nsec.sid);
if (ret != 0) if (ret != 0)
goto out; goto out;
new->nsec.ns = ns;
new->nsec.ifindex = ifindex; new->nsec.ifindex = ifindex;
ret = sel_netif_insert(new); ret = sel_netif_insert(new);
if (ret != 0) if (ret != 0)
...@@ -184,6 +188,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid) ...@@ -184,6 +188,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
/** /**
* sel_netif_sid - Lookup the SID of a network interface * sel_netif_sid - Lookup the SID of a network interface
* @ns: the network namespace
* @ifindex: the network interface * @ifindex: the network interface
* @sid: interface SID * @sid: interface SID
* *
...@@ -195,12 +200,12 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid) ...@@ -195,12 +200,12 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
* on failure. * on failure.
* *
*/ */
int sel_netif_sid(int ifindex, u32 *sid) int sel_netif_sid(struct net *ns, int ifindex, u32 *sid)
{ {
struct sel_netif *netif; struct sel_netif *netif;
rcu_read_lock(); rcu_read_lock();
netif = sel_netif_find(ifindex); netif = sel_netif_find(ns, ifindex);
if (likely(netif != NULL)) { if (likely(netif != NULL)) {
*sid = netif->nsec.sid; *sid = netif->nsec.sid;
rcu_read_unlock(); rcu_read_unlock();
...@@ -208,11 +213,12 @@ int sel_netif_sid(int ifindex, u32 *sid) ...@@ -208,11 +213,12 @@ int sel_netif_sid(int ifindex, u32 *sid)
} }
rcu_read_unlock(); rcu_read_unlock();
return sel_netif_sid_slow(ifindex, sid); return sel_netif_sid_slow(ns, ifindex, sid);
} }
/** /**
* sel_netif_kill - Remove an entry from the network interface table * sel_netif_kill - Remove an entry from the network interface table
* @ns: the network namespace
* @ifindex: the network interface * @ifindex: the network interface
* *
* Description: * Description:
...@@ -220,13 +226,13 @@ int sel_netif_sid(int ifindex, u32 *sid) ...@@ -220,13 +226,13 @@ int sel_netif_sid(int ifindex, u32 *sid)
* table if it exists. * table if it exists.
* *
*/ */
static void sel_netif_kill(int ifindex) static void sel_netif_kill(const struct net *ns, int ifindex)
{ {
struct sel_netif *netif; struct sel_netif *netif;
rcu_read_lock(); rcu_read_lock();
spin_lock_bh(&sel_netif_lock); spin_lock_bh(&sel_netif_lock);
netif = sel_netif_find(ifindex); netif = sel_netif_find(ns, ifindex);
if (netif) if (netif)
sel_netif_destroy(netif); sel_netif_destroy(netif);
spin_unlock_bh(&sel_netif_lock); spin_unlock_bh(&sel_netif_lock);
...@@ -257,11 +263,8 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this, ...@@ -257,11 +263,8 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
{ {
struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct net_device *dev = netdev_notifier_info_to_dev(ptr);
if (dev_net(dev) != &init_net)
return NOTIFY_DONE;
if (event == NETDEV_DOWN) if (event == NETDEV_DOWN)
sel_netif_kill(dev->ifindex); sel_netif_kill(dev_net(dev), dev->ifindex);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment