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

Commit c9b7b979 authored by Paul Moore's avatar Paul Moore Committed by James Morris
Browse files

SELinux: Fix a RCU free problem with the netport cache



The netport cache doesn't free resources in a manner which is safe or orderly.
This patch fixes this by adding in a missing call to rcu_dereference() in
sel_netport_insert() as well as some general cleanup throughout the file.

Signed-off-by: default avatarPaul Moore <paul.moore@hp.com>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent a639e7ca
Loading
Loading
Loading
Loading
+18 −22
Original line number Diff line number Diff line
@@ -114,8 +114,7 @@ static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)

	idx = sel_netport_hashfn(pnum);
	list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list)
		if (port->psec.port == pnum &&
		    port->psec.protocol == protocol)
		if (port->psec.port == pnum && port->psec.protocol == protocol)
			return port;

	return NULL;
@@ -126,11 +125,10 @@ static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)
 * @port: the new port record
 *
 * Description:
 * Add a new port record to the network address hash table.  Returns zero on
 * success, negative values on failure.
 * Add a new port record to the network address hash table.
 *
 */
static int sel_netport_insert(struct sel_netport *port)
static void sel_netport_insert(struct sel_netport *port)
{
	unsigned int idx;

@@ -140,13 +138,13 @@ static int sel_netport_insert(struct sel_netport *port)
	list_add_rcu(&port->list, &sel_netport_hash[idx].list);
	if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) {
		struct sel_netport *tail;
		tail = list_entry(port->list.prev, struct sel_netport, list);
		list_del_rcu(port->list.prev);
		tail = list_entry(
			rcu_dereference(sel_netport_hash[idx].list.prev),
			struct sel_netport, list);
		list_del_rcu(&tail->list);
		call_rcu(&tail->rcu, sel_netport_free);
	} else
		sel_netport_hash[idx].size++;

	return 0;
}

/**
@@ -163,7 +161,7 @@ static int sel_netport_insert(struct sel_netport *port)
 */
static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
{
	int ret;
	int ret = -ENOMEM;
	struct sel_netport *port;
	struct sel_netport *new = NULL;

@@ -171,23 +169,20 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
	port = sel_netport_find(protocol, pnum);
	if (port != NULL) {
		*sid = port->psec.sid;
		ret = 0;
		goto out;
		spin_unlock_bh(&sel_netport_lock);
		return 0;
	}
	new = kzalloc(sizeof(*new), GFP_ATOMIC);
	if (new == NULL) {
		ret = -ENOMEM;
	if (new == NULL)
		goto out;
	}
	ret = security_port_sid(protocol, pnum, &new->psec.sid);
	ret = security_port_sid(protocol, pnum, sid);
	if (ret != 0)
		goto out;

	new->psec.port = pnum;
	new->psec.protocol = protocol;
	ret = sel_netport_insert(new);
	if (ret != 0)
		goto out;
	*sid = new->psec.sid;
	new->psec.sid = *sid;
	sel_netport_insert(new);

out:
	spin_unlock_bh(&sel_netport_lock);
@@ -239,11 +234,12 @@ int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid)
static void sel_netport_flush(void)
{
	unsigned int idx;
	struct sel_netport *port;
	struct sel_netport *port, *port_tmp;

	spin_lock_bh(&sel_netport_lock);
	for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) {
		list_for_each_entry(port, &sel_netport_hash[idx].list, list) {
		list_for_each_entry_safe(port, port_tmp,
					 &sel_netport_hash[idx].list, list) {
			list_del_rcu(&port->list);
			call_rcu(&port->rcu, sel_netport_free);
		}