netlabel: Pass a family parameter to netlbl_skbuff_err().
[linux-block.git] / net / ipv6 / calipso.c
CommitLineData
cb72d382
HD
1/*
2 * CALIPSO - Common Architecture Label IPv6 Security Option
3 *
4 * This is an implementation of the CALIPSO protocol as specified in
5 * RFC 5570.
6 *
7 * Authors: Paul Moore <paul.moore@hp.com>
8 * Huw Davies <huw@codeweavers.com>
9 *
10 */
11
12/* (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
13 * (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
23 * the GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see <http://www.gnu.org/licenses/>.
27 *
28 */
29
30#include <linux/init.h>
31#include <linux/types.h>
32#include <linux/rcupdate.h>
33#include <linux/list.h>
34#include <linux/spinlock.h>
35#include <linux/string.h>
36#include <linux/jhash.h>
37#include <linux/audit.h>
38#include <linux/slab.h>
39#include <net/ip.h>
40#include <net/icmp.h>
41#include <net/tcp.h>
42#include <net/netlabel.h>
43#include <net/calipso.h>
44#include <linux/atomic.h>
45#include <linux/bug.h>
46#include <asm/unaligned.h>
ceba1832
HD
47#include <linux/crc-ccitt.h>
48
49/* Maximium size of the calipso option including
50 * the two-byte TLV header.
51 */
52#define CALIPSO_OPT_LEN_MAX (2 + 252)
53
54/* Size of the minimum calipso option including
55 * the two-byte TLV header.
56 */
57#define CALIPSO_HDR_LEN (2 + 8)
58
59/* Maximium size of the calipso option including
60 * the two-byte TLV header and upto 3 bytes of
61 * leading pad and 7 bytes of trailing pad.
62 */
63#define CALIPSO_OPT_LEN_MAX_WITH_PAD (3 + CALIPSO_OPT_LEN_MAX + 7)
64
2917f57b
HD
65 /* Maximium size of u32 aligned buffer required to hold calipso
66 * option. Max of 3 initial pad bytes starting from buffer + 3.
67 * i.e. the worst case is when the previous tlv finishes on 4n + 3.
68 */
69#define CALIPSO_MAX_BUFFER (6 + CALIPSO_OPT_LEN_MAX)
cb72d382
HD
70
71/* List of available DOI definitions */
72static DEFINE_SPINLOCK(calipso_doi_list_lock);
73static LIST_HEAD(calipso_doi_list);
74
75/* DOI List Functions
76 */
77
78/**
79 * calipso_doi_search - Searches for a DOI definition
80 * @doi: the DOI to search for
81 *
82 * Description:
83 * Search the DOI definition list for a DOI definition with a DOI value that
84 * matches @doi. The caller is responsible for calling rcu_read_[un]lock().
85 * Returns a pointer to the DOI definition on success and NULL on failure.
86 */
87static struct calipso_doi *calipso_doi_search(u32 doi)
88{
89 struct calipso_doi *iter;
90
91 list_for_each_entry_rcu(iter, &calipso_doi_list, list)
92 if (iter->doi == doi && atomic_read(&iter->refcount))
93 return iter;
94 return NULL;
95}
96
97/**
98 * calipso_doi_add - Add a new DOI to the CALIPSO protocol engine
99 * @doi_def: the DOI structure
100 * @audit_info: NetLabel audit information
101 *
102 * Description:
103 * The caller defines a new DOI for use by the CALIPSO engine and calls this
104 * function to add it to the list of acceptable domains. The caller must
105 * ensure that the mapping table specified in @doi_def->map meets all of the
106 * requirements of the mapping type (see calipso.h for details). Returns
107 * zero on success and non-zero on failure.
108 *
109 */
110static int calipso_doi_add(struct calipso_doi *doi_def,
111 struct netlbl_audit *audit_info)
112{
113 int ret_val = -EINVAL;
114 u32 doi;
115 u32 doi_type;
116 struct audit_buffer *audit_buf;
117
118 doi = doi_def->doi;
119 doi_type = doi_def->type;
120
121 if (doi_def->doi == CALIPSO_DOI_UNKNOWN)
122 goto doi_add_return;
123
124 atomic_set(&doi_def->refcount, 1);
125
126 spin_lock(&calipso_doi_list_lock);
127 if (calipso_doi_search(doi_def->doi)) {
128 spin_unlock(&calipso_doi_list_lock);
129 ret_val = -EEXIST;
130 goto doi_add_return;
131 }
132 list_add_tail_rcu(&doi_def->list, &calipso_doi_list);
133 spin_unlock(&calipso_doi_list_lock);
134 ret_val = 0;
135
136doi_add_return:
137 audit_buf = netlbl_audit_start(AUDIT_MAC_CALIPSO_ADD, audit_info);
138 if (audit_buf) {
139 const char *type_str;
140
141 switch (doi_type) {
142 case CALIPSO_MAP_PASS:
143 type_str = "pass";
144 break;
145 default:
146 type_str = "(unknown)";
147 }
148 audit_log_format(audit_buf,
149 " calipso_doi=%u calipso_type=%s res=%u",
150 doi, type_str, ret_val == 0 ? 1 : 0);
151 audit_log_end(audit_buf);
152 }
153
154 return ret_val;
155}
156
157/**
158 * calipso_doi_free - Frees a DOI definition
159 * @doi_def: the DOI definition
160 *
161 * Description:
162 * This function frees all of the memory associated with a DOI definition.
163 *
164 */
165static void calipso_doi_free(struct calipso_doi *doi_def)
166{
167 kfree(doi_def);
168}
169
a5e34490
HD
170/**
171 * calipso_doi_free_rcu - Frees a DOI definition via the RCU pointer
172 * @entry: the entry's RCU field
173 *
174 * Description:
175 * This function is designed to be used as a callback to the call_rcu()
176 * function so that the memory allocated to the DOI definition can be released
177 * safely.
178 *
179 */
180static void calipso_doi_free_rcu(struct rcu_head *entry)
181{
182 struct calipso_doi *doi_def;
183
184 doi_def = container_of(entry, struct calipso_doi, rcu);
185 calipso_doi_free(doi_def);
186}
187
d7cce015
HD
188/**
189 * calipso_doi_remove - Remove an existing DOI from the CALIPSO protocol engine
190 * @doi: the DOI value
191 * @audit_secid: the LSM secid to use in the audit message
192 *
193 * Description:
194 * Removes a DOI definition from the CALIPSO engine. The NetLabel routines will
195 * be called to release their own LSM domain mappings as well as our own
196 * domain list. Returns zero on success and negative values on failure.
197 *
198 */
199static int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info)
200{
201 int ret_val;
202 struct calipso_doi *doi_def;
203 struct audit_buffer *audit_buf;
204
205 spin_lock(&calipso_doi_list_lock);
206 doi_def = calipso_doi_search(doi);
207 if (!doi_def) {
208 spin_unlock(&calipso_doi_list_lock);
209 ret_val = -ENOENT;
210 goto doi_remove_return;
211 }
212 if (!atomic_dec_and_test(&doi_def->refcount)) {
213 spin_unlock(&calipso_doi_list_lock);
214 ret_val = -EBUSY;
215 goto doi_remove_return;
216 }
217 list_del_rcu(&doi_def->list);
218 spin_unlock(&calipso_doi_list_lock);
219
220 call_rcu(&doi_def->rcu, calipso_doi_free_rcu);
221 ret_val = 0;
222
223doi_remove_return:
224 audit_buf = netlbl_audit_start(AUDIT_MAC_CALIPSO_DEL, audit_info);
225 if (audit_buf) {
226 audit_log_format(audit_buf,
227 " calipso_doi=%u res=%u",
228 doi, ret_val == 0 ? 1 : 0);
229 audit_log_end(audit_buf);
230 }
231
232 return ret_val;
233}
234
a5e34490
HD
235/**
236 * calipso_doi_getdef - Returns a reference to a valid DOI definition
237 * @doi: the DOI value
238 *
239 * Description:
240 * Searches for a valid DOI definition and if one is found it is returned to
241 * the caller. Otherwise NULL is returned. The caller must ensure that
242 * calipso_doi_putdef() is called when the caller is done.
243 *
244 */
245static struct calipso_doi *calipso_doi_getdef(u32 doi)
246{
247 struct calipso_doi *doi_def;
248
249 rcu_read_lock();
250 doi_def = calipso_doi_search(doi);
251 if (!doi_def)
252 goto doi_getdef_return;
253 if (!atomic_inc_not_zero(&doi_def->refcount))
254 doi_def = NULL;
255
256doi_getdef_return:
257 rcu_read_unlock();
258 return doi_def;
259}
260
261/**
262 * calipso_doi_putdef - Releases a reference for the given DOI definition
263 * @doi_def: the DOI definition
264 *
265 * Description:
266 * Releases a DOI definition reference obtained from calipso_doi_getdef().
267 *
268 */
269static void calipso_doi_putdef(struct calipso_doi *doi_def)
270{
271 if (!doi_def)
272 return;
273
274 if (!atomic_dec_and_test(&doi_def->refcount))
275 return;
276 spin_lock(&calipso_doi_list_lock);
277 list_del_rcu(&doi_def->list);
278 spin_unlock(&calipso_doi_list_lock);
279
280 call_rcu(&doi_def->rcu, calipso_doi_free_rcu);
281}
282
e1ce69df
HD
283/**
284 * calipso_doi_walk - Iterate through the DOI definitions
285 * @skip_cnt: skip past this number of DOI definitions, updated
286 * @callback: callback for each DOI definition
287 * @cb_arg: argument for the callback function
288 *
289 * Description:
290 * Iterate over the DOI definition list, skipping the first @skip_cnt entries.
291 * For each entry call @callback, if @callback returns a negative value stop
292 * 'walking' through the list and return. Updates the value in @skip_cnt upon
293 * return. Returns zero on success, negative values on failure.
294 *
295 */
296static int calipso_doi_walk(u32 *skip_cnt,
297 int (*callback)(struct calipso_doi *doi_def,
298 void *arg),
299 void *cb_arg)
300{
301 int ret_val = -ENOENT;
302 u32 doi_cnt = 0;
303 struct calipso_doi *iter_doi;
304
305 rcu_read_lock();
306 list_for_each_entry_rcu(iter_doi, &calipso_doi_list, list)
307 if (atomic_read(&iter_doi->refcount) > 0) {
308 if (doi_cnt++ < *skip_cnt)
309 continue;
310 ret_val = callback(iter_doi, cb_arg);
311 if (ret_val < 0) {
312 doi_cnt--;
313 goto doi_walk_return;
314 }
315 }
316
317doi_walk_return:
318 rcu_read_unlock();
319 *skip_cnt = doi_cnt;
320 return ret_val;
321}
322
ceba1832
HD
323/**
324 * calipso_map_cat_hton - Perform a category mapping from host to network
325 * @doi_def: the DOI definition
326 * @secattr: the security attributes
327 * @net_cat: the zero'd out category bitmap in network/CALIPSO format
328 * @net_cat_len: the length of the CALIPSO bitmap in bytes
329 *
330 * Description:
331 * Perform a label mapping to translate a local MLS category bitmap to the
332 * correct CALIPSO bitmap using the given DOI definition. Returns the minimum
333 * size in bytes of the network bitmap on success, negative values otherwise.
334 *
335 */
336static int calipso_map_cat_hton(const struct calipso_doi *doi_def,
337 const struct netlbl_lsm_secattr *secattr,
338 unsigned char *net_cat,
339 u32 net_cat_len)
340{
341 int spot = -1;
342 u32 net_spot_max = 0;
343 u32 net_clen_bits = net_cat_len * 8;
344
345 for (;;) {
346 spot = netlbl_catmap_walk(secattr->attr.mls.cat,
347 spot + 1);
348 if (spot < 0)
349 break;
350 if (spot >= net_clen_bits)
351 return -ENOSPC;
352 netlbl_bitmap_setbit(net_cat, spot, 1);
353
354 if (spot > net_spot_max)
355 net_spot_max = spot;
356 }
357
358 return (net_spot_max / 32 + 1) * 4;
359}
360
361/**
362 * calipso_map_cat_ntoh - Perform a category mapping from network to host
363 * @doi_def: the DOI definition
364 * @net_cat: the category bitmap in network/CALIPSO format
365 * @net_cat_len: the length of the CALIPSO bitmap in bytes
366 * @secattr: the security attributes
367 *
368 * Description:
369 * Perform a label mapping to translate a CALIPSO bitmap to the correct local
370 * MLS category bitmap using the given DOI definition. Returns zero on
371 * success, negative values on failure.
372 *
373 */
374static int calipso_map_cat_ntoh(const struct calipso_doi *doi_def,
375 const unsigned char *net_cat,
376 u32 net_cat_len,
377 struct netlbl_lsm_secattr *secattr)
378{
379 int ret_val;
380 int spot = -1;
381 u32 net_clen_bits = net_cat_len * 8;
382
383 for (;;) {
384 spot = netlbl_bitmap_walk(net_cat,
385 net_clen_bits,
386 spot + 1,
387 1);
388 if (spot < 0) {
389 if (spot == -2)
390 return -EFAULT;
391 return 0;
392 }
393
394 ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat,
395 spot,
396 GFP_ATOMIC);
397 if (ret_val != 0)
398 return ret_val;
399 }
400
401 return -EINVAL;
402}
403
404/**
405 * calipso_pad_write - Writes pad bytes in TLV format
406 * @buf: the buffer
407 * @offset: offset from start of buffer to write padding
408 * @count: number of pad bytes to write
409 *
410 * Description:
411 * Write @count bytes of TLV padding into @buffer starting at offset @offset.
412 * @count should be less than 8 - see RFC 4942.
413 *
414 */
415static int calipso_pad_write(unsigned char *buf, unsigned int offset,
416 unsigned int count)
417{
418 if (WARN_ON_ONCE(count >= 8))
419 return -EINVAL;
420
421 switch (count) {
422 case 0:
423 break;
424 case 1:
425 buf[offset] = IPV6_TLV_PAD1;
426 break;
427 default:
428 buf[offset] = IPV6_TLV_PADN;
429 buf[offset + 1] = count - 2;
430 if (count > 2)
431 memset(buf + offset + 2, 0, count - 2);
432 break;
433 }
434 return 0;
435}
436
437/**
438 * calipso_genopt - Generate a CALIPSO option
439 * @buf: the option buffer
440 * @start: offset from which to write
441 * @buf_len: the size of opt_buf
442 * @doi_def: the CALIPSO DOI to use
443 * @secattr: the security attributes
444 *
445 * Description:
446 * Generate a CALIPSO option using the DOI definition and security attributes
447 * passed to the function. This also generates upto three bytes of leading
448 * padding that ensures that the option is 4n + 2 aligned. It returns the
449 * number of bytes written (including any initial padding).
450 */
451static int calipso_genopt(unsigned char *buf, u32 start, u32 buf_len,
452 const struct calipso_doi *doi_def,
453 const struct netlbl_lsm_secattr *secattr)
454{
455 int ret_val;
456 u32 len, pad;
457 u16 crc;
458 static const unsigned char padding[4] = {2, 1, 0, 3};
459 unsigned char *calipso;
460
461 /* CALIPSO has 4n + 2 alignment */
462 pad = padding[start & 3];
463 if (buf_len <= start + pad + CALIPSO_HDR_LEN)
464 return -ENOSPC;
465
466 if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0)
467 return -EPERM;
468
469 len = CALIPSO_HDR_LEN;
470
471 if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
472 ret_val = calipso_map_cat_hton(doi_def,
473 secattr,
474 buf + start + pad + len,
475 buf_len - start - pad - len);
476 if (ret_val < 0)
477 return ret_val;
478 len += ret_val;
479 }
480
481 calipso_pad_write(buf, start, pad);
482 calipso = buf + start + pad;
483
484 calipso[0] = IPV6_TLV_CALIPSO;
485 calipso[1] = len - 2;
486 *(__be32 *)(calipso + 2) = htonl(doi_def->doi);
487 calipso[6] = (len - CALIPSO_HDR_LEN) / 4;
488 calipso[7] = secattr->attr.mls.lvl,
489 crc = ~crc_ccitt(0xffff, calipso, len);
490 calipso[8] = crc & 0xff;
491 calipso[9] = (crc >> 8) & 0xff;
492 return pad + len;
493}
494
495/* Hop-by-hop hdr helper functions
496 */
497
498/**
499 * calipso_opt_update - Replaces socket's hop options with a new set
500 * @sk: the socket
501 * @hop: new hop options
502 *
503 * Description:
504 * Replaces @sk's hop options with @hop. @hop may be NULL to leave
505 * the socket with no hop options.
506 *
507 */
508static int calipso_opt_update(struct sock *sk, struct ipv6_opt_hdr *hop)
509{
510 struct ipv6_txoptions *old = txopt_get(inet6_sk(sk)), *txopts;
511
512 txopts = ipv6_renew_options_kern(sk, old, IPV6_HOPOPTS,
513 hop, hop ? ipv6_optlen(hop) : 0);
514 txopt_put(old);
515 if (IS_ERR(txopts))
516 return PTR_ERR(txopts);
517
518 txopts = ipv6_update_options(sk, txopts);
519 if (txopts) {
520 atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
521 txopt_put(txopts);
522 }
523
524 return 0;
525}
526
527/**
528 * calipso_tlv_len - Returns the length of the TLV
529 * @opt: the option header
530 * @offset: offset of the TLV within the header
531 *
532 * Description:
533 * Returns the length of the TLV option at offset @offset within
534 * the option header @opt. Checks that the entire TLV fits inside
535 * the option header, returns a negative value if this is not the case.
536 */
537static int calipso_tlv_len(struct ipv6_opt_hdr *opt, unsigned int offset)
538{
539 unsigned char *tlv = (unsigned char *)opt;
540 unsigned int opt_len = ipv6_optlen(opt), tlv_len;
541
542 if (offset < sizeof(*opt) || offset >= opt_len)
543 return -EINVAL;
544 if (tlv[offset] == IPV6_TLV_PAD1)
545 return 1;
546 if (offset + 1 >= opt_len)
547 return -EINVAL;
548 tlv_len = tlv[offset + 1] + 2;
549 if (offset + tlv_len > opt_len)
550 return -EINVAL;
551 return tlv_len;
552}
553
554/**
555 * calipso_opt_find - Finds the CALIPSO option in an IPv6 hop options header
556 * @hop: the hop options header
557 * @start: on return holds the offset of any leading padding
558 * @end: on return holds the offset of the first non-pad TLV after CALIPSO
559 *
560 * Description:
561 * Finds the space occupied by a CALIPSO option (including any leading and
562 * trailing padding).
563 *
564 * If a CALIPSO option exists set @start and @end to the
565 * offsets within @hop of the start of padding before the first
566 * CALIPSO option and the end of padding after the first CALIPSO
567 * option. In this case the function returns 0.
568 *
569 * In the absence of a CALIPSO option, @start and @end will be
570 * set to the start and end of any trailing padding in the header.
571 * This is useful when appending a new option, as the caller may want
572 * to overwrite some of this padding. In this case the function will
573 * return -ENOENT.
574 */
575static int calipso_opt_find(struct ipv6_opt_hdr *hop, unsigned int *start,
576 unsigned int *end)
577{
578 int ret_val = -ENOENT, tlv_len;
579 unsigned int opt_len, offset, offset_s = 0, offset_e = 0;
580 unsigned char *opt = (unsigned char *)hop;
581
582 opt_len = ipv6_optlen(hop);
583 offset = sizeof(*hop);
584
585 while (offset < opt_len) {
586 tlv_len = calipso_tlv_len(hop, offset);
587 if (tlv_len < 0)
588 return tlv_len;
589
590 switch (opt[offset]) {
591 case IPV6_TLV_PAD1:
592 case IPV6_TLV_PADN:
593 if (offset_e)
594 offset_e = offset;
595 break;
596 case IPV6_TLV_CALIPSO:
597 ret_val = 0;
598 offset_e = offset;
599 break;
600 default:
601 if (offset_e == 0)
602 offset_s = offset;
603 else
604 goto out;
605 }
606 offset += tlv_len;
607 }
608
609out:
610 if (offset_s)
611 *start = offset_s + calipso_tlv_len(hop, offset_s);
612 else
613 *start = sizeof(*hop);
614 if (offset_e)
615 *end = offset_e + calipso_tlv_len(hop, offset_e);
616 else
617 *end = opt_len;
618
619 return ret_val;
620}
621
622/**
623 * calipso_opt_insert - Inserts a CALIPSO option into an IPv6 hop opt hdr
624 * @hop: the original hop options header
625 * @doi_def: the CALIPSO DOI to use
626 * @secattr: the specific security attributes of the socket
627 *
628 * Description:
629 * Creates a new hop options header based on @hop with a
630 * CALIPSO option added to it. If @hop already contains a CALIPSO
631 * option this is overwritten, otherwise the new option is appended
632 * after any existing options. If @hop is NULL then the new header
633 * will contain just the CALIPSO option and any needed padding.
634 *
635 */
636static struct ipv6_opt_hdr *
637calipso_opt_insert(struct ipv6_opt_hdr *hop,
638 const struct calipso_doi *doi_def,
639 const struct netlbl_lsm_secattr *secattr)
640{
641 unsigned int start, end, buf_len, pad, hop_len;
642 struct ipv6_opt_hdr *new;
643 int ret_val;
644
645 if (hop) {
646 hop_len = ipv6_optlen(hop);
647 ret_val = calipso_opt_find(hop, &start, &end);
648 if (ret_val && ret_val != -ENOENT)
649 return ERR_PTR(ret_val);
650 } else {
651 hop_len = 0;
652 start = sizeof(*hop);
653 end = 0;
654 }
655
656 buf_len = hop_len + start - end + CALIPSO_OPT_LEN_MAX_WITH_PAD;
657 new = kzalloc(buf_len, GFP_ATOMIC);
658 if (!new)
659 return ERR_PTR(-ENOMEM);
660
661 if (start > sizeof(*hop))
662 memcpy(new, hop, start);
663 ret_val = calipso_genopt((unsigned char *)new, start, buf_len, doi_def,
664 secattr);
665 if (ret_val < 0)
666 return ERR_PTR(ret_val);
667
668 buf_len = start + ret_val;
669 /* At this point buf_len aligns to 4n, so (buf_len & 4) pads to 8n */
670 pad = ((buf_len & 4) + (end & 7)) & 7;
671 calipso_pad_write((unsigned char *)new, buf_len, pad);
672 buf_len += pad;
673
674 if (end != hop_len) {
675 memcpy((char *)new + buf_len, (char *)hop + end, hop_len - end);
676 buf_len += hop_len - end;
677 }
678 new->nexthdr = 0;
679 new->hdrlen = buf_len / 8 - 1;
680
681 return new;
682}
683
684/**
685 * calipso_opt_del - Removes the CALIPSO option from an option header
686 * @hop: the original header
687 * @new: the new header
688 *
689 * Description:
690 * Creates a new header based on @hop without any CALIPSO option. If @hop
691 * doesn't contain a CALIPSO option it returns -ENOENT. If @hop contains
692 * no other non-padding options, it returns zero with @new set to NULL.
693 * Otherwise it returns zero, creates a new header without the CALIPSO
694 * option (and removing as much padding as possible) and returns with
695 * @new set to that header.
696 *
697 */
698static int calipso_opt_del(struct ipv6_opt_hdr *hop,
699 struct ipv6_opt_hdr **new)
700{
701 int ret_val;
702 unsigned int start, end, delta, pad, hop_len;
703
704 ret_val = calipso_opt_find(hop, &start, &end);
705 if (ret_val)
706 return ret_val;
707
708 hop_len = ipv6_optlen(hop);
709 if (start == sizeof(*hop) && end == hop_len) {
710 /* There's no other option in the header so return NULL */
711 *new = NULL;
712 return 0;
713 }
714
715 delta = (end - start) & ~7;
716 *new = kzalloc(hop_len - delta, GFP_ATOMIC);
717 if (!*new)
718 return -ENOMEM;
719
720 memcpy(*new, hop, start);
721 (*new)->hdrlen -= delta / 8;
722 pad = (end - start) & 7;
723 calipso_pad_write((unsigned char *)*new, start, pad);
724 if (end != hop_len)
725 memcpy((char *)*new + start + pad, (char *)hop + end,
726 hop_len - end);
727
728 return 0;
729}
730
731/**
732 * calipso_opt_getattr - Get the security attributes from a memory block
733 * @calipso: the CALIPSO option
734 * @secattr: the security attributes
735 *
736 * Description:
737 * Inspect @calipso and return the security attributes in @secattr.
738 * Returns zero on success and negative values on failure.
739 *
740 */
741static int calipso_opt_getattr(const unsigned char *calipso,
742 struct netlbl_lsm_secattr *secattr)
743{
744 int ret_val = -ENOMSG;
745 u32 doi, len = calipso[1], cat_len = calipso[6] * 4;
746 struct calipso_doi *doi_def;
747
748 if (cat_len + 8 > len)
749 return -EINVAL;
750
751 doi = get_unaligned_be32(calipso + 2);
752 rcu_read_lock();
753 doi_def = calipso_doi_search(doi);
754 if (!doi_def)
755 goto getattr_return;
756
757 secattr->attr.mls.lvl = calipso[7];
758 secattr->flags |= NETLBL_SECATTR_MLS_LVL;
759
760 if (cat_len) {
761 ret_val = calipso_map_cat_ntoh(doi_def,
762 calipso + 10,
763 cat_len,
764 secattr);
765 if (ret_val != 0) {
766 netlbl_catmap_free(secattr->attr.mls.cat);
767 goto getattr_return;
768 }
769
770 secattr->flags |= NETLBL_SECATTR_MLS_CAT;
771 }
772
773 secattr->type = NETLBL_NLTYPE_CALIPSO;
774
775getattr_return:
776 rcu_read_unlock();
777 return ret_val;
778}
779
780/* sock functions.
781 */
782
783/**
784 * calipso_sock_getattr - Get the security attributes from a sock
785 * @sk: the sock
786 * @secattr: the security attributes
787 *
788 * Description:
789 * Query @sk to see if there is a CALIPSO option attached to the sock and if
790 * there is return the CALIPSO security attributes in @secattr. This function
791 * requires that @sk be locked, or privately held, but it does not do any
792 * locking itself. Returns zero on success and negative values on failure.
793 *
794 */
795static int calipso_sock_getattr(struct sock *sk,
796 struct netlbl_lsm_secattr *secattr)
797{
798 struct ipv6_opt_hdr *hop;
799 int opt_len, len, ret_val = -ENOMSG, offset;
800 unsigned char *opt;
801 struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
802
803 if (!txopts || !txopts->hopopt)
804 goto done;
805
806 hop = txopts->hopopt;
807 opt = (unsigned char *)hop;
808 opt_len = ipv6_optlen(hop);
809 offset = sizeof(*hop);
810 while (offset < opt_len) {
811 len = calipso_tlv_len(hop, offset);
812 if (len < 0) {
813 ret_val = len;
814 goto done;
815 }
816 switch (opt[offset]) {
817 case IPV6_TLV_CALIPSO:
818 if (len < CALIPSO_HDR_LEN)
819 ret_val = -EINVAL;
820 else
821 ret_val = calipso_opt_getattr(&opt[offset],
822 secattr);
823 goto done;
824 default:
825 offset += len;
826 break;
827 }
828 }
829done:
830 txopt_put(txopts);
831 return ret_val;
832}
833
834/**
835 * calipso_sock_setattr - Add a CALIPSO option to a socket
836 * @sk: the socket
837 * @doi_def: the CALIPSO DOI to use
838 * @secattr: the specific security attributes of the socket
839 *
840 * Description:
841 * Set the CALIPSO option on the given socket using the DOI definition and
842 * security attributes passed to the function. This function requires
843 * exclusive access to @sk, which means it either needs to be in the
844 * process of being created or locked. Returns zero on success and negative
845 * values on failure.
846 *
847 */
848static int calipso_sock_setattr(struct sock *sk,
849 const struct calipso_doi *doi_def,
850 const struct netlbl_lsm_secattr *secattr)
851{
852 int ret_val;
853 struct ipv6_opt_hdr *old, *new;
854 struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
855
856 old = NULL;
857 if (txopts)
858 old = txopts->hopopt;
859
860 new = calipso_opt_insert(old, doi_def, secattr);
861 txopt_put(txopts);
862 if (IS_ERR(new))
863 return PTR_ERR(new);
864
865 ret_val = calipso_opt_update(sk, new);
866
867 kfree(new);
868 return ret_val;
869}
870
871/**
872 * calipso_sock_delattr - Delete the CALIPSO option from a socket
873 * @sk: the socket
874 *
875 * Description:
876 * Removes the CALIPSO option from a socket, if present.
877 *
878 */
879static void calipso_sock_delattr(struct sock *sk)
880{
881 struct ipv6_opt_hdr *new_hop;
882 struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
883
884 if (!txopts || !txopts->hopopt)
885 goto done;
886
887 if (calipso_opt_del(txopts->hopopt, &new_hop))
888 goto done;
889
890 calipso_opt_update(sk, new_hop);
891 kfree(new_hop);
892
893done:
894 txopt_put(txopts);
895}
896
e1adea92
HD
897/* request sock functions.
898 */
899
900/**
901 * calipso_req_setattr - Add a CALIPSO option to a connection request socket
902 * @req: the connection request socket
903 * @doi_def: the CALIPSO DOI to use
904 * @secattr: the specific security attributes of the socket
905 *
906 * Description:
907 * Set the CALIPSO option on the given socket using the DOI definition and
908 * security attributes passed to the function. Returns zero on success and
909 * negative values on failure.
910 *
911 */
912static int calipso_req_setattr(struct request_sock *req,
913 const struct calipso_doi *doi_def,
914 const struct netlbl_lsm_secattr *secattr)
915{
916 struct ipv6_txoptions *txopts;
917 struct inet_request_sock *req_inet = inet_rsk(req);
918 struct ipv6_opt_hdr *old, *new;
919 struct sock *sk = sk_to_full_sk(req_to_sk(req));
920
921 if (req_inet->ipv6_opt && req_inet->ipv6_opt->hopopt)
922 old = req_inet->ipv6_opt->hopopt;
923 else
924 old = NULL;
925
926 new = calipso_opt_insert(old, doi_def, secattr);
927 if (IS_ERR(new))
928 return PTR_ERR(new);
929
930 txopts = ipv6_renew_options_kern(sk, req_inet->ipv6_opt, IPV6_HOPOPTS,
931 new, new ? ipv6_optlen(new) : 0);
932
933 kfree(new);
934
935 if (IS_ERR(txopts))
936 return PTR_ERR(txopts);
937
938 txopts = xchg(&req_inet->ipv6_opt, txopts);
939 if (txopts) {
940 atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
941 txopt_put(txopts);
942 }
943
944 return 0;
945}
946
947/**
948 * calipso_req_delattr - Delete the CALIPSO option from a request socket
949 * @reg: the request socket
950 *
951 * Description:
952 * Removes the CALIPSO option from a request socket, if present.
953 *
954 */
955static void calipso_req_delattr(struct request_sock *req)
956{
957 struct inet_request_sock *req_inet = inet_rsk(req);
958 struct ipv6_opt_hdr *new;
959 struct ipv6_txoptions *txopts;
960 struct sock *sk = sk_to_full_sk(req_to_sk(req));
961
962 if (!req_inet->ipv6_opt || !req_inet->ipv6_opt->hopopt)
963 return;
964
965 if (calipso_opt_del(req_inet->ipv6_opt->hopopt, &new))
966 return; /* Nothing to do */
967
968 txopts = ipv6_renew_options_kern(sk, req_inet->ipv6_opt, IPV6_HOPOPTS,
969 new, new ? ipv6_optlen(new) : 0);
970
971 if (!IS_ERR(txopts)) {
972 txopts = xchg(&req_inet->ipv6_opt, txopts);
973 if (txopts) {
974 atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
975 txopt_put(txopts);
976 }
977 }
978 kfree(new);
979}
980
2917f57b
HD
981/* skbuff functions.
982 */
983
984/**
985 * calipso_skbuff_optptr - Find the CALIPSO option in the packet
986 * @skb: the packet
987 *
988 * Description:
989 * Parse the packet's IP header looking for a CALIPSO option. Returns a pointer
990 * to the start of the CALIPSO option on success, NULL if one if not found.
991 *
992 */
993static unsigned char *calipso_skbuff_optptr(const struct sk_buff *skb)
994{
995 const struct ipv6hdr *ip6_hdr = ipv6_hdr(skb);
996 int offset;
997
998 if (ip6_hdr->nexthdr != NEXTHDR_HOP)
999 return NULL;
1000
1001 offset = ipv6_find_tlv(skb, sizeof(*ip6_hdr), IPV6_TLV_CALIPSO);
1002 if (offset >= 0)
1003 return (unsigned char *)ip6_hdr + offset;
1004
1005 return NULL;
1006}
1007
1008/**
1009 * calipso_skbuff_setattr - Set the CALIPSO option on a packet
1010 * @skb: the packet
1011 * @doi_def: the CALIPSO DOI to use
1012 * @secattr: the security attributes
1013 *
1014 * Description:
1015 * Set the CALIPSO option on the given packet based on the security attributes.
1016 * Returns a pointer to the IP header on success and NULL on failure.
1017 *
1018 */
1019static int calipso_skbuff_setattr(struct sk_buff *skb,
1020 const struct calipso_doi *doi_def,
1021 const struct netlbl_lsm_secattr *secattr)
1022{
1023 int ret_val;
1024 struct ipv6hdr *ip6_hdr;
1025 struct ipv6_opt_hdr *hop;
1026 unsigned char buf[CALIPSO_MAX_BUFFER];
1027 int len_delta, new_end, pad;
1028 unsigned int start, end;
1029
1030 ip6_hdr = ipv6_hdr(skb);
1031 if (ip6_hdr->nexthdr == NEXTHDR_HOP) {
1032 hop = (struct ipv6_opt_hdr *)(ip6_hdr + 1);
1033 ret_val = calipso_opt_find(hop, &start, &end);
1034 if (ret_val && ret_val != -ENOENT)
1035 return ret_val;
1036 } else {
1037 start = 0;
1038 end = 0;
1039 }
1040
1041 memset(buf, 0, sizeof(buf));
1042 ret_val = calipso_genopt(buf, start & 3, sizeof(buf), doi_def, secattr);
1043 if (ret_val < 0)
1044 return ret_val;
1045
1046 new_end = start + ret_val;
1047 /* At this point new_end aligns to 4n, so (new_end & 4) pads to 8n */
1048 pad = ((new_end & 4) + (end & 7)) & 7;
1049 len_delta = new_end - (int)end + pad;
1050 ret_val = skb_cow(skb, skb_headroom(skb) + len_delta);
1051 if (ret_val < 0)
1052 return ret_val;
1053
1054 if (len_delta) {
1055 if (len_delta > 0)
1056 skb_push(skb, len_delta);
1057 else
1058 skb_pull(skb, -len_delta);
1059 memmove((char *)ip6_hdr - len_delta, ip6_hdr,
1060 sizeof(*ip6_hdr) + start);
1061 skb_reset_network_header(skb);
1062 ip6_hdr = ipv6_hdr(skb);
1063 }
1064
1065 hop = (struct ipv6_opt_hdr *)(ip6_hdr + 1);
1066 if (start == 0) {
1067 struct ipv6_opt_hdr *new_hop = (struct ipv6_opt_hdr *)buf;
1068
1069 new_hop->nexthdr = ip6_hdr->nexthdr;
1070 new_hop->hdrlen = len_delta / 8 - 1;
1071 ip6_hdr->nexthdr = NEXTHDR_HOP;
1072 } else {
1073 hop->hdrlen += len_delta / 8;
1074 }
1075 memcpy((char *)hop + start, buf + (start & 3), new_end - start);
1076 calipso_pad_write((unsigned char *)hop, new_end, pad);
1077
1078 return 0;
1079}
1080
1081/**
1082 * calipso_skbuff_delattr - Delete any CALIPSO options from a packet
1083 * @skb: the packet
1084 *
1085 * Description:
1086 * Removes any and all CALIPSO options from the given packet. Returns zero on
1087 * success, negative values on failure.
1088 *
1089 */
1090static int calipso_skbuff_delattr(struct sk_buff *skb)
1091{
1092 int ret_val;
1093 struct ipv6hdr *ip6_hdr;
1094 struct ipv6_opt_hdr *old_hop;
1095 u32 old_hop_len, start = 0, end = 0, delta, size, pad;
1096
1097 if (!calipso_skbuff_optptr(skb))
1098 return 0;
1099
1100 /* since we are changing the packet we should make a copy */
1101 ret_val = skb_cow(skb, skb_headroom(skb));
1102 if (ret_val < 0)
1103 return ret_val;
1104
1105 ip6_hdr = ipv6_hdr(skb);
1106 old_hop = (struct ipv6_opt_hdr *)(ip6_hdr + 1);
1107 old_hop_len = ipv6_optlen(old_hop);
1108
1109 ret_val = calipso_opt_find(old_hop, &start, &end);
1110 if (ret_val)
1111 return ret_val;
1112
1113 if (start == sizeof(*old_hop) && end == old_hop_len) {
1114 /* There's no other option in the header so we delete
1115 * the whole thing. */
1116 delta = old_hop_len;
1117 size = sizeof(*ip6_hdr);
1118 ip6_hdr->nexthdr = old_hop->nexthdr;
1119 } else {
1120 delta = (end - start) & ~7;
1121 if (delta)
1122 old_hop->hdrlen -= delta / 8;
1123 pad = (end - start) & 7;
1124 size = sizeof(*ip6_hdr) + start + pad;
1125 calipso_pad_write((unsigned char *)old_hop, start, pad);
1126 }
1127
1128 if (delta) {
1129 skb_pull(skb, delta);
1130 memmove((char *)ip6_hdr + delta, ip6_hdr, size);
1131 skb_reset_network_header(skb);
1132 }
1133
1134 return 0;
1135}
1136
cb72d382
HD
1137static const struct netlbl_calipso_ops ops = {
1138 .doi_add = calipso_doi_add,
1139 .doi_free = calipso_doi_free,
d7cce015 1140 .doi_remove = calipso_doi_remove,
a5e34490
HD
1141 .doi_getdef = calipso_doi_getdef,
1142 .doi_putdef = calipso_doi_putdef,
e1ce69df 1143 .doi_walk = calipso_doi_walk,
ceba1832
HD
1144 .sock_getattr = calipso_sock_getattr,
1145 .sock_setattr = calipso_sock_setattr,
1146 .sock_delattr = calipso_sock_delattr,
e1adea92
HD
1147 .req_setattr = calipso_req_setattr,
1148 .req_delattr = calipso_req_delattr,
2917f57b
HD
1149 .opt_getattr = calipso_opt_getattr,
1150 .skbuff_optptr = calipso_skbuff_optptr,
1151 .skbuff_setattr = calipso_skbuff_setattr,
1152 .skbuff_delattr = calipso_skbuff_delattr,
cb72d382
HD
1153};
1154
1155/**
1156 * calipso_init - Initialize the CALIPSO module
1157 *
1158 * Description:
1159 * Initialize the CALIPSO module and prepare it for use. Returns zero on
1160 * success and negative values on failure.
1161 *
1162 */
1163int __init calipso_init(void)
1164{
1165 netlbl_calipso_ops_register(&ops);
1166 return 0;
1167}
1168
1169void calipso_exit(void)
1170{
1171 netlbl_calipso_ops_register(NULL);
1172}