Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 858f61c4 authored by James Morris's avatar James Morris
Browse files

Merge branch 'next' of git://git.infradead.org/users/pcmoore/selinux into next

parents 6c8ff877 4093a844
Loading
Loading
Loading
Loading
+79 −56
Original line number Diff line number Diff line
@@ -2097,6 +2097,41 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)

/* binprm security operations */

static int check_nnp_nosuid(const struct linux_binprm *bprm,
			    const struct task_security_struct *old_tsec,
			    const struct task_security_struct *new_tsec)
{
	int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
	int nosuid = (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID);
	int rc;

	if (!nnp && !nosuid)
		return 0; /* neither NNP nor nosuid */

	if (new_tsec->sid == old_tsec->sid)
		return 0; /* No change in credentials */

	/*
	 * The only transitions we permit under NNP or nosuid
	 * are transitions to bounded SIDs, i.e. SIDs that are
	 * guaranteed to only be allowed a subset of the permissions
	 * of the current SID.
	 */
	rc = security_bounded_transition(old_tsec->sid, new_tsec->sid);
	if (rc) {
		/*
		 * On failure, preserve the errno values for NNP vs nosuid.
		 * NNP:  Operation not permitted for caller.
		 * nosuid:  Permission denied to file.
		 */
		if (nnp)
			return -EPERM;
		else
			return -EACCES;
	}
	return 0;
}

static int selinux_bprm_set_creds(struct linux_binprm *bprm)
{
	const struct task_security_struct *old_tsec;
@@ -2133,14 +2168,10 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
		/* Reset exec SID on execve. */
		new_tsec->exec_sid = 0;

		/*
		 * Minimize confusion: if no_new_privs or nosuid and a
		 * transition is explicitly requested, then fail the exec.
		 */
		if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)
			return -EPERM;
		if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
			return -EACCES;
		/* Fail on NNP or nosuid if not an allowed transition. */
		rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
		if (rc)
			return rc;
	} else {
		/* Check for a default transition on this program. */
		rc = security_transition_sid(old_tsec->sid, isec->sid,
@@ -2148,15 +2179,19 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
					     &new_tsec->sid);
		if (rc)
			return rc;

		/*
		 * Fallback to old SID on NNP or nosuid if not an allowed
		 * transition.
		 */
		rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
		if (rc)
			new_tsec->sid = old_tsec->sid;
	}

	ad.type = LSM_AUDIT_DATA_PATH;
	ad.u.path = bprm->file->f_path;

	if ((bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ||
	    (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS))
		new_tsec->sid = old_tsec->sid;

	if (new_tsec->sid == old_tsec->sid) {
		rc = avc_has_perm(old_tsec->sid, isec->sid,
				  SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
@@ -4272,15 +4307,15 @@ static int selinux_socket_unix_may_send(struct socket *sock,
			    &ad);
}

static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
				    u32 peer_sid,
static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
				    char *addrp, u16 family, u32 peer_sid,
				    struct common_audit_data *ad)
{
	int err;
	u32 if_sid;
	u32 node_sid;

	err = sel_netif_sid(ifindex, &if_sid);
	err = sel_netif_sid(ns, ifindex, &if_sid);
	if (err)
		return err;
	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)
		err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
		if (err)
			return err;
		err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
					       peer_sid, &ad);
		err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
					       addrp, family, peer_sid, &ad);
		if (err) {
			selinux_netlbl_err(skb, err, 0);
			return err;
@@ -4692,10 +4727,9 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
	err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
	if (err) {
		if (err == -EINVAL) {
			audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
				  "SELinux:  unrecognized netlink message"
				  " type=%hu for sclass=%hu\n",
				  nlh->nlmsg_type, sksec->sclass);
			WARN_ONCE(1, "selinux_nlmsg_perm: unrecognized netlink message:"
				  " protocol=%hu nlmsg_type=%hu sclass=%hu\n",
				  sk->sk_protocol, nlh->nlmsg_type, sksec->sclass);
			if (!selinux_enforcing || security_get_allow_unknown())
				err = 0;
		}
@@ -4713,7 +4747,8 @@ out:

#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)
{
	int err;
@@ -4739,14 +4774,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,

	ad.type = LSM_AUDIT_DATA_NET;
	ad.u.net = &net;
	ad.u.net->netif = ifindex;
	ad.u.net->netif = indev->ifindex;
	ad.u.net->family = family;
	if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
		return NF_DROP;

	if (peerlbl_active) {
		err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
					       peer_sid, &ad);
		err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex,
					       addrp, family, peer_sid, &ad);
		if (err) {
			selinux_netlbl_err(skb, err, 1);
			return NF_DROP;
@@ -4775,7 +4810,7 @@ static unsigned int selinux_ipv4_forward(const struct nf_hook_ops *ops,
					 const struct net_device *out,
					 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)
@@ -4785,7 +4820,7 @@ static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops,
					 const struct net_device *out,
					 int (*okfn)(struct sk_buff *))
{
	return selinux_ip_forward(skb, in->ifindex, PF_INET6);
	return selinux_ip_forward(skb, in, PF_INET6);
}
#endif	/* IPV6 */

@@ -4873,11 +4908,13 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
	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)
{
	u32 secmark_perm;
	u32 peer_sid;
	int ifindex = outdev->ifindex;
	struct sock *sk;
	struct common_audit_data ad;
	struct lsm_network_audit net = {0,};
@@ -4958,6 +4995,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
			case PF_INET6:
				if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
					return NF_ACCEPT;
				break;
			default:
				return NF_DROP_ERR(-ECONNREFUSED);
			}
@@ -4989,7 +5027,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
		u32 if_sid;
		u32 node_sid;

		if (sel_netif_sid(ifindex, &if_sid))
		if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid))
			return NF_DROP;
		if (avc_has_perm(peer_sid, if_sid,
				 SECCLASS_NETIF, NETIF__EGRESS, &ad))
@@ -5011,7 +5049,7 @@ static unsigned int selinux_ipv4_postroute(const struct nf_hook_ops *ops,
					   const struct net_device *out,
					   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)
@@ -5021,7 +5059,7 @@ static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops,
					   const struct net_device *out,
					   int (*okfn)(struct sk_buff *))
{
	return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
	return selinux_ip_postroute(skb, out, PF_INET6);
}
#endif	/* IPV6 */

@@ -6035,7 +6073,7 @@ security_initcall(selinux_init);

#if defined(CONFIG_NETFILTER)

static struct nf_hook_ops selinux_ipv4_ops[] = {
static struct nf_hook_ops selinux_nf_ops[] = {
	{
		.hook =		selinux_ipv4_postroute,
		.owner =	THIS_MODULE,
@@ -6056,12 +6094,8 @@ static struct nf_hook_ops selinux_ipv4_ops[] = {
		.pf =		NFPROTO_IPV4,
		.hooknum =	NF_INET_LOCAL_OUT,
		.priority =	NF_IP_PRI_SELINUX_FIRST,
	}
};

	},
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)

static struct nf_hook_ops selinux_ipv6_ops[] = {
	{
		.hook =		selinux_ipv6_postroute,
		.owner =	THIS_MODULE,
@@ -6075,32 +6109,24 @@ static struct nf_hook_ops selinux_ipv6_ops[] = {
		.pf =		NFPROTO_IPV6,
		.hooknum =	NF_INET_FORWARD,
		.priority =	NF_IP6_PRI_SELINUX_FIRST,
	}
};

	},
#endif	/* IPV6 */
};

static int __init selinux_nf_ip_init(void)
{
	int err = 0;
	int err;

	if (!selinux_enabled)
		goto out;
		return 0;

	printk(KERN_DEBUG "SELinux:  Registering netfilter hooks\n");

	err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
	err = nf_register_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops));
	if (err)
		panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
		panic("SELinux: nf_register_hooks: error %d\n", err);

#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
	err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
	if (err)
		panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
#endif	/* IPV6 */

out:
	return err;
	return 0;
}

__initcall(selinux_nf_ip_init);
@@ -6110,10 +6136,7 @@ static void selinux_nf_ip_exit(void)
{
	printk(KERN_DEBUG "SELinux:  Unregistering netfilter hooks\n");

	nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
	nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
#endif	/* IPV6 */
	nf_unregister_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops));
}
#endif

+3 −1
Original line number Diff line number Diff line
@@ -17,9 +17,11 @@
#ifndef _SELINUX_NETIF_H_
#define _SELINUX_NETIF_H_

#include <net/net_namespace.h>

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_ */
+2 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/binfmts.h>
#include <linux/in.h>
#include <linux/spinlock.h>
#include <net/net_namespace.h>
#include "flask.h"
#include "avc.h"

@@ -78,6 +79,7 @@ struct ipc_security_struct {
};

struct netif_security_struct {
	struct net *ns;			/* network namespace */
	int ifindex;			/* device index */
	u32 sid;			/* SID for this interface */
};
+23 −20
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];

/**
 * sel_netif_hashfn - Hashing function for the interface table
 * @ns: the network namespace
 * @ifindex: the network interface
 *
 * Description:
@@ -52,13 +53,14 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
 * 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
 * @ns: the network namespace
 * @ifindex: the network interface
 *
 * Description:
@@ -66,15 +68,15 @@ static inline u32 sel_netif_hashfn(int ifindex)
 * 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;

	list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list)
		/* all of the devices should normally fit in the hash, so we
		 * optimize for that case */
		if (likely(netif->nsec.ifindex == ifindex))
		if (net_eq(netif->nsec.ns, ns) &&
		    netif->nsec.ifindex == ifindex)
			return netif;

	return NULL;
@@ -96,7 +98,7 @@ static int sel_netif_insert(struct sel_netif *netif)
	if (sel_netif_total >= SEL_NETIF_HASH_MAX)
		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]);
	sel_netif_total++;

@@ -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
 * @ns: the network namespace
 * @ifindex: the network interface
 * @sid: interface SID
 *
@@ -130,7 +133,7 @@ static void sel_netif_destroy(struct sel_netif *netif)
 * 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;
	struct sel_netif *netif;
@@ -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
	 * currently support containers */

	dev = dev_get_by_index(&init_net, ifindex);
	dev = dev_get_by_index(ns, ifindex);
	if (unlikely(dev == NULL)) {
		printk(KERN_WARNING
		       "SELinux: failure in sel_netif_sid_slow(),"
@@ -149,7 +152,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
	}

	spin_lock_bh(&sel_netif_lock);
	netif = sel_netif_find(ifindex);
	netif = sel_netif_find(ns, ifindex);
	if (netif != NULL) {
		*sid = netif->nsec.sid;
		ret = 0;
@@ -163,6 +166,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
	ret = security_netif_sid(dev->name, &new->nsec.sid);
	if (ret != 0)
		goto out;
	new->nsec.ns = ns;
	new->nsec.ifindex = ifindex;
	ret = sel_netif_insert(new);
	if (ret != 0)
@@ -184,6 +188,7 @@ out:

/**
 * sel_netif_sid - Lookup the SID of a network interface
 * @ns: the network namespace
 * @ifindex: the network interface
 * @sid: interface SID
 *
@@ -195,12 +200,12 @@ out:
 * 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;

	rcu_read_lock();
	netif = sel_netif_find(ifindex);
	netif = sel_netif_find(ns, ifindex);
	if (likely(netif != NULL)) {
		*sid = netif->nsec.sid;
		rcu_read_unlock();
@@ -208,11 +213,12 @@ int sel_netif_sid(int ifindex, u32 *sid)
	}
	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
 * @ns: the network namespace
 * @ifindex: the network interface
 *
 * Description:
@@ -220,13 +226,13 @@ int sel_netif_sid(int ifindex, u32 *sid)
 * 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;

	rcu_read_lock();
	spin_lock_bh(&sel_netif_lock);
	netif = sel_netif_find(ifindex);
	netif = sel_netif_find(ns, ifindex);
	if (netif)
		sel_netif_destroy(netif);
	spin_unlock_bh(&sel_netif_lock);
@@ -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);

	if (dev_net(dev) != &init_net)
		return NOTIFY_DONE;

	if (event == NETDEV_DOWN)
		sel_netif_kill(dev->ifindex);
		sel_netif_kill(dev_net(dev), dev->ifindex);

	return NOTIFY_DONE;
}
+8 −6
Original line number Diff line number Diff line
@@ -728,7 +728,7 @@ static int security_validtrans_handle_fail(struct context *ocontext,
	if (context_struct_to_string(tcontext, &t, &tlen))
		goto out;
	audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
		  "security_validate_transition:  denied for"
		  "op=security_validate_transition seresult=denied"
		  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
		  o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
out:
@@ -877,7 +877,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
			audit_log(current->audit_context,
				  GFP_ATOMIC, AUDIT_SELINUX_ERR,
				  "op=security_bounded_transition "
				  "result=denied "
				  "seresult=denied "
				  "oldcontext=%s newcontext=%s",
				  old_name, new_name);
		}
@@ -1351,8 +1351,8 @@ static int compute_sid_handle_invalid_context(
	if (context_struct_to_string(newcontext, &n, &nlen))
		goto out;
	audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
		  "security_compute_sid:  invalid context %s"
		  " for scontext=%s"
		  "op=security_compute_sid invalid_context=%s"
		  " scontext=%s"
		  " tcontext=%s"
		  " tclass=%s",
		  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)
		rc = convert_context_handle_invalid_context(&newcon);
		if (rc) {
			if (!context_struct_to_string(&newcon, &s, &len)) {
				audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
					  "security_sid_mls_copy: invalid context %s", s);
				audit_log(current->audit_context,
					  GFP_ATOMIC, AUDIT_SELINUX_ERR,
					  "op=security_sid_mls_copy "
					  "invalid_context=%s", s);
				kfree(s);
			}
			goto out_unlock;