Kernel generates mapping change message, XFRM_MSG_MAPPING, when a source port chage is detected on a input state with UDP encapsulation set. Kernel generates a message for each IPsec packet with new source port. For a high speed flow per packet mapping change message can be excessive, and can overload the user space listener. Introduce rate limiting for XFRM_MSG_MAPPING message to the user space. The rate limiting is configurable via netlink, when adding a new SA or updating it. Use the new attribute XFRMA_MTIMER_THRESH in seconds. v1->v2 change: update xfrm_sa_len() v2->v3 changes: use u32 insted unsigned long to reduce size of struct xfrm_state fix xfrm_ompat size Reported-by: kernel test robot <lkp@intel.com> accept XFRM_MSG_MAPPING only when XFRMA_ENCAP is present
Unified · Split
| @@ -200,6 +200,11 @@ struct xfrm_state { · 199 unmodified lines | |||
| 200 | struct xfrm_algo_aead *aead; | 200 | struct xfrm_algo_aead *aead; |
| 201 | const char *geniv; | 201 | const char *geniv; |
| 202 | 202 | ||
| 203 | /* mapping change rate limiting */ | ||
| 204 | __be16 new_mapping_sport; | ||
| 205 | u32 new_mapping; /* seconds */ | ||
| 206 | u32 mapping_maxage; /* seconds for input SA */ | ||
| 207 | |||
| 203 | /* Data for encapsulator */ | 208 | /* Data for encapsulator */ |
| 204 | struct xfrm_encap_tmpl *encap; | 209 | struct xfrm_encap_tmpl *encap; |
| 205 | struct sock __rcu *encap_sk; | 210 | struct sock __rcu *encap_sk; |
| @@ -313,6 +313,7 @@ enum xfrm_attr_type_t { · 312 unmodified lines | |||
| 313 | XFRMA_SET_MARK, /* __u32 */ | 313 | XFRMA_SET_MARK, /* __u32 */ |
| 314 | XFRMA_SET_MARK_MASK, /* __u32 */ | 314 | XFRMA_SET_MARK_MASK, /* __u32 */ |
| 315 | XFRMA_IF_ID, /* __u32 */ | 315 | XFRMA_IF_ID, /* __u32 */ |
| 316 | XFRMA_MTIMER_THRESH, /* __u32 in seconds for input SA */ | ||
| 316 | __XFRMA_MAX | 317 | __XFRMA_MAX |
| 317 | 318 | ||
| 318 | #define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */ | 319 | #define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */ |
| @@ -127,6 +127,7 @@ static const struct nla_policy compat_policy[XFRMA_MAX+1] = { · 126 unmodified lines | |||
| 127 | [XFRMA_SET_MARK] = { .type = NLA_U32 }, | 127 | [XFRMA_SET_MARK] = { .type = NLA_U32 }, |
| 128 | [XFRMA_SET_MARK_MASK] = { .type = NLA_U32 }, | 128 | [XFRMA_SET_MARK_MASK] = { .type = NLA_U32 }, |
| 129 | [XFRMA_IF_ID] = { .type = NLA_U32 }, | 129 | [XFRMA_IF_ID] = { .type = NLA_U32 }, |
| 130 | [XFRMA_MTIMER_THRESH] = { .type = NLA_U32 }, | ||
| 130 | }; | 131 | }; |
| 131 | 132 | ||
| 132 | static struct nlmsghdr *xfrm_nlmsg_put_compat(struct sk_buff *skb, | 133 | static struct nlmsghdr *xfrm_nlmsg_put_compat(struct sk_buff *skb, |
| @@ -274,9 +275,10 @@ static int xfrm_xlate64_attr(struct sk_buff *dst, const struct nlattr *src) · 141 unmodified lines | |||
| 274 | case XFRMA_SET_MARK: | 275 | case XFRMA_SET_MARK: |
| 275 | case XFRMA_SET_MARK_MASK: | 276 | case XFRMA_SET_MARK_MASK: |
| 276 | case XFRMA_IF_ID: | 277 | case XFRMA_IF_ID: |
| 278 | case XFRMA_MTIMER_THRESH: | ||
| 277 | return xfrm_nla_cpy(dst, src, nla_len(src)); | 279 | return xfrm_nla_cpy(dst, src, nla_len(src)); |
| 278 | default: | 280 | default: |
| 279 | BUILD_BUG_ON(XFRMA_MAX != XFRMA_IF_ID); | 281 | BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH); |
| 280 | pr_warn_once("unsupported nla_type %d\n", src->nla_type); | 282 | pr_warn_once("unsupported nla_type %d\n", src->nla_type); |
| 281 | return -EOPNOTSUPP; | 283 | return -EOPNOTSUPP; |
| 282 | } | 284 | } |
| @@ -431,7 +433,7 @@ static int xfrm_xlate32_attr(void *dst, const struct nlattr *nla, · 148 unmodified lines | |||
| 431 | int err; | 433 | int err; |
| 432 | 434 | ||
| 433 | if (type > XFRMA_MAX) { | 435 | if (type > XFRMA_MAX) { |
| 434 | BUILD_BUG_ON(XFRMA_MAX != XFRMA_IF_ID); | 436 | BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH); |
| 435 | NL_SET_ERR_MSG(extack, "Bad attribute"); | 437 | NL_SET_ERR_MSG(extack, "Bad attribute"); |
| 436 | return -EOPNOTSUPP; | 438 | return -EOPNOTSUPP; |
| 437 | } | 439 | } |
| @@ -1593,6 +1593,9 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, · 1592 unmodified lines | |||
| 1593 | x->km.seq = orig->km.seq; | 1593 | x->km.seq = orig->km.seq; |
| 1594 | x->replay = orig->replay; | 1594 | x->replay = orig->replay; |
| 1595 | x->preplay = orig->preplay; | 1595 | x->preplay = orig->preplay; |
| 1596 | x->mapping_maxage = orig->mapping_maxage; | ||
| 1597 | x->new_mapping = 0; | ||
| 1598 | x->new_mapping_sport = 0; | ||
| 1596 | 1599 | ||
| 1597 | return x; | 1600 | return x; |
| 1598 | 1601 | ||
| @@ -2242,7 +2245,7 @@ int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) · 643 unmodified lines | |||
| 2242 | } | 2245 | } |
| 2243 | EXPORT_SYMBOL(km_query); | 2246 | EXPORT_SYMBOL(km_query); |
| 2244 | 2247 | ||
| 2245 | int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) | 2248 | static int __km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) |
| 2246 | { | 2249 | { |
| 2247 | int err = -EINVAL; | 2250 | int err = -EINVAL; |
| 2248 | struct xfrm_mgr *km; | 2251 | struct xfrm_mgr *km; |
| @@ -2257,6 +2260,24 @@ int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) · 8 unmodified lines | |||
| 2257 | rcu_read_unlock(); | 2260 | rcu_read_unlock(); |
| 2258 | return err; | 2261 | return err; |
| 2259 | } | 2262 | } |
| 2263 | |||
| 2264 | int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) | ||
| 2265 | { | ||
| 2266 | int ret = 0; | ||
| 2267 | |||
| 2268 | if (x->mapping_maxage) { | ||
| 2269 | if ((jiffies / HZ - x->new_mapping) > x->mapping_maxage || | ||
| 2270 | x->new_mapping_sport != sport) { | ||
| 2271 | x->new_mapping_sport = sport; | ||
| 2272 | x->new_mapping = jiffies / HZ; | ||
| 2273 | ret = __km_new_mapping(x, ipaddr, sport); | ||
| 2274 | } | ||
| 2275 | } else { | ||
| 2276 | ret = __km_new_mapping(x, ipaddr, sport); | ||
| 2277 | } | ||
| 2278 | |||
| 2279 | return ret; | ||
| 2280 | } | ||
| 2260 | EXPORT_SYMBOL(km_new_mapping); | 2281 | EXPORT_SYMBOL(km_new_mapping); |
| 2261 | 2282 | ||
| 2262 | void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid) | 2283 | void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid) |
| @@ -282,6 +282,10 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, · 281 unmodified lines | |||
| 282 | 282 | ||
| 283 | err = 0; | 283 | err = 0; |
| 284 | 284 | ||
| 285 | if (attrs[XFRMA_MTIMER_THRESH]) | ||
| 286 | if (!attrs[XFRMA_ENCAP]) | ||
| 287 | err = -EINVAL; | ||
| 288 | |||
| 285 | out: | 289 | out: |
| 286 | return err; | 290 | return err; |
| 287 | } | 291 | } |
| @@ -521,6 +525,7 @@ static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs, · 233 unmodified lines | |||
| 521 | struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; | 525 | struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; |
| 522 | struct nlattr *et = attrs[XFRMA_ETIMER_THRESH]; | 526 | struct nlattr *et = attrs[XFRMA_ETIMER_THRESH]; |
| 523 | struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH]; | 527 | struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH]; |
| 528 | struct nlattr *mt = attrs[XFRMA_MTIMER_THRESH]; | ||
| 524 | 529 | ||
| 525 | if (re) { | 530 | if (re) { |
| 526 | struct xfrm_replay_state_esn *replay_esn; | 531 | struct xfrm_replay_state_esn *replay_esn; |
| @@ -552,6 +557,9 @@ static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs, · 25 unmodified lines | |||
| 552 | 557 | ||
| 553 | if (rt) | 558 | if (rt) |
| 554 | x->replay_maxdiff = nla_get_u32(rt); | 559 | x->replay_maxdiff = nla_get_u32(rt); |
| 560 | |||
| 561 | if (mt) | ||
| 562 | x->mapping_maxage = nla_get_u32(mt); | ||
| 555 | } | 563 | } |
| 556 | 564 | ||
| 557 | static void xfrm_smark_init(struct nlattr **attrs, struct xfrm_mark *m) | 565 | static void xfrm_smark_init(struct nlattr **attrs, struct xfrm_mark *m) |
| @@ -1024,8 +1032,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x, · 466 unmodified lines | |||
| 1024 | if (ret) | 1032 | if (ret) |
| 1025 | goto out; | 1033 | goto out; |
| 1026 | } | 1034 | } |
| 1027 | if (x->security) | 1035 | if (x->security) { |
| 1028 | ret = copy_sec_ctx(x->security, skb); | 1036 | ret = copy_sec_ctx(x->security, skb); |
| 1037 | if (ret) | ||
| 1038 | goto out; | ||
| 1039 | } | ||
| 1040 | if (x->mapping_maxage) | ||
| 1041 | ret = nla_put_u32(skb, XFRMA_MTIMER_THRESH, x->mapping_maxage); | ||
| 1029 | out: | 1042 | out: |
| 1030 | return ret; | 1043 | return ret; |
| 1031 | } | 1044 | } |
| @@ -3069,6 +3082,9 @@ static inline unsigned int xfrm_sa_len(struct xfrm_state *x) · 2037 unmodified lines | |||
| 3069 | /* Must count x->lastused as it may become non-zero behind our back. */ | 3082 | /* Must count x->lastused as it may become non-zero behind our back. */ |
| 3070 | l += nla_total_size_64bit(sizeof(u64)); | 3083 | l += nla_total_size_64bit(sizeof(u64)); |
| 3071 | 3084 | ||
| 3085 | if (x->mapping_maxage) | ||
| 3086 | l += nla_total_size(sizeof(x->mapping_maxage)); | ||
| 3087 | |||
| 3072 | return l; | 3088 | return l; |
| 3073 | } | 3089 | } |
| 3074 | 3090 | ||