Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * NetLabel Network Address Lists
4 : : *
5 : : * This file contains network address list functions used to manage ordered
6 : : * lists of network addresses for use by the NetLabel subsystem. The NetLabel
7 : : * system manages static and dynamic label mappings for network protocols such
8 : : * as CIPSO and RIPSO.
9 : : *
10 : : * Author: Paul Moore <paul@paul-moore.com>
11 : : */
12 : :
13 : : /*
14 : : * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
15 : : */
16 : :
17 : : #include <linux/types.h>
18 : : #include <linux/rcupdate.h>
19 : : #include <linux/list.h>
20 : : #include <linux/spinlock.h>
21 : : #include <linux/in.h>
22 : : #include <linux/in6.h>
23 : : #include <linux/ip.h>
24 : : #include <linux/ipv6.h>
25 : : #include <net/ip.h>
26 : : #include <net/ipv6.h>
27 : : #include <linux/audit.h>
28 : :
29 : : #include "netlabel_addrlist.h"
30 : :
31 : : /*
32 : : * Address List Functions
33 : : */
34 : :
35 : : /**
36 : : * netlbl_af4list_search - Search for a matching IPv4 address entry
37 : : * @addr: IPv4 address
38 : : * @head: the list head
39 : : *
40 : : * Description:
41 : : * Searches the IPv4 address list given by @head. If a matching address entry
42 : : * is found it is returned, otherwise NULL is returned. The caller is
43 : : * responsible for calling the rcu_read_[un]lock() functions.
44 : : *
45 : : */
46 : 0 : struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
47 : : struct list_head *head)
48 : : {
49 : 0 : struct netlbl_af4list *iter;
50 : :
51 [ # # # # ]: 0 : list_for_each_entry_rcu(iter, head, list)
52 [ # # # # : 0 : if (iter->valid && (addr & iter->mask) == iter->addr)
# # # # ]
53 : 0 : return iter;
54 : :
55 : : return NULL;
56 : : }
57 : :
58 : : /**
59 : : * netlbl_af4list_search_exact - Search for an exact IPv4 address entry
60 : : * @addr: IPv4 address
61 : : * @mask: IPv4 address mask
62 : : * @head: the list head
63 : : *
64 : : * Description:
65 : : * Searches the IPv4 address list given by @head. If an exact match if found
66 : : * it is returned, otherwise NULL is returned. The caller is responsible for
67 : : * calling the rcu_read_[un]lock() functions.
68 : : *
69 : : */
70 : 0 : struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
71 : : __be32 mask,
72 : : struct list_head *head)
73 : : {
74 : 0 : struct netlbl_af4list *iter;
75 : :
76 [ # # # # ]: 0 : list_for_each_entry_rcu(iter, head, list)
77 [ # # # # : 0 : if (iter->valid && iter->addr == addr && iter->mask == mask)
# # # # #
# # # ]
78 : 0 : return iter;
79 : :
80 : : return NULL;
81 : : }
82 : :
83 : :
84 : : #if IS_ENABLED(CONFIG_IPV6)
85 : : /**
86 : : * netlbl_af6list_search - Search for a matching IPv6 address entry
87 : : * @addr: IPv6 address
88 : : * @head: the list head
89 : : *
90 : : * Description:
91 : : * Searches the IPv6 address list given by @head. If a matching address entry
92 : : * is found it is returned, otherwise NULL is returned. The caller is
93 : : * responsible for calling the rcu_read_[un]lock() functions.
94 : : *
95 : : */
96 : 0 : struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
97 : : struct list_head *head)
98 : : {
99 : 0 : struct netlbl_af6list *iter;
100 : :
101 [ # # ]: 0 : list_for_each_entry_rcu(iter, head, list)
102 [ # # # # ]: 0 : if (iter->valid &&
103 : : ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
104 : 0 : return iter;
105 : :
106 : : return NULL;
107 : : }
108 : :
109 : : /**
110 : : * netlbl_af6list_search_exact - Search for an exact IPv6 address entry
111 : : * @addr: IPv6 address
112 : : * @mask: IPv6 address mask
113 : : * @head: the list head
114 : : *
115 : : * Description:
116 : : * Searches the IPv6 address list given by @head. If an exact match if found
117 : : * it is returned, otherwise NULL is returned. The caller is responsible for
118 : : * calling the rcu_read_[un]lock() functions.
119 : : *
120 : : */
121 : 0 : struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
122 : : const struct in6_addr *mask,
123 : : struct list_head *head)
124 : : {
125 : 0 : struct netlbl_af6list *iter;
126 : :
127 [ # # ]: 0 : list_for_each_entry_rcu(iter, head, list)
128 [ # # # # ]: 0 : if (iter->valid &&
129 [ # # ]: 0 : ipv6_addr_equal(&iter->addr, addr) &&
130 : : ipv6_addr_equal(&iter->mask, mask))
131 : 0 : return iter;
132 : :
133 : : return NULL;
134 : : }
135 : : #endif /* IPv6 */
136 : :
137 : : /**
138 : : * netlbl_af4list_add - Add a new IPv4 address entry to a list
139 : : * @entry: address entry
140 : : * @head: the list head
141 : : *
142 : : * Description:
143 : : * Add a new address entry to the list pointed to by @head. On success zero is
144 : : * returned, otherwise a negative value is returned. The caller is responsible
145 : : * for calling the necessary locking functions.
146 : : *
147 : : */
148 : 0 : int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)
149 : : {
150 : 0 : struct netlbl_af4list *iter;
151 : :
152 : 0 : iter = netlbl_af4list_search(entry->addr, head);
153 [ # # ]: 0 : if (iter != NULL &&
154 [ # # ]: 0 : iter->addr == entry->addr && iter->mask == entry->mask)
155 : : return -EEXIST;
156 : :
157 : : /* in order to speed up address searches through the list (the common
158 : : * case) we need to keep the list in order based on the size of the
159 : : * address mask such that the entry with the widest mask (smallest
160 : : * numerical value) appears first in the list */
161 [ # # ]: 0 : list_for_each_entry_rcu(iter, head, list)
162 [ # # ]: 0 : if (iter->valid &&
163 [ # # ]: 0 : ntohl(entry->mask) > ntohl(iter->mask)) {
164 : 0 : __list_add_rcu(&entry->list,
165 : : iter->list.prev,
166 : : &iter->list);
167 : 0 : return 0;
168 : : }
169 : 0 : list_add_tail_rcu(&entry->list, head);
170 : 0 : return 0;
171 : : }
172 : :
173 : : #if IS_ENABLED(CONFIG_IPV6)
174 : : /**
175 : : * netlbl_af6list_add - Add a new IPv6 address entry to a list
176 : : * @entry: address entry
177 : : * @head: the list head
178 : : *
179 : : * Description:
180 : : * Add a new address entry to the list pointed to by @head. On success zero is
181 : : * returned, otherwise a negative value is returned. The caller is responsible
182 : : * for calling the necessary locking functions.
183 : : *
184 : : */
185 : 0 : int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)
186 : : {
187 : 0 : struct netlbl_af6list *iter;
188 : :
189 : 0 : iter = netlbl_af6list_search(&entry->addr, head);
190 [ # # # # ]: 0 : if (iter != NULL &&
191 [ # # ]: 0 : ipv6_addr_equal(&iter->addr, &entry->addr) &&
192 : : ipv6_addr_equal(&iter->mask, &entry->mask))
193 : : return -EEXIST;
194 : :
195 : : /* in order to speed up address searches through the list (the common
196 : : * case) we need to keep the list in order based on the size of the
197 : : * address mask such that the entry with the widest mask (smallest
198 : : * numerical value) appears first in the list */
199 [ # # ]: 0 : list_for_each_entry_rcu(iter, head, list)
200 [ # # # # ]: 0 : if (iter->valid &&
201 [ # # ]: 0 : ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
202 : 0 : __list_add_rcu(&entry->list,
203 : : iter->list.prev,
204 : : &iter->list);
205 : 0 : return 0;
206 : : }
207 : 0 : list_add_tail_rcu(&entry->list, head);
208 : 0 : return 0;
209 : : }
210 : : #endif /* IPv6 */
211 : :
212 : : /**
213 : : * netlbl_af4list_remove_entry - Remove an IPv4 address entry
214 : : * @entry: address entry
215 : : *
216 : : * Description:
217 : : * Remove the specified IP address entry. The caller is responsible for
218 : : * calling the necessary locking functions.
219 : : *
220 : : */
221 : 0 : void netlbl_af4list_remove_entry(struct netlbl_af4list *entry)
222 : : {
223 : 0 : entry->valid = 0;
224 : 0 : list_del_rcu(&entry->list);
225 : 0 : }
226 : :
227 : : /**
228 : : * netlbl_af4list_remove - Remove an IPv4 address entry
229 : : * @addr: IP address
230 : : * @mask: IP address mask
231 : : * @head: the list head
232 : : *
233 : : * Description:
234 : : * Remove an IP address entry from the list pointed to by @head. Returns the
235 : : * entry on success, NULL on failure. The caller is responsible for calling
236 : : * the necessary locking functions.
237 : : *
238 : : */
239 : 0 : struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
240 : : struct list_head *head)
241 : : {
242 : 0 : struct netlbl_af4list *entry;
243 : :
244 : 0 : entry = netlbl_af4list_search_exact(addr, mask, head);
245 [ # # ]: 0 : if (entry == NULL)
246 : : return NULL;
247 : 0 : netlbl_af4list_remove_entry(entry);
248 : 0 : return entry;
249 : : }
250 : :
251 : : #if IS_ENABLED(CONFIG_IPV6)
252 : : /**
253 : : * netlbl_af6list_remove_entry - Remove an IPv6 address entry
254 : : * @entry: address entry
255 : : *
256 : : * Description:
257 : : * Remove the specified IP address entry. The caller is responsible for
258 : : * calling the necessary locking functions.
259 : : *
260 : : */
261 : 0 : void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
262 : : {
263 : 0 : entry->valid = 0;
264 : 0 : list_del_rcu(&entry->list);
265 : 0 : }
266 : :
267 : : /**
268 : : * netlbl_af6list_remove - Remove an IPv6 address entry
269 : : * @addr: IP address
270 : : * @mask: IP address mask
271 : : * @head: the list head
272 : : *
273 : : * Description:
274 : : * Remove an IP address entry from the list pointed to by @head. Returns the
275 : : * entry on success, NULL on failure. The caller is responsible for calling
276 : : * the necessary locking functions.
277 : : *
278 : : */
279 : 0 : struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
280 : : const struct in6_addr *mask,
281 : : struct list_head *head)
282 : : {
283 : 0 : struct netlbl_af6list *entry;
284 : :
285 : 0 : entry = netlbl_af6list_search_exact(addr, mask, head);
286 [ # # ]: 0 : if (entry == NULL)
287 : : return NULL;
288 : 0 : netlbl_af6list_remove_entry(entry);
289 : 0 : return entry;
290 : : }
291 : : #endif /* IPv6 */
292 : :
293 : : /*
294 : : * Audit Helper Functions
295 : : */
296 : :
297 : : #ifdef CONFIG_AUDIT
298 : : /**
299 : : * netlbl_af4list_audit_addr - Audit an IPv4 address
300 : : * @audit_buf: audit buffer
301 : : * @src: true if source address, false if destination
302 : : * @dev: network interface
303 : : * @addr: IP address
304 : : * @mask: IP address mask
305 : : *
306 : : * Description:
307 : : * Write the IPv4 address and address mask, if necessary, to @audit_buf.
308 : : *
309 : : */
310 : 0 : void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
311 : : int src, const char *dev,
312 : : __be32 addr, __be32 mask)
313 : : {
314 : 0 : u32 mask_val = ntohl(mask);
315 [ # # ]: 0 : char *dir = (src ? "src" : "dst");
316 : :
317 [ # # ]: 0 : if (dev != NULL)
318 : 0 : audit_log_format(audit_buf, " netif=%s", dev);
319 : 0 : audit_log_format(audit_buf, " %s=%pI4", dir, &addr);
320 [ # # ]: 0 : if (mask_val != 0xffffffff) {
321 : : u32 mask_len = 0;
322 [ # # ]: 0 : while (mask_val > 0) {
323 : 0 : mask_val <<= 1;
324 : 0 : mask_len++;
325 : : }
326 : 0 : audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
327 : : }
328 : 0 : }
329 : :
330 : : #if IS_ENABLED(CONFIG_IPV6)
331 : : /**
332 : : * netlbl_af6list_audit_addr - Audit an IPv6 address
333 : : * @audit_buf: audit buffer
334 : : * @src: true if source address, false if destination
335 : : * @dev: network interface
336 : : * @addr: IP address
337 : : * @mask: IP address mask
338 : : *
339 : : * Description:
340 : : * Write the IPv6 address and address mask, if necessary, to @audit_buf.
341 : : *
342 : : */
343 : 0 : void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
344 : : int src,
345 : : const char *dev,
346 : : const struct in6_addr *addr,
347 : : const struct in6_addr *mask)
348 : : {
349 [ # # ]: 0 : char *dir = (src ? "src" : "dst");
350 : :
351 [ # # ]: 0 : if (dev != NULL)
352 : 0 : audit_log_format(audit_buf, " netif=%s", dev);
353 : 0 : audit_log_format(audit_buf, " %s=%pI6", dir, addr);
354 [ # # ]: 0 : if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
355 : : u32 mask_len = 0;
356 : : u32 mask_val;
357 : : int iter = -1;
358 [ # # ]: 0 : while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
359 : 0 : mask_len += 32;
360 : : mask_val = ntohl(mask->s6_addr32[iter]);
361 [ # # ]: 0 : while (mask_val > 0) {
362 : 0 : mask_val <<= 1;
363 : 0 : mask_len++;
364 : : }
365 : 0 : audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
366 : : }
367 : 0 : }
368 : : #endif /* IPv6 */
369 : : #endif /* CONFIG_AUDIT */
|