aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_user.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_user.c')
-rw-r--r--net/xfrm/xfrm_user.c149
1 files changed, 142 insertions, 7 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 0cdd9a07e0..ac87a09ba8 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -7,7 +7,7 @@
7 * Kazunori MIYAZAWA @USAGI 7 * Kazunori MIYAZAWA @USAGI
8 * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 8 * Kunihiro Ishiguro <kunihiro@ipinfusion.com>
9 * IPv6 support 9 * IPv6 support
10 * 10 *
11 */ 11 */
12 12
13#include <linux/module.h> 13#include <linux/module.h>
@@ -88,6 +88,34 @@ static int verify_encap_tmpl(struct rtattr **xfrma)
88 return 0; 88 return 0;
89} 89}
90 90
91
92static inline int verify_sec_ctx_len(struct rtattr **xfrma)
93{
94 struct rtattr *rt = xfrma[XFRMA_SEC_CTX - 1];
95 struct xfrm_user_sec_ctx *uctx;
96 int len = 0;
97
98 if (!rt)
99 return 0;
100
101 if (rt->rta_len < sizeof(*uctx))
102 return -EINVAL;
103
104 uctx = RTA_DATA(rt);
105
106 if (uctx->ctx_len > PAGE_SIZE)
107 return -EINVAL;
108
109 len += sizeof(struct xfrm_user_sec_ctx);
110 len += uctx->ctx_len;
111
112 if (uctx->len != len)
113 return -EINVAL;
114
115 return 0;
116}
117
118
91static int verify_newsa_info(struct xfrm_usersa_info *p, 119static int verify_newsa_info(struct xfrm_usersa_info *p,
92 struct rtattr **xfrma) 120 struct rtattr **xfrma)
93{ 121{
@@ -145,6 +173,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
145 goto out; 173 goto out;
146 if ((err = verify_encap_tmpl(xfrma))) 174 if ((err = verify_encap_tmpl(xfrma)))
147 goto out; 175 goto out;
176 if ((err = verify_sec_ctx_len(xfrma)))
177 goto out;
148 178
149 err = -EINVAL; 179 err = -EINVAL;
150 switch (p->mode) { 180 switch (p->mode) {
@@ -209,6 +239,30 @@ static int attach_encap_tmpl(struct xfrm_encap_tmpl **encapp, struct rtattr *u_a
209 return 0; 239 return 0;
210} 240}
211 241
242
243static inline int xfrm_user_sec_ctx_size(struct xfrm_policy *xp)
244{
245 struct xfrm_sec_ctx *xfrm_ctx = xp->security;
246 int len = 0;
247
248 if (xfrm_ctx) {
249 len += sizeof(struct xfrm_user_sec_ctx);
250 len += xfrm_ctx->ctx_len;
251 }
252 return len;
253}
254
255static int attach_sec_ctx(struct xfrm_state *x, struct rtattr *u_arg)
256{
257 struct xfrm_user_sec_ctx *uctx;
258
259 if (!u_arg)
260 return 0;
261
262 uctx = RTA_DATA(u_arg);
263 return security_xfrm_state_alloc(x, uctx);
264}
265
212static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) 266static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
213{ 267{
214 memcpy(&x->id, &p->id, sizeof(x->id)); 268 memcpy(&x->id, &p->id, sizeof(x->id));
@@ -253,6 +307,9 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
253 if (err) 307 if (err)
254 goto error; 308 goto error;
255 309
310 if ((err = attach_sec_ctx(x, xfrma[XFRMA_SEC_CTX-1])))
311 goto error;
312
256 x->km.seq = p->seq; 313 x->km.seq = p->seq;
257 314
258 return x; 315 return x;
@@ -272,11 +329,11 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
272 int err; 329 int err;
273 struct km_event c; 330 struct km_event c;
274 331
275 err = verify_newsa_info(p, (struct rtattr **) xfrma); 332 err = verify_newsa_info(p, (struct rtattr **)xfrma);
276 if (err) 333 if (err)
277 return err; 334 return err;
278 335
279 x = xfrm_state_construct(p, (struct rtattr **) xfrma, &err); 336 x = xfrm_state_construct(p, (struct rtattr **)xfrma, &err);
280 if (!x) 337 if (!x)
281 return err; 338 return err;
282 339
@@ -390,6 +447,19 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
390 if (x->encap) 447 if (x->encap)
391 RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); 448 RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
392 449
450 if (x->security) {
451 int ctx_size = sizeof(struct xfrm_sec_ctx) +
452 x->security->ctx_len;
453 struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size);
454 struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt);
455
456 uctx->exttype = XFRMA_SEC_CTX;
457 uctx->len = ctx_size;
458 uctx->ctx_doi = x->security->ctx_doi;
459 uctx->ctx_alg = x->security->ctx_alg;
460 uctx->ctx_len = x->security->ctx_len;
461 memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len);
462 }
393 nlh->nlmsg_len = skb->tail - b; 463 nlh->nlmsg_len = skb->tail - b;
394out: 464out:
395 sp->this_idx++; 465 sp->this_idx++;
@@ -603,6 +673,18 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
603 return verify_policy_dir(p->dir); 673 return verify_policy_dir(p->dir);
604} 674}
605 675
676static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct rtattr **xfrma)
677{
678 struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1];
679 struct xfrm_user_sec_ctx *uctx;
680
681 if (!rt)
682 return 0;
683
684 uctx = RTA_DATA(rt);
685 return security_xfrm_policy_alloc(pol, uctx);
686}
687
606static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, 688static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,
607 int nr) 689 int nr)
608{ 690{
@@ -681,7 +763,10 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p,
681 } 763 }
682 764
683 copy_from_user_policy(xp, p); 765 copy_from_user_policy(xp, p);
684 err = copy_from_user_tmpl(xp, xfrma); 766
767 if (!(err = copy_from_user_tmpl(xp, xfrma)))
768 err = copy_from_user_sec_ctx(xp, xfrma);
769
685 if (err) { 770 if (err) {
686 *errp = err; 771 *errp = err;
687 kfree(xp); 772 kfree(xp);
@@ -702,8 +787,11 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
702 err = verify_newpolicy_info(p); 787 err = verify_newpolicy_info(p);
703 if (err) 788 if (err)
704 return err; 789 return err;
790 err = verify_sec_ctx_len((struct rtattr **)xfrma);
791 if (err)
792 return err;
705 793
706 xp = xfrm_policy_construct(p, (struct rtattr **) xfrma, &err); 794 xp = xfrm_policy_construct(p, (struct rtattr **)xfrma, &err);
707 if (!xp) 795 if (!xp)
708 return err; 796 return err;
709 797
@@ -714,6 +802,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
714 excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; 802 excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
715 err = xfrm_policy_insert(p->dir, xp, excl); 803 err = xfrm_policy_insert(p->dir, xp, excl);
716 if (err) { 804 if (err) {
805 security_xfrm_policy_free(xp);
717 kfree(xp); 806 kfree(xp);
718 return err; 807 return err;
719 } 808 }
@@ -761,6 +850,27 @@ rtattr_failure:
761 return -1; 850 return -1;
762} 851}
763 852
853static int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb)
854{
855 if (xp->security) {
856 int ctx_size = sizeof(struct xfrm_sec_ctx) +
857 xp->security->ctx_len;
858 struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size);
859 struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt);
860
861 uctx->exttype = XFRMA_SEC_CTX;
862 uctx->len = ctx_size;
863 uctx->ctx_doi = xp->security->ctx_doi;
864 uctx->ctx_alg = xp->security->ctx_alg;
865 uctx->ctx_len = xp->security->ctx_len;
866 memcpy(uctx + 1, xp->security->ctx_str, xp->security->ctx_len);
867 }
868 return 0;
869
870 rtattr_failure:
871 return -1;
872}
873
764static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) 874static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr)
765{ 875{
766 struct xfrm_dump_info *sp = ptr; 876 struct xfrm_dump_info *sp = ptr;
@@ -782,6 +892,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
782 copy_to_user_policy(xp, p, dir); 892 copy_to_user_policy(xp, p, dir);
783 if (copy_to_user_tmpl(xp, skb) < 0) 893 if (copy_to_user_tmpl(xp, skb) < 0)
784 goto nlmsg_failure; 894 goto nlmsg_failure;
895 if (copy_to_user_sec_ctx(xp, skb))
896 goto nlmsg_failure;
785 897
786 nlh->nlmsg_len = skb->tail - b; 898 nlh->nlmsg_len = skb->tail - b;
787out: 899out:
@@ -852,8 +964,25 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
852 964
853 if (p->index) 965 if (p->index)
854 xp = xfrm_policy_byid(p->dir, p->index, delete); 966 xp = xfrm_policy_byid(p->dir, p->index, delete);
855 else 967 else {
856 xp = xfrm_policy_bysel(p->dir, &p->sel, delete); 968 struct rtattr **rtattrs = (struct rtattr **)xfrma;
969 struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1];
970 struct xfrm_policy tmp;
971
972 err = verify_sec_ctx_len(rtattrs);
973 if (err)
974 return err;
975
976 memset(&tmp, 0, sizeof(struct xfrm_policy));
977 if (rt) {
978 struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt);
979
980 if ((err = security_xfrm_policy_alloc(&tmp, uctx)))
981 return err;
982 }
983 xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, delete);
984 security_xfrm_policy_free(&tmp);
985 }
857 if (xp == NULL) 986 if (xp == NULL)
858 return -ENOENT; 987 return -ENOENT;
859 988
@@ -1224,6 +1353,8 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
1224 1353
1225 if (copy_to_user_tmpl(xp, skb) < 0) 1354 if (copy_to_user_tmpl(xp, skb) < 0)
1226 goto nlmsg_failure; 1355 goto nlmsg_failure;
1356 if (copy_to_user_sec_ctx(xp, skb))
1357 goto nlmsg_failure;
1227 1358
1228 nlh->nlmsg_len = skb->tail - b; 1359 nlh->nlmsg_len = skb->tail - b;
1229 return skb->len; 1360 return skb->len;
@@ -1241,6 +1372,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
1241 1372
1242 len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); 1373 len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
1243 len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire)); 1374 len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire));
1375 len += RTA_SPACE(xfrm_user_sec_ctx_size(xp));
1244 skb = alloc_skb(len, GFP_ATOMIC); 1376 skb = alloc_skb(len, GFP_ATOMIC);
1245 if (skb == NULL) 1377 if (skb == NULL)
1246 return -ENOMEM; 1378 return -ENOMEM;
@@ -1324,6 +1456,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
1324 copy_to_user_policy(xp, &upe->pol, dir); 1456 copy_to_user_policy(xp, &upe->pol, dir);
1325 if (copy_to_user_tmpl(xp, skb) < 0) 1457 if (copy_to_user_tmpl(xp, skb) < 0)
1326 goto nlmsg_failure; 1458 goto nlmsg_failure;
1459 if (copy_to_user_sec_ctx(xp, skb))
1460 goto nlmsg_failure;
1327 upe->hard = !!hard; 1461 upe->hard = !!hard;
1328 1462
1329 nlh->nlmsg_len = skb->tail - b; 1463 nlh->nlmsg_len = skb->tail - b;
@@ -1341,6 +1475,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve
1341 1475
1342 len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); 1476 len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
1343 len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire)); 1477 len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire));
1478 len += RTA_SPACE(xfrm_user_sec_ctx_size(xp));
1344 skb = alloc_skb(len, GFP_ATOMIC); 1479 skb = alloc_skb(len, GFP_ATOMIC);
1345 if (skb == NULL) 1480 if (skb == NULL)
1346 return -ENOMEM; 1481 return -ENOMEM;