aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/xfrm.h2
-rw-r--r--net/xfrm/xfrm_user.c31
2 files changed, 27 insertions, 6 deletions
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 22e61fdf75a2..28e493b5b94c 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -84,6 +84,8 @@ struct xfrm_replay_state {
84 __u32 bitmap; 84 __u32 bitmap;
85}; 85};
86 86
87#define XFRMA_REPLAY_ESN_MAX 4096
88
87struct xfrm_replay_state_esn { 89struct xfrm_replay_state_esn {
88 unsigned int bmp_len; 90 unsigned int bmp_len;
89 __u32 oseq; 91 __u32 oseq;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 8024b3dea8c2..5927065e97cf 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -123,9 +123,21 @@ static inline int verify_replay(struct xfrm_usersa_info *p,
123 struct nlattr **attrs) 123 struct nlattr **attrs)
124{ 124{
125 struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL]; 125 struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
126 struct xfrm_replay_state_esn *rs;
126 127
127 if ((p->flags & XFRM_STATE_ESN) && !rt) 128 if (p->flags & XFRM_STATE_ESN) {
128 return -EINVAL; 129 if (!rt)
130 return -EINVAL;
131
132 rs = nla_data(rt);
133
134 if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
135 return -EINVAL;
136
137 if (nla_len(rt) < xfrm_replay_state_esn_len(rs) &&
138 nla_len(rt) != sizeof(*rs))
139 return -EINVAL;
140 }
129 141
130 if (!rt) 142 if (!rt)
131 return 0; 143 return 0;
@@ -370,14 +382,15 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es
370 struct nlattr *rp) 382 struct nlattr *rp)
371{ 383{
372 struct xfrm_replay_state_esn *up; 384 struct xfrm_replay_state_esn *up;
385 int ulen;
373 386
374 if (!replay_esn || !rp) 387 if (!replay_esn || !rp)
375 return 0; 388 return 0;
376 389
377 up = nla_data(rp); 390 up = nla_data(rp);
391 ulen = xfrm_replay_state_esn_len(up);
378 392
379 if (xfrm_replay_state_esn_len(replay_esn) != 393 if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen)
380 xfrm_replay_state_esn_len(up))
381 return -EINVAL; 394 return -EINVAL;
382 395
383 return 0; 396 return 0;
@@ -388,22 +401,28 @@ static int xfrm_alloc_replay_state_esn(struct xfrm_replay_state_esn **replay_esn
388 struct nlattr *rta) 401 struct nlattr *rta)
389{ 402{
390 struct xfrm_replay_state_esn *p, *pp, *up; 403 struct xfrm_replay_state_esn *p, *pp, *up;
404 int klen, ulen;
391 405
392 if (!rta) 406 if (!rta)
393 return 0; 407 return 0;
394 408
395 up = nla_data(rta); 409 up = nla_data(rta);
410 klen = xfrm_replay_state_esn_len(up);
411 ulen = nla_len(rta) >= klen ? klen : sizeof(*up);
396 412
397 p = kmemdup(up, xfrm_replay_state_esn_len(up), GFP_KERNEL); 413 p = kzalloc(klen, GFP_KERNEL);
398 if (!p) 414 if (!p)
399 return -ENOMEM; 415 return -ENOMEM;
400 416
401 pp = kmemdup(up, xfrm_replay_state_esn_len(up), GFP_KERNEL); 417 pp = kzalloc(klen, GFP_KERNEL);
402 if (!pp) { 418 if (!pp) {
403 kfree(p); 419 kfree(p);
404 return -ENOMEM; 420 return -ENOMEM;
405 } 421 }
406 422
423 memcpy(p, up, ulen);
424 memcpy(pp, up, ulen);
425
407 *replay_esn = p; 426 *replay_esn = p;
408 *preplay_esn = pp; 427 *preplay_esn = pp;
409 428