aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlabel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-07-29 20:38:46 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-29 20:38:46 -0400
commit7a1e8b80fb1e8ead4cec15d1fc494ed290e4d2e9 (patch)
tree55a36d4256f1ae793b5c8e88c0f158737447193f /net/netlabel
parenta867d7349e94b6409b08629886a819f802377e91 (diff)
parent7616ac70d1bb4f2e9d25c1a82d283f3368a7b632 (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris: "Highlights: - TPM core and driver updates/fixes - IPv6 security labeling (CALIPSO) - Lots of Apparmor fixes - Seccomp: remove 2-phase API, close hole where ptrace can change syscall #" * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (156 commits) apparmor: fix SECURITY_APPARMOR_HASH_DEFAULT parameter handling tpm: Add TPM 2.0 support to the Nuvoton i2c driver (NPCT6xx family) tpm: Factor out common startup code tpm: use devm_add_action_or_reset tpm2_i2c_nuvoton: add irq validity check tpm: read burstcount from TPM_STS in one 32-bit transaction tpm: fix byte-order for the value read by tpm2_get_tpm_pt tpm_tis_core: convert max timeouts from msec to jiffies apparmor: fix arg_size computation for when setprocattr is null terminated apparmor: fix oops, validate buffer size in apparmor_setprocattr() apparmor: do not expose kernel stack apparmor: fix module parameters can be changed after policy is locked apparmor: fix oops in profile_unpack() when policy_db is not present apparmor: don't check for vmalloc_addr if kvzalloc() failed apparmor: add missing id bounds check on dfa verification apparmor: allow SYS_CAP_RESOURCE to be sufficient to prlimit another task apparmor: use list_next_entry instead of list_entry_next apparmor: fix refcount race when finding a child profile apparmor: fix ref count leak when profile sha1 hash is read apparmor: check that xindex is in trans_table bounds ...
Diffstat (limited to 'net/netlabel')
-rw-r--r--net/netlabel/Kconfig1
-rw-r--r--net/netlabel/Makefile2
-rw-r--r--net/netlabel/netlabel_calipso.c740
-rw-r--r--net/netlabel/netlabel_calipso.h151
-rw-r--r--net/netlabel/netlabel_domainhash.c293
-rw-r--r--net/netlabel/netlabel_domainhash.h17
-rw-r--r--net/netlabel/netlabel_kapi.c394
-rw-r--r--net/netlabel/netlabel_mgmt.c85
-rw-r--r--net/netlabel/netlabel_mgmt.h27
-rw-r--r--net/netlabel/netlabel_unlabeled.c5
-rw-r--r--net/netlabel/netlabel_user.c5
11 files changed, 1619 insertions, 101 deletions
diff --git a/net/netlabel/Kconfig b/net/netlabel/Kconfig
index 56958c85f2b4..d9eaa30ffe3f 100644
--- a/net/netlabel/Kconfig
+++ b/net/netlabel/Kconfig
@@ -5,6 +5,7 @@
5config NETLABEL 5config NETLABEL
6 bool "NetLabel subsystem support" 6 bool "NetLabel subsystem support"
7 depends on SECURITY 7 depends on SECURITY
8 select CRC_CCITT if IPV6
8 default n 9 default n
9 ---help--- 10 ---help---
10 NetLabel provides support for explicit network packet labeling 11 NetLabel provides support for explicit network packet labeling
diff --git a/net/netlabel/Makefile b/net/netlabel/Makefile
index d2732fc952e2..d341ede0dca5 100644
--- a/net/netlabel/Makefile
+++ b/net/netlabel/Makefile
@@ -12,4 +12,4 @@ obj-y += netlabel_mgmt.o
12# protocol modules 12# protocol modules
13obj-y += netlabel_unlabeled.o 13obj-y += netlabel_unlabeled.o
14obj-y += netlabel_cipso_v4.o 14obj-y += netlabel_cipso_v4.o
15 15obj-$(subst m,y,$(CONFIG_IPV6)) += netlabel_calipso.o
diff --git a/net/netlabel/netlabel_calipso.c b/net/netlabel/netlabel_calipso.c
new file mode 100644
index 000000000000..2ec93c5e77bb
--- /dev/null
+++ b/net/netlabel/netlabel_calipso.c
@@ -0,0 +1,740 @@
1/*
2 * NetLabel CALIPSO/IPv6 Support
3 *
4 * This file defines the CALIPSO/IPv6 functions for the NetLabel system. The
5 * NetLabel system manages static and dynamic label mappings for network
6 * protocols such as CIPSO and CALIPSO.
7 *
8 * Authors: Paul Moore <paul@paul-moore.com>
9 * Huw Davies <huw@codeweavers.com>
10 *
11 */
12
13/* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
14 * (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
24 * the GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, see <http://www.gnu.org/licenses/>.
28 *
29 */
30
31#include <linux/types.h>
32#include <linux/socket.h>
33#include <linux/string.h>
34#include <linux/skbuff.h>
35#include <linux/audit.h>
36#include <linux/slab.h>
37#include <net/sock.h>
38#include <net/netlink.h>
39#include <net/genetlink.h>
40#include <net/netlabel.h>
41#include <net/calipso.h>
42#include <linux/atomic.h>
43
44#include "netlabel_user.h"
45#include "netlabel_calipso.h"
46#include "netlabel_mgmt.h"
47#include "netlabel_domainhash.h"
48
49/* Argument struct for calipso_doi_walk() */
50struct netlbl_calipso_doiwalk_arg {
51 struct netlink_callback *nl_cb;
52 struct sk_buff *skb;
53 u32 seq;
54};
55
56/* Argument struct for netlbl_domhsh_walk() */
57struct netlbl_domhsh_walk_arg {
58 struct netlbl_audit *audit_info;
59 u32 doi;
60};
61
62/* NetLabel Generic NETLINK CALIPSO family */
63static struct genl_family netlbl_calipso_gnl_family = {
64 .id = GENL_ID_GENERATE,
65 .hdrsize = 0,
66 .name = NETLBL_NLTYPE_CALIPSO_NAME,
67 .version = NETLBL_PROTO_VERSION,
68 .maxattr = NLBL_CALIPSO_A_MAX,
69};
70
71/* NetLabel Netlink attribute policy */
72static const struct nla_policy calipso_genl_policy[NLBL_CALIPSO_A_MAX + 1] = {
73 [NLBL_CALIPSO_A_DOI] = { .type = NLA_U32 },
74 [NLBL_CALIPSO_A_MTYPE] = { .type = NLA_U32 },
75};
76
77/* NetLabel Command Handlers
78 */
79/**
80 * netlbl_calipso_add_pass - Adds a CALIPSO pass DOI definition
81 * @info: the Generic NETLINK info block
82 * @audit_info: NetLabel audit information
83 *
84 * Description:
85 * Create a new CALIPSO_MAP_PASS DOI definition based on the given ADD message
86 * and add it to the CALIPSO engine. Return zero on success and non-zero on
87 * error.
88 *
89 */
90static int netlbl_calipso_add_pass(struct genl_info *info,
91 struct netlbl_audit *audit_info)
92{
93 int ret_val;
94 struct calipso_doi *doi_def = NULL;
95
96 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
97 if (!doi_def)
98 return -ENOMEM;
99 doi_def->type = CALIPSO_MAP_PASS;
100 doi_def->doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
101 ret_val = calipso_doi_add(doi_def, audit_info);
102 if (ret_val != 0)
103 calipso_doi_free(doi_def);
104
105 return ret_val;
106}
107
108/**
109 * netlbl_calipso_add - Handle an ADD message
110 * @skb: the NETLINK buffer
111 * @info: the Generic NETLINK info block
112 *
113 * Description:
114 * Create a new DOI definition based on the given ADD message and add it to the
115 * CALIPSO engine. Returns zero on success, negative values on failure.
116 *
117 */
118static int netlbl_calipso_add(struct sk_buff *skb, struct genl_info *info)
119
120{
121 int ret_val = -EINVAL;
122 struct netlbl_audit audit_info;
123
124 if (!info->attrs[NLBL_CALIPSO_A_DOI] ||
125 !info->attrs[NLBL_CALIPSO_A_MTYPE])
126 return -EINVAL;
127
128 netlbl_netlink_auditinfo(skb, &audit_info);
129 switch (nla_get_u32(info->attrs[NLBL_CALIPSO_A_MTYPE])) {
130 case CALIPSO_MAP_PASS:
131 ret_val = netlbl_calipso_add_pass(info, &audit_info);
132 break;
133 }
134 if (ret_val == 0)
135 atomic_inc(&netlabel_mgmt_protocount);
136
137 return ret_val;
138}
139
140/**
141 * netlbl_calipso_list - Handle a LIST message
142 * @skb: the NETLINK buffer
143 * @info: the Generic NETLINK info block
144 *
145 * Description:
146 * Process a user generated LIST message and respond accordingly.
147 * Returns zero on success and negative values on error.
148 *
149 */
150static int netlbl_calipso_list(struct sk_buff *skb, struct genl_info *info)
151{
152 int ret_val;
153 struct sk_buff *ans_skb = NULL;
154 void *data;
155 u32 doi;
156 struct calipso_doi *doi_def;
157
158 if (!info->attrs[NLBL_CALIPSO_A_DOI]) {
159 ret_val = -EINVAL;
160 goto list_failure;
161 }
162
163 doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
164
165 doi_def = calipso_doi_getdef(doi);
166 if (!doi_def) {
167 ret_val = -EINVAL;
168 goto list_failure;
169 }
170
171 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
172 if (!ans_skb) {
173 ret_val = -ENOMEM;
174 goto list_failure_put;
175 }
176 data = genlmsg_put_reply(ans_skb, info, &netlbl_calipso_gnl_family,
177 0, NLBL_CALIPSO_C_LIST);
178 if (!data) {
179 ret_val = -ENOMEM;
180 goto list_failure_put;
181 }
182
183 ret_val = nla_put_u32(ans_skb, NLBL_CALIPSO_A_MTYPE, doi_def->type);
184 if (ret_val != 0)
185 goto list_failure_put;
186
187 calipso_doi_putdef(doi_def);
188
189 genlmsg_end(ans_skb, data);
190 return genlmsg_reply(ans_skb, info);
191
192list_failure_put:
193 calipso_doi_putdef(doi_def);
194list_failure:
195 kfree_skb(ans_skb);
196 return ret_val;
197}
198
199/**
200 * netlbl_calipso_listall_cb - calipso_doi_walk() callback for LISTALL
201 * @doi_def: the CALIPSO DOI definition
202 * @arg: the netlbl_calipso_doiwalk_arg structure
203 *
204 * Description:
205 * This function is designed to be used as a callback to the
206 * calipso_doi_walk() function for use in generating a response for a LISTALL
207 * message. Returns the size of the message on success, negative values on
208 * failure.
209 *
210 */
211static int netlbl_calipso_listall_cb(struct calipso_doi *doi_def, void *arg)
212{
213 int ret_val = -ENOMEM;
214 struct netlbl_calipso_doiwalk_arg *cb_arg = arg;
215 void *data;
216
217 data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
218 cb_arg->seq, &netlbl_calipso_gnl_family,
219 NLM_F_MULTI, NLBL_CALIPSO_C_LISTALL);
220 if (!data)
221 goto listall_cb_failure;
222
223 ret_val = nla_put_u32(cb_arg->skb, NLBL_CALIPSO_A_DOI, doi_def->doi);
224 if (ret_val != 0)
225 goto listall_cb_failure;
226 ret_val = nla_put_u32(cb_arg->skb,
227 NLBL_CALIPSO_A_MTYPE,
228 doi_def->type);
229 if (ret_val != 0)
230 goto listall_cb_failure;
231
232 genlmsg_end(cb_arg->skb, data);
233 return 0;
234
235listall_cb_failure:
236 genlmsg_cancel(cb_arg->skb, data);
237 return ret_val;
238}
239
240/**
241 * netlbl_calipso_listall - Handle a LISTALL message
242 * @skb: the NETLINK buffer
243 * @cb: the NETLINK callback
244 *
245 * Description:
246 * Process a user generated LISTALL message and respond accordingly. Returns
247 * zero on success and negative values on error.
248 *
249 */
250static int netlbl_calipso_listall(struct sk_buff *skb,
251 struct netlink_callback *cb)
252{
253 struct netlbl_calipso_doiwalk_arg cb_arg;
254 u32 doi_skip = cb->args[0];
255
256 cb_arg.nl_cb = cb;
257 cb_arg.skb = skb;
258 cb_arg.seq = cb->nlh->nlmsg_seq;
259
260 calipso_doi_walk(&doi_skip, netlbl_calipso_listall_cb, &cb_arg);
261
262 cb->args[0] = doi_skip;
263 return skb->len;
264}
265
266/**
267 * netlbl_calipso_remove_cb - netlbl_calipso_remove() callback for REMOVE
268 * @entry: LSM domain mapping entry
269 * @arg: the netlbl_domhsh_walk_arg structure
270 *
271 * Description:
272 * This function is intended for use by netlbl_calipso_remove() as the callback
273 * for the netlbl_domhsh_walk() function; it removes LSM domain map entries
274 * which are associated with the CALIPSO DOI specified in @arg. Returns zero on
275 * success, negative values on failure.
276 *
277 */
278static int netlbl_calipso_remove_cb(struct netlbl_dom_map *entry, void *arg)
279{
280 struct netlbl_domhsh_walk_arg *cb_arg = arg;
281
282 if (entry->def.type == NETLBL_NLTYPE_CALIPSO &&
283 entry->def.calipso->doi == cb_arg->doi)
284 return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
285
286 return 0;
287}
288
289/**
290 * netlbl_calipso_remove - Handle a REMOVE message
291 * @skb: the NETLINK buffer
292 * @info: the Generic NETLINK info block
293 *
294 * Description:
295 * Process a user generated REMOVE message and respond accordingly. Returns
296 * zero on success, negative values on failure.
297 *
298 */
299static int netlbl_calipso_remove(struct sk_buff *skb, struct genl_info *info)
300{
301 int ret_val = -EINVAL;
302 struct netlbl_domhsh_walk_arg cb_arg;
303 struct netlbl_audit audit_info;
304 u32 skip_bkt = 0;
305 u32 skip_chain = 0;
306
307 if (!info->attrs[NLBL_CALIPSO_A_DOI])
308 return -EINVAL;
309
310 netlbl_netlink_auditinfo(skb, &audit_info);
311 cb_arg.doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
312 cb_arg.audit_info = &audit_info;
313 ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
314 netlbl_calipso_remove_cb, &cb_arg);
315 if (ret_val == 0 || ret_val == -ENOENT) {
316 ret_val = calipso_doi_remove(cb_arg.doi, &audit_info);
317 if (ret_val == 0)
318 atomic_dec(&netlabel_mgmt_protocount);
319 }
320
321 return ret_val;
322}
323
324/* NetLabel Generic NETLINK Command Definitions
325 */
326
327static const struct genl_ops netlbl_calipso_ops[] = {
328 {
329 .cmd = NLBL_CALIPSO_C_ADD,
330 .flags = GENL_ADMIN_PERM,
331 .policy = calipso_genl_policy,
332 .doit = netlbl_calipso_add,
333 .dumpit = NULL,
334 },
335 {
336 .cmd = NLBL_CALIPSO_C_REMOVE,
337 .flags = GENL_ADMIN_PERM,
338 .policy = calipso_genl_policy,
339 .doit = netlbl_calipso_remove,
340 .dumpit = NULL,
341 },
342 {
343 .cmd = NLBL_CALIPSO_C_LIST,
344 .flags = 0,
345 .policy = calipso_genl_policy,
346 .doit = netlbl_calipso_list,
347 .dumpit = NULL,
348 },
349 {
350 .cmd = NLBL_CALIPSO_C_LISTALL,
351 .flags = 0,
352 .policy = calipso_genl_policy,
353 .doit = NULL,
354 .dumpit = netlbl_calipso_listall,
355 },
356};
357
358/* NetLabel Generic NETLINK Protocol Functions
359 */
360
361/**
362 * netlbl_calipso_genl_init - Register the CALIPSO NetLabel component
363 *
364 * Description:
365 * Register the CALIPSO packet NetLabel component with the Generic NETLINK
366 * mechanism. Returns zero on success, negative values on failure.
367 *
368 */
369int __init netlbl_calipso_genl_init(void)
370{
371 return genl_register_family_with_ops(&netlbl_calipso_gnl_family,
372 netlbl_calipso_ops);
373}
374
375static const struct netlbl_calipso_ops *calipso_ops;
376
377/**
378 * netlbl_calipso_ops_register - Register the CALIPSO operations
379 *
380 * Description:
381 * Register the CALIPSO packet engine operations.
382 *
383 */
384const struct netlbl_calipso_ops *
385netlbl_calipso_ops_register(const struct netlbl_calipso_ops *ops)
386{
387 return xchg(&calipso_ops, ops);
388}
389EXPORT_SYMBOL(netlbl_calipso_ops_register);
390
391static const struct netlbl_calipso_ops *netlbl_calipso_ops_get(void)
392{
393 return ACCESS_ONCE(calipso_ops);
394}
395
396/**
397 * calipso_doi_add - Add a new DOI to the CALIPSO protocol engine
398 * @doi_def: the DOI structure
399 * @audit_info: NetLabel audit information
400 *
401 * Description:
402 * The caller defines a new DOI for use by the CALIPSO engine and calls this
403 * function to add it to the list of acceptable domains. The caller must
404 * ensure that the mapping table specified in @doi_def->map meets all of the
405 * requirements of the mapping type (see calipso.h for details). Returns
406 * zero on success and non-zero on failure.
407 *
408 */
409int calipso_doi_add(struct calipso_doi *doi_def,
410 struct netlbl_audit *audit_info)
411{
412 int ret_val = -ENOMSG;
413 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
414
415 if (ops)
416 ret_val = ops->doi_add(doi_def, audit_info);
417 return ret_val;
418}
419
420/**
421 * calipso_doi_free - Frees a DOI definition
422 * @doi_def: the DOI definition
423 *
424 * Description:
425 * This function frees all of the memory associated with a DOI definition.
426 *
427 */
428void calipso_doi_free(struct calipso_doi *doi_def)
429{
430 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
431
432 if (ops)
433 ops->doi_free(doi_def);
434}
435
436/**
437 * calipso_doi_remove - Remove an existing DOI from the CALIPSO protocol engine
438 * @doi: the DOI value
439 * @audit_secid: the LSM secid to use in the audit message
440 *
441 * Description:
442 * Removes a DOI definition from the CALIPSO engine. The NetLabel routines will
443 * be called to release their own LSM domain mappings as well as our own
444 * domain list. Returns zero on success and negative values on failure.
445 *
446 */
447int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info)
448{
449 int ret_val = -ENOMSG;
450 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
451
452 if (ops)
453 ret_val = ops->doi_remove(doi, audit_info);
454 return ret_val;
455}
456
457/**
458 * calipso_doi_getdef - Returns a reference to a valid DOI definition
459 * @doi: the DOI value
460 *
461 * Description:
462 * Searches for a valid DOI definition and if one is found it is returned to
463 * the caller. Otherwise NULL is returned. The caller must ensure that
464 * calipso_doi_putdef() is called when the caller is done.
465 *
466 */
467struct calipso_doi *calipso_doi_getdef(u32 doi)
468{
469 struct calipso_doi *ret_val = NULL;
470 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
471
472 if (ops)
473 ret_val = ops->doi_getdef(doi);
474 return ret_val;
475}
476
477/**
478 * calipso_doi_putdef - Releases a reference for the given DOI definition
479 * @doi_def: the DOI definition
480 *
481 * Description:
482 * Releases a DOI definition reference obtained from calipso_doi_getdef().
483 *
484 */
485void calipso_doi_putdef(struct calipso_doi *doi_def)
486{
487 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
488
489 if (ops)
490 ops->doi_putdef(doi_def);
491}
492
493/**
494 * calipso_doi_walk - Iterate through the DOI definitions
495 * @skip_cnt: skip past this number of DOI definitions, updated
496 * @callback: callback for each DOI definition
497 * @cb_arg: argument for the callback function
498 *
499 * Description:
500 * Iterate over the DOI definition list, skipping the first @skip_cnt entries.
501 * For each entry call @callback, if @callback returns a negative value stop
502 * 'walking' through the list and return. Updates the value in @skip_cnt upon
503 * return. Returns zero on success, negative values on failure.
504 *
505 */
506int calipso_doi_walk(u32 *skip_cnt,
507 int (*callback)(struct calipso_doi *doi_def, void *arg),
508 void *cb_arg)
509{
510 int ret_val = -ENOMSG;
511 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
512
513 if (ops)
514 ret_val = ops->doi_walk(skip_cnt, callback, cb_arg);
515 return ret_val;
516}
517
518/**
519 * calipso_sock_getattr - Get the security attributes from a sock
520 * @sk: the sock
521 * @secattr: the security attributes
522 *
523 * Description:
524 * Query @sk to see if there is a CALIPSO option attached to the sock and if
525 * there is return the CALIPSO security attributes in @secattr. This function
526 * requires that @sk be locked, or privately held, but it does not do any
527 * locking itself. Returns zero on success and negative values on failure.
528 *
529 */
530int calipso_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
531{
532 int ret_val = -ENOMSG;
533 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
534
535 if (ops)
536 ret_val = ops->sock_getattr(sk, secattr);
537 return ret_val;
538}
539
540/**
541 * calipso_sock_setattr - Add a CALIPSO option to a socket
542 * @sk: the socket
543 * @doi_def: the CALIPSO DOI to use
544 * @secattr: the specific security attributes of the socket
545 *
546 * Description:
547 * Set the CALIPSO option on the given socket using the DOI definition and
548 * security attributes passed to the function. This function requires
549 * exclusive access to @sk, which means it either needs to be in the
550 * process of being created or locked. Returns zero on success and negative
551 * values on failure.
552 *
553 */
554int calipso_sock_setattr(struct sock *sk,
555 const struct calipso_doi *doi_def,
556 const struct netlbl_lsm_secattr *secattr)
557{
558 int ret_val = -ENOMSG;
559 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
560
561 if (ops)
562 ret_val = ops->sock_setattr(sk, doi_def, secattr);
563 return ret_val;
564}
565
566/**
567 * calipso_sock_delattr - Delete the CALIPSO option from a socket
568 * @sk: the socket
569 *
570 * Description:
571 * Removes the CALIPSO option from a socket, if present.
572 *
573 */
574void calipso_sock_delattr(struct sock *sk)
575{
576 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
577
578 if (ops)
579 ops->sock_delattr(sk);
580}
581
582/**
583 * calipso_req_setattr - Add a CALIPSO option to a connection request socket
584 * @req: the connection request socket
585 * @doi_def: the CALIPSO DOI to use
586 * @secattr: the specific security attributes of the socket
587 *
588 * Description:
589 * Set the CALIPSO option on the given socket using the DOI definition and
590 * security attributes passed to the function. Returns zero on success and
591 * negative values on failure.
592 *
593 */
594int calipso_req_setattr(struct request_sock *req,
595 const struct calipso_doi *doi_def,
596 const struct netlbl_lsm_secattr *secattr)
597{
598 int ret_val = -ENOMSG;
599 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
600
601 if (ops)
602 ret_val = ops->req_setattr(req, doi_def, secattr);
603 return ret_val;
604}
605
606/**
607 * calipso_req_delattr - Delete the CALIPSO option from a request socket
608 * @reg: the request socket
609 *
610 * Description:
611 * Removes the CALIPSO option from a request socket, if present.
612 *
613 */
614void calipso_req_delattr(struct request_sock *req)
615{
616 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
617
618 if (ops)
619 ops->req_delattr(req);
620}
621
622/**
623 * calipso_optptr - Find the CALIPSO option in the packet
624 * @skb: the packet
625 *
626 * Description:
627 * Parse the packet's IP header looking for a CALIPSO option. Returns a pointer
628 * to the start of the CALIPSO option on success, NULL if one if not found.
629 *
630 */
631unsigned char *calipso_optptr(const struct sk_buff *skb)
632{
633 unsigned char *ret_val = NULL;
634 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
635
636 if (ops)
637 ret_val = ops->skbuff_optptr(skb);
638 return ret_val;
639}
640
641/**
642 * calipso_getattr - Get the security attributes from a memory block.
643 * @calipso: the CALIPSO option
644 * @secattr: the security attributes
645 *
646 * Description:
647 * Inspect @calipso and return the security attributes in @secattr.
648 * Returns zero on success and negative values on failure.
649 *
650 */
651int calipso_getattr(const unsigned char *calipso,
652 struct netlbl_lsm_secattr *secattr)
653{
654 int ret_val = -ENOMSG;
655 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
656
657 if (ops)
658 ret_val = ops->opt_getattr(calipso, secattr);
659 return ret_val;
660}
661
662/**
663 * calipso_skbuff_setattr - Set the CALIPSO option on a packet
664 * @skb: the packet
665 * @doi_def: the CALIPSO DOI to use
666 * @secattr: the security attributes
667 *
668 * Description:
669 * Set the CALIPSO option on the given packet based on the security attributes.
670 * Returns a pointer to the IP header on success and NULL on failure.
671 *
672 */
673int calipso_skbuff_setattr(struct sk_buff *skb,
674 const struct calipso_doi *doi_def,
675 const struct netlbl_lsm_secattr *secattr)
676{
677 int ret_val = -ENOMSG;
678 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
679
680 if (ops)
681 ret_val = ops->skbuff_setattr(skb, doi_def, secattr);
682 return ret_val;
683}
684
685/**
686 * calipso_skbuff_delattr - Delete any CALIPSO options from a packet
687 * @skb: the packet
688 *
689 * Description:
690 * Removes any and all CALIPSO options from the given packet. Returns zero on
691 * success, negative values on failure.
692 *
693 */
694int calipso_skbuff_delattr(struct sk_buff *skb)
695{
696 int ret_val = -ENOMSG;
697 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
698
699 if (ops)
700 ret_val = ops->skbuff_delattr(skb);
701 return ret_val;
702}
703
704/**
705 * calipso_cache_invalidate - Invalidates the current CALIPSO cache
706 *
707 * Description:
708 * Invalidates and frees any entries in the CALIPSO cache. Returns zero on
709 * success and negative values on failure.
710 *
711 */
712void calipso_cache_invalidate(void)
713{
714 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
715
716 if (ops)
717 ops->cache_invalidate();
718}
719
720/**
721 * calipso_cache_add - Add an entry to the CALIPSO cache
722 * @calipso_ptr: the CALIPSO option
723 * @secattr: the packet's security attributes
724 *
725 * Description:
726 * Add a new entry into the CALIPSO label mapping cache.
727 * Returns zero on success, negative values on failure.
728 *
729 */
730int calipso_cache_add(const unsigned char *calipso_ptr,
731 const struct netlbl_lsm_secattr *secattr)
732
733{
734 int ret_val = -ENOMSG;
735 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
736
737 if (ops)
738 ret_val = ops->cache_add(calipso_ptr, secattr);
739 return ret_val;
740}
diff --git a/net/netlabel/netlabel_calipso.h b/net/netlabel/netlabel_calipso.h
new file mode 100644
index 000000000000..9fd291cd0fc5
--- /dev/null
+++ b/net/netlabel/netlabel_calipso.h
@@ -0,0 +1,151 @@
1/*
2 * NetLabel CALIPSO Support
3 *
4 * This file defines the CALIPSO functions for the NetLabel system. The
5 * NetLabel system manages static and dynamic label mappings for network
6 * protocols such as CIPSO and RIPSO.
7 *
8 * Authors: Paul Moore <paul@paul-moore.com>
9 * Huw Davies <huw@codeweavers.com>
10 *
11 */
12
13/* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
14 * (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
24 * the GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, see <http://www.gnu.org/licenses/>.
28 *
29 */
30
31#ifndef _NETLABEL_CALIPSO
32#define _NETLABEL_CALIPSO
33
34#include <net/netlabel.h>
35#include <net/calipso.h>
36
37/* The following NetLabel payloads are supported by the CALIPSO subsystem.
38 *
39 * o ADD:
40 * Sent by an application to add a new DOI mapping table.
41 *
42 * Required attributes:
43 *
44 * NLBL_CALIPSO_A_DOI
45 * NLBL_CALIPSO_A_MTYPE
46 *
47 * If using CALIPSO_MAP_PASS no additional attributes are required.
48 *
49 * o REMOVE:
50 * Sent by an application to remove a specific DOI mapping table from the
51 * CALIPSO system.
52 *
53 * Required attributes:
54 *
55 * NLBL_CALIPSO_A_DOI
56 *
57 * o LIST:
58 * Sent by an application to list the details of a DOI definition. On
59 * success the kernel should send a response using the following format.
60 *
61 * Required attributes:
62 *
63 * NLBL_CALIPSO_A_DOI
64 *
65 * The valid response message format depends on the type of the DOI mapping,
66 * the defined formats are shown below.
67 *
68 * Required attributes:
69 *
70 * NLBL_CALIPSO_A_MTYPE
71 *
72 * If using CALIPSO_MAP_PASS no additional attributes are required.
73 *
74 * o LISTALL:
75 * This message is sent by an application to list the valid DOIs on the
76 * system. When sent by an application there is no payload and the
77 * NLM_F_DUMP flag should be set. The kernel should respond with a series of
78 * the following messages.
79 *
80 * Required attributes:
81 *
82 * NLBL_CALIPSO_A_DOI
83 * NLBL_CALIPSO_A_MTYPE
84 *
85 */
86
87/* NetLabel CALIPSO commands */
88enum {
89 NLBL_CALIPSO_C_UNSPEC,
90 NLBL_CALIPSO_C_ADD,
91 NLBL_CALIPSO_C_REMOVE,
92 NLBL_CALIPSO_C_LIST,
93 NLBL_CALIPSO_C_LISTALL,
94 __NLBL_CALIPSO_C_MAX,
95};
96
97/* NetLabel CALIPSO attributes */
98enum {
99 NLBL_CALIPSO_A_UNSPEC,
100 NLBL_CALIPSO_A_DOI,
101 /* (NLA_U32)
102 * the DOI value */
103 NLBL_CALIPSO_A_MTYPE,
104 /* (NLA_U32)
105 * the mapping table type (defined in the calipso.h header as
106 * CALIPSO_MAP_*) */
107 __NLBL_CALIPSO_A_MAX,
108};
109
110#define NLBL_CALIPSO_A_MAX (__NLBL_CALIPSO_A_MAX - 1)
111
112/* NetLabel protocol functions */
113#if IS_ENABLED(CONFIG_IPV6)
114int netlbl_calipso_genl_init(void);
115#else
116static inline int netlbl_calipso_genl_init(void)
117{
118 return 0;
119}
120#endif
121
122int calipso_doi_add(struct calipso_doi *doi_def,
123 struct netlbl_audit *audit_info);
124void calipso_doi_free(struct calipso_doi *doi_def);
125int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info);
126struct calipso_doi *calipso_doi_getdef(u32 doi);
127void calipso_doi_putdef(struct calipso_doi *doi_def);
128int calipso_doi_walk(u32 *skip_cnt,
129 int (*callback)(struct calipso_doi *doi_def, void *arg),
130 void *cb_arg);
131int calipso_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
132int calipso_sock_setattr(struct sock *sk,
133 const struct calipso_doi *doi_def,
134 const struct netlbl_lsm_secattr *secattr);
135void calipso_sock_delattr(struct sock *sk);
136int calipso_req_setattr(struct request_sock *req,
137 const struct calipso_doi *doi_def,
138 const struct netlbl_lsm_secattr *secattr);
139void calipso_req_delattr(struct request_sock *req);
140unsigned char *calipso_optptr(const struct sk_buff *skb);
141int calipso_getattr(const unsigned char *calipso,
142 struct netlbl_lsm_secattr *secattr);
143int calipso_skbuff_setattr(struct sk_buff *skb,
144 const struct calipso_doi *doi_def,
145 const struct netlbl_lsm_secattr *secattr);
146int calipso_skbuff_delattr(struct sk_buff *skb);
147void calipso_cache_invalidate(void);
148int calipso_cache_add(const unsigned char *calipso_ptr,
149 const struct netlbl_lsm_secattr *secattr);
150
151#endif
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c
index ada67422234b..41d0e95d171e 100644
--- a/net/netlabel/netlabel_domainhash.c
+++ b/net/netlabel/netlabel_domainhash.c
@@ -37,10 +37,12 @@
37#include <linux/slab.h> 37#include <linux/slab.h>
38#include <net/netlabel.h> 38#include <net/netlabel.h>
39#include <net/cipso_ipv4.h> 39#include <net/cipso_ipv4.h>
40#include <net/calipso.h>
40#include <asm/bug.h> 41#include <asm/bug.h>
41 42
42#include "netlabel_mgmt.h" 43#include "netlabel_mgmt.h"
43#include "netlabel_addrlist.h" 44#include "netlabel_addrlist.h"
45#include "netlabel_calipso.h"
44#include "netlabel_domainhash.h" 46#include "netlabel_domainhash.h"
45#include "netlabel_user.h" 47#include "netlabel_user.h"
46 48
@@ -55,8 +57,9 @@ struct netlbl_domhsh_tbl {
55static DEFINE_SPINLOCK(netlbl_domhsh_lock); 57static DEFINE_SPINLOCK(netlbl_domhsh_lock);
56#define netlbl_domhsh_rcu_deref(p) \ 58#define netlbl_domhsh_rcu_deref(p) \
57 rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock)) 59 rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock))
58static struct netlbl_domhsh_tbl *netlbl_domhsh; 60static struct netlbl_domhsh_tbl __rcu *netlbl_domhsh;
59static struct netlbl_dom_map *netlbl_domhsh_def; 61static struct netlbl_dom_map __rcu *netlbl_domhsh_def_ipv4;
62static struct netlbl_dom_map __rcu *netlbl_domhsh_def_ipv6;
60 63
61/* 64/*
62 * Domain Hash Table Helper Functions 65 * Domain Hash Table Helper Functions
@@ -126,18 +129,26 @@ static u32 netlbl_domhsh_hash(const char *key)
126 return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1); 129 return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1);
127} 130}
128 131
132static bool netlbl_family_match(u16 f1, u16 f2)
133{
134 return (f1 == f2) || (f1 == AF_UNSPEC) || (f2 == AF_UNSPEC);
135}
136
129/** 137/**
130 * netlbl_domhsh_search - Search for a domain entry 138 * netlbl_domhsh_search - Search for a domain entry
131 * @domain: the domain 139 * @domain: the domain
140 * @family: the address family
132 * 141 *
133 * Description: 142 * Description:
134 * Searches the domain hash table and returns a pointer to the hash table 143 * Searches the domain hash table and returns a pointer to the hash table
135 * entry if found, otherwise NULL is returned. The caller is responsible for 144 * entry if found, otherwise NULL is returned. @family may be %AF_UNSPEC
145 * which matches any address family entries. The caller is responsible for
136 * ensuring that the hash table is protected with either a RCU read lock or the 146 * ensuring that the hash table is protected with either a RCU read lock or the
137 * hash table lock. 147 * hash table lock.
138 * 148 *
139 */ 149 */
140static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) 150static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain,
151 u16 family)
141{ 152{
142 u32 bkt; 153 u32 bkt;
143 struct list_head *bkt_list; 154 struct list_head *bkt_list;
@@ -147,7 +158,9 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
147 bkt = netlbl_domhsh_hash(domain); 158 bkt = netlbl_domhsh_hash(domain);
148 bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt]; 159 bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt];
149 list_for_each_entry_rcu(iter, bkt_list, list) 160 list_for_each_entry_rcu(iter, bkt_list, list)
150 if (iter->valid && strcmp(iter->domain, domain) == 0) 161 if (iter->valid &&
162 netlbl_family_match(iter->family, family) &&
163 strcmp(iter->domain, domain) == 0)
151 return iter; 164 return iter;
152 } 165 }
153 166
@@ -157,28 +170,37 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
157/** 170/**
158 * netlbl_domhsh_search_def - Search for a domain entry 171 * netlbl_domhsh_search_def - Search for a domain entry
159 * @domain: the domain 172 * @domain: the domain
160 * @def: return default if no match is found 173 * @family: the address family
161 * 174 *
162 * Description: 175 * Description:
163 * Searches the domain hash table and returns a pointer to the hash table 176 * Searches the domain hash table and returns a pointer to the hash table
164 * entry if an exact match is found, if an exact match is not present in the 177 * entry if an exact match is found, if an exact match is not present in the
165 * hash table then the default entry is returned if valid otherwise NULL is 178 * hash table then the default entry is returned if valid otherwise NULL is
166 * returned. The caller is responsible ensuring that the hash table is 179 * returned. @family may be %AF_UNSPEC which matches any address family
180 * entries. The caller is responsible ensuring that the hash table is
167 * protected with either a RCU read lock or the hash table lock. 181 * protected with either a RCU read lock or the hash table lock.
168 * 182 *
169 */ 183 */
170static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) 184static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain,
185 u16 family)
171{ 186{
172 struct netlbl_dom_map *entry; 187 struct netlbl_dom_map *entry;
173 188
174 entry = netlbl_domhsh_search(domain); 189 entry = netlbl_domhsh_search(domain, family);
175 if (entry == NULL) { 190 if (entry != NULL)
176 entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def); 191 return entry;
177 if (entry != NULL && !entry->valid) 192 if (family == AF_INET || family == AF_UNSPEC) {
178 entry = NULL; 193 entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def_ipv4);
194 if (entry != NULL && entry->valid)
195 return entry;
196 }
197 if (family == AF_INET6 || family == AF_UNSPEC) {
198 entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def_ipv6);
199 if (entry != NULL && entry->valid)
200 return entry;
179 } 201 }
180 202
181 return entry; 203 return NULL;
182} 204}
183 205
184/** 206/**
@@ -203,6 +225,7 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
203{ 225{
204 struct audit_buffer *audit_buf; 226 struct audit_buffer *audit_buf;
205 struct cipso_v4_doi *cipsov4 = NULL; 227 struct cipso_v4_doi *cipsov4 = NULL;
228 struct calipso_doi *calipso = NULL;
206 u32 type; 229 u32 type;
207 230
208 audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info); 231 audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
@@ -221,12 +244,14 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
221 struct netlbl_domaddr6_map *map6; 244 struct netlbl_domaddr6_map *map6;
222 map6 = netlbl_domhsh_addr6_entry(addr6); 245 map6 = netlbl_domhsh_addr6_entry(addr6);
223 type = map6->def.type; 246 type = map6->def.type;
247 calipso = map6->def.calipso;
224 netlbl_af6list_audit_addr(audit_buf, 0, NULL, 248 netlbl_af6list_audit_addr(audit_buf, 0, NULL,
225 &addr6->addr, &addr6->mask); 249 &addr6->addr, &addr6->mask);
226#endif /* IPv6 */ 250#endif /* IPv6 */
227 } else { 251 } else {
228 type = entry->def.type; 252 type = entry->def.type;
229 cipsov4 = entry->def.cipso; 253 cipsov4 = entry->def.cipso;
254 calipso = entry->def.calipso;
230 } 255 }
231 switch (type) { 256 switch (type) {
232 case NETLBL_NLTYPE_UNLABELED: 257 case NETLBL_NLTYPE_UNLABELED:
@@ -238,6 +263,12 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
238 " nlbl_protocol=cipsov4 cipso_doi=%u", 263 " nlbl_protocol=cipsov4 cipso_doi=%u",
239 cipsov4->doi); 264 cipsov4->doi);
240 break; 265 break;
266 case NETLBL_NLTYPE_CALIPSO:
267 BUG_ON(calipso == NULL);
268 audit_log_format(audit_buf,
269 " nlbl_protocol=calipso calipso_doi=%u",
270 calipso->doi);
271 break;
241 } 272 }
242 audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0); 273 audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
243 audit_log_end(audit_buf); 274 audit_log_end(audit_buf);
@@ -264,13 +295,25 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
264 if (entry == NULL) 295 if (entry == NULL)
265 return -EINVAL; 296 return -EINVAL;
266 297
298 if (entry->family != AF_INET && entry->family != AF_INET6 &&
299 (entry->family != AF_UNSPEC ||
300 entry->def.type != NETLBL_NLTYPE_UNLABELED))
301 return -EINVAL;
302
267 switch (entry->def.type) { 303 switch (entry->def.type) {
268 case NETLBL_NLTYPE_UNLABELED: 304 case NETLBL_NLTYPE_UNLABELED:
269 if (entry->def.cipso != NULL || entry->def.addrsel != NULL) 305 if (entry->def.cipso != NULL || entry->def.calipso != NULL ||
306 entry->def.addrsel != NULL)
270 return -EINVAL; 307 return -EINVAL;
271 break; 308 break;
272 case NETLBL_NLTYPE_CIPSOV4: 309 case NETLBL_NLTYPE_CIPSOV4:
273 if (entry->def.cipso == NULL) 310 if (entry->family != AF_INET ||
311 entry->def.cipso == NULL)
312 return -EINVAL;
313 break;
314 case NETLBL_NLTYPE_CALIPSO:
315 if (entry->family != AF_INET6 ||
316 entry->def.calipso == NULL)
274 return -EINVAL; 317 return -EINVAL;
275 break; 318 break;
276 case NETLBL_NLTYPE_ADDRSELECT: 319 case NETLBL_NLTYPE_ADDRSELECT:
@@ -294,6 +337,12 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
294 map6 = netlbl_domhsh_addr6_entry(iter6); 337 map6 = netlbl_domhsh_addr6_entry(iter6);
295 switch (map6->def.type) { 338 switch (map6->def.type) {
296 case NETLBL_NLTYPE_UNLABELED: 339 case NETLBL_NLTYPE_UNLABELED:
340 if (map6->def.calipso != NULL)
341 return -EINVAL;
342 break;
343 case NETLBL_NLTYPE_CALIPSO:
344 if (map6->def.calipso == NULL)
345 return -EINVAL;
297 break; 346 break;
298 default: 347 default:
299 return -EINVAL; 348 return -EINVAL;
@@ -358,15 +407,18 @@ int __init netlbl_domhsh_init(u32 size)
358 * 407 *
359 * Description: 408 * Description:
360 * Adds a new entry to the domain hash table and handles any updates to the 409 * Adds a new entry to the domain hash table and handles any updates to the
361 * lower level protocol handler (i.e. CIPSO). Returns zero on success, 410 * lower level protocol handler (i.e. CIPSO). @entry->family may be set to
362 * negative on failure. 411 * %AF_UNSPEC which will add an entry that matches all address families. This
412 * is only useful for the unlabelled type and will only succeed if there is no
413 * existing entry for any address family with the same domain. Returns zero
414 * on success, negative on failure.
363 * 415 *
364 */ 416 */
365int netlbl_domhsh_add(struct netlbl_dom_map *entry, 417int netlbl_domhsh_add(struct netlbl_dom_map *entry,
366 struct netlbl_audit *audit_info) 418 struct netlbl_audit *audit_info)
367{ 419{
368 int ret_val = 0; 420 int ret_val = 0;
369 struct netlbl_dom_map *entry_old; 421 struct netlbl_dom_map *entry_old, *entry_b;
370 struct netlbl_af4list *iter4; 422 struct netlbl_af4list *iter4;
371 struct netlbl_af4list *tmp4; 423 struct netlbl_af4list *tmp4;
372#if IS_ENABLED(CONFIG_IPV6) 424#if IS_ENABLED(CONFIG_IPV6)
@@ -385,9 +437,10 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
385 rcu_read_lock(); 437 rcu_read_lock();
386 spin_lock(&netlbl_domhsh_lock); 438 spin_lock(&netlbl_domhsh_lock);
387 if (entry->domain != NULL) 439 if (entry->domain != NULL)
388 entry_old = netlbl_domhsh_search(entry->domain); 440 entry_old = netlbl_domhsh_search(entry->domain, entry->family);
389 else 441 else
390 entry_old = netlbl_domhsh_search_def(entry->domain); 442 entry_old = netlbl_domhsh_search_def(entry->domain,
443 entry->family);
391 if (entry_old == NULL) { 444 if (entry_old == NULL) {
392 entry->valid = 1; 445 entry->valid = 1;
393 446
@@ -397,7 +450,41 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
397 &rcu_dereference(netlbl_domhsh)->tbl[bkt]); 450 &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
398 } else { 451 } else {
399 INIT_LIST_HEAD(&entry->list); 452 INIT_LIST_HEAD(&entry->list);
400 rcu_assign_pointer(netlbl_domhsh_def, entry); 453 switch (entry->family) {
454 case AF_INET:
455 rcu_assign_pointer(netlbl_domhsh_def_ipv4,
456 entry);
457 break;
458 case AF_INET6:
459 rcu_assign_pointer(netlbl_domhsh_def_ipv6,
460 entry);
461 break;
462 case AF_UNSPEC:
463 if (entry->def.type !=
464 NETLBL_NLTYPE_UNLABELED) {
465 ret_val = -EINVAL;
466 goto add_return;
467 }
468 entry_b = kzalloc(sizeof(*entry_b), GFP_ATOMIC);
469 if (entry_b == NULL) {
470 ret_val = -ENOMEM;
471 goto add_return;
472 }
473 entry_b->family = AF_INET6;
474 entry_b->def.type = NETLBL_NLTYPE_UNLABELED;
475 entry_b->valid = 1;
476 entry->family = AF_INET;
477 rcu_assign_pointer(netlbl_domhsh_def_ipv4,
478 entry);
479 rcu_assign_pointer(netlbl_domhsh_def_ipv6,
480 entry_b);
481 break;
482 default:
483 /* Already checked in
484 * netlbl_domhsh_validate(). */
485 ret_val = -EINVAL;
486 goto add_return;
487 }
401 } 488 }
402 489
403 if (entry->def.type == NETLBL_NLTYPE_ADDRSELECT) { 490 if (entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
@@ -513,10 +600,12 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
513 spin_lock(&netlbl_domhsh_lock); 600 spin_lock(&netlbl_domhsh_lock);
514 if (entry->valid) { 601 if (entry->valid) {
515 entry->valid = 0; 602 entry->valid = 0;
516 if (entry != rcu_dereference(netlbl_domhsh_def)) 603 if (entry == rcu_dereference(netlbl_domhsh_def_ipv4))
517 list_del_rcu(&entry->list); 604 RCU_INIT_POINTER(netlbl_domhsh_def_ipv4, NULL);
605 else if (entry == rcu_dereference(netlbl_domhsh_def_ipv6))
606 RCU_INIT_POINTER(netlbl_domhsh_def_ipv6, NULL);
518 else 607 else
519 RCU_INIT_POINTER(netlbl_domhsh_def, NULL); 608 list_del_rcu(&entry->list);
520 } else 609 } else
521 ret_val = -ENOENT; 610 ret_val = -ENOENT;
522 spin_unlock(&netlbl_domhsh_lock); 611 spin_unlock(&netlbl_domhsh_lock);
@@ -533,6 +622,10 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
533 if (ret_val == 0) { 622 if (ret_val == 0) {
534 struct netlbl_af4list *iter4; 623 struct netlbl_af4list *iter4;
535 struct netlbl_domaddr4_map *map4; 624 struct netlbl_domaddr4_map *map4;
625#if IS_ENABLED(CONFIG_IPV6)
626 struct netlbl_af6list *iter6;
627 struct netlbl_domaddr6_map *map6;
628#endif /* IPv6 */
536 629
537 switch (entry->def.type) { 630 switch (entry->def.type) {
538 case NETLBL_NLTYPE_ADDRSELECT: 631 case NETLBL_NLTYPE_ADDRSELECT:
@@ -541,12 +634,22 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
541 map4 = netlbl_domhsh_addr4_entry(iter4); 634 map4 = netlbl_domhsh_addr4_entry(iter4);
542 cipso_v4_doi_putdef(map4->def.cipso); 635 cipso_v4_doi_putdef(map4->def.cipso);
543 } 636 }
544 /* no need to check the IPv6 list since we currently 637#if IS_ENABLED(CONFIG_IPV6)
545 * support only unlabeled protocols for IPv6 */ 638 netlbl_af6list_foreach_rcu(iter6,
639 &entry->def.addrsel->list6) {
640 map6 = netlbl_domhsh_addr6_entry(iter6);
641 calipso_doi_putdef(map6->def.calipso);
642 }
643#endif /* IPv6 */
546 break; 644 break;
547 case NETLBL_NLTYPE_CIPSOV4: 645 case NETLBL_NLTYPE_CIPSOV4:
548 cipso_v4_doi_putdef(entry->def.cipso); 646 cipso_v4_doi_putdef(entry->def.cipso);
549 break; 647 break;
648#if IS_ENABLED(CONFIG_IPV6)
649 case NETLBL_NLTYPE_CALIPSO:
650 calipso_doi_putdef(entry->def.calipso);
651 break;
652#endif /* IPv6 */
550 } 653 }
551 call_rcu(&entry->rcu, netlbl_domhsh_free_entry); 654 call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
552 } 655 }
@@ -583,9 +686,9 @@ int netlbl_domhsh_remove_af4(const char *domain,
583 rcu_read_lock(); 686 rcu_read_lock();
584 687
585 if (domain) 688 if (domain)
586 entry_map = netlbl_domhsh_search(domain); 689 entry_map = netlbl_domhsh_search(domain, AF_INET);
587 else 690 else
588 entry_map = netlbl_domhsh_search_def(domain); 691 entry_map = netlbl_domhsh_search_def(domain, AF_INET);
589 if (entry_map == NULL || 692 if (entry_map == NULL ||
590 entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT) 693 entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
591 goto remove_af4_failure; 694 goto remove_af4_failure;
@@ -622,28 +725,114 @@ remove_af4_failure:
622 return -ENOENT; 725 return -ENOENT;
623} 726}
624 727
728#if IS_ENABLED(CONFIG_IPV6)
729/**
730 * netlbl_domhsh_remove_af6 - Removes an address selector entry
731 * @domain: the domain
732 * @addr: IPv6 address
733 * @mask: IPv6 address mask
734 * @audit_info: NetLabel audit information
735 *
736 * Description:
737 * Removes an individual address selector from a domain mapping and potentially
738 * the entire mapping if it is empty. Returns zero on success, negative values
739 * on failure.
740 *
741 */
742int netlbl_domhsh_remove_af6(const char *domain,
743 const struct in6_addr *addr,
744 const struct in6_addr *mask,
745 struct netlbl_audit *audit_info)
746{
747 struct netlbl_dom_map *entry_map;
748 struct netlbl_af6list *entry_addr;
749 struct netlbl_af4list *iter4;
750 struct netlbl_af6list *iter6;
751 struct netlbl_domaddr6_map *entry;
752
753 rcu_read_lock();
754
755 if (domain)
756 entry_map = netlbl_domhsh_search(domain, AF_INET6);
757 else
758 entry_map = netlbl_domhsh_search_def(domain, AF_INET6);
759 if (entry_map == NULL ||
760 entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
761 goto remove_af6_failure;
762
763 spin_lock(&netlbl_domhsh_lock);
764 entry_addr = netlbl_af6list_remove(addr, mask,
765 &entry_map->def.addrsel->list6);
766 spin_unlock(&netlbl_domhsh_lock);
767
768 if (entry_addr == NULL)
769 goto remove_af6_failure;
770 netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4)
771 goto remove_af6_single_addr;
772 netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6)
773 goto remove_af6_single_addr;
774 /* the domain mapping is empty so remove it from the mapping table */
775 netlbl_domhsh_remove_entry(entry_map, audit_info);
776
777remove_af6_single_addr:
778 rcu_read_unlock();
779 /* yick, we can't use call_rcu here because we don't have a rcu head
780 * pointer but hopefully this should be a rare case so the pause
781 * shouldn't be a problem */
782 synchronize_rcu();
783 entry = netlbl_domhsh_addr6_entry(entry_addr);
784 calipso_doi_putdef(entry->def.calipso);
785 kfree(entry);
786 return 0;
787
788remove_af6_failure:
789 rcu_read_unlock();
790 return -ENOENT;
791}
792#endif /* IPv6 */
793
625/** 794/**
626 * netlbl_domhsh_remove - Removes an entry from the domain hash table 795 * netlbl_domhsh_remove - Removes an entry from the domain hash table
627 * @domain: the domain to remove 796 * @domain: the domain to remove
797 * @family: address family
628 * @audit_info: NetLabel audit information 798 * @audit_info: NetLabel audit information
629 * 799 *
630 * Description: 800 * Description:
631 * Removes an entry from the domain hash table and handles any updates to the 801 * Removes an entry from the domain hash table and handles any updates to the
632 * lower level protocol handler (i.e. CIPSO). Returns zero on success, 802 * lower level protocol handler (i.e. CIPSO). @family may be %AF_UNSPEC which
633 * negative on failure. 803 * removes all address family entries. Returns zero on success, negative on
804 * failure.
634 * 805 *
635 */ 806 */
636int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) 807int netlbl_domhsh_remove(const char *domain, u16 family,
808 struct netlbl_audit *audit_info)
637{ 809{
638 int ret_val; 810 int ret_val = -EINVAL;
639 struct netlbl_dom_map *entry; 811 struct netlbl_dom_map *entry;
640 812
641 rcu_read_lock(); 813 rcu_read_lock();
642 if (domain) 814
643 entry = netlbl_domhsh_search(domain); 815 if (family == AF_INET || family == AF_UNSPEC) {
644 else 816 if (domain)
645 entry = netlbl_domhsh_search_def(domain); 817 entry = netlbl_domhsh_search(domain, AF_INET);
646 ret_val = netlbl_domhsh_remove_entry(entry, audit_info); 818 else
819 entry = netlbl_domhsh_search_def(domain, AF_INET);
820 ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
821 if (ret_val && ret_val != -ENOENT)
822 goto done;
823 }
824 if (family == AF_INET6 || family == AF_UNSPEC) {
825 int ret_val2;
826
827 if (domain)
828 entry = netlbl_domhsh_search(domain, AF_INET6);
829 else
830 entry = netlbl_domhsh_search_def(domain, AF_INET6);
831 ret_val2 = netlbl_domhsh_remove_entry(entry, audit_info);
832 if (ret_val2 != -ENOENT)
833 ret_val = ret_val2;
834 }
835done:
647 rcu_read_unlock(); 836 rcu_read_unlock();
648 837
649 return ret_val; 838 return ret_val;
@@ -651,32 +840,38 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
651 840
652/** 841/**
653 * netlbl_domhsh_remove_default - Removes the default entry from the table 842 * netlbl_domhsh_remove_default - Removes the default entry from the table
843 * @family: address family
654 * @audit_info: NetLabel audit information 844 * @audit_info: NetLabel audit information
655 * 845 *
656 * Description: 846 * Description:
657 * Removes/resets the default entry for the domain hash table and handles any 847 * Removes/resets the default entry corresponding to @family from the domain
658 * updates to the lower level protocol handler (i.e. CIPSO). Returns zero on 848 * hash table and handles any updates to the lower level protocol handler
659 * success, non-zero on failure. 849 * (i.e. CIPSO). @family may be %AF_UNSPEC which removes all address family
850 * entries. Returns zero on success, negative on failure.
660 * 851 *
661 */ 852 */
662int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info) 853int netlbl_domhsh_remove_default(u16 family, struct netlbl_audit *audit_info)
663{ 854{
664 return netlbl_domhsh_remove(NULL, audit_info); 855 return netlbl_domhsh_remove(NULL, family, audit_info);
665} 856}
666 857
667/** 858/**
668 * netlbl_domhsh_getentry - Get an entry from the domain hash table 859 * netlbl_domhsh_getentry - Get an entry from the domain hash table
669 * @domain: the domain name to search for 860 * @domain: the domain name to search for
861 * @family: address family
670 * 862 *
671 * Description: 863 * Description:
672 * Look through the domain hash table searching for an entry to match @domain, 864 * Look through the domain hash table searching for an entry to match @domain,
673 * return a pointer to a copy of the entry or NULL. The caller is responsible 865 * with address family @family, return a pointer to a copy of the entry or
674 * for ensuring that rcu_read_[un]lock() is called. 866 * NULL. The caller is responsible for ensuring that rcu_read_[un]lock() is
867 * called.
675 * 868 *
676 */ 869 */
677struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain) 870struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain, u16 family)
678{ 871{
679 return netlbl_domhsh_search_def(domain); 872 if (family == AF_UNSPEC)
873 return NULL;
874 return netlbl_domhsh_search_def(domain, family);
680} 875}
681 876
682/** 877/**
@@ -696,7 +891,7 @@ struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
696 struct netlbl_dom_map *dom_iter; 891 struct netlbl_dom_map *dom_iter;
697 struct netlbl_af4list *addr_iter; 892 struct netlbl_af4list *addr_iter;
698 893
699 dom_iter = netlbl_domhsh_search_def(domain); 894 dom_iter = netlbl_domhsh_search_def(domain, AF_INET);
700 if (dom_iter == NULL) 895 if (dom_iter == NULL)
701 return NULL; 896 return NULL;
702 897
@@ -726,7 +921,7 @@ struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
726 struct netlbl_dom_map *dom_iter; 921 struct netlbl_dom_map *dom_iter;
727 struct netlbl_af6list *addr_iter; 922 struct netlbl_af6list *addr_iter;
728 923
729 dom_iter = netlbl_domhsh_search_def(domain); 924 dom_iter = netlbl_domhsh_search_def(domain, AF_INET6);
730 if (dom_iter == NULL) 925 if (dom_iter == NULL)
731 return NULL; 926 return NULL;
732 927
diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h
index 680caf4dff56..1f9247781927 100644
--- a/net/netlabel/netlabel_domainhash.h
+++ b/net/netlabel/netlabel_domainhash.h
@@ -51,6 +51,7 @@ struct netlbl_dommap_def {
51 union { 51 union {
52 struct netlbl_domaddr_map *addrsel; 52 struct netlbl_domaddr_map *addrsel;
53 struct cipso_v4_doi *cipso; 53 struct cipso_v4_doi *cipso;
54 struct calipso_doi *calipso;
54 }; 55 };
55}; 56};
56#define netlbl_domhsh_addr4_entry(iter) \ 57#define netlbl_domhsh_addr4_entry(iter) \
@@ -70,6 +71,7 @@ struct netlbl_domaddr6_map {
70 71
71struct netlbl_dom_map { 72struct netlbl_dom_map {
72 char *domain; 73 char *domain;
74 u16 family;
73 struct netlbl_dommap_def def; 75 struct netlbl_dommap_def def;
74 76
75 u32 valid; 77 u32 valid;
@@ -91,14 +93,23 @@ int netlbl_domhsh_remove_af4(const char *domain,
91 const struct in_addr *addr, 93 const struct in_addr *addr,
92 const struct in_addr *mask, 94 const struct in_addr *mask,
93 struct netlbl_audit *audit_info); 95 struct netlbl_audit *audit_info);
94int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); 96int netlbl_domhsh_remove_af6(const char *domain,
95int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info); 97 const struct in6_addr *addr,
96struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); 98 const struct in6_addr *mask,
99 struct netlbl_audit *audit_info);
100int netlbl_domhsh_remove(const char *domain, u16 family,
101 struct netlbl_audit *audit_info);
102int netlbl_domhsh_remove_default(u16 family, struct netlbl_audit *audit_info);
103struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain, u16 family);
97struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain, 104struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
98 __be32 addr); 105 __be32 addr);
99#if IS_ENABLED(CONFIG_IPV6) 106#if IS_ENABLED(CONFIG_IPV6)
100struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain, 107struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
101 const struct in6_addr *addr); 108 const struct in6_addr *addr);
109int netlbl_domhsh_remove_af6(const char *domain,
110 const struct in6_addr *addr,
111 const struct in6_addr *mask,
112 struct netlbl_audit *audit_info);
102#endif /* IPv6 */ 113#endif /* IPv6 */
103 114
104int netlbl_domhsh_walk(u32 *skip_bkt, 115int netlbl_domhsh_walk(u32 *skip_bkt,
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index 1325776daa27..28c56b95fb7f 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -37,12 +37,14 @@
37#include <net/ipv6.h> 37#include <net/ipv6.h>
38#include <net/netlabel.h> 38#include <net/netlabel.h>
39#include <net/cipso_ipv4.h> 39#include <net/cipso_ipv4.h>
40#include <net/calipso.h>
40#include <asm/bug.h> 41#include <asm/bug.h>
41#include <linux/atomic.h> 42#include <linux/atomic.h>
42 43
43#include "netlabel_domainhash.h" 44#include "netlabel_domainhash.h"
44#include "netlabel_unlabeled.h" 45#include "netlabel_unlabeled.h"
45#include "netlabel_cipso_v4.h" 46#include "netlabel_cipso_v4.h"
47#include "netlabel_calipso.h"
46#include "netlabel_user.h" 48#include "netlabel_user.h"
47#include "netlabel_mgmt.h" 49#include "netlabel_mgmt.h"
48#include "netlabel_addrlist.h" 50#include "netlabel_addrlist.h"
@@ -72,12 +74,17 @@ int netlbl_cfg_map_del(const char *domain,
72 struct netlbl_audit *audit_info) 74 struct netlbl_audit *audit_info)
73{ 75{
74 if (addr == NULL && mask == NULL) { 76 if (addr == NULL && mask == NULL) {
75 return netlbl_domhsh_remove(domain, audit_info); 77 return netlbl_domhsh_remove(domain, family, audit_info);
76 } else if (addr != NULL && mask != NULL) { 78 } else if (addr != NULL && mask != NULL) {
77 switch (family) { 79 switch (family) {
78 case AF_INET: 80 case AF_INET:
79 return netlbl_domhsh_remove_af4(domain, addr, mask, 81 return netlbl_domhsh_remove_af4(domain, addr, mask,
80 audit_info); 82 audit_info);
83#if IS_ENABLED(CONFIG_IPV6)
84 case AF_INET6:
85 return netlbl_domhsh_remove_af6(domain, addr, mask,
86 audit_info);
87#endif /* IPv6 */
81 default: 88 default:
82 return -EPFNOSUPPORT; 89 return -EPFNOSUPPORT;
83 } 90 }
@@ -119,6 +126,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
119 if (entry->domain == NULL) 126 if (entry->domain == NULL)
120 goto cfg_unlbl_map_add_failure; 127 goto cfg_unlbl_map_add_failure;
121 } 128 }
129 entry->family = family;
122 130
123 if (addr == NULL && mask == NULL) 131 if (addr == NULL && mask == NULL)
124 entry->def.type = NETLBL_NLTYPE_UNLABELED; 132 entry->def.type = NETLBL_NLTYPE_UNLABELED;
@@ -345,6 +353,7 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
345 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 353 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
346 if (entry == NULL) 354 if (entry == NULL)
347 goto out_entry; 355 goto out_entry;
356 entry->family = AF_INET;
348 if (domain != NULL) { 357 if (domain != NULL) {
349 entry->domain = kstrdup(domain, GFP_ATOMIC); 358 entry->domain = kstrdup(domain, GFP_ATOMIC);
350 if (entry->domain == NULL) 359 if (entry->domain == NULL)
@@ -399,6 +408,139 @@ out_entry:
399 return ret_val; 408 return ret_val;
400} 409}
401 410
411/**
412 * netlbl_cfg_calipso_add - Add a new CALIPSO DOI definition
413 * @doi_def: CALIPSO DOI definition
414 * @audit_info: NetLabel audit information
415 *
416 * Description:
417 * Add a new CALIPSO DOI definition as defined by @doi_def. Returns zero on
418 * success and negative values on failure.
419 *
420 */
421int netlbl_cfg_calipso_add(struct calipso_doi *doi_def,
422 struct netlbl_audit *audit_info)
423{
424#if IS_ENABLED(CONFIG_IPV6)
425 return calipso_doi_add(doi_def, audit_info);
426#else /* IPv6 */
427 return -ENOSYS;
428#endif /* IPv6 */
429}
430
431/**
432 * netlbl_cfg_calipso_del - Remove an existing CALIPSO DOI definition
433 * @doi: CALIPSO DOI
434 * @audit_info: NetLabel audit information
435 *
436 * Description:
437 * Remove an existing CALIPSO DOI definition matching @doi. Returns zero on
438 * success and negative values on failure.
439 *
440 */
441void netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info)
442{
443#if IS_ENABLED(CONFIG_IPV6)
444 calipso_doi_remove(doi, audit_info);
445#endif /* IPv6 */
446}
447
448/**
449 * netlbl_cfg_calipso_map_add - Add a new CALIPSO DOI mapping
450 * @doi: the CALIPSO DOI
451 * @domain: the domain mapping to add
452 * @addr: IP address
453 * @mask: IP address mask
454 * @audit_info: NetLabel audit information
455 *
456 * Description:
457 * Add a new NetLabel/LSM domain mapping for the given CALIPSO DOI to the
458 * NetLabel subsystem. A @domain value of NULL adds a new default domain
459 * mapping. Returns zero on success, negative values on failure.
460 *
461 */
462int netlbl_cfg_calipso_map_add(u32 doi,
463 const char *domain,
464 const struct in6_addr *addr,
465 const struct in6_addr *mask,
466 struct netlbl_audit *audit_info)
467{
468#if IS_ENABLED(CONFIG_IPV6)
469 int ret_val = -ENOMEM;
470 struct calipso_doi *doi_def;
471 struct netlbl_dom_map *entry;
472 struct netlbl_domaddr_map *addrmap = NULL;
473 struct netlbl_domaddr6_map *addrinfo = NULL;
474
475 doi_def = calipso_doi_getdef(doi);
476 if (doi_def == NULL)
477 return -ENOENT;
478
479 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
480 if (entry == NULL)
481 goto out_entry;
482 entry->family = AF_INET6;
483 if (domain != NULL) {
484 entry->domain = kstrdup(domain, GFP_ATOMIC);
485 if (entry->domain == NULL)
486 goto out_domain;
487 }
488
489 if (addr == NULL && mask == NULL) {
490 entry->def.calipso = doi_def;
491 entry->def.type = NETLBL_NLTYPE_CALIPSO;
492 } else if (addr != NULL && mask != NULL) {
493 addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
494 if (addrmap == NULL)
495 goto out_addrmap;
496 INIT_LIST_HEAD(&addrmap->list4);
497 INIT_LIST_HEAD(&addrmap->list6);
498
499 addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
500 if (addrinfo == NULL)
501 goto out_addrinfo;
502 addrinfo->def.calipso = doi_def;
503 addrinfo->def.type = NETLBL_NLTYPE_CALIPSO;
504 addrinfo->list.addr = *addr;
505 addrinfo->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
506 addrinfo->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
507 addrinfo->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
508 addrinfo->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
509 addrinfo->list.mask = *mask;
510 addrinfo->list.valid = 1;
511 ret_val = netlbl_af6list_add(&addrinfo->list, &addrmap->list6);
512 if (ret_val != 0)
513 goto cfg_calipso_map_add_failure;
514
515 entry->def.addrsel = addrmap;
516 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
517 } else {
518 ret_val = -EINVAL;
519 goto out_addrmap;
520 }
521
522 ret_val = netlbl_domhsh_add(entry, audit_info);
523 if (ret_val != 0)
524 goto cfg_calipso_map_add_failure;
525
526 return 0;
527
528cfg_calipso_map_add_failure:
529 kfree(addrinfo);
530out_addrinfo:
531 kfree(addrmap);
532out_addrmap:
533 kfree(entry->domain);
534out_domain:
535 kfree(entry);
536out_entry:
537 calipso_doi_putdef(doi_def);
538 return ret_val;
539#else /* IPv6 */
540 return -ENOSYS;
541#endif /* IPv6 */
542}
543
402/* 544/*
403 * Security Attribute Functions 545 * Security Attribute Functions
404 */ 546 */
@@ -519,6 +661,7 @@ int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset)
519 661
520 return -ENOENT; 662 return -ENOENT;
521} 663}
664EXPORT_SYMBOL(netlbl_catmap_walk);
522 665
523/** 666/**
524 * netlbl_catmap_walkrng - Find the end of a string of set bits 667 * netlbl_catmap_walkrng - Find the end of a string of set bits
@@ -609,20 +752,19 @@ int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap,
609 off = catmap->startbit; 752 off = catmap->startbit;
610 *offset = off; 753 *offset = off;
611 } 754 }
612 iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_NONE, 0); 755 iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_WALK, 0);
613 if (iter == NULL) { 756 if (iter == NULL) {
614 *offset = (u32)-1; 757 *offset = (u32)-1;
615 return 0; 758 return 0;
616 } 759 }
617 760
618 if (off < iter->startbit) { 761 if (off < iter->startbit) {
619 off = iter->startbit; 762 *offset = iter->startbit;
620 *offset = off; 763 off = 0;
621 } else 764 } else
622 off -= iter->startbit; 765 off -= iter->startbit;
623
624 idx = off / NETLBL_CATMAP_MAPSIZE; 766 idx = off / NETLBL_CATMAP_MAPSIZE;
625 *bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_SIZE); 767 *bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_MAPSIZE);
626 768
627 return 0; 769 return 0;
628} 770}
@@ -655,6 +797,7 @@ int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap,
655 797
656 return 0; 798 return 0;
657} 799}
800EXPORT_SYMBOL(netlbl_catmap_setbit);
658 801
659/** 802/**
660 * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap 803 * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap
@@ -727,6 +870,76 @@ int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
727 return 0; 870 return 0;
728} 871}
729 872
873/* Bitmap functions
874 */
875
876/**
877 * netlbl_bitmap_walk - Walk a bitmap looking for a bit
878 * @bitmap: the bitmap
879 * @bitmap_len: length in bits
880 * @offset: starting offset
881 * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
882 *
883 * Description:
884 * Starting at @offset, walk the bitmap from left to right until either the
885 * desired bit is found or we reach the end. Return the bit offset, -1 if
886 * not found, or -2 if error.
887 */
888int netlbl_bitmap_walk(const unsigned char *bitmap, u32 bitmap_len,
889 u32 offset, u8 state)
890{
891 u32 bit_spot;
892 u32 byte_offset;
893 unsigned char bitmask;
894 unsigned char byte;
895
896 byte_offset = offset / 8;
897 byte = bitmap[byte_offset];
898 bit_spot = offset;
899 bitmask = 0x80 >> (offset % 8);
900
901 while (bit_spot < bitmap_len) {
902 if ((state && (byte & bitmask) == bitmask) ||
903 (state == 0 && (byte & bitmask) == 0))
904 return bit_spot;
905
906 bit_spot++;
907 bitmask >>= 1;
908 if (bitmask == 0) {
909 byte = bitmap[++byte_offset];
910 bitmask = 0x80;
911 }
912 }
913
914 return -1;
915}
916EXPORT_SYMBOL(netlbl_bitmap_walk);
917
918/**
919 * netlbl_bitmap_setbit - Sets a single bit in a bitmap
920 * @bitmap: the bitmap
921 * @bit: the bit
922 * @state: if non-zero, set the bit (1) else clear the bit (0)
923 *
924 * Description:
925 * Set a single bit in the bitmask. Returns zero on success, negative values
926 * on error.
927 */
928void netlbl_bitmap_setbit(unsigned char *bitmap, u32 bit, u8 state)
929{
930 u32 byte_spot;
931 u8 bitmask;
932
933 /* gcc always rounds to zero when doing integer division */
934 byte_spot = bit / 8;
935 bitmask = 0x80 >> (bit % 8);
936 if (state)
937 bitmap[byte_spot] |= bitmask;
938 else
939 bitmap[byte_spot] &= ~bitmask;
940}
941EXPORT_SYMBOL(netlbl_bitmap_setbit);
942
730/* 943/*
731 * LSM Functions 944 * LSM Functions
732 */ 945 */
@@ -774,7 +987,7 @@ int netlbl_sock_setattr(struct sock *sk,
774 struct netlbl_dom_map *dom_entry; 987 struct netlbl_dom_map *dom_entry;
775 988
776 rcu_read_lock(); 989 rcu_read_lock();
777 dom_entry = netlbl_domhsh_getentry(secattr->domain); 990 dom_entry = netlbl_domhsh_getentry(secattr->domain, family);
778 if (dom_entry == NULL) { 991 if (dom_entry == NULL) {
779 ret_val = -ENOENT; 992 ret_val = -ENOENT;
780 goto socket_setattr_return; 993 goto socket_setattr_return;
@@ -799,9 +1012,21 @@ int netlbl_sock_setattr(struct sock *sk,
799 break; 1012 break;
800#if IS_ENABLED(CONFIG_IPV6) 1013#if IS_ENABLED(CONFIG_IPV6)
801 case AF_INET6: 1014 case AF_INET6:
802 /* since we don't support any IPv6 labeling protocols right 1015 switch (dom_entry->def.type) {
803 * now we can optimize everything away until we do */ 1016 case NETLBL_NLTYPE_ADDRSELECT:
804 ret_val = 0; 1017 ret_val = -EDESTADDRREQ;
1018 break;
1019 case NETLBL_NLTYPE_CALIPSO:
1020 ret_val = calipso_sock_setattr(sk,
1021 dom_entry->def.calipso,
1022 secattr);
1023 break;
1024 case NETLBL_NLTYPE_UNLABELED:
1025 ret_val = 0;
1026 break;
1027 default:
1028 ret_val = -ENOENT;
1029 }
805 break; 1030 break;
806#endif /* IPv6 */ 1031#endif /* IPv6 */
807 default: 1032 default:
@@ -824,7 +1049,16 @@ socket_setattr_return:
824 */ 1049 */
825void netlbl_sock_delattr(struct sock *sk) 1050void netlbl_sock_delattr(struct sock *sk)
826{ 1051{
827 cipso_v4_sock_delattr(sk); 1052 switch (sk->sk_family) {
1053 case AF_INET:
1054 cipso_v4_sock_delattr(sk);
1055 break;
1056#if IS_ENABLED(CONFIG_IPV6)
1057 case AF_INET6:
1058 calipso_sock_delattr(sk);
1059 break;
1060#endif /* IPv6 */
1061 }
828} 1062}
829 1063
830/** 1064/**
@@ -850,7 +1084,7 @@ int netlbl_sock_getattr(struct sock *sk,
850 break; 1084 break;
851#if IS_ENABLED(CONFIG_IPV6) 1085#if IS_ENABLED(CONFIG_IPV6)
852 case AF_INET6: 1086 case AF_INET6:
853 ret_val = -ENOMSG; 1087 ret_val = calipso_sock_getattr(sk, secattr);
854 break; 1088 break;
855#endif /* IPv6 */ 1089#endif /* IPv6 */
856 default: 1090 default:
@@ -878,6 +1112,9 @@ int netlbl_conn_setattr(struct sock *sk,
878{ 1112{
879 int ret_val; 1113 int ret_val;
880 struct sockaddr_in *addr4; 1114 struct sockaddr_in *addr4;
1115#if IS_ENABLED(CONFIG_IPV6)
1116 struct sockaddr_in6 *addr6;
1117#endif
881 struct netlbl_dommap_def *entry; 1118 struct netlbl_dommap_def *entry;
882 1119
883 rcu_read_lock(); 1120 rcu_read_lock();
@@ -898,7 +1135,7 @@ int netlbl_conn_setattr(struct sock *sk,
898 case NETLBL_NLTYPE_UNLABELED: 1135 case NETLBL_NLTYPE_UNLABELED:
899 /* just delete the protocols we support for right now 1136 /* just delete the protocols we support for right now
900 * but we could remove other protocols if needed */ 1137 * but we could remove other protocols if needed */
901 cipso_v4_sock_delattr(sk); 1138 netlbl_sock_delattr(sk);
902 ret_val = 0; 1139 ret_val = 0;
903 break; 1140 break;
904 default: 1141 default:
@@ -907,9 +1144,27 @@ int netlbl_conn_setattr(struct sock *sk,
907 break; 1144 break;
908#if IS_ENABLED(CONFIG_IPV6) 1145#if IS_ENABLED(CONFIG_IPV6)
909 case AF_INET6: 1146 case AF_INET6:
910 /* since we don't support any IPv6 labeling protocols right 1147 addr6 = (struct sockaddr_in6 *)addr;
911 * now we can optimize everything away until we do */ 1148 entry = netlbl_domhsh_getentry_af6(secattr->domain,
912 ret_val = 0; 1149 &addr6->sin6_addr);
1150 if (entry == NULL) {
1151 ret_val = -ENOENT;
1152 goto conn_setattr_return;
1153 }
1154 switch (entry->type) {
1155 case NETLBL_NLTYPE_CALIPSO:
1156 ret_val = calipso_sock_setattr(sk,
1157 entry->calipso, secattr);
1158 break;
1159 case NETLBL_NLTYPE_UNLABELED:
1160 /* just delete the protocols we support for right now
1161 * but we could remove other protocols if needed */
1162 netlbl_sock_delattr(sk);
1163 ret_val = 0;
1164 break;
1165 default:
1166 ret_val = -ENOENT;
1167 }
913 break; 1168 break;
914#endif /* IPv6 */ 1169#endif /* IPv6 */
915 default: 1170 default:
@@ -936,12 +1191,13 @@ int netlbl_req_setattr(struct request_sock *req,
936{ 1191{
937 int ret_val; 1192 int ret_val;
938 struct netlbl_dommap_def *entry; 1193 struct netlbl_dommap_def *entry;
1194 struct inet_request_sock *ireq = inet_rsk(req);
939 1195
940 rcu_read_lock(); 1196 rcu_read_lock();
941 switch (req->rsk_ops->family) { 1197 switch (req->rsk_ops->family) {
942 case AF_INET: 1198 case AF_INET:
943 entry = netlbl_domhsh_getentry_af4(secattr->domain, 1199 entry = netlbl_domhsh_getentry_af4(secattr->domain,
944 inet_rsk(req)->ir_rmt_addr); 1200 ireq->ir_rmt_addr);
945 if (entry == NULL) { 1201 if (entry == NULL) {
946 ret_val = -ENOENT; 1202 ret_val = -ENOENT;
947 goto req_setattr_return; 1203 goto req_setattr_return;
@@ -952,9 +1208,7 @@ int netlbl_req_setattr(struct request_sock *req,
952 entry->cipso, secattr); 1208 entry->cipso, secattr);
953 break; 1209 break;
954 case NETLBL_NLTYPE_UNLABELED: 1210 case NETLBL_NLTYPE_UNLABELED:
955 /* just delete the protocols we support for right now 1211 netlbl_req_delattr(req);
956 * but we could remove other protocols if needed */
957 cipso_v4_req_delattr(req);
958 ret_val = 0; 1212 ret_val = 0;
959 break; 1213 break;
960 default: 1214 default:
@@ -963,9 +1217,24 @@ int netlbl_req_setattr(struct request_sock *req,
963 break; 1217 break;
964#if IS_ENABLED(CONFIG_IPV6) 1218#if IS_ENABLED(CONFIG_IPV6)
965 case AF_INET6: 1219 case AF_INET6:
966 /* since we don't support any IPv6 labeling protocols right 1220 entry = netlbl_domhsh_getentry_af6(secattr->domain,
967 * now we can optimize everything away until we do */ 1221 &ireq->ir_v6_rmt_addr);
968 ret_val = 0; 1222 if (entry == NULL) {
1223 ret_val = -ENOENT;
1224 goto req_setattr_return;
1225 }
1226 switch (entry->type) {
1227 case NETLBL_NLTYPE_CALIPSO:
1228 ret_val = calipso_req_setattr(req,
1229 entry->calipso, secattr);
1230 break;
1231 case NETLBL_NLTYPE_UNLABELED:
1232 netlbl_req_delattr(req);
1233 ret_val = 0;
1234 break;
1235 default:
1236 ret_val = -ENOENT;
1237 }
969 break; 1238 break;
970#endif /* IPv6 */ 1239#endif /* IPv6 */
971 default: 1240 default:
@@ -987,7 +1256,16 @@ req_setattr_return:
987*/ 1256*/
988void netlbl_req_delattr(struct request_sock *req) 1257void netlbl_req_delattr(struct request_sock *req)
989{ 1258{
990 cipso_v4_req_delattr(req); 1259 switch (req->rsk_ops->family) {
1260 case AF_INET:
1261 cipso_v4_req_delattr(req);
1262 break;
1263#if IS_ENABLED(CONFIG_IPV6)
1264 case AF_INET6:
1265 calipso_req_delattr(req);
1266 break;
1267#endif /* IPv6 */
1268 }
991} 1269}
992 1270
993/** 1271/**
@@ -1007,13 +1285,17 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
1007{ 1285{
1008 int ret_val; 1286 int ret_val;
1009 struct iphdr *hdr4; 1287 struct iphdr *hdr4;
1288#if IS_ENABLED(CONFIG_IPV6)
1289 struct ipv6hdr *hdr6;
1290#endif
1010 struct netlbl_dommap_def *entry; 1291 struct netlbl_dommap_def *entry;
1011 1292
1012 rcu_read_lock(); 1293 rcu_read_lock();
1013 switch (family) { 1294 switch (family) {
1014 case AF_INET: 1295 case AF_INET:
1015 hdr4 = ip_hdr(skb); 1296 hdr4 = ip_hdr(skb);
1016 entry = netlbl_domhsh_getentry_af4(secattr->domain,hdr4->daddr); 1297 entry = netlbl_domhsh_getentry_af4(secattr->domain,
1298 hdr4->daddr);
1017 if (entry == NULL) { 1299 if (entry == NULL) {
1018 ret_val = -ENOENT; 1300 ret_val = -ENOENT;
1019 goto skbuff_setattr_return; 1301 goto skbuff_setattr_return;
@@ -1034,9 +1316,26 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
1034 break; 1316 break;
1035#if IS_ENABLED(CONFIG_IPV6) 1317#if IS_ENABLED(CONFIG_IPV6)
1036 case AF_INET6: 1318 case AF_INET6:
1037 /* since we don't support any IPv6 labeling protocols right 1319 hdr6 = ipv6_hdr(skb);
1038 * now we can optimize everything away until we do */ 1320 entry = netlbl_domhsh_getentry_af6(secattr->domain,
1039 ret_val = 0; 1321 &hdr6->daddr);
1322 if (entry == NULL) {
1323 ret_val = -ENOENT;
1324 goto skbuff_setattr_return;
1325 }
1326 switch (entry->type) {
1327 case NETLBL_NLTYPE_CALIPSO:
1328 ret_val = calipso_skbuff_setattr(skb, entry->calipso,
1329 secattr);
1330 break;
1331 case NETLBL_NLTYPE_UNLABELED:
1332 /* just delete the protocols we support for right now
1333 * but we could remove other protocols if needed */
1334 ret_val = calipso_skbuff_delattr(skb);
1335 break;
1336 default:
1337 ret_val = -ENOENT;
1338 }
1040 break; 1339 break;
1041#endif /* IPv6 */ 1340#endif /* IPv6 */
1042 default: 1341 default:
@@ -1075,6 +1374,9 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
1075 break; 1374 break;
1076#if IS_ENABLED(CONFIG_IPV6) 1375#if IS_ENABLED(CONFIG_IPV6)
1077 case AF_INET6: 1376 case AF_INET6:
1377 ptr = calipso_optptr(skb);
1378 if (ptr && calipso_getattr(ptr, secattr) == 0)
1379 return 0;
1078 break; 1380 break;
1079#endif /* IPv6 */ 1381#endif /* IPv6 */
1080 } 1382 }
@@ -1085,6 +1387,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
1085/** 1387/**
1086 * netlbl_skbuff_err - Handle a LSM error on a sk_buff 1388 * netlbl_skbuff_err - Handle a LSM error on a sk_buff
1087 * @skb: the packet 1389 * @skb: the packet
1390 * @family: the family
1088 * @error: the error code 1391 * @error: the error code
1089 * @gateway: true if host is acting as a gateway, false otherwise 1392 * @gateway: true if host is acting as a gateway, false otherwise
1090 * 1393 *
@@ -1094,10 +1397,14 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
1094 * according to the packet's labeling protocol. 1397 * according to the packet's labeling protocol.
1095 * 1398 *
1096 */ 1399 */
1097void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway) 1400void netlbl_skbuff_err(struct sk_buff *skb, u16 family, int error, int gateway)
1098{ 1401{
1099 if (cipso_v4_optptr(skb)) 1402 switch (family) {
1100 cipso_v4_error(skb, error, gateway); 1403 case AF_INET:
1404 if (cipso_v4_optptr(skb))
1405 cipso_v4_error(skb, error, gateway);
1406 break;
1407 }
1101} 1408}
1102 1409
1103/** 1410/**
@@ -1112,11 +1419,15 @@ void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway)
1112void netlbl_cache_invalidate(void) 1419void netlbl_cache_invalidate(void)
1113{ 1420{
1114 cipso_v4_cache_invalidate(); 1421 cipso_v4_cache_invalidate();
1422#if IS_ENABLED(CONFIG_IPV6)
1423 calipso_cache_invalidate();
1424#endif /* IPv6 */
1115} 1425}
1116 1426
1117/** 1427/**
1118 * netlbl_cache_add - Add an entry to a NetLabel protocol cache 1428 * netlbl_cache_add - Add an entry to a NetLabel protocol cache
1119 * @skb: the packet 1429 * @skb: the packet
1430 * @family: the family
1120 * @secattr: the packet's security attributes 1431 * @secattr: the packet's security attributes
1121 * 1432 *
1122 * Description: 1433 * Description:
@@ -1125,7 +1436,7 @@ void netlbl_cache_invalidate(void)
1125 * values on error. 1436 * values on error.
1126 * 1437 *
1127 */ 1438 */
1128int netlbl_cache_add(const struct sk_buff *skb, 1439int netlbl_cache_add(const struct sk_buff *skb, u16 family,
1129 const struct netlbl_lsm_secattr *secattr) 1440 const struct netlbl_lsm_secattr *secattr)
1130{ 1441{
1131 unsigned char *ptr; 1442 unsigned char *ptr;
@@ -1133,10 +1444,20 @@ int netlbl_cache_add(const struct sk_buff *skb,
1133 if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0) 1444 if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
1134 return -ENOMSG; 1445 return -ENOMSG;
1135 1446
1136 ptr = cipso_v4_optptr(skb); 1447 switch (family) {
1137 if (ptr) 1448 case AF_INET:
1138 return cipso_v4_cache_add(ptr, secattr); 1449 ptr = cipso_v4_optptr(skb);
1139 1450 if (ptr)
1451 return cipso_v4_cache_add(ptr, secattr);
1452 break;
1453#if IS_ENABLED(CONFIG_IPV6)
1454 case AF_INET6:
1455 ptr = calipso_optptr(skb);
1456 if (ptr)
1457 return calipso_cache_add(ptr, secattr);
1458 break;
1459#endif /* IPv6 */
1460 }
1140 return -ENOMSG; 1461 return -ENOMSG;
1141} 1462}
1142 1463
@@ -1161,6 +1482,7 @@ struct audit_buffer *netlbl_audit_start(int type,
1161{ 1482{
1162 return netlbl_audit_start_common(type, audit_info); 1483 return netlbl_audit_start_common(type, audit_info);
1163} 1484}
1485EXPORT_SYMBOL(netlbl_audit_start);
1164 1486
1165/* 1487/*
1166 * Setup Functions 1488 * Setup Functions
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index 13f777f20995..f85d0e07af2d 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -41,8 +41,10 @@
41#include <net/ipv6.h> 41#include <net/ipv6.h>
42#include <net/netlabel.h> 42#include <net/netlabel.h>
43#include <net/cipso_ipv4.h> 43#include <net/cipso_ipv4.h>
44#include <net/calipso.h>
44#include <linux/atomic.h> 45#include <linux/atomic.h>
45 46
47#include "netlabel_calipso.h"
46#include "netlabel_domainhash.h" 48#include "netlabel_domainhash.h"
47#include "netlabel_user.h" 49#include "netlabel_user.h"
48#include "netlabel_mgmt.h" 50#include "netlabel_mgmt.h"
@@ -72,6 +74,8 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
72 [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 }, 74 [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
73 [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 }, 75 [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
74 [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 }, 76 [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
77 [NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 },
78 [NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 },
75}; 79};
76 80
77/* 81/*
@@ -95,6 +99,9 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
95 int ret_val = -EINVAL; 99 int ret_val = -EINVAL;
96 struct netlbl_domaddr_map *addrmap = NULL; 100 struct netlbl_domaddr_map *addrmap = NULL;
97 struct cipso_v4_doi *cipsov4 = NULL; 101 struct cipso_v4_doi *cipsov4 = NULL;
102#if IS_ENABLED(CONFIG_IPV6)
103 struct calipso_doi *calipso = NULL;
104#endif
98 u32 tmp_val; 105 u32 tmp_val;
99 struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL); 106 struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
100 107
@@ -119,6 +126,11 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
119 126
120 switch (entry->def.type) { 127 switch (entry->def.type) {
121 case NETLBL_NLTYPE_UNLABELED: 128 case NETLBL_NLTYPE_UNLABELED:
129 if (info->attrs[NLBL_MGMT_A_FAMILY])
130 entry->family =
131 nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
132 else
133 entry->family = AF_UNSPEC;
122 break; 134 break;
123 case NETLBL_NLTYPE_CIPSOV4: 135 case NETLBL_NLTYPE_CIPSOV4:
124 if (!info->attrs[NLBL_MGMT_A_CV4DOI]) 136 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
@@ -128,12 +140,30 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
128 cipsov4 = cipso_v4_doi_getdef(tmp_val); 140 cipsov4 = cipso_v4_doi_getdef(tmp_val);
129 if (cipsov4 == NULL) 141 if (cipsov4 == NULL)
130 goto add_free_domain; 142 goto add_free_domain;
143 entry->family = AF_INET;
131 entry->def.cipso = cipsov4; 144 entry->def.cipso = cipsov4;
132 break; 145 break;
146#if IS_ENABLED(CONFIG_IPV6)
147 case NETLBL_NLTYPE_CALIPSO:
148 if (!info->attrs[NLBL_MGMT_A_CLPDOI])
149 goto add_free_domain;
150
151 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
152 calipso = calipso_doi_getdef(tmp_val);
153 if (calipso == NULL)
154 goto add_free_domain;
155 entry->family = AF_INET6;
156 entry->def.calipso = calipso;
157 break;
158#endif /* IPv6 */
133 default: 159 default:
134 goto add_free_domain; 160 goto add_free_domain;
135 } 161 }
136 162
163 if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
164 (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
165 goto add_doi_put_def;
166
137 if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) { 167 if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
138 struct in_addr *addr; 168 struct in_addr *addr;
139 struct in_addr *mask; 169 struct in_addr *mask;
@@ -178,6 +208,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
178 goto add_free_addrmap; 208 goto add_free_addrmap;
179 } 209 }
180 210
211 entry->family = AF_INET;
181 entry->def.type = NETLBL_NLTYPE_ADDRSELECT; 212 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
182 entry->def.addrsel = addrmap; 213 entry->def.addrsel = addrmap;
183#if IS_ENABLED(CONFIG_IPV6) 214#if IS_ENABLED(CONFIG_IPV6)
@@ -220,6 +251,8 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
220 map->list.mask = *mask; 251 map->list.mask = *mask;
221 map->list.valid = 1; 252 map->list.valid = 1;
222 map->def.type = entry->def.type; 253 map->def.type = entry->def.type;
254 if (calipso)
255 map->def.calipso = calipso;
223 256
224 ret_val = netlbl_af6list_add(&map->list, &addrmap->list6); 257 ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
225 if (ret_val != 0) { 258 if (ret_val != 0) {
@@ -227,6 +260,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
227 goto add_free_addrmap; 260 goto add_free_addrmap;
228 } 261 }
229 262
263 entry->family = AF_INET6;
230 entry->def.type = NETLBL_NLTYPE_ADDRSELECT; 264 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
231 entry->def.addrsel = addrmap; 265 entry->def.addrsel = addrmap;
232#endif /* IPv6 */ 266#endif /* IPv6 */
@@ -242,6 +276,9 @@ add_free_addrmap:
242 kfree(addrmap); 276 kfree(addrmap);
243add_doi_put_def: 277add_doi_put_def:
244 cipso_v4_doi_putdef(cipsov4); 278 cipso_v4_doi_putdef(cipsov4);
279#if IS_ENABLED(CONFIG_IPV6)
280 calipso_doi_putdef(calipso);
281#endif
245add_free_domain: 282add_free_domain:
246 kfree(entry->domain); 283 kfree(entry->domain);
247add_free_entry: 284add_free_entry:
@@ -278,6 +315,10 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
278 return ret_val; 315 return ret_val;
279 } 316 }
280 317
318 ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
319 if (ret_val != 0)
320 return ret_val;
321
281 switch (entry->def.type) { 322 switch (entry->def.type) {
282 case NETLBL_NLTYPE_ADDRSELECT: 323 case NETLBL_NLTYPE_ADDRSELECT:
283 nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST); 324 nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
@@ -340,6 +381,15 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
340 if (ret_val != 0) 381 if (ret_val != 0)
341 return ret_val; 382 return ret_val;
342 383
384 switch (map6->def.type) {
385 case NETLBL_NLTYPE_CALIPSO:
386 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
387 map6->def.calipso->doi);
388 if (ret_val != 0)
389 return ret_val;
390 break;
391 }
392
343 nla_nest_end(skb, nla_b); 393 nla_nest_end(skb, nla_b);
344 } 394 }
345#endif /* IPv6 */ 395#endif /* IPv6 */
@@ -347,15 +397,25 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
347 nla_nest_end(skb, nla_a); 397 nla_nest_end(skb, nla_a);
348 break; 398 break;
349 case NETLBL_NLTYPE_UNLABELED: 399 case NETLBL_NLTYPE_UNLABELED:
350 ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type); 400 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
401 entry->def.type);
351 break; 402 break;
352 case NETLBL_NLTYPE_CIPSOV4: 403 case NETLBL_NLTYPE_CIPSOV4:
353 ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type); 404 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
405 entry->def.type);
354 if (ret_val != 0) 406 if (ret_val != 0)
355 return ret_val; 407 return ret_val;
356 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, 408 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
357 entry->def.cipso->doi); 409 entry->def.cipso->doi);
358 break; 410 break;
411 case NETLBL_NLTYPE_CALIPSO:
412 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
413 entry->def.type);
414 if (ret_val != 0)
415 return ret_val;
416 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
417 entry->def.calipso->doi);
418 break;
359 } 419 }
360 420
361 return ret_val; 421 return ret_val;
@@ -418,7 +478,7 @@ static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
418 netlbl_netlink_auditinfo(skb, &audit_info); 478 netlbl_netlink_auditinfo(skb, &audit_info);
419 479
420 domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]); 480 domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
421 return netlbl_domhsh_remove(domain, &audit_info); 481 return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
422} 482}
423 483
424/** 484/**
@@ -536,7 +596,7 @@ static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
536 596
537 netlbl_netlink_auditinfo(skb, &audit_info); 597 netlbl_netlink_auditinfo(skb, &audit_info);
538 598
539 return netlbl_domhsh_remove_default(&audit_info); 599 return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
540} 600}
541 601
542/** 602/**
@@ -556,6 +616,12 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
556 struct sk_buff *ans_skb = NULL; 616 struct sk_buff *ans_skb = NULL;
557 void *data; 617 void *data;
558 struct netlbl_dom_map *entry; 618 struct netlbl_dom_map *entry;
619 u16 family;
620
621 if (info->attrs[NLBL_MGMT_A_FAMILY])
622 family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
623 else
624 family = AF_INET;
559 625
560 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 626 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
561 if (ans_skb == NULL) 627 if (ans_skb == NULL)
@@ -566,7 +632,7 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
566 goto listdef_failure; 632 goto listdef_failure;
567 633
568 rcu_read_lock(); 634 rcu_read_lock();
569 entry = netlbl_domhsh_getentry(NULL); 635 entry = netlbl_domhsh_getentry(NULL, family);
570 if (entry == NULL) { 636 if (entry == NULL) {
571 ret_val = -ENOENT; 637 ret_val = -ENOENT;
572 goto listdef_failure_lock; 638 goto listdef_failure_lock;
@@ -651,6 +717,15 @@ static int netlbl_mgmt_protocols(struct sk_buff *skb,
651 goto protocols_return; 717 goto protocols_return;
652 protos_sent++; 718 protos_sent++;
653 } 719 }
720#if IS_ENABLED(CONFIG_IPV6)
721 if (protos_sent == 2) {
722 if (netlbl_mgmt_protocols_cb(skb,
723 cb,
724 NETLBL_NLTYPE_CALIPSO) < 0)
725 goto protocols_return;
726 protos_sent++;
727 }
728#endif
654 729
655protocols_return: 730protocols_return:
656 cb->args[0] = protos_sent; 731 cb->args[0] = protos_sent;
diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h
index 8b6e1ab62b48..ea01e42bca78 100644
--- a/net/netlabel/netlabel_mgmt.h
+++ b/net/netlabel/netlabel_mgmt.h
@@ -58,7 +58,10 @@
58 * 58 *
59 * NLBL_MGMT_A_CV4DOI 59 * NLBL_MGMT_A_CV4DOI
60 * 60 *
61 * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. 61 * If using NETLBL_NLTYPE_UNLABELED no other attributes are required,
62 * however the following attribute may optionally be sent:
63 *
64 * NLBL_MGMT_A_FAMILY
62 * 65 *
63 * o REMOVE: 66 * o REMOVE:
64 * Sent by an application to remove a domain mapping from the NetLabel 67 * Sent by an application to remove a domain mapping from the NetLabel
@@ -77,6 +80,7 @@
77 * Required attributes: 80 * Required attributes:
78 * 81 *
79 * NLBL_MGMT_A_DOMAIN 82 * NLBL_MGMT_A_DOMAIN
83 * NLBL_MGMT_A_FAMILY
80 * 84 *
81 * If the IP address selectors are not used the following attribute is 85 * If the IP address selectors are not used the following attribute is
82 * required: 86 * required:
@@ -108,7 +112,10 @@
108 * 112 *
109 * NLBL_MGMT_A_CV4DOI 113 * NLBL_MGMT_A_CV4DOI
110 * 114 *
111 * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. 115 * If using NETLBL_NLTYPE_UNLABELED no other attributes are required,
116 * however the following attribute may optionally be sent:
117 *
118 * NLBL_MGMT_A_FAMILY
112 * 119 *
113 * o REMOVEDEF: 120 * o REMOVEDEF:
114 * Sent by an application to remove the default domain mapping from the 121 * Sent by an application to remove the default domain mapping from the
@@ -117,13 +124,17 @@
117 * o LISTDEF: 124 * o LISTDEF:
118 * This message can be sent either from an application or by the kernel in 125 * This message can be sent either from an application or by the kernel in
119 * response to an application generated LISTDEF message. When sent by an 126 * response to an application generated LISTDEF message. When sent by an
120 * application there is no payload. On success the kernel should send a 127 * application there may be an optional payload.
121 * response using the following format.
122 * 128 *
123 * If the IP address selectors are not used the following attribute is 129 * NLBL_MGMT_A_FAMILY
130 *
131 * On success the kernel should send a response using the following format:
132 *
133 * If the IP address selectors are not used the following attributes are
124 * required: 134 * required:
125 * 135 *
126 * NLBL_MGMT_A_PROTOCOL 136 * NLBL_MGMT_A_PROTOCOL
137 * NLBL_MGMT_A_FAMILY
127 * 138 *
128 * If the IP address selectors are used then the following attritbute is 139 * If the IP address selectors are used then the following attritbute is
129 * required: 140 * required:
@@ -209,6 +220,12 @@ enum {
209 /* (NLA_NESTED) 220 /* (NLA_NESTED)
210 * the selector list, there must be at least one 221 * the selector list, there must be at least one
211 * NLBL_MGMT_A_ADDRSELECTOR attribute */ 222 * NLBL_MGMT_A_ADDRSELECTOR attribute */
223 NLBL_MGMT_A_FAMILY,
224 /* (NLA_U16)
225 * The address family */
226 NLBL_MGMT_A_CLPDOI,
227 /* (NLA_U32)
228 * the CALIPSO DOI value */
212 __NLBL_MGMT_A_MAX, 229 __NLBL_MGMT_A_MAX,
213}; 230};
214#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1) 231#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 9eaa9a1e8629..4528cff9138b 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -116,8 +116,8 @@ struct netlbl_unlhsh_walk_arg {
116static DEFINE_SPINLOCK(netlbl_unlhsh_lock); 116static DEFINE_SPINLOCK(netlbl_unlhsh_lock);
117#define netlbl_unlhsh_rcu_deref(p) \ 117#define netlbl_unlhsh_rcu_deref(p) \
118 rcu_dereference_check(p, lockdep_is_held(&netlbl_unlhsh_lock)) 118 rcu_dereference_check(p, lockdep_is_held(&netlbl_unlhsh_lock))
119static struct netlbl_unlhsh_tbl *netlbl_unlhsh; 119static struct netlbl_unlhsh_tbl __rcu *netlbl_unlhsh;
120static struct netlbl_unlhsh_iface *netlbl_unlhsh_def; 120static struct netlbl_unlhsh_iface __rcu *netlbl_unlhsh_def;
121 121
122/* Accept unlabeled packets flag */ 122/* Accept unlabeled packets flag */
123static u8 netlabel_unlabel_acceptflg; 123static u8 netlabel_unlabel_acceptflg;
@@ -1537,6 +1537,7 @@ int __init netlbl_unlabel_defconf(void)
1537 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 1537 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1538 if (entry == NULL) 1538 if (entry == NULL)
1539 return -ENOMEM; 1539 return -ENOMEM;
1540 entry->family = AF_UNSPEC;
1540 entry->def.type = NETLBL_NLTYPE_UNLABELED; 1541 entry->def.type = NETLBL_NLTYPE_UNLABELED;
1541 ret_val = netlbl_domhsh_add_default(entry, &audit_info); 1542 ret_val = netlbl_domhsh_add_default(entry, &audit_info);
1542 if (ret_val != 0) 1543 if (ret_val != 0)
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index adf8b7900da2..58495f44c62a 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -44,6 +44,7 @@
44#include "netlabel_mgmt.h" 44#include "netlabel_mgmt.h"
45#include "netlabel_unlabeled.h" 45#include "netlabel_unlabeled.h"
46#include "netlabel_cipso_v4.h" 46#include "netlabel_cipso_v4.h"
47#include "netlabel_calipso.h"
47#include "netlabel_user.h" 48#include "netlabel_user.h"
48 49
49/* 50/*
@@ -71,6 +72,10 @@ int __init netlbl_netlink_init(void)
71 if (ret_val != 0) 72 if (ret_val != 0)
72 return ret_val; 73 return ret_val;
73 74
75 ret_val = netlbl_calipso_genl_init();
76 if (ret_val != 0)
77 return ret_val;
78
74 return netlbl_unlabel_genl_init(); 79 return netlbl_unlabel_genl_init();
75} 80}
76 81