blob: 6f9c6589a022f2ead3337b3589b675aaf383c805 [file] [log] [blame]
Huw Daviescb72d382016-06-27 15:02:46 -04001/*
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
Huw Daviese1ce69d2016-06-27 15:02:48 -040049/* 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
Huw Daviesd7cce012016-06-27 15:02:49 -040056/* Argument struct for netlbl_domhsh_walk() */
57struct netlbl_domhsh_walk_arg {
58 struct netlbl_audit *audit_info;
59 u32 doi;
60};
61
Huw Daviescb72d382016-06-27 15:02:46 -040062/* 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
Huw Daviesa5e34492016-06-27 15:02:47 -0400140/**
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
Huw Daviese1ce69d2016-06-27 15:02:48 -0400199/**
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
Huw Daviesd7cce012016-06-27 15:02:49 -0400266/**
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
Huw Daviescb72d382016-06-27 15:02:46 -0400324/* 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 },
Huw Daviesa5e34492016-06-27 15:02:47 -0400335 {
Huw Daviesd7cce012016-06-27 15:02:49 -0400336 .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 {
Huw Daviesa5e34492016-06-27 15:02:47 -0400343 .cmd = NLBL_CALIPSO_C_LIST,
344 .flags = 0,
345 .policy = calipso_genl_policy,
346 .doit = netlbl_calipso_list,
347 .dumpit = NULL,
348 },
Huw Daviese1ce69d2016-06-27 15:02:48 -0400349 {
350 .cmd = NLBL_CALIPSO_C_LISTALL,
351 .flags = 0,
352 .policy = calipso_genl_policy,
353 .doit = NULL,
354 .dumpit = netlbl_calipso_listall,
355 },
Huw Daviescb72d382016-06-27 15:02:46 -0400356};
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}
Huw Daviesa5e34492016-06-27 15:02:47 -0400435
436/**
Huw Daviesd7cce012016-06-27 15:02:49 -0400437 * 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/**
Huw Daviesa5e34492016-06-27 15:02:47 -0400458 * 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}
Huw Daviese1ce69d2016-06-27 15:02:48 -0400492
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}
Huw Daviesceba1832016-06-27 15:02:51 -0400517
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}