Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cipso: don't use IPCB() to locate the CIPSO IP option

Using the IPCB() macro to get the IPv4 options is convenient, but
unfortunately NetLabel often needs to examine the CIPSO option outside
of the scope of the IP layer in the stack. While historically IPCB()
worked above the IP layer, due to the inclusion of the inet_skb_param
struct at the head of the {tcp,udp}_skb_cb structs, recent commit
971f10ec ("tcp: better TCP_SKB_CB layout to reduce cache line misses")
reordered the tcp_skb_cb struct and invalidated this IPCB() trick.

This patch fixes the problem by creating a new function,
cipso_v4_optptr(), which locates the CIPSO option inside the IP header
without calling IPCB(). Unfortunately, this isn't as fast as a simple
lookup so some additional tweaks were made to limit the use of this
new function.

Cc: <stable@vger.kernel.org> # 3.18
Reported-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Paul Moore <pmoore@redhat.com>
Tested-by: Casey Schaufler <casey@schaufler-ca.com>

+56 -35
+16 -9
include/net/cipso_ipv4.h
··· 121 121 #endif 122 122 123 123 /* 124 - * Helper Functions 125 - */ 126 - 127 - #define CIPSO_V4_OPTEXIST(x) (IPCB(x)->opt.cipso != 0) 128 - #define CIPSO_V4_OPTPTR(x) (skb_network_header(x) + IPCB(x)->opt.cipso) 129 - 130 - /* 131 124 * DOI List Functions 132 125 */ 133 126 ··· 183 190 184 191 #ifdef CONFIG_NETLABEL 185 192 void cipso_v4_cache_invalidate(void); 186 - int cipso_v4_cache_add(const struct sk_buff *skb, 193 + int cipso_v4_cache_add(const unsigned char *cipso_ptr, 187 194 const struct netlbl_lsm_secattr *secattr); 188 195 #else 189 196 static inline void cipso_v4_cache_invalidate(void) ··· 191 198 return; 192 199 } 193 200 194 - static inline int cipso_v4_cache_add(const struct sk_buff *skb, 201 + static inline int cipso_v4_cache_add(const unsigned char *cipso_ptr, 195 202 const struct netlbl_lsm_secattr *secattr) 196 203 { 197 204 return 0; ··· 204 211 205 212 #ifdef CONFIG_NETLABEL 206 213 void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway); 214 + int cipso_v4_getattr(const unsigned char *cipso, 215 + struct netlbl_lsm_secattr *secattr); 207 216 int cipso_v4_sock_setattr(struct sock *sk, 208 217 const struct cipso_v4_doi *doi_def, 209 218 const struct netlbl_lsm_secattr *secattr); ··· 221 226 int cipso_v4_skbuff_delattr(struct sk_buff *skb); 222 227 int cipso_v4_skbuff_getattr(const struct sk_buff *skb, 223 228 struct netlbl_lsm_secattr *secattr); 229 + unsigned char *cipso_v4_optptr(const struct sk_buff *skb); 224 230 int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option); 225 231 #else 226 232 static inline void cipso_v4_error(struct sk_buff *skb, ··· 229 233 u32 gateway) 230 234 { 231 235 return; 236 + } 237 + 238 + static inline int cipso_v4_getattr(const unsigned char *cipso, 239 + struct netlbl_lsm_secattr *secattr) 240 + { 241 + return -ENOSYS; 232 242 } 233 243 234 244 static inline int cipso_v4_sock_setattr(struct sock *sk, ··· 282 280 struct netlbl_lsm_secattr *secattr) 283 281 { 284 282 return -ENOSYS; 283 + } 284 + 285 + static inline unsigned char *cipso_v4_optptr(const struct sk_buff *skb) 286 + { 287 + return NULL; 285 288 } 286 289 287 290 static inline int cipso_v4_validate(const struct sk_buff *skb,
+30 -21
net/ipv4/cipso_ipv4.c
··· 378 378 * negative values on failure. 379 379 * 380 380 */ 381 - int cipso_v4_cache_add(const struct sk_buff *skb, 381 + int cipso_v4_cache_add(const unsigned char *cipso_ptr, 382 382 const struct netlbl_lsm_secattr *secattr) 383 383 { 384 384 int ret_val = -EPERM; 385 385 u32 bkt; 386 386 struct cipso_v4_map_cache_entry *entry = NULL; 387 387 struct cipso_v4_map_cache_entry *old_entry = NULL; 388 - unsigned char *cipso_ptr; 389 388 u32 cipso_ptr_len; 390 389 391 390 if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0) 392 391 return 0; 393 392 394 - cipso_ptr = CIPSO_V4_OPTPTR(skb); 395 393 cipso_ptr_len = cipso_ptr[1]; 396 394 397 395 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); ··· 1577 1579 } 1578 1580 1579 1581 /** 1582 + * cipso_v4_optptr - Find the CIPSO option in the packet 1583 + * @skb: the packet 1584 + * 1585 + * Description: 1586 + * Parse the packet's IP header looking for a CIPSO option. Returns a pointer 1587 + * to the start of the CIPSO option on success, NULL if one if not found. 1588 + * 1589 + */ 1590 + unsigned char *cipso_v4_optptr(const struct sk_buff *skb) 1591 + { 1592 + const struct iphdr *iph = ip_hdr(skb); 1593 + unsigned char *optptr = (unsigned char *)&(ip_hdr(skb)[1]); 1594 + int optlen; 1595 + int taglen; 1596 + 1597 + for (optlen = iph->ihl*4 - sizeof(struct iphdr); optlen > 0; ) { 1598 + if (optptr[0] == IPOPT_CIPSO) 1599 + return optptr; 1600 + taglen = optptr[1]; 1601 + optlen -= taglen; 1602 + optptr += taglen; 1603 + } 1604 + 1605 + return NULL; 1606 + } 1607 + 1608 + /** 1580 1609 * cipso_v4_validate - Validate a CIPSO option 1581 1610 * @option: the start of the option, on error it is set to point to the error 1582 1611 * ··· 2144 2119 * on success and negative values on failure. 2145 2120 * 2146 2121 */ 2147 - static int cipso_v4_getattr(const unsigned char *cipso, 2148 - struct netlbl_lsm_secattr *secattr) 2122 + int cipso_v4_getattr(const unsigned char *cipso, 2123 + struct netlbl_lsm_secattr *secattr) 2149 2124 { 2150 2125 int ret_val = -ENOMSG; 2151 2126 u32 doi; ··· 2328 2303 ip_send_check(iph); 2329 2304 2330 2305 return 0; 2331 - } 2332 - 2333 - /** 2334 - * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option 2335 - * @skb: the packet 2336 - * @secattr: the security attributes 2337 - * 2338 - * Description: 2339 - * Parse the given packet's CIPSO option and return the security attributes. 2340 - * Returns zero on success and negative values on failure. 2341 - * 2342 - */ 2343 - int cipso_v4_skbuff_getattr(const struct sk_buff *skb, 2344 - struct netlbl_lsm_secattr *secattr) 2345 - { 2346 - return cipso_v4_getattr(CIPSO_V4_OPTPTR(skb), secattr); 2347 2306 } 2348 2307 2349 2308 /*
+10 -5
net/netlabel/netlabel_kapi.c
··· 1065 1065 u16 family, 1066 1066 struct netlbl_lsm_secattr *secattr) 1067 1067 { 1068 + unsigned char *ptr; 1069 + 1068 1070 switch (family) { 1069 1071 case AF_INET: 1070 - if (CIPSO_V4_OPTEXIST(skb) && 1071 - cipso_v4_skbuff_getattr(skb, secattr) == 0) 1072 + ptr = cipso_v4_optptr(skb); 1073 + if (ptr && cipso_v4_getattr(ptr, secattr) == 0) 1072 1074 return 0; 1073 1075 break; 1074 1076 #if IS_ENABLED(CONFIG_IPV6) ··· 1096 1094 */ 1097 1095 void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway) 1098 1096 { 1099 - if (CIPSO_V4_OPTEXIST(skb)) 1097 + if (cipso_v4_optptr(skb)) 1100 1098 cipso_v4_error(skb, error, gateway); 1101 1099 } 1102 1100 ··· 1128 1126 int netlbl_cache_add(const struct sk_buff *skb, 1129 1127 const struct netlbl_lsm_secattr *secattr) 1130 1128 { 1129 + unsigned char *ptr; 1130 + 1131 1131 if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0) 1132 1132 return -ENOMSG; 1133 1133 1134 - if (CIPSO_V4_OPTEXIST(skb)) 1135 - return cipso_v4_cache_add(skb, secattr); 1134 + ptr = cipso_v4_optptr(skb); 1135 + if (ptr) 1136 + return cipso_v4_cache_add(ptr, secattr); 1136 1137 1137 1138 return -ENOMSG; 1138 1139 }