Skip to content

Commit

Permalink
SMACK: Add the rcu synchronization mechanism in ipv6 hooks
Browse files Browse the repository at this point in the history
Add the rcu synchronization mechanism for accessing smk_ipv6_port_list
in smack IPv6 hooks. Access to the port list is vulnerable to a race
condition issue,it does not apply proper synchronization methods while
working on critical section. It is possible that when one thread is
reading the list, at the same time another thread is modifying the
same port list, which can cause the major problems.

To ensure proper synchronization between two threads, rcu mechanism
has been applied while accessing and modifying the port list. RCU will
also not affect the performance, as there are more accesses than
modification where RCU is most effective synchronization mechanism.

Signed-off-by: Vishal Goel <[email protected]>
Signed-off-by: Himanshu Shukla <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
  • Loading branch information
Vishal Goel authored and cschaufler committed Jan 10, 2017
1 parent 916cafd commit 3c7ce34
Showing 1 changed file with 15 additions and 5 deletions.
20 changes: 15 additions & 5 deletions security/smack/smack_lsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#define SMK_SENDING 2

#ifdef SMACK_IPV6_PORT_LABELING
DEFINE_MUTEX(smack_ipv6_lock);
static LIST_HEAD(smk_ipv6_port_list);
#endif
static struct kmem_cache *smack_inode_cache;
Expand Down Expand Up @@ -2603,17 +2604,20 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
* on the bound socket. Take the changes to the port
* as well.
*/
list_for_each_entry(spp, &smk_ipv6_port_list, list) {
rcu_read_lock();
list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) {
if (sk != spp->smk_sock)
continue;
spp->smk_in = ssp->smk_in;
spp->smk_out = ssp->smk_out;
rcu_read_unlock();
return;
}
/*
* A NULL address is only used for updating existing
* bound entries. If there isn't one, it's OK.
*/
rcu_read_unlock();
return;
}

Expand All @@ -2629,16 +2633,18 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
* Look for an existing port list entry.
* This is an indication that a port is getting reused.
*/
list_for_each_entry(spp, &smk_ipv6_port_list, list) {
rcu_read_lock();
list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) {
if (spp->smk_port != port)
continue;
spp->smk_port = port;
spp->smk_sock = sk;
spp->smk_in = ssp->smk_in;
spp->smk_out = ssp->smk_out;
rcu_read_unlock();
return;
}

rcu_read_unlock();
/*
* A new port entry is required.
*/
Expand All @@ -2651,7 +2657,9 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
spp->smk_in = ssp->smk_in;
spp->smk_out = ssp->smk_out;

list_add(&spp->list, &smk_ipv6_port_list);
mutex_lock(&smack_ipv6_lock);
list_add_rcu(&spp->list, &smk_ipv6_port_list);
mutex_unlock(&smack_ipv6_lock);
return;
}

Expand Down Expand Up @@ -2702,14 +2710,16 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
return 0;

port = ntohs(address->sin6_port);
list_for_each_entry(spp, &smk_ipv6_port_list, list) {
rcu_read_lock();
list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) {
if (spp->smk_port != port)
continue;
object = spp->smk_in;
if (act == SMK_CONNECTING)
ssp->smk_packet = spp->smk_out;
break;
}
rcu_read_unlock();

return smk_ipv6_check(skp, object, address, act);
}
Expand Down

0 comments on commit 3c7ce34

Please sign in to comment.