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: Paul Moore <paul.moore@hp.com> Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
parent
a639e7ca8e
commit
c9b7b97937
1 changed files with 18 additions and 22 deletions
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue