diff options
Diffstat (limited to 'net/xfrm/xfrm_user.c')
| -rw-r--r-- | net/xfrm/xfrm_user.c | 148 |
1 files changed, 141 insertions, 7 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 0cdd9a07e043..92e2b804c606 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 | |||
| 92 | static 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 | |||
| 91 | static int verify_newsa_info(struct xfrm_usersa_info *p, | 119 | static 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 | |||
| 243 | static 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 | |||
| 255 | static 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 | |||
| 212 | static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) | 266 | static 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; |
| 394 | out: | 464 | out: |
| 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 | ||
| 676 | static 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 | |||
| 606 | static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, | 688 | static 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 | ||
| @@ -761,6 +849,27 @@ rtattr_failure: | |||
| 761 | return -1; | 849 | return -1; |
| 762 | } | 850 | } |
| 763 | 851 | ||
| 852 | static int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) | ||
| 853 | { | ||
| 854 | if (xp->security) { | ||
| 855 | int ctx_size = sizeof(struct xfrm_sec_ctx) + | ||
| 856 | xp->security->ctx_len; | ||
| 857 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); | ||
| 858 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | ||
| 859 | |||
| 860 | uctx->exttype = XFRMA_SEC_CTX; | ||
| 861 | uctx->len = ctx_size; | ||
| 862 | uctx->ctx_doi = xp->security->ctx_doi; | ||
| 863 | uctx->ctx_alg = xp->security->ctx_alg; | ||
| 864 | uctx->ctx_len = xp->security->ctx_len; | ||
| 865 | memcpy(uctx + 1, xp->security->ctx_str, xp->security->ctx_len); | ||
| 866 | } | ||
| 867 | return 0; | ||
| 868 | |||
| 869 | rtattr_failure: | ||
| 870 | return -1; | ||
| 871 | } | ||
| 872 | |||
| 764 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) | 873 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) |
| 765 | { | 874 | { |
| 766 | struct xfrm_dump_info *sp = ptr; | 875 | struct xfrm_dump_info *sp = ptr; |
| @@ -782,6 +891,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
| 782 | copy_to_user_policy(xp, p, dir); | 891 | copy_to_user_policy(xp, p, dir); |
| 783 | if (copy_to_user_tmpl(xp, skb) < 0) | 892 | if (copy_to_user_tmpl(xp, skb) < 0) |
| 784 | goto nlmsg_failure; | 893 | goto nlmsg_failure; |
| 894 | if (copy_to_user_sec_ctx(xp, skb)) | ||
| 895 | goto nlmsg_failure; | ||
| 785 | 896 | ||
| 786 | nlh->nlmsg_len = skb->tail - b; | 897 | nlh->nlmsg_len = skb->tail - b; |
| 787 | out: | 898 | out: |
| @@ -852,8 +963,25 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
| 852 | 963 | ||
| 853 | if (p->index) | 964 | if (p->index) |
| 854 | xp = xfrm_policy_byid(p->dir, p->index, delete); | 965 | xp = xfrm_policy_byid(p->dir, p->index, delete); |
| 855 | else | 966 | else { |
| 856 | xp = xfrm_policy_bysel(p->dir, &p->sel, delete); | 967 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
| 968 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | ||
| 969 | struct xfrm_policy tmp; | ||
| 970 | |||
| 971 | err = verify_sec_ctx_len(rtattrs); | ||
| 972 | if (err) | ||
| 973 | return err; | ||
| 974 | |||
| 975 | memset(&tmp, 0, sizeof(struct xfrm_policy)); | ||
| 976 | if (rt) { | ||
| 977 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | ||
| 978 | |||
| 979 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | ||
| 980 | return err; | ||
| 981 | } | ||
| 982 | xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, delete); | ||
| 983 | security_xfrm_policy_free(&tmp); | ||
| 984 | } | ||
| 857 | if (xp == NULL) | 985 | if (xp == NULL) |
| 858 | return -ENOENT; | 986 | return -ENOENT; |
| 859 | 987 | ||
| @@ -1224,6 +1352,8 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, | |||
| 1224 | 1352 | ||
| 1225 | if (copy_to_user_tmpl(xp, skb) < 0) | 1353 | if (copy_to_user_tmpl(xp, skb) < 0) |
| 1226 | goto nlmsg_failure; | 1354 | goto nlmsg_failure; |
| 1355 | if (copy_to_user_sec_ctx(xp, skb)) | ||
| 1356 | goto nlmsg_failure; | ||
| 1227 | 1357 | ||
| 1228 | nlh->nlmsg_len = skb->tail - b; | 1358 | nlh->nlmsg_len = skb->tail - b; |
| 1229 | return skb->len; | 1359 | return skb->len; |
| @@ -1241,6 +1371,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, | |||
| 1241 | 1371 | ||
| 1242 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); | 1372 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); |
| 1243 | len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire)); | 1373 | len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire)); |
| 1374 | len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); | ||
| 1244 | skb = alloc_skb(len, GFP_ATOMIC); | 1375 | skb = alloc_skb(len, GFP_ATOMIC); |
| 1245 | if (skb == NULL) | 1376 | if (skb == NULL) |
| 1246 | return -ENOMEM; | 1377 | return -ENOMEM; |
| @@ -1324,6 +1455,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | |||
| 1324 | copy_to_user_policy(xp, &upe->pol, dir); | 1455 | copy_to_user_policy(xp, &upe->pol, dir); |
| 1325 | if (copy_to_user_tmpl(xp, skb) < 0) | 1456 | if (copy_to_user_tmpl(xp, skb) < 0) |
| 1326 | goto nlmsg_failure; | 1457 | goto nlmsg_failure; |
| 1458 | if (copy_to_user_sec_ctx(xp, skb)) | ||
| 1459 | goto nlmsg_failure; | ||
| 1327 | upe->hard = !!hard; | 1460 | upe->hard = !!hard; |
| 1328 | 1461 | ||
| 1329 | nlh->nlmsg_len = skb->tail - b; | 1462 | nlh->nlmsg_len = skb->tail - b; |
| @@ -1341,6 +1474,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve | |||
| 1341 | 1474 | ||
| 1342 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); | 1475 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); |
| 1343 | len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire)); | 1476 | len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire)); |
| 1477 | len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); | ||
| 1344 | skb = alloc_skb(len, GFP_ATOMIC); | 1478 | skb = alloc_skb(len, GFP_ATOMIC); |
| 1345 | if (skb == NULL) | 1479 | if (skb == NULL) |
| 1346 | return -ENOMEM; | 1480 | return -ENOMEM; |
