diff options
Diffstat (limited to 'net/xfrm/xfrm_user.c')
| -rw-r--r-- | net/xfrm/xfrm_user.c | 352 |
1 files changed, 311 insertions, 41 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index c21dc26141ea..c59a78d2923a 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | * | 10 | * |
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/crypto.h> | ||
| 13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 15 | #include <linux/types.h> | 16 | #include <linux/types.h> |
| @@ -27,6 +28,9 @@ | |||
| 27 | #include <net/xfrm.h> | 28 | #include <net/xfrm.h> |
| 28 | #include <net/netlink.h> | 29 | #include <net/netlink.h> |
| 29 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
| 31 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 32 | #include <linux/in6.h> | ||
| 33 | #endif | ||
| 30 | 34 | ||
| 31 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) | 35 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) |
| 32 | { | 36 | { |
| @@ -86,6 +90,22 @@ static int verify_encap_tmpl(struct rtattr **xfrma) | |||
| 86 | return 0; | 90 | return 0; |
| 87 | } | 91 | } |
| 88 | 92 | ||
| 93 | static int verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type, | ||
| 94 | xfrm_address_t **addrp) | ||
| 95 | { | ||
| 96 | struct rtattr *rt = xfrma[type - 1]; | ||
| 97 | |||
| 98 | if (!rt) | ||
| 99 | return 0; | ||
| 100 | |||
| 101 | if ((rt->rta_len - sizeof(*rt)) < sizeof(**addrp)) | ||
| 102 | return -EINVAL; | ||
| 103 | |||
| 104 | if (addrp) | ||
| 105 | *addrp = RTA_DATA(rt); | ||
| 106 | |||
| 107 | return 0; | ||
| 108 | } | ||
| 89 | 109 | ||
| 90 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) | 110 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) |
| 91 | { | 111 | { |
| @@ -156,6 +176,19 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
| 156 | goto out; | 176 | goto out; |
| 157 | break; | 177 | break; |
| 158 | 178 | ||
| 179 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 180 | case IPPROTO_DSTOPTS: | ||
| 181 | case IPPROTO_ROUTING: | ||
| 182 | if (xfrma[XFRMA_ALG_COMP-1] || | ||
| 183 | xfrma[XFRMA_ALG_AUTH-1] || | ||
| 184 | xfrma[XFRMA_ALG_CRYPT-1] || | ||
| 185 | xfrma[XFRMA_ENCAP-1] || | ||
| 186 | xfrma[XFRMA_SEC_CTX-1] || | ||
| 187 | !xfrma[XFRMA_COADDR-1]) | ||
| 188 | goto out; | ||
| 189 | break; | ||
| 190 | #endif | ||
| 191 | |||
| 159 | default: | 192 | default: |
| 160 | goto out; | 193 | goto out; |
| 161 | }; | 194 | }; |
| @@ -170,11 +203,14 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
| 170 | goto out; | 203 | goto out; |
| 171 | if ((err = verify_sec_ctx_len(xfrma))) | 204 | if ((err = verify_sec_ctx_len(xfrma))) |
| 172 | goto out; | 205 | goto out; |
| 206 | if ((err = verify_one_addr(xfrma, XFRMA_COADDR, NULL))) | ||
| 207 | goto out; | ||
| 173 | 208 | ||
| 174 | err = -EINVAL; | 209 | err = -EINVAL; |
| 175 | switch (p->mode) { | 210 | switch (p->mode) { |
| 176 | case 0: | 211 | case XFRM_MODE_TRANSPORT: |
| 177 | case 1: | 212 | case XFRM_MODE_TUNNEL: |
| 213 | case XFRM_MODE_ROUTEOPTIMIZATION: | ||
| 178 | break; | 214 | break; |
| 179 | 215 | ||
| 180 | default: | 216 | default: |
| @@ -212,6 +248,7 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, | |||
| 212 | return -ENOMEM; | 248 | return -ENOMEM; |
| 213 | 249 | ||
| 214 | memcpy(p, ualg, len); | 250 | memcpy(p, ualg, len); |
| 251 | strcpy(p->alg_name, algo->name); | ||
| 215 | *algpp = p; | 252 | *algpp = p; |
| 216 | return 0; | 253 | return 0; |
| 217 | } | 254 | } |
| @@ -258,6 +295,24 @@ static int attach_sec_ctx(struct xfrm_state *x, struct rtattr *u_arg) | |||
| 258 | return security_xfrm_state_alloc(x, uctx); | 295 | return security_xfrm_state_alloc(x, uctx); |
| 259 | } | 296 | } |
| 260 | 297 | ||
| 298 | static int attach_one_addr(xfrm_address_t **addrpp, struct rtattr *u_arg) | ||
| 299 | { | ||
| 300 | struct rtattr *rta = u_arg; | ||
| 301 | xfrm_address_t *p, *uaddrp; | ||
| 302 | |||
| 303 | if (!rta) | ||
| 304 | return 0; | ||
| 305 | |||
| 306 | uaddrp = RTA_DATA(rta); | ||
| 307 | p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
| 308 | if (!p) | ||
| 309 | return -ENOMEM; | ||
| 310 | |||
| 311 | memcpy(p, uaddrp, sizeof(*p)); | ||
| 312 | *addrpp = p; | ||
| 313 | return 0; | ||
| 314 | } | ||
| 315 | |||
| 261 | static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) | 316 | static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) |
| 262 | { | 317 | { |
| 263 | memcpy(&x->id, &p->id, sizeof(x->id)); | 318 | memcpy(&x->id, &p->id, sizeof(x->id)); |
| @@ -347,7 +402,8 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | |||
| 347 | goto error; | 402 | goto error; |
| 348 | if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) | 403 | if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) |
| 349 | goto error; | 404 | goto error; |
| 350 | 405 | if ((err = attach_one_addr(&x->coaddr, xfrma[XFRMA_COADDR-1]))) | |
| 406 | goto error; | ||
| 351 | err = xfrm_init_state(x); | 407 | err = xfrm_init_state(x); |
| 352 | if (err) | 408 | if (err) |
| 353 | goto error; | 409 | goto error; |
| @@ -416,16 +472,48 @@ out: | |||
| 416 | return err; | 472 | return err; |
| 417 | } | 473 | } |
| 418 | 474 | ||
| 475 | static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, | ||
| 476 | struct rtattr **xfrma, | ||
| 477 | int *errp) | ||
| 478 | { | ||
| 479 | struct xfrm_state *x = NULL; | ||
| 480 | int err; | ||
| 481 | |||
| 482 | if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { | ||
| 483 | err = -ESRCH; | ||
| 484 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | ||
| 485 | } else { | ||
| 486 | xfrm_address_t *saddr = NULL; | ||
| 487 | |||
| 488 | err = verify_one_addr(xfrma, XFRMA_SRCADDR, &saddr); | ||
| 489 | if (err) | ||
| 490 | goto out; | ||
| 491 | |||
| 492 | if (!saddr) { | ||
| 493 | err = -EINVAL; | ||
| 494 | goto out; | ||
| 495 | } | ||
| 496 | |||
| 497 | x = xfrm_state_lookup_byaddr(&p->daddr, saddr, p->proto, | ||
| 498 | p->family); | ||
| 499 | } | ||
| 500 | |||
| 501 | out: | ||
| 502 | if (!x && errp) | ||
| 503 | *errp = err; | ||
| 504 | return x; | ||
| 505 | } | ||
| 506 | |||
| 419 | static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 507 | static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
| 420 | { | 508 | { |
| 421 | struct xfrm_state *x; | 509 | struct xfrm_state *x; |
| 422 | int err; | 510 | int err = -ESRCH; |
| 423 | struct km_event c; | 511 | struct km_event c; |
| 424 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); | 512 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); |
| 425 | 513 | ||
| 426 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | 514 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); |
| 427 | if (x == NULL) | 515 | if (x == NULL) |
| 428 | return -ESRCH; | 516 | return err; |
| 429 | 517 | ||
| 430 | if ((err = security_xfrm_state_delete(x)) != 0) | 518 | if ((err = security_xfrm_state_delete(x)) != 0) |
| 431 | goto out; | 519 | goto out; |
| @@ -519,6 +607,13 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) | |||
| 519 | uctx->ctx_len = x->security->ctx_len; | 607 | uctx->ctx_len = x->security->ctx_len; |
| 520 | memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); | 608 | memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); |
| 521 | } | 609 | } |
| 610 | |||
| 611 | if (x->coaddr) | ||
| 612 | RTA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); | ||
| 613 | |||
| 614 | if (x->lastused) | ||
| 615 | RTA_PUT(skb, XFRMA_LASTUSED, sizeof(x->lastused), &x->lastused); | ||
| 616 | |||
| 522 | nlh->nlmsg_len = skb->tail - b; | 617 | nlh->nlmsg_len = skb->tail - b; |
| 523 | out: | 618 | out: |
| 524 | sp->this_idx++; | 619 | sp->this_idx++; |
| @@ -540,7 +635,7 @@ static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 540 | info.nlmsg_flags = NLM_F_MULTI; | 635 | info.nlmsg_flags = NLM_F_MULTI; |
| 541 | info.this_idx = 0; | 636 | info.this_idx = 0; |
| 542 | info.start_idx = cb->args[0]; | 637 | info.start_idx = cb->args[0]; |
| 543 | (void) xfrm_state_walk(IPSEC_PROTO_ANY, dump_one_state, &info); | 638 | (void) xfrm_state_walk(0, dump_one_state, &info); |
| 544 | cb->args[0] = info.this_idx; | 639 | cb->args[0] = info.this_idx; |
| 545 | 640 | ||
| 546 | return skb->len; | 641 | return skb->len; |
| @@ -576,10 +671,9 @@ static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | |||
| 576 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); | 671 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); |
| 577 | struct xfrm_state *x; | 672 | struct xfrm_state *x; |
| 578 | struct sk_buff *resp_skb; | 673 | struct sk_buff *resp_skb; |
| 579 | int err; | 674 | int err = -ESRCH; |
| 580 | 675 | ||
| 581 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | 676 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); |
| 582 | err = -ESRCH; | ||
| 583 | if (x == NULL) | 677 | if (x == NULL) |
| 584 | goto out_noput; | 678 | goto out_noput; |
| 585 | 679 | ||
| @@ -692,6 +786,22 @@ static int verify_policy_dir(__u8 dir) | |||
| 692 | return 0; | 786 | return 0; |
| 693 | } | 787 | } |
| 694 | 788 | ||
| 789 | static int verify_policy_type(__u8 type) | ||
| 790 | { | ||
| 791 | switch (type) { | ||
| 792 | case XFRM_POLICY_TYPE_MAIN: | ||
| 793 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
| 794 | case XFRM_POLICY_TYPE_SUB: | ||
| 795 | #endif | ||
| 796 | break; | ||
| 797 | |||
| 798 | default: | ||
| 799 | return -EINVAL; | ||
| 800 | }; | ||
| 801 | |||
| 802 | return 0; | ||
| 803 | } | ||
| 804 | |||
| 695 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) | 805 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) |
| 696 | { | 806 | { |
| 697 | switch (p->share) { | 807 | switch (p->share) { |
| @@ -785,6 +895,29 @@ static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) | |||
| 785 | return 0; | 895 | return 0; |
| 786 | } | 896 | } |
| 787 | 897 | ||
| 898 | static int copy_from_user_policy_type(u8 *tp, struct rtattr **xfrma) | ||
| 899 | { | ||
| 900 | struct rtattr *rt = xfrma[XFRMA_POLICY_TYPE-1]; | ||
| 901 | struct xfrm_userpolicy_type *upt; | ||
| 902 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
| 903 | int err; | ||
| 904 | |||
| 905 | if (rt) { | ||
| 906 | if (rt->rta_len < sizeof(*upt)) | ||
| 907 | return -EINVAL; | ||
| 908 | |||
| 909 | upt = RTA_DATA(rt); | ||
| 910 | type = upt->type; | ||
| 911 | } | ||
| 912 | |||
| 913 | err = verify_policy_type(type); | ||
| 914 | if (err) | ||
| 915 | return err; | ||
| 916 | |||
| 917 | *tp = type; | ||
| 918 | return 0; | ||
| 919 | } | ||
| 920 | |||
| 788 | static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p) | 921 | static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p) |
| 789 | { | 922 | { |
| 790 | xp->priority = p->priority; | 923 | xp->priority = p->priority; |
| @@ -823,16 +956,20 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, | |||
| 823 | 956 | ||
| 824 | copy_from_user_policy(xp, p); | 957 | copy_from_user_policy(xp, p); |
| 825 | 958 | ||
| 959 | err = copy_from_user_policy_type(&xp->type, xfrma); | ||
| 960 | if (err) | ||
| 961 | goto error; | ||
| 962 | |||
| 826 | if (!(err = copy_from_user_tmpl(xp, xfrma))) | 963 | if (!(err = copy_from_user_tmpl(xp, xfrma))) |
| 827 | err = copy_from_user_sec_ctx(xp, xfrma); | 964 | err = copy_from_user_sec_ctx(xp, xfrma); |
| 828 | 965 | if (err) | |
| 829 | if (err) { | 966 | goto error; |
| 830 | *errp = err; | ||
| 831 | kfree(xp); | ||
| 832 | xp = NULL; | ||
| 833 | } | ||
| 834 | 967 | ||
| 835 | return xp; | 968 | return xp; |
| 969 | error: | ||
| 970 | *errp = err; | ||
| 971 | kfree(xp); | ||
| 972 | return NULL; | ||
| 836 | } | 973 | } |
| 837 | 974 | ||
| 838 | static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 975 | static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
| @@ -909,27 +1046,63 @@ rtattr_failure: | |||
| 909 | return -1; | 1046 | return -1; |
| 910 | } | 1047 | } |
| 911 | 1048 | ||
| 912 | static int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) | 1049 | static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) |
| 913 | { | 1050 | { |
| 914 | if (xp->security) { | 1051 | int ctx_size = sizeof(struct xfrm_sec_ctx) + s->ctx_len; |
| 915 | int ctx_size = sizeof(struct xfrm_sec_ctx) + | 1052 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); |
| 916 | xp->security->ctx_len; | 1053 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); |
| 917 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); | 1054 | |
| 918 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | 1055 | uctx->exttype = XFRMA_SEC_CTX; |
| 1056 | uctx->len = ctx_size; | ||
| 1057 | uctx->ctx_doi = s->ctx_doi; | ||
| 1058 | uctx->ctx_alg = s->ctx_alg; | ||
| 1059 | uctx->ctx_len = s->ctx_len; | ||
| 1060 | memcpy(uctx + 1, s->ctx_str, s->ctx_len); | ||
| 1061 | return 0; | ||
| 919 | 1062 | ||
| 920 | uctx->exttype = XFRMA_SEC_CTX; | 1063 | rtattr_failure: |
| 921 | uctx->len = ctx_size; | 1064 | return -1; |
| 922 | uctx->ctx_doi = xp->security->ctx_doi; | 1065 | } |
| 923 | uctx->ctx_alg = xp->security->ctx_alg; | 1066 | |
| 924 | uctx->ctx_len = xp->security->ctx_len; | 1067 | static inline int copy_to_user_state_sec_ctx(struct xfrm_state *x, struct sk_buff *skb) |
| 925 | memcpy(uctx + 1, xp->security->ctx_str, xp->security->ctx_len); | 1068 | { |
| 1069 | if (x->security) { | ||
| 1070 | return copy_sec_ctx(x->security, skb); | ||
| 926 | } | 1071 | } |
| 927 | return 0; | 1072 | return 0; |
| 1073 | } | ||
| 928 | 1074 | ||
| 929 | rtattr_failure: | 1075 | static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) |
| 1076 | { | ||
| 1077 | if (xp->security) { | ||
| 1078 | return copy_sec_ctx(xp->security, skb); | ||
| 1079 | } | ||
| 1080 | return 0; | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
| 1084 | static int copy_to_user_policy_type(struct xfrm_policy *xp, struct sk_buff *skb) | ||
| 1085 | { | ||
| 1086 | struct xfrm_userpolicy_type upt; | ||
| 1087 | |||
| 1088 | memset(&upt, 0, sizeof(upt)); | ||
| 1089 | upt.type = xp->type; | ||
| 1090 | |||
| 1091 | RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); | ||
| 1092 | |||
| 1093 | return 0; | ||
| 1094 | |||
| 1095 | rtattr_failure: | ||
| 930 | return -1; | 1096 | return -1; |
| 931 | } | 1097 | } |
| 932 | 1098 | ||
| 1099 | #else | ||
| 1100 | static inline int copy_to_user_policy_type(struct xfrm_policy *xp, struct sk_buff *skb) | ||
| 1101 | { | ||
| 1102 | return 0; | ||
| 1103 | } | ||
| 1104 | #endif | ||
| 1105 | |||
| 933 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) | 1106 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) |
| 934 | { | 1107 | { |
| 935 | struct xfrm_dump_info *sp = ptr; | 1108 | struct xfrm_dump_info *sp = ptr; |
| @@ -953,6 +1126,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
| 953 | goto nlmsg_failure; | 1126 | goto nlmsg_failure; |
| 954 | if (copy_to_user_sec_ctx(xp, skb)) | 1127 | if (copy_to_user_sec_ctx(xp, skb)) |
| 955 | goto nlmsg_failure; | 1128 | goto nlmsg_failure; |
| 1129 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
| 1130 | goto nlmsg_failure; | ||
| 956 | 1131 | ||
| 957 | nlh->nlmsg_len = skb->tail - b; | 1132 | nlh->nlmsg_len = skb->tail - b; |
| 958 | out: | 1133 | out: |
| @@ -974,7 +1149,10 @@ static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 974 | info.nlmsg_flags = NLM_F_MULTI; | 1149 | info.nlmsg_flags = NLM_F_MULTI; |
| 975 | info.this_idx = 0; | 1150 | info.this_idx = 0; |
| 976 | info.start_idx = cb->args[0]; | 1151 | info.start_idx = cb->args[0]; |
| 977 | (void) xfrm_policy_walk(dump_one_policy, &info); | 1152 | (void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info); |
| 1153 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
| 1154 | (void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info); | ||
| 1155 | #endif | ||
| 978 | cb->args[0] = info.this_idx; | 1156 | cb->args[0] = info.this_idx; |
| 979 | 1157 | ||
| 980 | return skb->len; | 1158 | return skb->len; |
| @@ -1010,6 +1188,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
| 1010 | { | 1188 | { |
| 1011 | struct xfrm_policy *xp; | 1189 | struct xfrm_policy *xp; |
| 1012 | struct xfrm_userpolicy_id *p; | 1190 | struct xfrm_userpolicy_id *p; |
| 1191 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
| 1013 | int err; | 1192 | int err; |
| 1014 | struct km_event c; | 1193 | struct km_event c; |
| 1015 | int delete; | 1194 | int delete; |
| @@ -1017,12 +1196,16 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
| 1017 | p = NLMSG_DATA(nlh); | 1196 | p = NLMSG_DATA(nlh); |
| 1018 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; | 1197 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; |
| 1019 | 1198 | ||
| 1199 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
| 1200 | if (err) | ||
| 1201 | return err; | ||
| 1202 | |||
| 1020 | err = verify_policy_dir(p->dir); | 1203 | err = verify_policy_dir(p->dir); |
| 1021 | if (err) | 1204 | if (err) |
| 1022 | return err; | 1205 | return err; |
| 1023 | 1206 | ||
| 1024 | if (p->index) | 1207 | if (p->index) |
| 1025 | xp = xfrm_policy_byid(p->dir, p->index, delete); | 1208 | xp = xfrm_policy_byid(type, p->dir, p->index, delete); |
| 1026 | else { | 1209 | else { |
| 1027 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | 1210 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
| 1028 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | 1211 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; |
| @@ -1039,7 +1222,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
| 1039 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1222 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) |
| 1040 | return err; | 1223 | return err; |
| 1041 | } | 1224 | } |
| 1042 | xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, delete); | 1225 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, delete); |
| 1043 | security_xfrm_policy_free(&tmp); | 1226 | security_xfrm_policy_free(&tmp); |
| 1044 | } | 1227 | } |
| 1045 | if (xp == NULL) | 1228 | if (xp == NULL) |
| @@ -1222,9 +1405,16 @@ out: | |||
| 1222 | 1405 | ||
| 1223 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1406 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
| 1224 | { | 1407 | { |
| 1225 | struct km_event c; | 1408 | struct km_event c; |
| 1409 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
| 1410 | int err; | ||
| 1411 | |||
| 1412 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
| 1413 | if (err) | ||
| 1414 | return err; | ||
| 1226 | 1415 | ||
| 1227 | xfrm_policy_flush(); | 1416 | xfrm_policy_flush(type); |
| 1417 | c.data.type = type; | ||
| 1228 | c.event = nlh->nlmsg_type; | 1418 | c.event = nlh->nlmsg_type; |
| 1229 | c.seq = nlh->nlmsg_seq; | 1419 | c.seq = nlh->nlmsg_seq; |
| 1230 | c.pid = nlh->nlmsg_pid; | 1420 | c.pid = nlh->nlmsg_pid; |
| @@ -1237,10 +1427,15 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void * | |||
| 1237 | struct xfrm_policy *xp; | 1427 | struct xfrm_policy *xp; |
| 1238 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); | 1428 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); |
| 1239 | struct xfrm_userpolicy_info *p = &up->pol; | 1429 | struct xfrm_userpolicy_info *p = &up->pol; |
| 1430 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
| 1240 | int err = -ENOENT; | 1431 | int err = -ENOENT; |
| 1241 | 1432 | ||
| 1433 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
| 1434 | if (err) | ||
| 1435 | return err; | ||
| 1436 | |||
| 1242 | if (p->index) | 1437 | if (p->index) |
| 1243 | xp = xfrm_policy_byid(p->dir, p->index, 0); | 1438 | xp = xfrm_policy_byid(type, p->dir, p->index, 0); |
| 1244 | else { | 1439 | else { |
| 1245 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | 1440 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
| 1246 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | 1441 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; |
| @@ -1257,7 +1452,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void * | |||
| 1257 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1452 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) |
| 1258 | return err; | 1453 | return err; |
| 1259 | } | 1454 | } |
| 1260 | xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, 0); | 1455 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, 0); |
| 1261 | security_xfrm_policy_free(&tmp); | 1456 | security_xfrm_policy_free(&tmp); |
| 1262 | } | 1457 | } |
| 1263 | 1458 | ||
| @@ -1384,6 +1579,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | |||
| 1384 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), | 1579 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), |
| 1385 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | 1580 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), |
| 1386 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | 1581 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), |
| 1582 | [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), | ||
| 1387 | }; | 1583 | }; |
| 1388 | 1584 | ||
| 1389 | #undef XMSGSIZE | 1585 | #undef XMSGSIZE |
| @@ -1435,7 +1631,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err | |||
| 1435 | link = &xfrm_dispatch[type]; | 1631 | link = &xfrm_dispatch[type]; |
| 1436 | 1632 | ||
| 1437 | /* All operations require privileges, even GET */ | 1633 | /* All operations require privileges, even GET */ |
| 1438 | if (security_netlink_recv(skb)) { | 1634 | if (security_netlink_recv(skb, CAP_NET_ADMIN)) { |
| 1439 | *errp = -EPERM; | 1635 | *errp = -EPERM; |
| 1440 | return -1; | 1636 | return -1; |
| 1441 | } | 1637 | } |
| @@ -1708,7 +1904,9 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, | |||
| 1708 | 1904 | ||
| 1709 | if (copy_to_user_tmpl(xp, skb) < 0) | 1905 | if (copy_to_user_tmpl(xp, skb) < 0) |
| 1710 | goto nlmsg_failure; | 1906 | goto nlmsg_failure; |
| 1711 | if (copy_to_user_sec_ctx(xp, skb)) | 1907 | if (copy_to_user_state_sec_ctx(x, skb)) |
| 1908 | goto nlmsg_failure; | ||
| 1909 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
| 1712 | goto nlmsg_failure; | 1910 | goto nlmsg_failure; |
| 1713 | 1911 | ||
| 1714 | nlh->nlmsg_len = skb->tail - b; | 1912 | nlh->nlmsg_len = skb->tail - b; |
| @@ -1742,7 +1940,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, | |||
| 1742 | /* User gives us xfrm_user_policy_info followed by an array of 0 | 1940 | /* User gives us xfrm_user_policy_info followed by an array of 0 |
| 1743 | * or more templates. | 1941 | * or more templates. |
| 1744 | */ | 1942 | */ |
| 1745 | static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | 1943 | static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, |
| 1746 | u8 *data, int len, int *dir) | 1944 | u8 *data, int len, int *dir) |
| 1747 | { | 1945 | { |
| 1748 | struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; | 1946 | struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; |
| @@ -1750,7 +1948,7 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | |||
| 1750 | struct xfrm_policy *xp; | 1948 | struct xfrm_policy *xp; |
| 1751 | int nr; | 1949 | int nr; |
| 1752 | 1950 | ||
| 1753 | switch (family) { | 1951 | switch (sk->sk_family) { |
| 1754 | case AF_INET: | 1952 | case AF_INET: |
| 1755 | if (opt != IP_XFRM_POLICY) { | 1953 | if (opt != IP_XFRM_POLICY) { |
| 1756 | *dir = -EOPNOTSUPP; | 1954 | *dir = -EOPNOTSUPP; |
| @@ -1790,8 +1988,18 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | |||
| 1790 | } | 1988 | } |
| 1791 | 1989 | ||
| 1792 | copy_from_user_policy(xp, p); | 1990 | copy_from_user_policy(xp, p); |
| 1991 | xp->type = XFRM_POLICY_TYPE_MAIN; | ||
| 1793 | copy_templates(xp, ut, nr); | 1992 | copy_templates(xp, ut, nr); |
| 1794 | 1993 | ||
| 1994 | if (!xp->security) { | ||
| 1995 | int err = security_xfrm_sock_policy_alloc(xp, sk); | ||
| 1996 | if (err) { | ||
| 1997 | kfree(xp); | ||
| 1998 | *dir = err; | ||
| 1999 | return NULL; | ||
| 2000 | } | ||
| 2001 | } | ||
| 2002 | |||
| 1795 | *dir = p->dir; | 2003 | *dir = p->dir; |
| 1796 | 2004 | ||
| 1797 | return xp; | 2005 | return xp; |
| @@ -1814,6 +2022,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | |||
| 1814 | goto nlmsg_failure; | 2022 | goto nlmsg_failure; |
| 1815 | if (copy_to_user_sec_ctx(xp, skb)) | 2023 | if (copy_to_user_sec_ctx(xp, skb)) |
| 1816 | goto nlmsg_failure; | 2024 | goto nlmsg_failure; |
| 2025 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
| 2026 | goto nlmsg_failure; | ||
| 1817 | upe->hard = !!hard; | 2027 | upe->hard = !!hard; |
| 1818 | 2028 | ||
| 1819 | nlh->nlmsg_len = skb->tail - b; | 2029 | nlh->nlmsg_len = skb->tail - b; |
| @@ -1885,6 +2095,8 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * | |||
| 1885 | copy_to_user_policy(xp, p, dir); | 2095 | copy_to_user_policy(xp, p, dir); |
| 1886 | if (copy_to_user_tmpl(xp, skb) < 0) | 2096 | if (copy_to_user_tmpl(xp, skb) < 0) |
| 1887 | goto nlmsg_failure; | 2097 | goto nlmsg_failure; |
| 2098 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
| 2099 | goto nlmsg_failure; | ||
| 1888 | 2100 | ||
| 1889 | nlh->nlmsg_len = skb->tail - b; | 2101 | nlh->nlmsg_len = skb->tail - b; |
| 1890 | 2102 | ||
| @@ -1902,6 +2114,9 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
| 1902 | struct nlmsghdr *nlh; | 2114 | struct nlmsghdr *nlh; |
| 1903 | struct sk_buff *skb; | 2115 | struct sk_buff *skb; |
| 1904 | unsigned char *b; | 2116 | unsigned char *b; |
| 2117 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
| 2118 | struct xfrm_userpolicy_type upt; | ||
| 2119 | #endif | ||
| 1905 | int len = NLMSG_LENGTH(0); | 2120 | int len = NLMSG_LENGTH(0); |
| 1906 | 2121 | ||
| 1907 | skb = alloc_skb(len, GFP_ATOMIC); | 2122 | skb = alloc_skb(len, GFP_ATOMIC); |
| @@ -1911,6 +2126,13 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
| 1911 | 2126 | ||
| 1912 | 2127 | ||
| 1913 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0); | 2128 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0); |
| 2129 | nlh->nlmsg_flags = 0; | ||
| 2130 | |||
| 2131 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
| 2132 | memset(&upt, 0, sizeof(upt)); | ||
| 2133 | upt.type = c->data.type; | ||
| 2134 | RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); | ||
| 2135 | #endif | ||
| 1914 | 2136 | ||
| 1915 | nlh->nlmsg_len = skb->tail - b; | 2137 | nlh->nlmsg_len = skb->tail - b; |
| 1916 | 2138 | ||
| @@ -1918,6 +2140,9 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
| 1918 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); | 2140 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); |
| 1919 | 2141 | ||
| 1920 | nlmsg_failure: | 2142 | nlmsg_failure: |
| 2143 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
| 2144 | rtattr_failure: | ||
| 2145 | #endif | ||
| 1921 | kfree_skb(skb); | 2146 | kfree_skb(skb); |
| 1922 | return -1; | 2147 | return -1; |
| 1923 | } | 2148 | } |
| @@ -1942,19 +2167,64 @@ static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_ev | |||
| 1942 | 2167 | ||
| 1943 | } | 2168 | } |
| 1944 | 2169 | ||
| 2170 | static int build_report(struct sk_buff *skb, u8 proto, | ||
| 2171 | struct xfrm_selector *sel, xfrm_address_t *addr) | ||
| 2172 | { | ||
| 2173 | struct xfrm_user_report *ur; | ||
| 2174 | struct nlmsghdr *nlh; | ||
| 2175 | unsigned char *b = skb->tail; | ||
| 2176 | |||
| 2177 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur)); | ||
| 2178 | ur = NLMSG_DATA(nlh); | ||
| 2179 | nlh->nlmsg_flags = 0; | ||
| 2180 | |||
| 2181 | ur->proto = proto; | ||
| 2182 | memcpy(&ur->sel, sel, sizeof(ur->sel)); | ||
| 2183 | |||
| 2184 | if (addr) | ||
| 2185 | RTA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr); | ||
| 2186 | |||
| 2187 | nlh->nlmsg_len = skb->tail - b; | ||
| 2188 | return skb->len; | ||
| 2189 | |||
| 2190 | nlmsg_failure: | ||
| 2191 | rtattr_failure: | ||
| 2192 | skb_trim(skb, b - skb->data); | ||
| 2193 | return -1; | ||
| 2194 | } | ||
| 2195 | |||
| 2196 | static int xfrm_send_report(u8 proto, struct xfrm_selector *sel, | ||
| 2197 | xfrm_address_t *addr) | ||
| 2198 | { | ||
| 2199 | struct sk_buff *skb; | ||
| 2200 | size_t len; | ||
| 2201 | |||
| 2202 | len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct xfrm_user_report))); | ||
| 2203 | skb = alloc_skb(len, GFP_ATOMIC); | ||
| 2204 | if (skb == NULL) | ||
| 2205 | return -ENOMEM; | ||
| 2206 | |||
| 2207 | if (build_report(skb, proto, sel, addr) < 0) | ||
| 2208 | BUG(); | ||
| 2209 | |||
| 2210 | NETLINK_CB(skb).dst_group = XFRMNLGRP_REPORT; | ||
| 2211 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC); | ||
| 2212 | } | ||
| 2213 | |||
| 1945 | static struct xfrm_mgr netlink_mgr = { | 2214 | static struct xfrm_mgr netlink_mgr = { |
| 1946 | .id = "netlink", | 2215 | .id = "netlink", |
| 1947 | .notify = xfrm_send_state_notify, | 2216 | .notify = xfrm_send_state_notify, |
| 1948 | .acquire = xfrm_send_acquire, | 2217 | .acquire = xfrm_send_acquire, |
| 1949 | .compile_policy = xfrm_compile_policy, | 2218 | .compile_policy = xfrm_compile_policy, |
| 1950 | .notify_policy = xfrm_send_policy_notify, | 2219 | .notify_policy = xfrm_send_policy_notify, |
| 2220 | .report = xfrm_send_report, | ||
| 1951 | }; | 2221 | }; |
| 1952 | 2222 | ||
| 1953 | static int __init xfrm_user_init(void) | 2223 | static int __init xfrm_user_init(void) |
| 1954 | { | 2224 | { |
| 1955 | struct sock *nlsk; | 2225 | struct sock *nlsk; |
| 1956 | 2226 | ||
| 1957 | printk(KERN_INFO "Initializing IPsec netlink socket\n"); | 2227 | printk(KERN_INFO "Initializing XFRM netlink socket\n"); |
| 1958 | 2228 | ||
| 1959 | nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, | 2229 | nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, |
| 1960 | xfrm_netlink_rcv, THIS_MODULE); | 2230 | xfrm_netlink_rcv, THIS_MODULE); |
