Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * NetLabel Kernel API
4 : : *
5 : : * This file defines the kernel API for the NetLabel system. The NetLabel
6 : : * system manages static and dynamic label mappings for network protocols such
7 : : * as CIPSO and RIPSO.
8 : : *
9 : : * Author: Paul Moore <paul@paul-moore.com>
10 : : */
11 : :
12 : : /*
13 : : * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
14 : : */
15 : :
16 : : #include <linux/init.h>
17 : : #include <linux/types.h>
18 : : #include <linux/slab.h>
19 : : #include <linux/audit.h>
20 : : #include <linux/in.h>
21 : : #include <linux/in6.h>
22 : : #include <net/ip.h>
23 : : #include <net/ipv6.h>
24 : : #include <net/netlabel.h>
25 : : #include <net/cipso_ipv4.h>
26 : : #include <net/calipso.h>
27 : : #include <asm/bug.h>
28 : : #include <linux/atomic.h>
29 : :
30 : : #include "netlabel_domainhash.h"
31 : : #include "netlabel_unlabeled.h"
32 : : #include "netlabel_cipso_v4.h"
33 : : #include "netlabel_calipso.h"
34 : : #include "netlabel_user.h"
35 : : #include "netlabel_mgmt.h"
36 : : #include "netlabel_addrlist.h"
37 : :
38 : : /*
39 : : * Configuration Functions
40 : : */
41 : :
42 : : /**
43 : : * netlbl_cfg_map_del - Remove a NetLabel/LSM domain mapping
44 : : * @domain: the domain mapping to remove
45 : : * @family: address family
46 : : * @addr: IP address
47 : : * @mask: IP address mask
48 : : * @audit_info: NetLabel audit information
49 : : *
50 : : * Description:
51 : : * Removes a NetLabel/LSM domain mapping. A @domain value of NULL causes the
52 : : * default domain mapping to be removed. Returns zero on success, negative
53 : : * values on failure.
54 : : *
55 : : */
56 : 0 : int netlbl_cfg_map_del(const char *domain,
57 : : u16 family,
58 : : const void *addr,
59 : : const void *mask,
60 : : struct netlbl_audit *audit_info)
61 : : {
62 [ # # ]: 0 : if (addr == NULL && mask == NULL) {
63 : 0 : return netlbl_domhsh_remove(domain, family, audit_info);
64 [ # # ]: 0 : } else if (addr != NULL && mask != NULL) {
65 [ # # # ]: 0 : switch (family) {
66 : 0 : case AF_INET:
67 : 0 : return netlbl_domhsh_remove_af4(domain, addr, mask,
68 : : audit_info);
69 : : #if IS_ENABLED(CONFIG_IPV6)
70 : 0 : case AF_INET6:
71 : 0 : return netlbl_domhsh_remove_af6(domain, addr, mask,
72 : : audit_info);
73 : : #endif /* IPv6 */
74 : : default:
75 : : return -EPFNOSUPPORT;
76 : : }
77 : : } else
78 : : return -EINVAL;
79 : : }
80 : :
81 : : /**
82 : : * netlbl_cfg_unlbl_map_add - Add a new unlabeled mapping
83 : : * @domain: the domain mapping to add
84 : : * @family: address family
85 : : * @addr: IP address
86 : : * @mask: IP address mask
87 : : * @audit_info: NetLabel audit information
88 : : *
89 : : * Description:
90 : : * Adds a new unlabeled NetLabel/LSM domain mapping. A @domain value of NULL
91 : : * causes a new default domain mapping to be added. Returns zero on success,
92 : : * negative values on failure.
93 : : *
94 : : */
95 : 0 : int netlbl_cfg_unlbl_map_add(const char *domain,
96 : : u16 family,
97 : : const void *addr,
98 : : const void *mask,
99 : : struct netlbl_audit *audit_info)
100 : : {
101 : 0 : int ret_val = -ENOMEM;
102 : 0 : struct netlbl_dom_map *entry;
103 : 0 : struct netlbl_domaddr_map *addrmap = NULL;
104 : 0 : struct netlbl_domaddr4_map *map4 = NULL;
105 : 0 : struct netlbl_domaddr6_map *map6 = NULL;
106 : :
107 : 0 : entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
108 [ # # ]: 0 : if (entry == NULL)
109 : : return -ENOMEM;
110 [ # # ]: 0 : if (domain != NULL) {
111 : 0 : entry->domain = kstrdup(domain, GFP_ATOMIC);
112 [ # # ]: 0 : if (entry->domain == NULL)
113 : 0 : goto cfg_unlbl_map_add_failure;
114 : : }
115 : 0 : entry->family = family;
116 : :
117 [ # # ]: 0 : if (addr == NULL && mask == NULL)
118 : 0 : entry->def.type = NETLBL_NLTYPE_UNLABELED;
119 [ # # ]: 0 : else if (addr != NULL && mask != NULL) {
120 : 0 : addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
121 [ # # ]: 0 : if (addrmap == NULL)
122 : 0 : goto cfg_unlbl_map_add_failure;
123 [ # # # ]: 0 : INIT_LIST_HEAD(&addrmap->list4);
124 : 0 : INIT_LIST_HEAD(&addrmap->list6);
125 : :
126 [ # # # ]: 0 : switch (family) {
127 : : case AF_INET: {
128 : 0 : const struct in_addr *addr4 = addr;
129 : 0 : const struct in_addr *mask4 = mask;
130 : 0 : map4 = kzalloc(sizeof(*map4), GFP_ATOMIC);
131 [ # # ]: 0 : if (map4 == NULL)
132 : 0 : goto cfg_unlbl_map_add_failure;
133 : 0 : map4->def.type = NETLBL_NLTYPE_UNLABELED;
134 : 0 : map4->list.addr = addr4->s_addr & mask4->s_addr;
135 : 0 : map4->list.mask = mask4->s_addr;
136 : 0 : map4->list.valid = 1;
137 : 0 : ret_val = netlbl_af4list_add(&map4->list,
138 : : &addrmap->list4);
139 [ # # ]: 0 : if (ret_val != 0)
140 : 0 : goto cfg_unlbl_map_add_failure;
141 : : break;
142 : : }
143 : : #if IS_ENABLED(CONFIG_IPV6)
144 : : case AF_INET6: {
145 : 0 : const struct in6_addr *addr6 = addr;
146 : 0 : const struct in6_addr *mask6 = mask;
147 : 0 : map6 = kzalloc(sizeof(*map6), GFP_ATOMIC);
148 [ # # ]: 0 : if (map6 == NULL)
149 : 0 : goto cfg_unlbl_map_add_failure;
150 : 0 : map6->def.type = NETLBL_NLTYPE_UNLABELED;
151 : 0 : map6->list.addr = *addr6;
152 : 0 : map6->list.addr.s6_addr32[0] &= mask6->s6_addr32[0];
153 : 0 : map6->list.addr.s6_addr32[1] &= mask6->s6_addr32[1];
154 : 0 : map6->list.addr.s6_addr32[2] &= mask6->s6_addr32[2];
155 : 0 : map6->list.addr.s6_addr32[3] &= mask6->s6_addr32[3];
156 : 0 : map6->list.mask = *mask6;
157 : 0 : map6->list.valid = 1;
158 : 0 : ret_val = netlbl_af6list_add(&map6->list,
159 : : &addrmap->list6);
160 [ # # ]: 0 : if (ret_val != 0)
161 : 0 : goto cfg_unlbl_map_add_failure;
162 : : break;
163 : : }
164 : : #endif /* IPv6 */
165 : 0 : default:
166 : 0 : goto cfg_unlbl_map_add_failure;
167 : : }
168 : :
169 : 0 : entry->def.addrsel = addrmap;
170 : 0 : entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
171 : : } else {
172 : 0 : ret_val = -EINVAL;
173 : 0 : goto cfg_unlbl_map_add_failure;
174 : : }
175 : :
176 : 0 : ret_val = netlbl_domhsh_add(entry, audit_info);
177 [ # # ]: 0 : if (ret_val != 0)
178 : 0 : goto cfg_unlbl_map_add_failure;
179 : :
180 : : return 0;
181 : :
182 : 0 : cfg_unlbl_map_add_failure:
183 : 0 : kfree(entry->domain);
184 : 0 : kfree(entry);
185 : 0 : kfree(addrmap);
186 : 0 : kfree(map4);
187 : 0 : kfree(map6);
188 : 0 : return ret_val;
189 : : }
190 : :
191 : :
192 : : /**
193 : : * netlbl_cfg_unlbl_static_add - Adds a new static label
194 : : * @net: network namespace
195 : : * @dev_name: interface name
196 : : * @addr: IP address in network byte order (struct in[6]_addr)
197 : : * @mask: address mask in network byte order (struct in[6]_addr)
198 : : * @family: address family
199 : : * @secid: LSM secid value for the entry
200 : : * @audit_info: NetLabel audit information
201 : : *
202 : : * Description:
203 : : * Adds a new NetLabel static label to be used when protocol provided labels
204 : : * are not present on incoming traffic. If @dev_name is NULL then the default
205 : : * interface will be used. Returns zero on success, negative values on failure.
206 : : *
207 : : */
208 : 0 : int netlbl_cfg_unlbl_static_add(struct net *net,
209 : : const char *dev_name,
210 : : const void *addr,
211 : : const void *mask,
212 : : u16 family,
213 : : u32 secid,
214 : : struct netlbl_audit *audit_info)
215 : : {
216 : 0 : u32 addr_len;
217 : :
218 [ # # # ]: 0 : switch (family) {
219 : : case AF_INET:
220 : : addr_len = sizeof(struct in_addr);
221 : : break;
222 : : #if IS_ENABLED(CONFIG_IPV6)
223 : 0 : case AF_INET6:
224 : 0 : addr_len = sizeof(struct in6_addr);
225 : 0 : break;
226 : : #endif /* IPv6 */
227 : : default:
228 : : return -EPFNOSUPPORT;
229 : : }
230 : :
231 : 0 : return netlbl_unlhsh_add(net,
232 : : dev_name, addr, mask, addr_len,
233 : : secid, audit_info);
234 : : }
235 : :
236 : : /**
237 : : * netlbl_cfg_unlbl_static_del - Removes an existing static label
238 : : * @net: network namespace
239 : : * @dev_name: interface name
240 : : * @addr: IP address in network byte order (struct in[6]_addr)
241 : : * @mask: address mask in network byte order (struct in[6]_addr)
242 : : * @family: address family
243 : : * @audit_info: NetLabel audit information
244 : : *
245 : : * Description:
246 : : * Removes an existing NetLabel static label used when protocol provided labels
247 : : * are not present on incoming traffic. If @dev_name is NULL then the default
248 : : * interface will be used. Returns zero on success, negative values on failure.
249 : : *
250 : : */
251 : 0 : int netlbl_cfg_unlbl_static_del(struct net *net,
252 : : const char *dev_name,
253 : : const void *addr,
254 : : const void *mask,
255 : : u16 family,
256 : : struct netlbl_audit *audit_info)
257 : : {
258 : 0 : u32 addr_len;
259 : :
260 [ # # # ]: 0 : switch (family) {
261 : : case AF_INET:
262 : : addr_len = sizeof(struct in_addr);
263 : : break;
264 : : #if IS_ENABLED(CONFIG_IPV6)
265 : 0 : case AF_INET6:
266 : 0 : addr_len = sizeof(struct in6_addr);
267 : 0 : break;
268 : : #endif /* IPv6 */
269 : : default:
270 : : return -EPFNOSUPPORT;
271 : : }
272 : :
273 : 0 : return netlbl_unlhsh_remove(net,
274 : : dev_name, addr, mask, addr_len,
275 : : audit_info);
276 : : }
277 : :
278 : : /**
279 : : * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
280 : : * @doi_def: CIPSO DOI definition
281 : : * @audit_info: NetLabel audit information
282 : : *
283 : : * Description:
284 : : * Add a new CIPSO DOI definition as defined by @doi_def. Returns zero on
285 : : * success and negative values on failure.
286 : : *
287 : : */
288 : 0 : int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
289 : : struct netlbl_audit *audit_info)
290 : : {
291 : 0 : return cipso_v4_doi_add(doi_def, audit_info);
292 : : }
293 : :
294 : : /**
295 : : * netlbl_cfg_cipsov4_del - Remove an existing CIPSOv4 DOI definition
296 : : * @doi: CIPSO DOI
297 : : * @audit_info: NetLabel audit information
298 : : *
299 : : * Description:
300 : : * Remove an existing CIPSO DOI definition matching @doi. Returns zero on
301 : : * success and negative values on failure.
302 : : *
303 : : */
304 : 0 : void netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info)
305 : : {
306 : 0 : cipso_v4_doi_remove(doi, audit_info);
307 : 0 : }
308 : :
309 : : /**
310 : : * netlbl_cfg_cipsov4_map_add - Add a new CIPSOv4 DOI mapping
311 : : * @doi: the CIPSO DOI
312 : : * @domain: the domain mapping to add
313 : : * @addr: IP address
314 : : * @mask: IP address mask
315 : : * @audit_info: NetLabel audit information
316 : : *
317 : : * Description:
318 : : * Add a new NetLabel/LSM domain mapping for the given CIPSO DOI to the NetLabel
319 : : * subsystem. A @domain value of NULL adds a new default domain mapping.
320 : : * Returns zero on success, negative values on failure.
321 : : *
322 : : */
323 : 0 : int netlbl_cfg_cipsov4_map_add(u32 doi,
324 : : const char *domain,
325 : : const struct in_addr *addr,
326 : : const struct in_addr *mask,
327 : : struct netlbl_audit *audit_info)
328 : : {
329 : 0 : int ret_val = -ENOMEM;
330 : 0 : struct cipso_v4_doi *doi_def;
331 : 0 : struct netlbl_dom_map *entry;
332 : 0 : struct netlbl_domaddr_map *addrmap = NULL;
333 : 0 : struct netlbl_domaddr4_map *addrinfo = NULL;
334 : :
335 : 0 : doi_def = cipso_v4_doi_getdef(doi);
336 [ # # ]: 0 : if (doi_def == NULL)
337 : : return -ENOENT;
338 : :
339 : 0 : entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
340 [ # # ]: 0 : if (entry == NULL)
341 : 0 : goto out_entry;
342 : 0 : entry->family = AF_INET;
343 [ # # ]: 0 : if (domain != NULL) {
344 : 0 : entry->domain = kstrdup(domain, GFP_ATOMIC);
345 [ # # ]: 0 : if (entry->domain == NULL)
346 : 0 : goto out_domain;
347 : : }
348 : :
349 [ # # ]: 0 : if (addr == NULL && mask == NULL) {
350 : 0 : entry->def.cipso = doi_def;
351 : 0 : entry->def.type = NETLBL_NLTYPE_CIPSOV4;
352 [ # # ]: 0 : } else if (addr != NULL && mask != NULL) {
353 : 0 : addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
354 [ # # ]: 0 : if (addrmap == NULL)
355 : 0 : goto out_addrmap;
356 : 0 : INIT_LIST_HEAD(&addrmap->list4);
357 : 0 : INIT_LIST_HEAD(&addrmap->list6);
358 : :
359 : 0 : addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
360 [ # # ]: 0 : if (addrinfo == NULL)
361 : 0 : goto out_addrinfo;
362 : 0 : addrinfo->def.cipso = doi_def;
363 : 0 : addrinfo->def.type = NETLBL_NLTYPE_CIPSOV4;
364 : 0 : addrinfo->list.addr = addr->s_addr & mask->s_addr;
365 : 0 : addrinfo->list.mask = mask->s_addr;
366 : 0 : addrinfo->list.valid = 1;
367 : 0 : ret_val = netlbl_af4list_add(&addrinfo->list, &addrmap->list4);
368 [ # # ]: 0 : if (ret_val != 0)
369 : 0 : goto cfg_cipsov4_map_add_failure;
370 : :
371 : 0 : entry->def.addrsel = addrmap;
372 : 0 : entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
373 : : } else {
374 : 0 : ret_val = -EINVAL;
375 : 0 : goto out_addrmap;
376 : : }
377 : :
378 : 0 : ret_val = netlbl_domhsh_add(entry, audit_info);
379 [ # # ]: 0 : if (ret_val != 0)
380 : 0 : goto cfg_cipsov4_map_add_failure;
381 : :
382 : : return 0;
383 : :
384 : 0 : cfg_cipsov4_map_add_failure:
385 : 0 : kfree(addrinfo);
386 : 0 : out_addrinfo:
387 : 0 : kfree(addrmap);
388 : 0 : out_addrmap:
389 : 0 : kfree(entry->domain);
390 : 0 : out_domain:
391 : 0 : kfree(entry);
392 : 0 : out_entry:
393 : 0 : cipso_v4_doi_putdef(doi_def);
394 : 0 : return ret_val;
395 : : }
396 : :
397 : : /**
398 : : * netlbl_cfg_calipso_add - Add a new CALIPSO DOI definition
399 : : * @doi_def: CALIPSO DOI definition
400 : : * @audit_info: NetLabel audit information
401 : : *
402 : : * Description:
403 : : * Add a new CALIPSO DOI definition as defined by @doi_def. Returns zero on
404 : : * success and negative values on failure.
405 : : *
406 : : */
407 : 0 : int netlbl_cfg_calipso_add(struct calipso_doi *doi_def,
408 : : struct netlbl_audit *audit_info)
409 : : {
410 : : #if IS_ENABLED(CONFIG_IPV6)
411 : 0 : return calipso_doi_add(doi_def, audit_info);
412 : : #else /* IPv6 */
413 : : return -ENOSYS;
414 : : #endif /* IPv6 */
415 : : }
416 : :
417 : : /**
418 : : * netlbl_cfg_calipso_del - Remove an existing CALIPSO DOI definition
419 : : * @doi: CALIPSO DOI
420 : : * @audit_info: NetLabel audit information
421 : : *
422 : : * Description:
423 : : * Remove an existing CALIPSO DOI definition matching @doi. Returns zero on
424 : : * success and negative values on failure.
425 : : *
426 : : */
427 : 0 : void netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info)
428 : : {
429 : : #if IS_ENABLED(CONFIG_IPV6)
430 : 0 : calipso_doi_remove(doi, audit_info);
431 : : #endif /* IPv6 */
432 : 0 : }
433 : :
434 : : /**
435 : : * netlbl_cfg_calipso_map_add - Add a new CALIPSO DOI mapping
436 : : * @doi: the CALIPSO DOI
437 : : * @domain: the domain mapping to add
438 : : * @addr: IP address
439 : : * @mask: IP address mask
440 : : * @audit_info: NetLabel audit information
441 : : *
442 : : * Description:
443 : : * Add a new NetLabel/LSM domain mapping for the given CALIPSO DOI to the
444 : : * NetLabel subsystem. A @domain value of NULL adds a new default domain
445 : : * mapping. Returns zero on success, negative values on failure.
446 : : *
447 : : */
448 : 0 : int netlbl_cfg_calipso_map_add(u32 doi,
449 : : const char *domain,
450 : : const struct in6_addr *addr,
451 : : const struct in6_addr *mask,
452 : : struct netlbl_audit *audit_info)
453 : : {
454 : : #if IS_ENABLED(CONFIG_IPV6)
455 : 0 : int ret_val = -ENOMEM;
456 : 0 : struct calipso_doi *doi_def;
457 : 0 : struct netlbl_dom_map *entry;
458 : 0 : struct netlbl_domaddr_map *addrmap = NULL;
459 : 0 : struct netlbl_domaddr6_map *addrinfo = NULL;
460 : :
461 : 0 : doi_def = calipso_doi_getdef(doi);
462 [ # # ]: 0 : if (doi_def == NULL)
463 : : return -ENOENT;
464 : :
465 : 0 : entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
466 [ # # ]: 0 : if (entry == NULL)
467 : 0 : goto out_entry;
468 : 0 : entry->family = AF_INET6;
469 [ # # ]: 0 : if (domain != NULL) {
470 : 0 : entry->domain = kstrdup(domain, GFP_ATOMIC);
471 [ # # ]: 0 : if (entry->domain == NULL)
472 : 0 : goto out_domain;
473 : : }
474 : :
475 [ # # ]: 0 : if (addr == NULL && mask == NULL) {
476 : 0 : entry->def.calipso = doi_def;
477 : 0 : entry->def.type = NETLBL_NLTYPE_CALIPSO;
478 [ # # ]: 0 : } else if (addr != NULL && mask != NULL) {
479 : 0 : addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
480 [ # # ]: 0 : if (addrmap == NULL)
481 : 0 : goto out_addrmap;
482 : 0 : INIT_LIST_HEAD(&addrmap->list4);
483 : 0 : INIT_LIST_HEAD(&addrmap->list6);
484 : :
485 : 0 : addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
486 [ # # ]: 0 : if (addrinfo == NULL)
487 : 0 : goto out_addrinfo;
488 : 0 : addrinfo->def.calipso = doi_def;
489 : 0 : addrinfo->def.type = NETLBL_NLTYPE_CALIPSO;
490 : 0 : addrinfo->list.addr = *addr;
491 : 0 : addrinfo->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
492 : 0 : addrinfo->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
493 : 0 : addrinfo->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
494 : 0 : addrinfo->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
495 : 0 : addrinfo->list.mask = *mask;
496 : 0 : addrinfo->list.valid = 1;
497 : 0 : ret_val = netlbl_af6list_add(&addrinfo->list, &addrmap->list6);
498 [ # # ]: 0 : if (ret_val != 0)
499 : 0 : goto cfg_calipso_map_add_failure;
500 : :
501 : 0 : entry->def.addrsel = addrmap;
502 : 0 : entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
503 : : } else {
504 : 0 : ret_val = -EINVAL;
505 : 0 : goto out_addrmap;
506 : : }
507 : :
508 : 0 : ret_val = netlbl_domhsh_add(entry, audit_info);
509 [ # # ]: 0 : if (ret_val != 0)
510 : 0 : goto cfg_calipso_map_add_failure;
511 : :
512 : : return 0;
513 : :
514 : 0 : cfg_calipso_map_add_failure:
515 : 0 : kfree(addrinfo);
516 : 0 : out_addrinfo:
517 : 0 : kfree(addrmap);
518 : 0 : out_addrmap:
519 : 0 : kfree(entry->domain);
520 : 0 : out_domain:
521 : 0 : kfree(entry);
522 : 0 : out_entry:
523 : 0 : calipso_doi_putdef(doi_def);
524 : 0 : return ret_val;
525 : : #else /* IPv6 */
526 : : return -ENOSYS;
527 : : #endif /* IPv6 */
528 : : }
529 : :
530 : : /*
531 : : * Security Attribute Functions
532 : : */
533 : :
534 : : #define _CM_F_NONE 0x00000000
535 : : #define _CM_F_ALLOC 0x00000001
536 : : #define _CM_F_WALK 0x00000002
537 : :
538 : : /**
539 : : * _netlbl_catmap_getnode - Get a individual node from a catmap
540 : : * @catmap: pointer to the category bitmap
541 : : * @offset: the requested offset
542 : : * @cm_flags: catmap flags, see _CM_F_*
543 : : * @gfp_flags: memory allocation flags
544 : : *
545 : : * Description:
546 : : * Iterate through the catmap looking for the node associated with @offset.
547 : : * If the _CM_F_ALLOC flag is set in @cm_flags and there is no associated node,
548 : : * one will be created and inserted into the catmap. If the _CM_F_WALK flag is
549 : : * set in @cm_flags and there is no associated node, the next highest node will
550 : : * be returned. Returns a pointer to the node on success, NULL on failure.
551 : : *
552 : : */
553 : 0 : static struct netlbl_lsm_catmap *_netlbl_catmap_getnode(
554 : : struct netlbl_lsm_catmap **catmap,
555 : : u32 offset,
556 : : unsigned int cm_flags,
557 : : gfp_t gfp_flags)
558 : : {
559 : 0 : struct netlbl_lsm_catmap *iter = *catmap;
560 : 0 : struct netlbl_lsm_catmap *prev = NULL;
561 : :
562 [ # # ]: 0 : if (iter == NULL)
563 : 0 : goto catmap_getnode_alloc;
564 [ # # ]: 0 : if (offset < iter->startbit)
565 : 0 : goto catmap_getnode_walk;
566 [ # # # # ]: 0 : while (iter && offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
567 : 0 : prev = iter;
568 : 0 : iter = iter->next;
569 : : }
570 [ # # # # ]: 0 : if (iter == NULL || offset < iter->startbit)
571 : 0 : goto catmap_getnode_walk;
572 : :
573 : : return iter;
574 : :
575 : 0 : catmap_getnode_walk:
576 [ # # ]: 0 : if (cm_flags & _CM_F_WALK)
577 : : return iter;
578 : 0 : catmap_getnode_alloc:
579 [ # # ]: 0 : if (!(cm_flags & _CM_F_ALLOC))
580 : : return NULL;
581 : :
582 : 0 : iter = netlbl_catmap_alloc(gfp_flags);
583 [ # # ]: 0 : if (iter == NULL)
584 : : return NULL;
585 : 0 : iter->startbit = offset & ~(NETLBL_CATMAP_SIZE - 1);
586 : :
587 [ # # ]: 0 : if (prev == NULL) {
588 : 0 : iter->next = *catmap;
589 : 0 : *catmap = iter;
590 : : } else {
591 : 0 : iter->next = prev->next;
592 : 0 : prev->next = iter;
593 : : }
594 : :
595 : : return iter;
596 : : }
597 : :
598 : : /**
599 : : * netlbl_catmap_walk - Walk a LSM secattr catmap looking for a bit
600 : : * @catmap: the category bitmap
601 : : * @offset: the offset to start searching at, in bits
602 : : *
603 : : * Description:
604 : : * This function walks a LSM secattr category bitmap starting at @offset and
605 : : * returns the spot of the first set bit or -ENOENT if no bits are set.
606 : : *
607 : : */
608 : 0 : int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset)
609 : : {
610 : 0 : struct netlbl_lsm_catmap *iter;
611 : 0 : u32 idx;
612 : 0 : u32 bit;
613 : 0 : NETLBL_CATMAP_MAPTYPE bitmap;
614 : :
615 : 0 : iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0);
616 [ # # ]: 0 : if (iter == NULL)
617 : : return -ENOENT;
618 [ # # ]: 0 : if (offset > iter->startbit) {
619 : 0 : offset -= iter->startbit;
620 : 0 : idx = offset / NETLBL_CATMAP_MAPSIZE;
621 : 0 : bit = offset % NETLBL_CATMAP_MAPSIZE;
622 : : } else {
623 : : idx = 0;
624 : : bit = 0;
625 : : }
626 : 0 : bitmap = iter->bitmap[idx] >> bit;
627 : :
628 : 0 : for (;;) {
629 [ # # ]: 0 : if (bitmap != 0) {
630 [ # # ]: 0 : while ((bitmap & NETLBL_CATMAP_BIT) == 0) {
631 : 0 : bitmap >>= 1;
632 : 0 : bit++;
633 : : }
634 : 0 : return iter->startbit +
635 : 0 : (NETLBL_CATMAP_MAPSIZE * idx) + bit;
636 : : }
637 [ # # ]: 0 : if (++idx >= NETLBL_CATMAP_MAPCNT) {
638 [ # # ]: 0 : if (iter->next != NULL) {
639 : : iter = iter->next;
640 : : idx = 0;
641 : : } else
642 : : return -ENOENT;
643 : : }
644 : 0 : bitmap = iter->bitmap[idx];
645 : 0 : bit = 0;
646 : : }
647 : :
648 : : return -ENOENT;
649 : : }
650 : : EXPORT_SYMBOL(netlbl_catmap_walk);
651 : :
652 : : /**
653 : : * netlbl_catmap_walkrng - Find the end of a string of set bits
654 : : * @catmap: the category bitmap
655 : : * @offset: the offset to start searching at, in bits
656 : : *
657 : : * Description:
658 : : * This function walks a LSM secattr category bitmap starting at @offset and
659 : : * returns the spot of the first cleared bit or -ENOENT if the offset is past
660 : : * the end of the bitmap.
661 : : *
662 : : */
663 : 0 : int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset)
664 : : {
665 : 0 : struct netlbl_lsm_catmap *iter;
666 : 0 : struct netlbl_lsm_catmap *prev = NULL;
667 : 0 : u32 idx;
668 : 0 : u32 bit;
669 : 0 : NETLBL_CATMAP_MAPTYPE bitmask;
670 : 0 : NETLBL_CATMAP_MAPTYPE bitmap;
671 : :
672 : 0 : iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0);
673 [ # # ]: 0 : if (iter == NULL)
674 : : return -ENOENT;
675 [ # # ]: 0 : if (offset > iter->startbit) {
676 : 0 : offset -= iter->startbit;
677 : 0 : idx = offset / NETLBL_CATMAP_MAPSIZE;
678 : 0 : bit = offset % NETLBL_CATMAP_MAPSIZE;
679 : : } else {
680 : : idx = 0;
681 : : bit = 0;
682 : : }
683 : 0 : bitmask = NETLBL_CATMAP_BIT << bit;
684 : :
685 : 0 : for (;;) {
686 : 0 : bitmap = iter->bitmap[idx];
687 [ # # # # ]: 0 : while (bitmask != 0 && (bitmap & bitmask) != 0) {
688 : 0 : bitmask <<= 1;
689 : 0 : bit++;
690 : : }
691 : :
692 [ # # # # ]: 0 : if (prev && idx == 0 && bit == 0)
693 : 0 : return prev->startbit + NETLBL_CATMAP_SIZE - 1;
694 [ # # ]: 0 : else if (bitmask != 0)
695 : 0 : return iter->startbit +
696 : 0 : (NETLBL_CATMAP_MAPSIZE * idx) + bit - 1;
697 [ # # ]: 0 : else if (++idx >= NETLBL_CATMAP_MAPCNT) {
698 [ # # ]: 0 : if (iter->next == NULL)
699 : 0 : return iter->startbit + NETLBL_CATMAP_SIZE - 1;
700 : : prev = iter;
701 : : iter = iter->next;
702 : : idx = 0;
703 : : }
704 : : bitmask = NETLBL_CATMAP_BIT;
705 : : bit = 0;
706 : : }
707 : :
708 : : return -ENOENT;
709 : : }
710 : :
711 : : /**
712 : : * netlbl_catmap_getlong - Export an unsigned long bitmap
713 : : * @catmap: pointer to the category bitmap
714 : : * @offset: pointer to the requested offset
715 : : * @bitmap: the exported bitmap
716 : : *
717 : : * Description:
718 : : * Export a bitmap with an offset greater than or equal to @offset and return
719 : : * it in @bitmap. The @offset must be aligned to an unsigned long and will be
720 : : * updated on return if different from what was requested; if the catmap is
721 : : * empty at the requested offset and beyond, the @offset is set to (u32)-1.
722 : : * Returns zero on sucess, negative values on failure.
723 : : *
724 : : */
725 : 0 : int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap,
726 : : u32 *offset,
727 : : unsigned long *bitmap)
728 : : {
729 : 0 : struct netlbl_lsm_catmap *iter;
730 : 0 : u32 off = *offset;
731 : 0 : u32 idx;
732 : :
733 : : /* only allow aligned offsets */
734 [ # # ]: 0 : if ((off & (BITS_PER_LONG - 1)) != 0)
735 : : return -EINVAL;
736 : :
737 [ # # ]: 0 : if (off < catmap->startbit) {
738 : 0 : off = catmap->startbit;
739 : 0 : *offset = off;
740 : : }
741 : 0 : iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_WALK, 0);
742 [ # # ]: 0 : if (iter == NULL) {
743 : 0 : *offset = (u32)-1;
744 : 0 : return 0;
745 : : }
746 : :
747 [ # # ]: 0 : if (off < iter->startbit) {
748 : 0 : *offset = iter->startbit;
749 : 0 : off = 0;
750 : : } else
751 : 0 : off -= iter->startbit;
752 : 0 : idx = off / NETLBL_CATMAP_MAPSIZE;
753 : 0 : *bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_MAPSIZE);
754 : :
755 : 0 : return 0;
756 : : }
757 : :
758 : : /**
759 : : * netlbl_catmap_setbit - Set a bit in a LSM secattr catmap
760 : : * @catmap: pointer to the category bitmap
761 : : * @bit: the bit to set
762 : : * @flags: memory allocation flags
763 : : *
764 : : * Description:
765 : : * Set the bit specified by @bit in @catmap. Returns zero on success,
766 : : * negative values on failure.
767 : : *
768 : : */
769 : 0 : int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap,
770 : : u32 bit,
771 : : gfp_t flags)
772 : : {
773 : 0 : struct netlbl_lsm_catmap *iter;
774 : 0 : u32 idx;
775 : :
776 : 0 : iter = _netlbl_catmap_getnode(catmap, bit, _CM_F_ALLOC, flags);
777 [ # # ]: 0 : if (iter == NULL)
778 : : return -ENOMEM;
779 : :
780 : 0 : bit -= iter->startbit;
781 : 0 : idx = bit / NETLBL_CATMAP_MAPSIZE;
782 : 0 : iter->bitmap[idx] |= NETLBL_CATMAP_BIT << (bit % NETLBL_CATMAP_MAPSIZE);
783 : :
784 : 0 : return 0;
785 : : }
786 : : EXPORT_SYMBOL(netlbl_catmap_setbit);
787 : :
788 : : /**
789 : : * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap
790 : : * @catmap: pointer to the category bitmap
791 : : * @start: the starting bit
792 : : * @end: the last bit in the string
793 : : * @flags: memory allocation flags
794 : : *
795 : : * Description:
796 : : * Set a range of bits, starting at @start and ending with @end. Returns zero
797 : : * on success, negative values on failure.
798 : : *
799 : : */
800 : 0 : int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap,
801 : : u32 start,
802 : : u32 end,
803 : : gfp_t flags)
804 : : {
805 : 0 : int rc = 0;
806 : 0 : u32 spot = start;
807 : :
808 [ # # ]: 0 : while (rc == 0 && spot <= end) {
809 [ # # ]: 0 : if (((spot & (BITS_PER_LONG - 1)) == 0) &&
810 [ # # ]: 0 : ((end - spot) > BITS_PER_LONG)) {
811 : 0 : rc = netlbl_catmap_setlong(catmap,
812 : : spot,
813 : : (unsigned long)-1,
814 : : flags);
815 : 0 : spot += BITS_PER_LONG;
816 : : } else
817 : 0 : rc = netlbl_catmap_setbit(catmap, spot++, flags);
818 : : }
819 : :
820 : 0 : return rc;
821 : : }
822 : :
823 : : /**
824 : : * netlbl_catmap_setlong - Import an unsigned long bitmap
825 : : * @catmap: pointer to the category bitmap
826 : : * @offset: offset to the start of the imported bitmap
827 : : * @bitmap: the bitmap to import
828 : : * @flags: memory allocation flags
829 : : *
830 : : * Description:
831 : : * Import the bitmap specified in @bitmap into @catmap, using the offset
832 : : * in @offset. The offset must be aligned to an unsigned long. Returns zero
833 : : * on success, negative values on failure.
834 : : *
835 : : */
836 : 0 : int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
837 : : u32 offset,
838 : : unsigned long bitmap,
839 : : gfp_t flags)
840 : : {
841 : 0 : struct netlbl_lsm_catmap *iter;
842 : 0 : u32 idx;
843 : :
844 : : /* only allow aligned offsets */
845 [ # # ]: 0 : if ((offset & (BITS_PER_LONG - 1)) != 0)
846 : : return -EINVAL;
847 : :
848 : 0 : iter = _netlbl_catmap_getnode(catmap, offset, _CM_F_ALLOC, flags);
849 [ # # ]: 0 : if (iter == NULL)
850 : : return -ENOMEM;
851 : :
852 : 0 : offset -= iter->startbit;
853 : 0 : idx = offset / NETLBL_CATMAP_MAPSIZE;
854 : 0 : iter->bitmap[idx] |= bitmap << (offset % NETLBL_CATMAP_MAPSIZE);
855 : :
856 : 0 : return 0;
857 : : }
858 : :
859 : : /* Bitmap functions
860 : : */
861 : :
862 : : /**
863 : : * netlbl_bitmap_walk - Walk a bitmap looking for a bit
864 : : * @bitmap: the bitmap
865 : : * @bitmap_len: length in bits
866 : : * @offset: starting offset
867 : : * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
868 : : *
869 : : * Description:
870 : : * Starting at @offset, walk the bitmap from left to right until either the
871 : : * desired bit is found or we reach the end. Return the bit offset, -1 if
872 : : * not found, or -2 if error.
873 : : */
874 : 0 : int netlbl_bitmap_walk(const unsigned char *bitmap, u32 bitmap_len,
875 : : u32 offset, u8 state)
876 : : {
877 : 0 : u32 bit_spot;
878 : 0 : u32 byte_offset;
879 : 0 : unsigned char bitmask;
880 : 0 : unsigned char byte;
881 : :
882 : 0 : byte_offset = offset / 8;
883 : 0 : byte = bitmap[byte_offset];
884 : 0 : bit_spot = offset;
885 : 0 : bitmask = 0x80 >> (offset % 8);
886 : :
887 [ # # ]: 0 : while (bit_spot < bitmap_len) {
888 [ # # # # : 0 : if ((state && (byte & bitmask) == bitmask) ||
# # ]
889 [ # # ]: 0 : (state == 0 && (byte & bitmask) == 0))
890 : 0 : return bit_spot;
891 : :
892 [ # # ]: 0 : if (++bit_spot >= bitmap_len)
893 : : return -1;
894 : 0 : bitmask >>= 1;
895 [ # # ]: 0 : if (bitmask == 0) {
896 : 0 : byte = bitmap[++byte_offset];
897 : 0 : bitmask = 0x80;
898 : : }
899 : : }
900 : :
901 : : return -1;
902 : : }
903 : : EXPORT_SYMBOL(netlbl_bitmap_walk);
904 : :
905 : : /**
906 : : * netlbl_bitmap_setbit - Sets a single bit in a bitmap
907 : : * @bitmap: the bitmap
908 : : * @bit: the bit
909 : : * @state: if non-zero, set the bit (1) else clear the bit (0)
910 : : *
911 : : * Description:
912 : : * Set a single bit in the bitmask. Returns zero on success, negative values
913 : : * on error.
914 : : */
915 : 0 : void netlbl_bitmap_setbit(unsigned char *bitmap, u32 bit, u8 state)
916 : : {
917 : 0 : u32 byte_spot;
918 : 0 : u8 bitmask;
919 : :
920 : : /* gcc always rounds to zero when doing integer division */
921 : 0 : byte_spot = bit / 8;
922 : 0 : bitmask = 0x80 >> (bit % 8);
923 [ # # ]: 0 : if (state)
924 : 0 : bitmap[byte_spot] |= bitmask;
925 : : else
926 : 0 : bitmap[byte_spot] &= ~bitmask;
927 : 0 : }
928 : : EXPORT_SYMBOL(netlbl_bitmap_setbit);
929 : :
930 : : /*
931 : : * LSM Functions
932 : : */
933 : :
934 : : /**
935 : : * netlbl_enabled - Determine if the NetLabel subsystem is enabled
936 : : *
937 : : * Description:
938 : : * The LSM can use this function to determine if it should use NetLabel
939 : : * security attributes in it's enforcement mechanism. Currently, NetLabel is
940 : : * considered to be enabled when it's configuration contains a valid setup for
941 : : * at least one labeled protocol (i.e. NetLabel can understand incoming
942 : : * labeled packets of at least one type); otherwise NetLabel is considered to
943 : : * be disabled.
944 : : *
945 : : */
946 : 0 : int netlbl_enabled(void)
947 : : {
948 : : /* At some point we probably want to expose this mechanism to the user
949 : : * as well so that admins can toggle NetLabel regardless of the
950 : : * configuration */
951 : 0 : return (atomic_read(&netlabel_mgmt_protocount) > 0);
952 : : }
953 : :
954 : : /**
955 : : * netlbl_sock_setattr - Label a socket using the correct protocol
956 : : * @sk: the socket to label
957 : : * @family: protocol family
958 : : * @secattr: the security attributes
959 : : *
960 : : * Description:
961 : : * Attach the correct label to the given socket using the security attributes
962 : : * specified in @secattr. This function requires exclusive access to @sk,
963 : : * which means it either needs to be in the process of being created or locked.
964 : : * Returns zero on success, -EDESTADDRREQ if the domain is configured to use
965 : : * network address selectors (can't blindly label the socket), and negative
966 : : * values on all other failures.
967 : : *
968 : : */
969 : 2800 : int netlbl_sock_setattr(struct sock *sk,
970 : : u16 family,
971 : : const struct netlbl_lsm_secattr *secattr)
972 : : {
973 : 2800 : int ret_val;
974 : 2800 : struct netlbl_dom_map *dom_entry;
975 : :
976 : 2800 : rcu_read_lock();
977 : 2800 : dom_entry = netlbl_domhsh_getentry(secattr->domain, family);
978 [ - + ]: 2800 : if (dom_entry == NULL) {
979 : 0 : ret_val = -ENOENT;
980 : 0 : goto socket_setattr_return;
981 : : }
982 [ + + - ]: 2800 : switch (family) {
983 : 2576 : case AF_INET:
984 [ - + - - ]: 2576 : switch (dom_entry->def.type) {
985 : : case NETLBL_NLTYPE_ADDRSELECT:
986 : : ret_val = -EDESTADDRREQ;
987 : : break;
988 : 0 : case NETLBL_NLTYPE_CIPSOV4:
989 : 0 : ret_val = cipso_v4_sock_setattr(sk,
990 : 0 : dom_entry->def.cipso,
991 : : secattr);
992 : 0 : break;
993 : 2576 : case NETLBL_NLTYPE_UNLABELED:
994 : 2576 : ret_val = 0;
995 : 2576 : break;
996 : 0 : default:
997 : 0 : ret_val = -ENOENT;
998 : : }
999 : : break;
1000 : : #if IS_ENABLED(CONFIG_IPV6)
1001 : 224 : case AF_INET6:
1002 [ - + - - ]: 224 : switch (dom_entry->def.type) {
1003 : : case NETLBL_NLTYPE_ADDRSELECT:
1004 : : ret_val = -EDESTADDRREQ;
1005 : : break;
1006 : 0 : case NETLBL_NLTYPE_CALIPSO:
1007 : 0 : ret_val = calipso_sock_setattr(sk,
1008 : 0 : dom_entry->def.calipso,
1009 : : secattr);
1010 : 0 : break;
1011 : 224 : case NETLBL_NLTYPE_UNLABELED:
1012 : 224 : ret_val = 0;
1013 : 224 : break;
1014 : 0 : default:
1015 : 0 : ret_val = -ENOENT;
1016 : : }
1017 : : break;
1018 : : #endif /* IPv6 */
1019 : : default:
1020 : : ret_val = -EPROTONOSUPPORT;
1021 : : }
1022 : :
1023 : 2800 : socket_setattr_return:
1024 : 2800 : rcu_read_unlock();
1025 : 2800 : return ret_val;
1026 : : }
1027 : :
1028 : : /**
1029 : : * netlbl_sock_delattr - Delete all the NetLabel labels on a socket
1030 : : * @sk: the socket
1031 : : *
1032 : : * Description:
1033 : : * Remove all the NetLabel labeling from @sk. The caller is responsible for
1034 : : * ensuring that @sk is locked.
1035 : : *
1036 : : */
1037 : 0 : void netlbl_sock_delattr(struct sock *sk)
1038 : : {
1039 [ # # # ]: 0 : switch (sk->sk_family) {
1040 : 0 : case AF_INET:
1041 : 0 : cipso_v4_sock_delattr(sk);
1042 : 0 : break;
1043 : : #if IS_ENABLED(CONFIG_IPV6)
1044 : 0 : case AF_INET6:
1045 : 0 : calipso_sock_delattr(sk);
1046 : 0 : break;
1047 : : #endif /* IPv6 */
1048 : : }
1049 : 0 : }
1050 : :
1051 : : /**
1052 : : * netlbl_sock_getattr - Determine the security attributes of a sock
1053 : : * @sk: the sock
1054 : : * @secattr: the security attributes
1055 : : *
1056 : : * Description:
1057 : : * Examines the given sock to see if any NetLabel style labeling has been
1058 : : * applied to the sock, if so it parses the socket label and returns the
1059 : : * security attributes in @secattr. Returns zero on success, negative values
1060 : : * on failure.
1061 : : *
1062 : : */
1063 : 0 : int netlbl_sock_getattr(struct sock *sk,
1064 : : struct netlbl_lsm_secattr *secattr)
1065 : : {
1066 : 0 : int ret_val;
1067 : :
1068 [ # # # ]: 0 : switch (sk->sk_family) {
1069 : 0 : case AF_INET:
1070 : 0 : ret_val = cipso_v4_sock_getattr(sk, secattr);
1071 : 0 : break;
1072 : : #if IS_ENABLED(CONFIG_IPV6)
1073 : 0 : case AF_INET6:
1074 : 0 : ret_val = calipso_sock_getattr(sk, secattr);
1075 : 0 : break;
1076 : : #endif /* IPv6 */
1077 : : default:
1078 : : ret_val = -EPROTONOSUPPORT;
1079 : : }
1080 : :
1081 : 0 : return ret_val;
1082 : : }
1083 : :
1084 : : /**
1085 : : * netlbl_conn_setattr - Label a connected socket using the correct protocol
1086 : : * @sk: the socket to label
1087 : : * @addr: the destination address
1088 : : * @secattr: the security attributes
1089 : : *
1090 : : * Description:
1091 : : * Attach the correct label to the given connected socket using the security
1092 : : * attributes specified in @secattr. The caller is responsible for ensuring
1093 : : * that @sk is locked. Returns zero on success, negative values on failure.
1094 : : *
1095 : : */
1096 : 0 : int netlbl_conn_setattr(struct sock *sk,
1097 : : struct sockaddr *addr,
1098 : : const struct netlbl_lsm_secattr *secattr)
1099 : : {
1100 : 0 : int ret_val;
1101 : 0 : struct sockaddr_in *addr4;
1102 : : #if IS_ENABLED(CONFIG_IPV6)
1103 : 0 : struct sockaddr_in6 *addr6;
1104 : : #endif
1105 : 0 : struct netlbl_dommap_def *entry;
1106 : :
1107 : 0 : rcu_read_lock();
1108 [ # # # ]: 0 : switch (addr->sa_family) {
1109 : 0 : case AF_INET:
1110 : 0 : addr4 = (struct sockaddr_in *)addr;
1111 : 0 : entry = netlbl_domhsh_getentry_af4(secattr->domain,
1112 : : addr4->sin_addr.s_addr);
1113 [ # # ]: 0 : if (entry == NULL) {
1114 : 0 : ret_val = -ENOENT;
1115 : 0 : goto conn_setattr_return;
1116 : : }
1117 [ # # # ]: 0 : switch (entry->type) {
1118 : 0 : case NETLBL_NLTYPE_CIPSOV4:
1119 : 0 : ret_val = cipso_v4_sock_setattr(sk,
1120 : 0 : entry->cipso, secattr);
1121 : 0 : break;
1122 : 0 : case NETLBL_NLTYPE_UNLABELED:
1123 : : /* just delete the protocols we support for right now
1124 : : * but we could remove other protocols if needed */
1125 : 0 : netlbl_sock_delattr(sk);
1126 : 0 : ret_val = 0;
1127 : 0 : break;
1128 : : default:
1129 : : ret_val = -ENOENT;
1130 : : }
1131 : : break;
1132 : : #if IS_ENABLED(CONFIG_IPV6)
1133 : 0 : case AF_INET6:
1134 : 0 : addr6 = (struct sockaddr_in6 *)addr;
1135 : 0 : entry = netlbl_domhsh_getentry_af6(secattr->domain,
1136 : 0 : &addr6->sin6_addr);
1137 [ # # ]: 0 : if (entry == NULL) {
1138 : 0 : ret_val = -ENOENT;
1139 : 0 : goto conn_setattr_return;
1140 : : }
1141 [ # # # ]: 0 : switch (entry->type) {
1142 : 0 : case NETLBL_NLTYPE_CALIPSO:
1143 : 0 : ret_val = calipso_sock_setattr(sk,
1144 : 0 : entry->calipso, secattr);
1145 : 0 : break;
1146 : 0 : case NETLBL_NLTYPE_UNLABELED:
1147 : : /* just delete the protocols we support for right now
1148 : : * but we could remove other protocols if needed */
1149 : 0 : netlbl_sock_delattr(sk);
1150 : 0 : ret_val = 0;
1151 : 0 : break;
1152 : : default:
1153 : : ret_val = -ENOENT;
1154 : : }
1155 : : break;
1156 : : #endif /* IPv6 */
1157 : : default:
1158 : : ret_val = -EPROTONOSUPPORT;
1159 : : }
1160 : :
1161 : 0 : conn_setattr_return:
1162 : 0 : rcu_read_unlock();
1163 : 0 : return ret_val;
1164 : : }
1165 : :
1166 : : /**
1167 : : * netlbl_req_setattr - Label a request socket using the correct protocol
1168 : : * @req: the request socket to label
1169 : : * @secattr: the security attributes
1170 : : *
1171 : : * Description:
1172 : : * Attach the correct label to the given socket using the security attributes
1173 : : * specified in @secattr. Returns zero on success, negative values on failure.
1174 : : *
1175 : : */
1176 : 0 : int netlbl_req_setattr(struct request_sock *req,
1177 : : const struct netlbl_lsm_secattr *secattr)
1178 : : {
1179 : 0 : int ret_val;
1180 : 0 : struct netlbl_dommap_def *entry;
1181 : 0 : struct inet_request_sock *ireq = inet_rsk(req);
1182 : :
1183 : 0 : rcu_read_lock();
1184 [ # # # ]: 0 : switch (req->rsk_ops->family) {
1185 : 0 : case AF_INET:
1186 : 0 : entry = netlbl_domhsh_getentry_af4(secattr->domain,
1187 : : ireq->ir_rmt_addr);
1188 [ # # ]: 0 : if (entry == NULL) {
1189 : 0 : ret_val = -ENOENT;
1190 : 0 : goto req_setattr_return;
1191 : : }
1192 [ # # # ]: 0 : switch (entry->type) {
1193 : 0 : case NETLBL_NLTYPE_CIPSOV4:
1194 : 0 : ret_val = cipso_v4_req_setattr(req,
1195 : 0 : entry->cipso, secattr);
1196 : 0 : break;
1197 : 0 : case NETLBL_NLTYPE_UNLABELED:
1198 : 0 : netlbl_req_delattr(req);
1199 : 0 : ret_val = 0;
1200 : 0 : break;
1201 : : default:
1202 : : ret_val = -ENOENT;
1203 : : }
1204 : : break;
1205 : : #if IS_ENABLED(CONFIG_IPV6)
1206 : 0 : case AF_INET6:
1207 : 0 : entry = netlbl_domhsh_getentry_af6(secattr->domain,
1208 : 0 : &ireq->ir_v6_rmt_addr);
1209 [ # # ]: 0 : if (entry == NULL) {
1210 : 0 : ret_val = -ENOENT;
1211 : 0 : goto req_setattr_return;
1212 : : }
1213 [ # # # ]: 0 : switch (entry->type) {
1214 : 0 : case NETLBL_NLTYPE_CALIPSO:
1215 : 0 : ret_val = calipso_req_setattr(req,
1216 : 0 : entry->calipso, secattr);
1217 : 0 : break;
1218 : 0 : case NETLBL_NLTYPE_UNLABELED:
1219 : 0 : netlbl_req_delattr(req);
1220 : 0 : ret_val = 0;
1221 : 0 : break;
1222 : : default:
1223 : : ret_val = -ENOENT;
1224 : : }
1225 : : break;
1226 : : #endif /* IPv6 */
1227 : : default:
1228 : : ret_val = -EPROTONOSUPPORT;
1229 : : }
1230 : :
1231 : 0 : req_setattr_return:
1232 : 0 : rcu_read_unlock();
1233 : 0 : return ret_val;
1234 : : }
1235 : :
1236 : : /**
1237 : : * netlbl_req_delattr - Delete all the NetLabel labels on a socket
1238 : : * @req: the socket
1239 : : *
1240 : : * Description:
1241 : : * Remove all the NetLabel labeling from @req.
1242 : : *
1243 : : */
1244 : 0 : void netlbl_req_delattr(struct request_sock *req)
1245 : : {
1246 [ # # # ]: 0 : switch (req->rsk_ops->family) {
1247 : 0 : case AF_INET:
1248 : 0 : cipso_v4_req_delattr(req);
1249 : 0 : break;
1250 : : #if IS_ENABLED(CONFIG_IPV6)
1251 : 0 : case AF_INET6:
1252 : 0 : calipso_req_delattr(req);
1253 : 0 : break;
1254 : : #endif /* IPv6 */
1255 : : }
1256 : 0 : }
1257 : :
1258 : : /**
1259 : : * netlbl_skbuff_setattr - Label a packet using the correct protocol
1260 : : * @skb: the packet
1261 : : * @family: protocol family
1262 : : * @secattr: the security attributes
1263 : : *
1264 : : * Description:
1265 : : * Attach the correct label to the given packet using the security attributes
1266 : : * specified in @secattr. Returns zero on success, negative values on failure.
1267 : : *
1268 : : */
1269 : 0 : int netlbl_skbuff_setattr(struct sk_buff *skb,
1270 : : u16 family,
1271 : : const struct netlbl_lsm_secattr *secattr)
1272 : : {
1273 : 0 : int ret_val;
1274 : 0 : struct iphdr *hdr4;
1275 : : #if IS_ENABLED(CONFIG_IPV6)
1276 : 0 : struct ipv6hdr *hdr6;
1277 : : #endif
1278 : 0 : struct netlbl_dommap_def *entry;
1279 : :
1280 : 0 : rcu_read_lock();
1281 [ # # # ]: 0 : switch (family) {
1282 : : case AF_INET:
1283 : 0 : hdr4 = ip_hdr(skb);
1284 : 0 : entry = netlbl_domhsh_getentry_af4(secattr->domain,
1285 : : hdr4->daddr);
1286 [ # # ]: 0 : if (entry == NULL) {
1287 : 0 : ret_val = -ENOENT;
1288 : 0 : goto skbuff_setattr_return;
1289 : : }
1290 [ # # # ]: 0 : switch (entry->type) {
1291 : 0 : case NETLBL_NLTYPE_CIPSOV4:
1292 : 0 : ret_val = cipso_v4_skbuff_setattr(skb, entry->cipso,
1293 : : secattr);
1294 : 0 : break;
1295 : 0 : case NETLBL_NLTYPE_UNLABELED:
1296 : : /* just delete the protocols we support for right now
1297 : : * but we could remove other protocols if needed */
1298 : 0 : ret_val = cipso_v4_skbuff_delattr(skb);
1299 : 0 : break;
1300 : : default:
1301 : : ret_val = -ENOENT;
1302 : : }
1303 : : break;
1304 : : #if IS_ENABLED(CONFIG_IPV6)
1305 : : case AF_INET6:
1306 : 0 : hdr6 = ipv6_hdr(skb);
1307 : 0 : entry = netlbl_domhsh_getentry_af6(secattr->domain,
1308 : 0 : &hdr6->daddr);
1309 [ # # ]: 0 : if (entry == NULL) {
1310 : 0 : ret_val = -ENOENT;
1311 : 0 : goto skbuff_setattr_return;
1312 : : }
1313 [ # # # ]: 0 : switch (entry->type) {
1314 : 0 : case NETLBL_NLTYPE_CALIPSO:
1315 : 0 : ret_val = calipso_skbuff_setattr(skb, entry->calipso,
1316 : : secattr);
1317 : 0 : break;
1318 : 0 : case NETLBL_NLTYPE_UNLABELED:
1319 : : /* just delete the protocols we support for right now
1320 : : * but we could remove other protocols if needed */
1321 : 0 : ret_val = calipso_skbuff_delattr(skb);
1322 : 0 : break;
1323 : : default:
1324 : : ret_val = -ENOENT;
1325 : : }
1326 : : break;
1327 : : #endif /* IPv6 */
1328 : : default:
1329 : : ret_val = -EPROTONOSUPPORT;
1330 : : }
1331 : :
1332 : 0 : skbuff_setattr_return:
1333 : 0 : rcu_read_unlock();
1334 : 0 : return ret_val;
1335 : : }
1336 : :
1337 : : /**
1338 : : * netlbl_skbuff_getattr - Determine the security attributes of a packet
1339 : : * @skb: the packet
1340 : : * @family: protocol family
1341 : : * @secattr: the security attributes
1342 : : *
1343 : : * Description:
1344 : : * Examines the given packet to see if a recognized form of packet labeling
1345 : : * is present, if so it parses the packet label and returns the security
1346 : : * attributes in @secattr. Returns zero on success, negative values on
1347 : : * failure.
1348 : : *
1349 : : */
1350 : 0 : int netlbl_skbuff_getattr(const struct sk_buff *skb,
1351 : : u16 family,
1352 : : struct netlbl_lsm_secattr *secattr)
1353 : : {
1354 : 0 : unsigned char *ptr;
1355 : :
1356 [ # # # ]: 0 : switch (family) {
1357 : 0 : case AF_INET:
1358 : 0 : ptr = cipso_v4_optptr(skb);
1359 [ # # # # ]: 0 : if (ptr && cipso_v4_getattr(ptr, secattr) == 0)
1360 : : return 0;
1361 : : break;
1362 : : #if IS_ENABLED(CONFIG_IPV6)
1363 : 0 : case AF_INET6:
1364 : 0 : ptr = calipso_optptr(skb);
1365 [ # # # # ]: 0 : if (ptr && calipso_getattr(ptr, secattr) == 0)
1366 : : return 0;
1367 : : break;
1368 : : #endif /* IPv6 */
1369 : : }
1370 : :
1371 : 0 : return netlbl_unlabel_getattr(skb, family, secattr);
1372 : : }
1373 : :
1374 : : /**
1375 : : * netlbl_skbuff_err - Handle a LSM error on a sk_buff
1376 : : * @skb: the packet
1377 : : * @family: the family
1378 : : * @error: the error code
1379 : : * @gateway: true if host is acting as a gateway, false otherwise
1380 : : *
1381 : : * Description:
1382 : : * Deal with a LSM problem when handling the packet in @skb, typically this is
1383 : : * a permission denied problem (-EACCES). The correct action is determined
1384 : : * according to the packet's labeling protocol.
1385 : : *
1386 : : */
1387 : 0 : void netlbl_skbuff_err(struct sk_buff *skb, u16 family, int error, int gateway)
1388 : : {
1389 [ # # ]: 0 : switch (family) {
1390 : 0 : case AF_INET:
1391 [ # # ]: 0 : if (cipso_v4_optptr(skb))
1392 : 0 : cipso_v4_error(skb, error, gateway);
1393 : : break;
1394 : : }
1395 : 0 : }
1396 : :
1397 : : /**
1398 : : * netlbl_cache_invalidate - Invalidate all of the NetLabel protocol caches
1399 : : *
1400 : : * Description:
1401 : : * For all of the NetLabel protocols that support some form of label mapping
1402 : : * cache, invalidate the cache. Returns zero on success, negative values on
1403 : : * error.
1404 : : *
1405 : : */
1406 : 0 : void netlbl_cache_invalidate(void)
1407 : : {
1408 : 0 : cipso_v4_cache_invalidate();
1409 : : #if IS_ENABLED(CONFIG_IPV6)
1410 : 0 : calipso_cache_invalidate();
1411 : : #endif /* IPv6 */
1412 : 0 : }
1413 : :
1414 : : /**
1415 : : * netlbl_cache_add - Add an entry to a NetLabel protocol cache
1416 : : * @skb: the packet
1417 : : * @family: the family
1418 : : * @secattr: the packet's security attributes
1419 : : *
1420 : : * Description:
1421 : : * Add the LSM security attributes for the given packet to the underlying
1422 : : * NetLabel protocol's label mapping cache. Returns zero on success, negative
1423 : : * values on error.
1424 : : *
1425 : : */
1426 : 0 : int netlbl_cache_add(const struct sk_buff *skb, u16 family,
1427 : : const struct netlbl_lsm_secattr *secattr)
1428 : : {
1429 : 0 : unsigned char *ptr;
1430 : :
1431 [ # # ]: 0 : if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
1432 : : return -ENOMSG;
1433 : :
1434 [ # # # ]: 0 : switch (family) {
1435 : 0 : case AF_INET:
1436 : 0 : ptr = cipso_v4_optptr(skb);
1437 [ # # ]: 0 : if (ptr)
1438 : 0 : return cipso_v4_cache_add(ptr, secattr);
1439 : : break;
1440 : : #if IS_ENABLED(CONFIG_IPV6)
1441 : 0 : case AF_INET6:
1442 : 0 : ptr = calipso_optptr(skb);
1443 [ # # ]: 0 : if (ptr)
1444 : 0 : return calipso_cache_add(ptr, secattr);
1445 : : break;
1446 : : #endif /* IPv6 */
1447 : : }
1448 : : return -ENOMSG;
1449 : : }
1450 : :
1451 : : /*
1452 : : * Protocol Engine Functions
1453 : : */
1454 : :
1455 : : /**
1456 : : * netlbl_audit_start - Start an audit message
1457 : : * @type: audit message type
1458 : : * @audit_info: NetLabel audit information
1459 : : *
1460 : : * Description:
1461 : : * Start an audit message using the type specified in @type and fill the audit
1462 : : * message with some fields common to all NetLabel audit messages. This
1463 : : * function should only be used by protocol engines, not LSMs. Returns a
1464 : : * pointer to the audit buffer on success, NULL on failure.
1465 : : *
1466 : : */
1467 : 0 : struct audit_buffer *netlbl_audit_start(int type,
1468 : : struct netlbl_audit *audit_info)
1469 : : {
1470 : 0 : return netlbl_audit_start_common(type, audit_info);
1471 : : }
1472 : : EXPORT_SYMBOL(netlbl_audit_start);
1473 : :
1474 : : /*
1475 : : * Setup Functions
1476 : : */
1477 : :
1478 : : /**
1479 : : * netlbl_init - Initialize NetLabel
1480 : : *
1481 : : * Description:
1482 : : * Perform the required NetLabel initialization before first use.
1483 : : *
1484 : : */
1485 : 28 : static int __init netlbl_init(void)
1486 : : {
1487 : 28 : int ret_val;
1488 : :
1489 : 28 : printk(KERN_INFO "NetLabel: Initializing\n");
1490 : 28 : printk(KERN_INFO "NetLabel: domain hash size = %u\n",
1491 : : (1 << NETLBL_DOMHSH_BITSIZE));
1492 : 28 : printk(KERN_INFO "NetLabel: protocols = UNLABELED CIPSOv4 CALIPSO\n");
1493 : :
1494 : 28 : ret_val = netlbl_domhsh_init(NETLBL_DOMHSH_BITSIZE);
1495 [ - + ]: 28 : if (ret_val != 0)
1496 : 0 : goto init_failure;
1497 : :
1498 : 28 : ret_val = netlbl_unlabel_init(NETLBL_UNLHSH_BITSIZE);
1499 [ - + ]: 28 : if (ret_val != 0)
1500 : 0 : goto init_failure;
1501 : :
1502 : 28 : ret_val = netlbl_netlink_init();
1503 [ - + ]: 28 : if (ret_val != 0)
1504 : 0 : goto init_failure;
1505 : :
1506 : 28 : ret_val = netlbl_unlabel_defconf();
1507 [ - + ]: 28 : if (ret_val != 0)
1508 : 0 : goto init_failure;
1509 : 28 : printk(KERN_INFO "NetLabel: unlabeled traffic allowed by default\n");
1510 : :
1511 : 28 : return 0;
1512 : :
1513 : 0 : init_failure:
1514 : 0 : panic("NetLabel: failed to initialize properly (%d)\n", ret_val);
1515 : : }
1516 : :
1517 : : subsys_initcall(netlbl_init);
|