[PATCH net] selinux: fix potential memory leak in selinux_socket_bind()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
---
 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




[Index of Archives]     [Kernel Development]     [Kernel Announce]     [Kernel Newbies]     [Linux Networking Development]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Device Mapper]

  Powered by Linux