lkml.org 
[lkml]   [2019]   [Apr]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH net] selinux: fix potential memory leak in selinux_socket_bind()
Date
There might be memory leak if avc_has_perm() is failed after calling
sel_netport_sid() or sel_netnode_sid(), port and node list must be deleted
and freed firstly before it goto out.
call trace:
__sys_bind
security_socket_bind
selinux_socket_bind
sel_netport_sid
sel_netnode_sid

Fixes: 3e11217263("SELinux: Add network port SID cache")
Fixes: 88b7d370bb("selinux: fix address family in bind() and connect() to match address/port")
Signed-off-by: Mao Wenan <maowenan@huawei.com>
---
security/selinux/hooks.c | 15 +++++++++++----
security/selinux/include/netnode.h | 1 +
security/selinux/include/netport.h | 1 +
security/selinux/netnode.c | 38 ++++++++++++++++++++++++++++++++++++++
security/selinux/netport.c | 27 +++++++++++++++++++++++++++
5 files changed, 78 insertions(+), 4 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d5fdcb0..9f60336 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4570,8 +4570,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
sksec->sid, sid,
sksec->sclass,
SOCKET__NAME_BIND, &ad);
- if (err)
+ if (err) {
+ sel_netport_remove(sk->sk_protocol, snum);
goto out;
+ }
}
}

@@ -4598,9 +4600,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
}

err = sel_netnode_sid(addrp, family_sa, &sid);
- if (err)
+ if (err) {
+ sel_netport_remove(sk->sk_protocol, snum);
goto out;
-
+ }
if (family_sa == AF_INET)
ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
else
@@ -4609,9 +4612,13 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
err = avc_has_perm(&selinux_state,
sksec->sid, sid,
sksec->sclass, node_perm, &ad);
- if (err)
+ if (err) {
+ sel_netport_remove(sk->sk_protocol, snum);
+ sel_netnode_remove(addrp, family_sa);
goto out;
+ }
}
+
out:
return err;
err_af:
diff --git a/security/selinux/include/netnode.h b/security/selinux/include/netnode.h
index 937668d..a5b2221 100644
--- a/security/selinux/include/netnode.h
+++ b/security/selinux/include/netnode.h
@@ -30,5 +30,6 @@
void sel_netnode_flush(void);

int sel_netnode_sid(void *addr, u16 family, u32 *sid);
+void sel_netnode_remove(void *addr, u16 family);

#endif
diff --git a/security/selinux/include/netport.h b/security/selinux/include/netport.h
index d1ce896..5bd4d04 100644
--- a/security/selinux/include/netport.h
+++ b/security/selinux/include/netport.h
@@ -29,5 +29,6 @@
void sel_netport_flush(void);

int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid);
+void sel_netport_remove(u8 protocol, u16 pnum);

#endif
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index afa0d43..a91fbd9 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -185,6 +185,44 @@ static void sel_netnode_insert(struct sel_netnode *node)
}

/**
+ * sel_netnode_remove - Remove a node from the table
+ * @node: the node to remove
+ *
+ * Description:
+ * Remove a node record from the network address hash table.
+ *
+ */
+void sel_netnode_remove(void *addr, u16 family)
+{
+ unsigned int idx;
+ struct sel_netnode *node;
+
+ spin_lock_bh(&sel_netnode_lock);
+ node = sel_netnode_find(addr, family);
+ if (node == NULL) {
+ spin_unlock_bh(&sel_netnode_lock);
+ return;
+ }
+
+ switch (node->nsec.family) {
+ case PF_INET:
+ idx = sel_netnode_hashfn_ipv4(node->nsec.addr.ipv4);
+ break;
+ case PF_INET6:
+ idx = sel_netnode_hashfn_ipv6(&node->nsec.addr.ipv6);
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ list_del_rcu(&node->list);
+ kfree_rcu(node, rcu);
+ sel_netnode_hash[idx].size--;
+ spin_unlock_bh(&sel_netnode_lock);
+}
+
+/**
* sel_netnode_sid_slow - Lookup the SID of a network address using the policy
* @addr: the IP address
* @family: the address family
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
index 7a141ca..258db2f 100644
--- a/security/selinux/netport.c
+++ b/security/selinux/netport.c
@@ -134,6 +134,33 @@ static void sel_netport_insert(struct sel_netport *port)
}

/**
+ * sel_netport_remove - Remove a port from the table
+ * @port: the port to remove
+ *
+ * Description:
+ * Remove a port record from the network address hash table.
+ *
+ */
+void sel_netport_remove(u8 protocol, u16 pnum)
+{
+ unsigned int idx;
+ struct sel_netport *port;
+
+ spin_lock_bh(&sel_netport_lock);
+ port = sel_netport_find(protocol, pnum);
+ if (port == NULL) {
+ spin_unlock_bh(&sel_netport_lock);
+ return;
+ }
+
+ idx = sel_netport_hashfn(port->psec.port);
+ list_del_rcu(&port->list);
+ kfree_rcu(port, rcu);
+ sel_netport_hash[idx].size--;
+ spin_unlock_bh(&sel_netport_lock);
+}
+
+/**
* sel_netport_sid_slow - Lookup the SID of a network address using the policy
* @protocol: protocol
* @pnum: port
--
2.7.4
\
 
 \ /
  Last update: 2019-04-17 11:16    [W:0.129 / U:1.828 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site