diff options
author | Huw Davies <huw@codeweavers.com> | 2016-06-27 15:06:15 -0400 |
---|---|---|
committer | Paul Moore <paul@paul-moore.com> | 2016-06-27 15:06:15 -0400 |
commit | 2917f57b6bc15cc6787496ee5f2fdf17f0e9b7d3 (patch) | |
tree | cf6e68541ba82eb7c4b11a7ba563f423060d8b46 /net/ipv6 | |
parent | 0868383b822e4d8ebde980c7aac973a6aa81a3ec (diff) |
calipso: Allow the lsm to label the skbuff directly.
In some cases, the lsm needs to add the label to the skbuff directly.
A NF_INET_LOCAL_OUT IPv6 hook is added to selinux to match the IPv4
behaviour. This allows selinux to label the skbuffs that it requires.
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/calipso.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c index 067a5640ef17..fa371a8827cf 100644 --- a/net/ipv6/calipso.c +++ b/net/ipv6/calipso.c | |||
@@ -62,6 +62,11 @@ | |||
62 | */ | 62 | */ |
63 | #define CALIPSO_OPT_LEN_MAX_WITH_PAD (3 + CALIPSO_OPT_LEN_MAX + 7) | 63 | #define CALIPSO_OPT_LEN_MAX_WITH_PAD (3 + CALIPSO_OPT_LEN_MAX + 7) |
64 | 64 | ||
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) | ||
65 | 70 | ||
66 | /* List of available DOI definitions */ | 71 | /* List of available DOI definitions */ |
67 | static DEFINE_SPINLOCK(calipso_doi_list_lock); | 72 | static DEFINE_SPINLOCK(calipso_doi_list_lock); |
@@ -973,6 +978,162 @@ static void calipso_req_delattr(struct request_sock *req) | |||
973 | kfree(new); | 978 | kfree(new); |
974 | } | 979 | } |
975 | 980 | ||
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 | */ | ||
993 | static 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 | */ | ||
1019 | static 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 | */ | ||
1090 | static 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 | |||
976 | static const struct netlbl_calipso_ops ops = { | 1137 | static const struct netlbl_calipso_ops ops = { |
977 | .doi_add = calipso_doi_add, | 1138 | .doi_add = calipso_doi_add, |
978 | .doi_free = calipso_doi_free, | 1139 | .doi_free = calipso_doi_free, |
@@ -985,6 +1146,10 @@ static const struct netlbl_calipso_ops ops = { | |||
985 | .sock_delattr = calipso_sock_delattr, | 1146 | .sock_delattr = calipso_sock_delattr, |
986 | .req_setattr = calipso_req_setattr, | 1147 | .req_setattr = calipso_req_setattr, |
987 | .req_delattr = calipso_req_delattr, | 1148 | .req_delattr = calipso_req_delattr, |
1149 | .opt_getattr = calipso_opt_getattr, | ||
1150 | .skbuff_optptr = calipso_skbuff_optptr, | ||
1151 | .skbuff_setattr = calipso_skbuff_setattr, | ||
1152 | .skbuff_delattr = calipso_skbuff_delattr, | ||
988 | }; | 1153 | }; |
989 | 1154 | ||
990 | /** | 1155 | /** |