xref: /linux/security/selinux/netnode.c (revision 8bbecfb402f76b6977a6c5661ad3cfb0051a9776)
1  // SPDX-License-Identifier: GPL-2.0-only
2  /*
3   * Network node table
4   *
5   * SELinux must keep a mapping of network nodes 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 since most of these queries happen on
8   * a per-packet basis.
9   *
10   * Author: Paul Moore <paul@paul-moore.com>
11   *
12   * This code is heavily based on the "netif" concept originally developed by
13   * James Morris <jmorris@redhat.com>
14   *   (see security/selinux/netif.c for more information)
15   */
16  
17  /*
18   * (c) Copyright Hewlett-Packard Development Company, L.P., 2007
19   */
20  
21  #include <linux/types.h>
22  #include <linux/rcupdate.h>
23  #include <linux/list.h>
24  #include <linux/slab.h>
25  #include <linux/spinlock.h>
26  #include <linux/in.h>
27  #include <linux/in6.h>
28  #include <linux/ip.h>
29  #include <linux/ipv6.h>
30  #include <net/ip.h>
31  #include <net/ipv6.h>
32  
33  #include "netnode.h"
34  #include "objsec.h"
35  
36  #define SEL_NETNODE_HASH_SIZE       256
37  #define SEL_NETNODE_HASH_BKT_LIMIT   16
38  
39  struct sel_netnode_bkt {
40  	unsigned int size;
41  	struct list_head list;
42  };
43  
44  struct sel_netnode {
45  	struct netnode_security_struct nsec;
46  
47  	struct list_head list;
48  	struct rcu_head rcu;
49  };
50  
51  /* NOTE: we are using a combined hash table for both IPv4 and IPv6, the reason
52   * for this is that I suspect most users will not make heavy use of both
53   * address families at the same time so one table will usually end up wasted,
54   * if this becomes a problem we can always add a hash table for each address
55   * family later */
56  
57  static DEFINE_SPINLOCK(sel_netnode_lock);
58  static struct sel_netnode_bkt sel_netnode_hash[SEL_NETNODE_HASH_SIZE];
59  
60  /**
61   * sel_netnode_hashfn_ipv4 - IPv4 hashing function for the node table
62   * @addr: IPv4 address
63   *
64   * Description:
65   * This is the IPv4 hashing function for the node interface table, it returns
66   * the bucket number for the given IP address.
67   *
68   */
69  static unsigned int sel_netnode_hashfn_ipv4(__be32 addr)
70  {
71  	/* at some point we should determine if the mismatch in byte order
72  	 * affects the hash function dramatically */
73  	return (addr & (SEL_NETNODE_HASH_SIZE - 1));
74  }
75  
76  /**
77   * sel_netnode_hashfn_ipv6 - IPv6 hashing function for the node table
78   * @addr: IPv6 address
79   *
80   * Description:
81   * This is the IPv6 hashing function for the node interface table, it returns
82   * the bucket number for the given IP address.
83   *
84   */
85  static unsigned int sel_netnode_hashfn_ipv6(const struct in6_addr *addr)
86  {
87  	/* just hash the least significant 32 bits to keep things fast (they
88  	 * are the most likely to be different anyway), we can revisit this
89  	 * later if needed */
90  	return (addr->s6_addr32[3] & (SEL_NETNODE_HASH_SIZE - 1));
91  }
92  
93  /**
94   * sel_netnode_find - Search for a node record
95   * @addr: IP address
96   * @family: address family
97   *
98   * Description:
99   * Search the network node table and return the record matching @addr.  If an
100   * entry can not be found in the table return NULL.
101   *
102   */
103  static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
104  {
105  	unsigned int idx;
106  	struct sel_netnode *node;
107  
108  	switch (family) {
109  	case PF_INET:
110  		idx = sel_netnode_hashfn_ipv4(*(__be32 *)addr);
111  		break;
112  	case PF_INET6:
113  		idx = sel_netnode_hashfn_ipv6(addr);
114  		break;
115  	default:
116  		BUG();
117  		return NULL;
118  	}
119  
120  	list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list)
121  		if (node->nsec.family == family)
122  			switch (family) {
123  			case PF_INET:
124  				if (node->nsec.addr.ipv4 == *(__be32 *)addr)
125  					return node;
126  				break;
127  			case PF_INET6:
128  				if (ipv6_addr_equal(&node->nsec.addr.ipv6,
129  						    addr))
130  					return node;
131  				break;
132  			}
133  
134  	return NULL;
135  }
136  
137  /**
138   * sel_netnode_insert - Insert a new node into the table
139   * @node: the new node record
140   *
141   * Description:
142   * Add a new node record to the network address hash table.
143   *
144   */
145  static void sel_netnode_insert(struct sel_netnode *node)
146  {
147  	unsigned int idx;
148  
149  	switch (node->nsec.family) {
150  	case PF_INET:
151  		idx = sel_netnode_hashfn_ipv4(node->nsec.addr.ipv4);
152  		break;
153  	case PF_INET6:
154  		idx = sel_netnode_hashfn_ipv6(&node->nsec.addr.ipv6);
155  		break;
156  	default:
157  		BUG();
158  		return;
159  	}
160  
161  	/* we need to impose a limit on the growth of the hash table so check
162  	 * this bucket to make sure it is within the specified bounds */
163  	list_add_rcu(&node->list, &sel_netnode_hash[idx].list);
164  	if (sel_netnode_hash[idx].size == SEL_NETNODE_HASH_BKT_LIMIT) {
165  		struct sel_netnode *tail;
166  		tail = list_entry(
167  			rcu_dereference_protected(sel_netnode_hash[idx].list.prev,
168  						  lockdep_is_held(&sel_netnode_lock)),
169  			struct sel_netnode, list);
170  		list_del_rcu(&tail->list);
171  		kfree_rcu(tail, rcu);
172  	} else
173  		sel_netnode_hash[idx].size++;
174  }
175  
176  /**
177   * sel_netnode_sid_slow - Lookup the SID of a network address using the policy
178   * @addr: the IP address
179   * @family: the address family
180   * @sid: node SID
181   *
182   * Description:
183   * This function determines the SID of a network address by querying the
184   * security policy.  The result is added to the network address table to
185   * speedup future queries.  Returns zero on success, negative values on
186   * failure.
187   *
188   */
189  static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
190  {
191  	int ret;
192  	struct sel_netnode *node;
193  	struct sel_netnode *new;
194  
195  	spin_lock_bh(&sel_netnode_lock);
196  	node = sel_netnode_find(addr, family);
197  	if (node != NULL) {
198  		*sid = node->nsec.sid;
199  		spin_unlock_bh(&sel_netnode_lock);
200  		return 0;
201  	}
202  
203  	new = kzalloc(sizeof(*new), GFP_ATOMIC);
204  	switch (family) {
205  	case PF_INET:
206  		ret = security_node_sid(&selinux_state, PF_INET,
207  					addr, sizeof(struct in_addr), sid);
208  		if (new)
209  			new->nsec.addr.ipv4 = *(__be32 *)addr;
210  		break;
211  	case PF_INET6:
212  		ret = security_node_sid(&selinux_state, PF_INET6,
213  					addr, sizeof(struct in6_addr), sid);
214  		if (new)
215  			new->nsec.addr.ipv6 = *(struct in6_addr *)addr;
216  		break;
217  	default:
218  		BUG();
219  		ret = -EINVAL;
220  	}
221  	if (ret == 0 && new) {
222  		new->nsec.family = family;
223  		new->nsec.sid = *sid;
224  		sel_netnode_insert(new);
225  	} else
226  		kfree(new);
227  
228  	spin_unlock_bh(&sel_netnode_lock);
229  	if (unlikely(ret))
230  		pr_warn("SELinux: failure in %s(), unable to determine network node label\n",
231  			__func__);
232  	return ret;
233  }
234  
235  /**
236   * sel_netnode_sid - Lookup the SID of a network address
237   * @addr: the IP address
238   * @family: the address family
239   * @sid: node SID
240   *
241   * Description:
242   * This function determines the SID of a network address using the fastest
243   * method possible.  First the address table is queried, but if an entry
244   * can't be found then the policy is queried and the result is added to the
245   * table to speedup future queries.  Returns zero on success, negative values
246   * on failure.
247   *
248   */
249  int sel_netnode_sid(void *addr, u16 family, u32 *sid)
250  {
251  	struct sel_netnode *node;
252  
253  	rcu_read_lock();
254  	node = sel_netnode_find(addr, family);
255  	if (node != NULL) {
256  		*sid = node->nsec.sid;
257  		rcu_read_unlock();
258  		return 0;
259  	}
260  	rcu_read_unlock();
261  
262  	return sel_netnode_sid_slow(addr, family, sid);
263  }
264  
265  /**
266   * sel_netnode_flush - Flush the entire network address table
267   *
268   * Description:
269   * Remove all entries from the network address table.
270   *
271   */
272  void sel_netnode_flush(void)
273  {
274  	unsigned int idx;
275  	struct sel_netnode *node, *node_tmp;
276  
277  	spin_lock_bh(&sel_netnode_lock);
278  	for (idx = 0; idx < SEL_NETNODE_HASH_SIZE; idx++) {
279  		list_for_each_entry_safe(node, node_tmp,
280  					 &sel_netnode_hash[idx].list, list) {
281  				list_del_rcu(&node->list);
282  				kfree_rcu(node, rcu);
283  		}
284  		sel_netnode_hash[idx].size = 0;
285  	}
286  	spin_unlock_bh(&sel_netnode_lock);
287  }
288  
289  static __init int sel_netnode_init(void)
290  {
291  	int iter;
292  
293  	if (!selinux_enabled_boot)
294  		return 0;
295  
296  	for (iter = 0; iter < SEL_NETNODE_HASH_SIZE; iter++) {
297  		INIT_LIST_HEAD(&sel_netnode_hash[iter].list);
298  		sel_netnode_hash[iter].size = 0;
299  	}
300  
301  	return 0;
302  }
303  
304  __initcall(sel_netnode_init);
305