summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuw Davies <huw@codeweavers.com>2016-06-27 15:02:51 -0400
committerPaul Moore <paul@paul-moore.com>2016-06-27 15:02:51 -0400
commitceba1832b1b2da0149c51de62a847c00bca1677a (patch)
tree5f03426f96c98a387cc1087865fe99b32410561c
parent3faa8f982f958961fda68b8d63e682fe77a032d4 (diff)
calipso: Set the calipso socket label to match the secattr.
CALIPSO is a hop-by-hop IPv6 option. A lot of this patch is based on the equivalent CISPO code. The main difference is due to manipulating the options in the hop-by-hop header. Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Paul Moore <paul@paul-moore.com>
-rw-r--r--include/net/ipv6.h2
-rw-r--r--include/net/netlabel.h9
-rw-r--r--include/uapi/linux/in6.h1
-rw-r--r--net/ipv6/calipso.c595
-rw-r--r--net/ipv6/ipv6_sockglue.c1
-rw-r--r--net/netlabel/Kconfig1
-rw-r--r--net/netlabel/netlabel_calipso.c64
-rw-r--r--net/netlabel/netlabel_calipso.h5
-rw-r--r--net/netlabel/netlabel_kapi.c58
-rw-r--r--security/selinux/netlabel.c2
10 files changed, 728 insertions, 10 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 887313d978d0..4e279a83cdd0 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -319,6 +319,8 @@ struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
319 319
320bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb, 320bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb,
321 const struct inet6_skb_parm *opt); 321 const struct inet6_skb_parm *opt);
322struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
323 struct ipv6_txoptions *opt);
322 324
323static inline bool ipv6_accept_ra(struct inet6_dev *idev) 325static inline bool ipv6_accept_ra(struct inet6_dev *idev)
324{ 326{
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index 9fc2cab9be98..918a6044c89c 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -226,6 +226,9 @@ struct netlbl_lsm_secattr {
226 * @doi_getdef: returns a reference to a DOI 226 * @doi_getdef: returns a reference to a DOI
227 * @doi_putdef: releases a reference of a DOI 227 * @doi_putdef: releases a reference of a DOI
228 * @doi_walk: enumerate the DOI list 228 * @doi_walk: enumerate the DOI list
229 * @sock_getattr: retrieve the socket's attr
230 * @sock_setattr: set the socket's attr
231 * @sock_delattr: remove the socket's attr
229 * 232 *
230 * Description: 233 * Description:
231 * This structure is filled out by the CALIPSO engine and passed 234 * This structure is filled out by the CALIPSO engine and passed
@@ -243,6 +246,12 @@ struct netlbl_calipso_ops {
243 int (*doi_walk)(u32 *skip_cnt, 246 int (*doi_walk)(u32 *skip_cnt,
244 int (*callback)(struct calipso_doi *doi_def, void *arg), 247 int (*callback)(struct calipso_doi *doi_def, void *arg),
245 void *cb_arg); 248 void *cb_arg);
249 int (*sock_getattr)(struct sock *sk,
250 struct netlbl_lsm_secattr *secattr);
251 int (*sock_setattr)(struct sock *sk,
252 const struct calipso_doi *doi_def,
253 const struct netlbl_lsm_secattr *secattr);
254 void (*sock_delattr)(struct sock *sk);
246}; 255};
247 256
248/* 257/*
diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h
index 318a4828bf98..b39ea4f2e701 100644
--- a/include/uapi/linux/in6.h
+++ b/include/uapi/linux/in6.h
@@ -143,6 +143,7 @@ struct in6_flowlabel_req {
143#define IPV6_TLV_PAD1 0 143#define IPV6_TLV_PAD1 0
144#define IPV6_TLV_PADN 1 144#define IPV6_TLV_PADN 1
145#define IPV6_TLV_ROUTERALERT 5 145#define IPV6_TLV_ROUTERALERT 5
146#define IPV6_TLV_CALIPSO 7 /* RFC 5570 */
146#define IPV6_TLV_JUMBO 194 147#define IPV6_TLV_JUMBO 194
147#define IPV6_TLV_HAO 201 /* home address option */ 148#define IPV6_TLV_HAO 201 /* home address option */
148 149
diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c
index d7df7a4bd32e..959db5268b38 100644
--- a/net/ipv6/calipso.c
+++ b/net/ipv6/calipso.c
@@ -44,6 +44,24 @@
44#include <linux/atomic.h> 44#include <linux/atomic.h>
45#include <linux/bug.h> 45#include <linux/bug.h>
46#include <asm/unaligned.h> 46#include <asm/unaligned.h>
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
47 65
48/* List of available DOI definitions */ 66/* List of available DOI definitions */
49static DEFINE_SPINLOCK(calipso_doi_list_lock); 67static DEFINE_SPINLOCK(calipso_doi_list_lock);
@@ -297,6 +315,580 @@ doi_walk_return:
297 return ret_val; 315 return ret_val;
298} 316}
299 317
318/**
319 * calipso_map_cat_hton - Perform a category mapping from host to network
320 * @doi_def: the DOI definition
321 * @secattr: the security attributes
322 * @net_cat: the zero'd out category bitmap in network/CALIPSO format
323 * @net_cat_len: the length of the CALIPSO bitmap in bytes
324 *
325 * Description:
326 * Perform a label mapping to translate a local MLS category bitmap to the
327 * correct CALIPSO bitmap using the given DOI definition. Returns the minimum
328 * size in bytes of the network bitmap on success, negative values otherwise.
329 *
330 */
331static int calipso_map_cat_hton(const struct calipso_doi *doi_def,
332 const struct netlbl_lsm_secattr *secattr,
333 unsigned char *net_cat,
334 u32 net_cat_len)
335{
336 int spot = -1;
337 u32 net_spot_max = 0;
338 u32 net_clen_bits = net_cat_len * 8;
339
340 for (;;) {
341 spot = netlbl_catmap_walk(secattr->attr.mls.cat,
342 spot + 1);
343 if (spot < 0)
344 break;
345 if (spot >= net_clen_bits)
346 return -ENOSPC;
347 netlbl_bitmap_setbit(net_cat, spot, 1);
348
349 if (spot > net_spot_max)
350 net_spot_max = spot;
351 }
352
353 return (net_spot_max / 32 + 1) * 4;
354}
355
356/**
357 * calipso_map_cat_ntoh - Perform a category mapping from network to host
358 * @doi_def: the DOI definition
359 * @net_cat: the category bitmap in network/CALIPSO format
360 * @net_cat_len: the length of the CALIPSO bitmap in bytes
361 * @secattr: the security attributes
362 *
363 * Description:
364 * Perform a label mapping to translate a CALIPSO bitmap to the correct local
365 * MLS category bitmap using the given DOI definition. Returns zero on
366 * success, negative values on failure.
367 *
368 */
369static int calipso_map_cat_ntoh(const struct calipso_doi *doi_def,
370 const unsigned char *net_cat,
371 u32 net_cat_len,
372 struct netlbl_lsm_secattr *secattr)
373{
374 int ret_val;
375 int spot = -1;
376 u32 net_clen_bits = net_cat_len * 8;
377
378 for (;;) {
379 spot = netlbl_bitmap_walk(net_cat,
380 net_clen_bits,
381 spot + 1,
382 1);
383 if (spot < 0) {
384 if (spot == -2)
385 return -EFAULT;
386 return 0;
387 }
388
389 ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat,
390 spot,
391 GFP_ATOMIC);
392 if (ret_val != 0)
393 return ret_val;
394 }
395
396 return -EINVAL;
397}
398
399/**
400 * calipso_pad_write - Writes pad bytes in TLV format
401 * @buf: the buffer
402 * @offset: offset from start of buffer to write padding
403 * @count: number of pad bytes to write
404 *
405 * Description:
406 * Write @count bytes of TLV padding into @buffer starting at offset @offset.
407 * @count should be less than 8 - see RFC 4942.
408 *
409 */
410static int calipso_pad_write(unsigned char *buf, unsigned int offset,
411 unsigned int count)
412{
413 if (WARN_ON_ONCE(count >= 8))
414 return -EINVAL;
415
416 switch (count) {
417 case 0:
418 break;
419 case 1:
420 buf[offset] = IPV6_TLV_PAD1;
421 break;
422 default:
423 buf[offset] = IPV6_TLV_PADN;
424 buf[offset + 1] = count - 2;
425 if (count > 2)
426 memset(buf + offset + 2, 0, count - 2);
427 break;
428 }
429 return 0;
430}
431
432/**
433 * calipso_genopt - Generate a CALIPSO option
434 * @buf: the option buffer
435 * @start: offset from which to write
436 * @buf_len: the size of opt_buf
437 * @doi_def: the CALIPSO DOI to use
438 * @secattr: the security attributes
439 *
440 * Description:
441 * Generate a CALIPSO option using the DOI definition and security attributes
442 * passed to the function. This also generates upto three bytes of leading
443 * padding that ensures that the option is 4n + 2 aligned. It returns the
444 * number of bytes written (including any initial padding).
445 */
446static int calipso_genopt(unsigned char *buf, u32 start, u32 buf_len,
447 const struct calipso_doi *doi_def,
448 const struct netlbl_lsm_secattr *secattr)
449{
450 int ret_val;
451 u32 len, pad;
452 u16 crc;
453 static const unsigned char padding[4] = {2, 1, 0, 3};
454 unsigned char *calipso;
455
456 /* CALIPSO has 4n + 2 alignment */
457 pad = padding[start & 3];
458 if (buf_len <= start + pad + CALIPSO_HDR_LEN)
459 return -ENOSPC;
460
461 if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0)
462 return -EPERM;
463
464 len = CALIPSO_HDR_LEN;
465
466 if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
467 ret_val = calipso_map_cat_hton(doi_def,
468 secattr,
469 buf + start + pad + len,
470 buf_len - start - pad - len);
471 if (ret_val < 0)
472 return ret_val;
473 len += ret_val;
474 }
475
476 calipso_pad_write(buf, start, pad);
477 calipso = buf + start + pad;
478
479 calipso[0] = IPV6_TLV_CALIPSO;
480 calipso[1] = len - 2;
481 *(__be32 *)(calipso + 2) = htonl(doi_def->doi);
482 calipso[6] = (len - CALIPSO_HDR_LEN) / 4;
483 calipso[7] = secattr->attr.mls.lvl,
484 crc = ~crc_ccitt(0xffff, calipso, len);
485 calipso[8] = crc & 0xff;
486 calipso[9] = (crc >> 8) & 0xff;
487 return pad + len;
488}
489
490/* Hop-by-hop hdr helper functions
491 */
492
493/**
494 * calipso_opt_update - Replaces socket's hop options with a new set
495 * @sk: the socket
496 * @hop: new hop options
497 *
498 * Description:
499 * Replaces @sk's hop options with @hop. @hop may be NULL to leave
500 * the socket with no hop options.
501 *
502 */
503static int calipso_opt_update(struct sock *sk, struct ipv6_opt_hdr *hop)
504{
505 struct ipv6_txoptions *old = txopt_get(inet6_sk(sk)), *txopts;
506
507 txopts = ipv6_renew_options_kern(sk, old, IPV6_HOPOPTS,
508 hop, hop ? ipv6_optlen(hop) : 0);
509 txopt_put(old);
510 if (IS_ERR(txopts))
511 return PTR_ERR(txopts);
512
513 txopts = ipv6_update_options(sk, txopts);
514 if (txopts) {
515 atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
516 txopt_put(txopts);
517 }
518
519 return 0;
520}
521
522/**
523 * calipso_tlv_len - Returns the length of the TLV
524 * @opt: the option header
525 * @offset: offset of the TLV within the header
526 *
527 * Description:
528 * Returns the length of the TLV option at offset @offset within
529 * the option header @opt. Checks that the entire TLV fits inside
530 * the option header, returns a negative value if this is not the case.
531 */
532static int calipso_tlv_len(struct ipv6_opt_hdr *opt, unsigned int offset)
533{
534 unsigned char *tlv = (unsigned char *)opt;
535 unsigned int opt_len = ipv6_optlen(opt), tlv_len;
536
537 if (offset < sizeof(*opt) || offset >= opt_len)
538 return -EINVAL;
539 if (tlv[offset] == IPV6_TLV_PAD1)
540 return 1;
541 if (offset + 1 >= opt_len)
542 return -EINVAL;
543 tlv_len = tlv[offset + 1] + 2;
544 if (offset + tlv_len > opt_len)
545 return -EINVAL;
546 return tlv_len;
547}
548
549/**
550 * calipso_opt_find - Finds the CALIPSO option in an IPv6 hop options header
551 * @hop: the hop options header
552 * @start: on return holds the offset of any leading padding
553 * @end: on return holds the offset of the first non-pad TLV after CALIPSO
554 *
555 * Description:
556 * Finds the space occupied by a CALIPSO option (including any leading and
557 * trailing padding).
558 *
559 * If a CALIPSO option exists set @start and @end to the
560 * offsets within @hop of the start of padding before the first
561 * CALIPSO option and the end of padding after the first CALIPSO
562 * option. In this case the function returns 0.
563 *
564 * In the absence of a CALIPSO option, @start and @end will be
565 * set to the start and end of any trailing padding in the header.
566 * This is useful when appending a new option, as the caller may want
567 * to overwrite some of this padding. In this case the function will
568 * return -ENOENT.
569 */
570static int calipso_opt_find(struct ipv6_opt_hdr *hop, unsigned int *start,
571 unsigned int *end)
572{
573 int ret_val = -ENOENT, tlv_len;
574 unsigned int opt_len, offset, offset_s = 0, offset_e = 0;
575 unsigned char *opt = (unsigned char *)hop;
576
577 opt_len = ipv6_optlen(hop);
578 offset = sizeof(*hop);
579
580 while (offset < opt_len) {
581 tlv_len = calipso_tlv_len(hop, offset);
582 if (tlv_len < 0)
583 return tlv_len;
584
585 switch (opt[offset]) {
586 case IPV6_TLV_PAD1:
587 case IPV6_TLV_PADN:
588 if (offset_e)
589 offset_e = offset;
590 break;
591 case IPV6_TLV_CALIPSO:
592 ret_val = 0;
593 offset_e = offset;
594 break;
595 default:
596 if (offset_e == 0)
597 offset_s = offset;
598 else
599 goto out;
600 }
601 offset += tlv_len;
602 }
603
604out:
605 if (offset_s)
606 *start = offset_s + calipso_tlv_len(hop, offset_s);
607 else
608 *start = sizeof(*hop);
609 if (offset_e)
610 *end = offset_e + calipso_tlv_len(hop, offset_e);
611 else
612 *end = opt_len;
613
614 return ret_val;
615}
616
617/**
618 * calipso_opt_insert - Inserts a CALIPSO option into an IPv6 hop opt hdr
619 * @hop: the original hop options header
620 * @doi_def: the CALIPSO DOI to use
621 * @secattr: the specific security attributes of the socket
622 *
623 * Description:
624 * Creates a new hop options header based on @hop with a
625 * CALIPSO option added to it. If @hop already contains a CALIPSO
626 * option this is overwritten, otherwise the new option is appended
627 * after any existing options. If @hop is NULL then the new header
628 * will contain just the CALIPSO option and any needed padding.
629 *
630 */
631static struct ipv6_opt_hdr *
632calipso_opt_insert(struct ipv6_opt_hdr *hop,
633 const struct calipso_doi *doi_def,
634 const struct netlbl_lsm_secattr *secattr)
635{
636 unsigned int start, end, buf_len, pad, hop_len;
637 struct ipv6_opt_hdr *new;
638 int ret_val;
639
640 if (hop) {
641 hop_len = ipv6_optlen(hop);
642 ret_val = calipso_opt_find(hop, &start, &end);
643 if (ret_val && ret_val != -ENOENT)
644 return ERR_PTR(ret_val);
645 } else {
646 hop_len = 0;
647 start = sizeof(*hop);
648 end = 0;
649 }
650
651 buf_len = hop_len + start - end + CALIPSO_OPT_LEN_MAX_WITH_PAD;
652 new = kzalloc(buf_len, GFP_ATOMIC);
653 if (!new)
654 return ERR_PTR(-ENOMEM);
655
656 if (start > sizeof(*hop))
657 memcpy(new, hop, start);
658 ret_val = calipso_genopt((unsigned char *)new, start, buf_len, doi_def,
659 secattr);
660 if (ret_val < 0)
661 return ERR_PTR(ret_val);
662
663 buf_len = start + ret_val;
664 /* At this point buf_len aligns to 4n, so (buf_len & 4) pads to 8n */
665 pad = ((buf_len & 4) + (end & 7)) & 7;
666 calipso_pad_write((unsigned char *)new, buf_len, pad);
667 buf_len += pad;
668
669 if (end != hop_len) {
670 memcpy((char *)new + buf_len, (char *)hop + end, hop_len - end);
671 buf_len += hop_len - end;
672 }
673 new->nexthdr = 0;
674 new->hdrlen = buf_len / 8 - 1;
675
676 return new;
677}
678
679/**
680 * calipso_opt_del - Removes the CALIPSO option from an option header
681 * @hop: the original header
682 * @new: the new header
683 *
684 * Description:
685 * Creates a new header based on @hop without any CALIPSO option. If @hop
686 * doesn't contain a CALIPSO option it returns -ENOENT. If @hop contains
687 * no other non-padding options, it returns zero with @new set to NULL.
688 * Otherwise it returns zero, creates a new header without the CALIPSO
689 * option (and removing as much padding as possible) and returns with
690 * @new set to that header.
691 *
692 */
693static int calipso_opt_del(struct ipv6_opt_hdr *hop,
694 struct ipv6_opt_hdr **new)
695{
696 int ret_val;
697 unsigned int start, end, delta, pad, hop_len;
698
699 ret_val = calipso_opt_find(hop, &start, &end);
700 if (ret_val)
701 return ret_val;
702
703 hop_len = ipv6_optlen(hop);
704 if (start == sizeof(*hop) && end == hop_len) {
705 /* There's no other option in the header so return NULL */
706 *new = NULL;
707 return 0;
708 }
709
710 delta = (end - start) & ~7;
711 *new = kzalloc(hop_len - delta, GFP_ATOMIC);
712 if (!*new)
713 return -ENOMEM;
714
715 memcpy(*new, hop, start);
716 (*new)->hdrlen -= delta / 8;
717 pad = (end - start) & 7;
718 calipso_pad_write((unsigned char *)*new, start, pad);
719 if (end != hop_len)
720 memcpy((char *)*new + start + pad, (char *)hop + end,
721 hop_len - end);
722
723 return 0;
724}
725
726/**
727 * calipso_opt_getattr - Get the security attributes from a memory block
728 * @calipso: the CALIPSO option
729 * @secattr: the security attributes
730 *
731 * Description:
732 * Inspect @calipso and return the security attributes in @secattr.
733 * Returns zero on success and negative values on failure.
734 *
735 */
736static int calipso_opt_getattr(const unsigned char *calipso,
737 struct netlbl_lsm_secattr *secattr)
738{
739 int ret_val = -ENOMSG;
740 u32 doi, len = calipso[1], cat_len = calipso[6] * 4;
741 struct calipso_doi *doi_def;
742
743 if (cat_len + 8 > len)
744 return -EINVAL;
745
746 doi = get_unaligned_be32(calipso + 2);
747 rcu_read_lock();
748 doi_def = calipso_doi_search(doi);
749 if (!doi_def)
750 goto getattr_return;
751
752 secattr->attr.mls.lvl = calipso[7];
753 secattr->flags |= NETLBL_SECATTR_MLS_LVL;
754
755 if (cat_len) {
756 ret_val = calipso_map_cat_ntoh(doi_def,
757 calipso + 10,
758 cat_len,
759 secattr);
760 if (ret_val != 0) {
761 netlbl_catmap_free(secattr->attr.mls.cat);
762 goto getattr_return;
763 }
764
765 secattr->flags |= NETLBL_SECATTR_MLS_CAT;
766 }
767
768 secattr->type = NETLBL_NLTYPE_CALIPSO;
769
770getattr_return:
771 rcu_read_unlock();
772 return ret_val;
773}
774
775/* sock functions.
776 */
777
778/**
779 * calipso_sock_getattr - Get the security attributes from a sock
780 * @sk: the sock
781 * @secattr: the security attributes
782 *
783 * Description:
784 * Query @sk to see if there is a CALIPSO option attached to the sock and if
785 * there is return the CALIPSO security attributes in @secattr. This function
786 * requires that @sk be locked, or privately held, but it does not do any
787 * locking itself. Returns zero on success and negative values on failure.
788 *
789 */
790static int calipso_sock_getattr(struct sock *sk,
791 struct netlbl_lsm_secattr *secattr)
792{
793 struct ipv6_opt_hdr *hop;
794 int opt_len, len, ret_val = -ENOMSG, offset;
795 unsigned char *opt;
796 struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
797
798 if (!txopts || !txopts->hopopt)
799 goto done;
800
801 hop = txopts->hopopt;
802 opt = (unsigned char *)hop;
803 opt_len = ipv6_optlen(hop);
804 offset = sizeof(*hop);
805 while (offset < opt_len) {
806 len = calipso_tlv_len(hop, offset);
807 if (len < 0) {
808 ret_val = len;
809 goto done;
810 }
811 switch (opt[offset]) {
812 case IPV6_TLV_CALIPSO:
813 if (len < CALIPSO_HDR_LEN)
814 ret_val = -EINVAL;
815 else
816 ret_val = calipso_opt_getattr(&opt[offset],
817 secattr);
818 goto done;
819 default:
820 offset += len;
821 break;
822 }
823 }
824done:
825 txopt_put(txopts);
826 return ret_val;
827}
828
829/**
830 * calipso_sock_setattr - Add a CALIPSO option to a socket
831 * @sk: the socket
832 * @doi_def: the CALIPSO DOI to use
833 * @secattr: the specific security attributes of the socket
834 *
835 * Description:
836 * Set the CALIPSO option on the given socket using the DOI definition and
837 * security attributes passed to the function. This function requires
838 * exclusive access to @sk, which means it either needs to be in the
839 * process of being created or locked. Returns zero on success and negative
840 * values on failure.
841 *
842 */
843static int calipso_sock_setattr(struct sock *sk,
844 const struct calipso_doi *doi_def,
845 const struct netlbl_lsm_secattr *secattr)
846{
847 int ret_val;
848 struct ipv6_opt_hdr *old, *new;
849 struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
850
851 old = NULL;
852 if (txopts)
853 old = txopts->hopopt;
854
855 new = calipso_opt_insert(old, doi_def, secattr);
856 txopt_put(txopts);
857 if (IS_ERR(new))
858 return PTR_ERR(new);
859
860 ret_val = calipso_opt_update(sk, new);
861
862 kfree(new);
863 return ret_val;
864}
865
866/**
867 * calipso_sock_delattr - Delete the CALIPSO option from a socket
868 * @sk: the socket
869 *
870 * Description:
871 * Removes the CALIPSO option from a socket, if present.
872 *
873 */
874static void calipso_sock_delattr(struct sock *sk)
875{
876 struct ipv6_opt_hdr *new_hop;
877 struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
878
879 if (!txopts || !txopts->hopopt)
880 goto done;
881
882 if (calipso_opt_del(txopts->hopopt, &new_hop))
883 goto done;
884
885 calipso_opt_update(sk, new_hop);
886 kfree(new_hop);
887
888done:
889 txopt_put(txopts);
890}
891
300static const struct netlbl_calipso_ops ops = { 892static const struct netlbl_calipso_ops ops = {
301 .doi_add = calipso_doi_add, 893 .doi_add = calipso_doi_add,
302 .doi_free = calipso_doi_free, 894 .doi_free = calipso_doi_free,
@@ -304,6 +896,9 @@ static const struct netlbl_calipso_ops ops = {
304 .doi_getdef = calipso_doi_getdef, 896 .doi_getdef = calipso_doi_getdef,
305 .doi_putdef = calipso_doi_putdef, 897 .doi_putdef = calipso_doi_putdef,
306 .doi_walk = calipso_doi_walk, 898 .doi_walk = calipso_doi_walk,
899 .sock_getattr = calipso_sock_getattr,
900 .sock_setattr = calipso_sock_setattr,
901 .sock_delattr = calipso_sock_delattr,
307}; 902};
308 903
309/** 904/**
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 4449ad1f8114..8a80d59bed34 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -98,7 +98,6 @@ int ip6_ra_control(struct sock *sk, int sel)
98 return 0; 98 return 0;
99} 99}
100 100
101static
102struct ipv6_txoptions *ipv6_update_options(struct sock *sk, 101struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
103 struct ipv6_txoptions *opt) 102 struct ipv6_txoptions *opt)
104{ 103{
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/netlabel_calipso.c b/net/netlabel/netlabel_calipso.c
index 2857673e8802..6f9c6589a022 100644
--- a/net/netlabel/netlabel_calipso.c
+++ b/net/netlabel/netlabel_calipso.c
@@ -514,3 +514,67 @@ int calipso_doi_walk(u32 *skip_cnt,
514 ret_val = ops->doi_walk(skip_cnt, callback, cb_arg); 514 ret_val = ops->doi_walk(skip_cnt, callback, cb_arg);
515 return ret_val; 515 return ret_val;
516} 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}
diff --git a/net/netlabel/netlabel_calipso.h b/net/netlabel/netlabel_calipso.h
index ed78554ba472..49bc116705c4 100644
--- a/net/netlabel/netlabel_calipso.h
+++ b/net/netlabel/netlabel_calipso.h
@@ -128,5 +128,10 @@ void calipso_doi_putdef(struct calipso_doi *doi_def);
128int calipso_doi_walk(u32 *skip_cnt, 128int calipso_doi_walk(u32 *skip_cnt,
129 int (*callback)(struct calipso_doi *doi_def, void *arg), 129 int (*callback)(struct calipso_doi *doi_def, void *arg),
130 void *cb_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);
131 136
132#endif 137#endif
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index 54f13a33b52c..00bab51c291e 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"
@@ -521,6 +523,7 @@ int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset)
521 523
522 return -ENOENT; 524 return -ENOENT;
523} 525}
526EXPORT_SYMBOL(netlbl_catmap_walk);
524 527
525/** 528/**
526 * netlbl_catmap_walkrng - Find the end of a string of set bits 529 * netlbl_catmap_walkrng - Find the end of a string of set bits
@@ -656,6 +659,7 @@ int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap,
656 659
657 return 0; 660 return 0;
658} 661}
662EXPORT_SYMBOL(netlbl_catmap_setbit);
659 663
660/** 664/**
661 * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap 665 * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap
@@ -870,9 +874,21 @@ int netlbl_sock_setattr(struct sock *sk,
870 break; 874 break;
871#if IS_ENABLED(CONFIG_IPV6) 875#if IS_ENABLED(CONFIG_IPV6)
872 case AF_INET6: 876 case AF_INET6:
873 /* since we don't support any IPv6 labeling protocols right 877 switch (dom_entry->def.type) {
874 * now we can optimize everything away until we do */ 878 case NETLBL_NLTYPE_ADDRSELECT:
875 ret_val = 0; 879 ret_val = -EDESTADDRREQ;
880 break;
881 case NETLBL_NLTYPE_CALIPSO:
882 ret_val = calipso_sock_setattr(sk,
883 dom_entry->def.calipso,
884 secattr);
885 break;
886 case NETLBL_NLTYPE_UNLABELED:
887 ret_val = 0;
888 break;
889 default:
890 ret_val = -ENOENT;
891 }
876 break; 892 break;
877#endif /* IPv6 */ 893#endif /* IPv6 */
878 default: 894 default:
@@ -899,6 +915,11 @@ void netlbl_sock_delattr(struct sock *sk)
899 case AF_INET: 915 case AF_INET:
900 cipso_v4_sock_delattr(sk); 916 cipso_v4_sock_delattr(sk);
901 break; 917 break;
918#if IS_ENABLED(CONFIG_IPV6)
919 case AF_INET6:
920 calipso_sock_delattr(sk);
921 break;
922#endif /* IPv6 */
902 } 923 }
903} 924}
904 925
@@ -925,7 +946,7 @@ int netlbl_sock_getattr(struct sock *sk,
925 break; 946 break;
926#if IS_ENABLED(CONFIG_IPV6) 947#if IS_ENABLED(CONFIG_IPV6)
927 case AF_INET6: 948 case AF_INET6:
928 ret_val = -ENOMSG; 949 ret_val = calipso_sock_getattr(sk, secattr);
929 break; 950 break;
930#endif /* IPv6 */ 951#endif /* IPv6 */
931 default: 952 default:
@@ -953,6 +974,9 @@ int netlbl_conn_setattr(struct sock *sk,
953{ 974{
954 int ret_val; 975 int ret_val;
955 struct sockaddr_in *addr4; 976 struct sockaddr_in *addr4;
977#if IS_ENABLED(CONFIG_IPV6)
978 struct sockaddr_in6 *addr6;
979#endif
956 struct netlbl_dommap_def *entry; 980 struct netlbl_dommap_def *entry;
957 981
958 rcu_read_lock(); 982 rcu_read_lock();
@@ -973,7 +997,7 @@ int netlbl_conn_setattr(struct sock *sk,
973 case NETLBL_NLTYPE_UNLABELED: 997 case NETLBL_NLTYPE_UNLABELED:
974 /* just delete the protocols we support for right now 998 /* just delete the protocols we support for right now
975 * but we could remove other protocols if needed */ 999 * but we could remove other protocols if needed */
976 cipso_v4_sock_delattr(sk); 1000 netlbl_sock_delattr(sk);
977 ret_val = 0; 1001 ret_val = 0;
978 break; 1002 break;
979 default: 1003 default:
@@ -982,9 +1006,27 @@ int netlbl_conn_setattr(struct sock *sk,
982 break; 1006 break;
983#if IS_ENABLED(CONFIG_IPV6) 1007#if IS_ENABLED(CONFIG_IPV6)
984 case AF_INET6: 1008 case AF_INET6:
985 /* since we don't support any IPv6 labeling protocols right 1009 addr6 = (struct sockaddr_in6 *)addr;
986 * now we can optimize everything away until we do */ 1010 entry = netlbl_domhsh_getentry_af6(secattr->domain,
987 ret_val = 0; 1011 &addr6->sin6_addr);
1012 if (entry == NULL) {
1013 ret_val = -ENOENT;
1014 goto conn_setattr_return;
1015 }
1016 switch (entry->type) {
1017 case NETLBL_NLTYPE_CALIPSO:
1018 ret_val = calipso_sock_setattr(sk,
1019 entry->calipso, secattr);
1020 break;
1021 case NETLBL_NLTYPE_UNLABELED:
1022 /* just delete the protocols we support for right now
1023 * but we could remove other protocols if needed */
1024 netlbl_sock_delattr(sk);
1025 ret_val = 0;
1026 break;
1027 default:
1028 ret_val = -ENOENT;
1029 }
988 break; 1030 break;
989#endif /* IPv6 */ 1031#endif /* IPv6 */
990 default: 1032 default:
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 1f989a539fd4..5470f32eca54 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -333,7 +333,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
333 struct sk_security_struct *sksec = sk->sk_security; 333 struct sk_security_struct *sksec = sk->sk_security;
334 struct netlbl_lsm_secattr *secattr; 334 struct netlbl_lsm_secattr *secattr;
335 335
336 if (family != PF_INET) 336 if (family != PF_INET && family != PF_INET6)
337 return 0; 337 return 0;
338 338
339 secattr = selinux_netlbl_sock_genattr(sk); 339 secattr = selinux_netlbl_sock_genattr(sk);