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

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
...@@ -114,8 +114,7 @@ static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum) ...@@ -114,8 +114,7 @@ static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)
idx = sel_netport_hashfn(pnum); idx = sel_netport_hashfn(pnum);
list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list) list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list)
if (port->psec.port == pnum && if (port->psec.port == pnum && port->psec.protocol == protocol)
port->psec.protocol == protocol)
return port; return port;
return NULL; return NULL;
...@@ -126,11 +125,10 @@ static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum) ...@@ -126,11 +125,10 @@ static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)
* @port: the new port record * @port: the new port record
* *
* Description: * Description:
* Add a new port record to the network address hash table. Returns zero on * Add a new port record to the network address hash table.
* success, negative values on failure.
* *
*/ */
static int sel_netport_insert(struct sel_netport *port) static void sel_netport_insert(struct sel_netport *port)
{ {
unsigned int idx; unsigned int idx;
...@@ -140,13 +138,13 @@ static int sel_netport_insert(struct sel_netport *port) ...@@ -140,13 +138,13 @@ static int sel_netport_insert(struct sel_netport *port)
list_add_rcu(&port->list, &sel_netport_hash[idx].list); list_add_rcu(&port->list, &sel_netport_hash[idx].list);
if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) { if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) {
struct sel_netport *tail; struct sel_netport *tail;
tail = list_entry(port->list.prev, struct sel_netport, list); tail = list_entry(
list_del_rcu(port->list.prev); rcu_dereference(sel_netport_hash[idx].list.prev),
struct sel_netport, list);
list_del_rcu(&tail->list);
call_rcu(&tail->rcu, sel_netport_free); call_rcu(&tail->rcu, sel_netport_free);
} else } else
sel_netport_hash[idx].size++; sel_netport_hash[idx].size++;
return 0;
} }
/** /**
...@@ -163,7 +161,7 @@ static int sel_netport_insert(struct sel_netport *port) ...@@ -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) static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
{ {
int ret; int ret = -ENOMEM;
struct sel_netport *port; struct sel_netport *port;
struct sel_netport *new = NULL; struct sel_netport *new = NULL;
...@@ -171,23 +169,20 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) ...@@ -171,23 +169,20 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
port = sel_netport_find(protocol, pnum); port = sel_netport_find(protocol, pnum);
if (port != NULL) { if (port != NULL) {
*sid = port->psec.sid; *sid = port->psec.sid;
ret = 0; spin_unlock_bh(&sel_netport_lock);
goto out; return 0;
} }
new = kzalloc(sizeof(*new), GFP_ATOMIC); new = kzalloc(sizeof(*new), GFP_ATOMIC);
if (new == NULL) { if (new == NULL)
ret = -ENOMEM;
goto out; goto out;
} ret = security_port_sid(protocol, pnum, sid);
ret = security_port_sid(protocol, pnum, &new->psec.sid);
if (ret != 0) if (ret != 0)
goto out; goto out;
new->psec.port = pnum; new->psec.port = pnum;
new->psec.protocol = protocol; new->psec.protocol = protocol;
ret = sel_netport_insert(new); new->psec.sid = *sid;
if (ret != 0) sel_netport_insert(new);
goto out;
*sid = new->psec.sid;
out: out:
spin_unlock_bh(&sel_netport_lock); spin_unlock_bh(&sel_netport_lock);
...@@ -239,11 +234,12 @@ int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid) ...@@ -239,11 +234,12 @@ int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid)
static void sel_netport_flush(void) static void sel_netport_flush(void)
{ {
unsigned int idx; unsigned int idx;
struct sel_netport *port; struct sel_netport *port, *port_tmp;
spin_lock_bh(&sel_netport_lock); spin_lock_bh(&sel_netport_lock);
for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) { 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); list_del_rcu(&port->list);
call_rcu(&port->rcu, sel_netport_free); call_rcu(&port->rcu, sel_netport_free);
} }
......
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