aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Moore <pmoore@redhat.com>2015-02-11 14:46:37 -0500
committerPaul Moore <pmoore@redhat.com>2015-02-11 14:46:37 -0500
commit04f81f0154e4bf002be6f4d85668ce1257efa4d9 (patch)
tree6572c58a65fe65aa738419e43e45e59c32538357
parent6eb4e2b41b264f57ee02d16ee61683952945484d (diff)
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>
-rw-r--r--include/net/cipso_ipv4.h25
-rw-r--r--net/ipv4/cipso_ipv4.c51
-rw-r--r--net/netlabel/netlabel_kapi.c15
3 files changed, 56 insertions, 35 deletions
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h
index a6fd939f202d..3ebb168b9afc 100644
--- a/include/net/cipso_ipv4.h
+++ b/include/net/cipso_ipv4.h
@@ -121,13 +121,6 @@ extern int cipso_v4_rbm_strictvalid;
121#endif 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 * DOI List Functions 124 * DOI List Functions
132 */ 125 */
133 126
@@ -190,7 +183,7 @@ static inline int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
190 183
191#ifdef CONFIG_NETLABEL 184#ifdef CONFIG_NETLABEL
192void cipso_v4_cache_invalidate(void); 185void cipso_v4_cache_invalidate(void);
193int cipso_v4_cache_add(const struct sk_buff *skb, 186int cipso_v4_cache_add(const unsigned char *cipso_ptr,
194 const struct netlbl_lsm_secattr *secattr); 187 const struct netlbl_lsm_secattr *secattr);
195#else 188#else
196static inline void cipso_v4_cache_invalidate(void) 189static inline void cipso_v4_cache_invalidate(void)
@@ -198,7 +191,7 @@ static inline void cipso_v4_cache_invalidate(void)
198 return; 191 return;
199} 192}
200 193
201static inline int cipso_v4_cache_add(const struct sk_buff *skb, 194static inline int cipso_v4_cache_add(const unsigned char *cipso_ptr,
202 const struct netlbl_lsm_secattr *secattr) 195 const struct netlbl_lsm_secattr *secattr)
203{ 196{
204 return 0; 197 return 0;
@@ -211,6 +204,8 @@ static inline int cipso_v4_cache_add(const struct sk_buff *skb,
211 204
212#ifdef CONFIG_NETLABEL 205#ifdef CONFIG_NETLABEL
213void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway); 206void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
207int cipso_v4_getattr(const unsigned char *cipso,
208 struct netlbl_lsm_secattr *secattr);
214int cipso_v4_sock_setattr(struct sock *sk, 209int cipso_v4_sock_setattr(struct sock *sk,
215 const struct cipso_v4_doi *doi_def, 210 const struct cipso_v4_doi *doi_def,
216 const struct netlbl_lsm_secattr *secattr); 211 const struct netlbl_lsm_secattr *secattr);
@@ -226,6 +221,7 @@ int cipso_v4_skbuff_setattr(struct sk_buff *skb,
226int cipso_v4_skbuff_delattr(struct sk_buff *skb); 221int cipso_v4_skbuff_delattr(struct sk_buff *skb);
227int cipso_v4_skbuff_getattr(const struct sk_buff *skb, 222int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
228 struct netlbl_lsm_secattr *secattr); 223 struct netlbl_lsm_secattr *secattr);
224unsigned char *cipso_v4_optptr(const struct sk_buff *skb);
229int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option); 225int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option);
230#else 226#else
231static inline void cipso_v4_error(struct sk_buff *skb, 227static inline void cipso_v4_error(struct sk_buff *skb,
@@ -235,6 +231,12 @@ static inline void cipso_v4_error(struct sk_buff *skb,
235 return; 231 return;
236} 232}
237 233
234static inline int cipso_v4_getattr(const unsigned char *cipso,
235 struct netlbl_lsm_secattr *secattr)
236{
237 return -ENOSYS;
238}
239
238static inline int cipso_v4_sock_setattr(struct sock *sk, 240static inline int cipso_v4_sock_setattr(struct sock *sk,
239 const struct cipso_v4_doi *doi_def, 241 const struct cipso_v4_doi *doi_def,
240 const struct netlbl_lsm_secattr *secattr) 242 const struct netlbl_lsm_secattr *secattr)
@@ -282,6 +284,11 @@ static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
282 return -ENOSYS; 284 return -ENOSYS;
283} 285}
284 286
287static inline unsigned char *cipso_v4_optptr(const struct sk_buff *skb)
288{
289 return NULL;
290}
291
285static inline int cipso_v4_validate(const struct sk_buff *skb, 292static inline int cipso_v4_validate(const struct sk_buff *skb,
286 unsigned char **option) 293 unsigned char **option)
287{ 294{
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 5160c710f2eb..e361ea6f3fc8 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -378,20 +378,18 @@ static int cipso_v4_cache_check(const unsigned char *key,
378 * negative values on failure. 378 * negative values on failure.
379 * 379 *
380 */ 380 */
381int cipso_v4_cache_add(const struct sk_buff *skb, 381int cipso_v4_cache_add(const unsigned char *cipso_ptr,
382 const struct netlbl_lsm_secattr *secattr) 382 const struct netlbl_lsm_secattr *secattr)
383{ 383{
384 int ret_val = -EPERM; 384 int ret_val = -EPERM;
385 u32 bkt; 385 u32 bkt;
386 struct cipso_v4_map_cache_entry *entry = NULL; 386 struct cipso_v4_map_cache_entry *entry = NULL;
387 struct cipso_v4_map_cache_entry *old_entry = NULL; 387 struct cipso_v4_map_cache_entry *old_entry = NULL;
388 unsigned char *cipso_ptr;
389 u32 cipso_ptr_len; 388 u32 cipso_ptr_len;
390 389
391 if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0) 390 if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)
392 return 0; 391 return 0;
393 392
394 cipso_ptr = CIPSO_V4_OPTPTR(skb);
395 cipso_ptr_len = cipso_ptr[1]; 393 cipso_ptr_len = cipso_ptr[1];
396 394
397 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 395 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
@@ -1579,6 +1577,33 @@ static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def,
1579} 1577}
1580 1578
1581/** 1579/**
1580 * cipso_v4_optptr - Find the CIPSO option in the packet
1581 * @skb: the packet
1582 *
1583 * Description:
1584 * Parse the packet's IP header looking for a CIPSO option. Returns a pointer
1585 * to the start of the CIPSO option on success, NULL if one if not found.
1586 *
1587 */
1588unsigned char *cipso_v4_optptr(const struct sk_buff *skb)
1589{
1590 const struct iphdr *iph = ip_hdr(skb);
1591 unsigned char *optptr = (unsigned char *)&(ip_hdr(skb)[1]);
1592 int optlen;
1593 int taglen;
1594
1595 for (optlen = iph->ihl*4 - sizeof(struct iphdr); optlen > 0; ) {
1596 if (optptr[0] == IPOPT_CIPSO)
1597 return optptr;
1598 taglen = optptr[1];
1599 optlen -= taglen;
1600 optptr += taglen;
1601 }
1602
1603 return NULL;
1604}
1605
1606/**
1582 * cipso_v4_validate - Validate a CIPSO option 1607 * cipso_v4_validate - Validate a CIPSO option
1583 * @option: the start of the option, on error it is set to point to the error 1608 * @option: the start of the option, on error it is set to point to the error
1584 * 1609 *
@@ -2119,8 +2144,8 @@ void cipso_v4_req_delattr(struct request_sock *req)
2119 * on success and negative values on failure. 2144 * on success and negative values on failure.
2120 * 2145 *
2121 */ 2146 */
2122static int cipso_v4_getattr(const unsigned char *cipso, 2147int cipso_v4_getattr(const unsigned char *cipso,
2123 struct netlbl_lsm_secattr *secattr) 2148 struct netlbl_lsm_secattr *secattr)
2124{ 2149{
2125 int ret_val = -ENOMSG; 2150 int ret_val = -ENOMSG;
2126 u32 doi; 2151 u32 doi;
@@ -2305,22 +2330,6 @@ int cipso_v4_skbuff_delattr(struct sk_buff *skb)
2305 return 0; 2330 return 0;
2306} 2331}
2307 2332
2308/**
2309 * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
2310 * @skb: the packet
2311 * @secattr: the security attributes
2312 *
2313 * Description:
2314 * Parse the given packet's CIPSO option and return the security attributes.
2315 * Returns zero on success and negative values on failure.
2316 *
2317 */
2318int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
2319 struct netlbl_lsm_secattr *secattr)
2320{
2321 return cipso_v4_getattr(CIPSO_V4_OPTPTR(skb), secattr);
2322}
2323
2324/* 2333/*
2325 * Setup Functions 2334 * Setup Functions
2326 */ 2335 */
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index a845cd4cf21e..28cddc85b700 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -1065,10 +1065,12 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
1065 u16 family, 1065 u16 family,
1066 struct netlbl_lsm_secattr *secattr) 1066 struct netlbl_lsm_secattr *secattr)
1067{ 1067{
1068 unsigned char *ptr;
1069
1068 switch (family) { 1070 switch (family) {
1069 case AF_INET: 1071 case AF_INET:
1070 if (CIPSO_V4_OPTEXIST(skb) && 1072 ptr = cipso_v4_optptr(skb);
1071 cipso_v4_skbuff_getattr(skb, secattr) == 0) 1073 if (ptr && cipso_v4_getattr(ptr, secattr) == 0)
1072 return 0; 1074 return 0;
1073 break; 1075 break;
1074#if IS_ENABLED(CONFIG_IPV6) 1076#if IS_ENABLED(CONFIG_IPV6)
@@ -1094,7 +1096,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
1094 */ 1096 */
1095void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway) 1097void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway)
1096{ 1098{
1097 if (CIPSO_V4_OPTEXIST(skb)) 1099 if (cipso_v4_optptr(skb))
1098 cipso_v4_error(skb, error, gateway); 1100 cipso_v4_error(skb, error, gateway);
1099} 1101}
1100 1102
@@ -1126,11 +1128,14 @@ void netlbl_cache_invalidate(void)
1126int netlbl_cache_add(const struct sk_buff *skb, 1128int netlbl_cache_add(const struct sk_buff *skb,
1127 const struct netlbl_lsm_secattr *secattr) 1129 const struct netlbl_lsm_secattr *secattr)
1128{ 1130{
1131 unsigned char *ptr;
1132
1129 if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0) 1133 if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
1130 return -ENOMSG; 1134 return -ENOMSG;
1131 1135
1132 if (CIPSO_V4_OPTEXIST(skb)) 1136 ptr = cipso_v4_optptr(skb);
1133 return cipso_v4_cache_add(skb, secattr); 1137 if (ptr)
1138 return cipso_v4_cache_add(ptr, secattr);
1134 1139
1135 return -ENOMSG; 1140 return -ENOMSG;
1136} 1141}