1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Network port table
4  *
5  * SELinux must keep a mapping of network ports to labels/SIDs.  This
6  * mapping is maintained as part of the normal policy but a fast cache is
7  * needed to reduce the lookup overhead.
8  *
9  * Author: Paul Moore <paul@paul-moore.com>
10  *
11  * This code is heavily based on the "netif" concept originally developed by
12  * James Morris <jmorris@redhat.com>
13  *   (see security/selinux/netif.c for more information)
14  */
15 
16 /*
17  * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
18  */
19 
20 #include <linux/types.h>
21 #include <linux/rcupdate.h>
22 #include <linux/list.h>
23 #include <linux/slab.h>
24 #include <linux/spinlock.h>
25 #include <linux/in.h>
26 #include <linux/in6.h>
27 #include <linux/ip.h>
28 #include <linux/ipv6.h>
29 #include <net/ip.h>
30 #include <net/ipv6.h>
31 
32 #include "netport.h"
33 #include "objsec.h"
34 
35 #define SEL_NETPORT_HASH_SIZE       256
36 #define SEL_NETPORT_HASH_BKT_LIMIT   16
37 
38 struct sel_netport_bkt {
39 	int size;
40 	struct list_head list;
41 };
42 
43 struct sel_netport {
44 	struct netport_security_struct psec;
45 
46 	struct list_head list;
47 	struct rcu_head rcu;
48 };
49 
50 static DEFINE_SPINLOCK(sel_netport_lock);
51 static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE];
52 
53 /**
54  * sel_netport_hashfn - Hashing function for the port table
55  * @pnum: port number
56  *
57  * Description:
58  * This is the hashing function for the port table, it returns the bucket
59  * number for the given port.
60  *
61  */
62 static unsigned int sel_netport_hashfn(u16 pnum)
63 {
64 	return (pnum & (SEL_NETPORT_HASH_SIZE - 1));
65 }
66 
67 /**
68  * sel_netport_find - Search for a port record
69  * @protocol: protocol
70  * @pnum: port
71  *
72  * Description:
73  * Search the network port table and return the matching record.  If an entry
74  * can not be found in the table return NULL.
75  *
76  */
77 static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)
78 {
79 	unsigned int idx;
80 	struct sel_netport *port;
81 
82 	idx = sel_netport_hashfn(pnum);
83 	list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list)
84 		if (port->psec.port == pnum && port->psec.protocol == protocol)
85 			return port;
86 
87 	return NULL;
88 }
89 
90 /**
91  * sel_netport_insert - Insert a new port into the table
92  * @port: the new port record
93  *
94  * Description:
95  * Add a new port record to the network address hash table.
96  *
97  */
98 static void sel_netport_insert(struct sel_netport *port)
99 {
100 	unsigned int idx;
101 
102 	/* we need to impose a limit on the growth of the hash table so check
103 	 * this bucket to make sure it is within the specified bounds */
104 	idx = sel_netport_hashfn(port->psec.port);
105 	list_add_rcu(&port->list, &sel_netport_hash[idx].list);
106 	if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) {
107 		struct sel_netport *tail;
108 		tail = list_entry(
109 			rcu_dereference_protected(
110 				list_tail_rcu(&sel_netport_hash[idx].list),
111 				lockdep_is_held(&sel_netport_lock)),
112 			struct sel_netport, list);
113 		list_del_rcu(&tail->list);
114 		kfree_rcu(tail, rcu);
115 	} else
116 		sel_netport_hash[idx].size++;
117 }
118 
119 /**
120  * sel_netport_sid_slow - Lookup the SID of a network address using the policy
121  * @protocol: protocol
122  * @pnum: port
123  * @sid: port SID
124  *
125  * Description:
126  * This function determines the SID of a network port by querying the security
127  * policy.  The result is added to the network port table to speedup future
128  * queries.  Returns zero on success, negative values on failure.
129  *
130  */
131 static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
132 {
133 	int ret;
134 	struct sel_netport *port;
135 	struct sel_netport *new;
136 
137 	spin_lock_bh(&sel_netport_lock);
138 	port = sel_netport_find(protocol, pnum);
139 	if (port != NULL) {
140 		*sid = port->psec.sid;
141 		spin_unlock_bh(&sel_netport_lock);
142 		return 0;
143 	}
144 
145 	ret = security_port_sid(protocol, pnum, sid);
146 	if (ret != 0)
147 		goto out;
148 
149 	/* If this memory allocation fails still return 0. The SID
150 	 * is valid, it just won't be added to the cache.
151 	 */
152 	new = kmalloc(sizeof(*new), GFP_ATOMIC);
153 	if (new) {
154 		new->psec.port = pnum;
155 		new->psec.protocol = protocol;
156 		new->psec.sid = *sid;
157 		sel_netport_insert(new);
158 	}
159 
160 out:
161 	spin_unlock_bh(&sel_netport_lock);
162 	if (unlikely(ret))
163 		pr_warn("SELinux: failure in %s(), unable to determine network port label\n",
164 			__func__);
165 	return ret;
166 }
167 
168 /**
169  * sel_netport_sid - Lookup the SID of a network port
170  * @protocol: protocol
171  * @pnum: port
172  * @sid: port SID
173  *
174  * Description:
175  * This function determines the SID of a network port using the fastest method
176  * possible.  First the port table is queried, but if an entry can't be found
177  * then the policy is queried and the result is added to the table to speedup
178  * future queries.  Returns zero on success, negative values on failure.
179  *
180  */
181 int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid)
182 {
183 	struct sel_netport *port;
184 
185 	rcu_read_lock();
186 	port = sel_netport_find(protocol, pnum);
187 	if (likely(port != NULL)) {
188 		*sid = port->psec.sid;
189 		rcu_read_unlock();
190 		return 0;
191 	}
192 	rcu_read_unlock();
193 
194 	return sel_netport_sid_slow(protocol, pnum, sid);
195 }
196 
197 /**
198  * sel_netport_flush - Flush the entire network port table
199  *
200  * Description:
201  * Remove all entries from the network address table.
202  *
203  */
204 void sel_netport_flush(void)
205 {
206 	unsigned int idx;
207 	struct sel_netport *port, *port_tmp;
208 
209 	spin_lock_bh(&sel_netport_lock);
210 	for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) {
211 		list_for_each_entry_safe(port, port_tmp,
212 					 &sel_netport_hash[idx].list, list) {
213 			list_del_rcu(&port->list);
214 			kfree_rcu(port, rcu);
215 		}
216 		sel_netport_hash[idx].size = 0;
217 	}
218 	spin_unlock_bh(&sel_netport_lock);
219 }
220 
221 static __init int sel_netport_init(void)
222 {
223 	int iter;
224 
225 	if (!selinux_enabled_boot)
226 		return 0;
227 
228 	for (iter = 0; iter < SEL_NETPORT_HASH_SIZE; iter++) {
229 		INIT_LIST_HEAD(&sel_netport_hash[iter].list);
230 		sel_netport_hash[iter].size = 0;
231 	}
232 
233 	return 0;
234 }
235 
236 __initcall(sel_netport_init);
237