diff options
Diffstat (limited to 'net/xfrm/xfrm_user.c')
-rw-r--r-- | net/xfrm/xfrm_user.c | 348 |
1 files changed, 308 insertions, 40 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index fa79ddc4239e..c59a78d2923a 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -28,6 +28,9 @@ | |||
28 | #include <net/xfrm.h> | 28 | #include <net/xfrm.h> |
29 | #include <net/netlink.h> | 29 | #include <net/netlink.h> |
30 | #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 | ||
31 | 34 | ||
32 | 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) |
33 | { | 36 | { |
@@ -87,6 +90,22 @@ static int verify_encap_tmpl(struct rtattr **xfrma) | |||
87 | return 0; | 90 | return 0; |
88 | } | 91 | } |
89 | 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 | } | ||
90 | 109 | ||
91 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) | 110 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) |
92 | { | 111 | { |
@@ -157,6 +176,19 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
157 | goto out; | 176 | goto out; |
158 | break; | 177 | break; |
159 | 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 | |||
160 | default: | 192 | default: |
161 | goto out; | 193 | goto out; |
162 | }; | 194 | }; |
@@ -171,11 +203,14 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
171 | goto out; | 203 | goto out; |
172 | if ((err = verify_sec_ctx_len(xfrma))) | 204 | if ((err = verify_sec_ctx_len(xfrma))) |
173 | goto out; | 205 | goto out; |
206 | if ((err = verify_one_addr(xfrma, XFRMA_COADDR, NULL))) | ||
207 | goto out; | ||
174 | 208 | ||
175 | err = -EINVAL; | 209 | err = -EINVAL; |
176 | switch (p->mode) { | 210 | switch (p->mode) { |
177 | case 0: | 211 | case XFRM_MODE_TRANSPORT: |
178 | case 1: | 212 | case XFRM_MODE_TUNNEL: |
213 | case XFRM_MODE_ROUTEOPTIMIZATION: | ||
179 | break; | 214 | break; |
180 | 215 | ||
181 | default: | 216 | default: |
@@ -260,6 +295,24 @@ static int attach_sec_ctx(struct xfrm_state *x, struct rtattr *u_arg) | |||
260 | return security_xfrm_state_alloc(x, uctx); | 295 | return security_xfrm_state_alloc(x, uctx); |
261 | } | 296 | } |
262 | 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 | |||
263 | 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) |
264 | { | 317 | { |
265 | memcpy(&x->id, &p->id, sizeof(x->id)); | 318 | memcpy(&x->id, &p->id, sizeof(x->id)); |
@@ -349,7 +402,8 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | |||
349 | goto error; | 402 | goto error; |
350 | if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) | 403 | if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) |
351 | goto error; | 404 | goto error; |
352 | 405 | if ((err = attach_one_addr(&x->coaddr, xfrma[XFRMA_COADDR-1]))) | |
406 | goto error; | ||
353 | err = xfrm_init_state(x); | 407 | err = xfrm_init_state(x); |
354 | if (err) | 408 | if (err) |
355 | goto error; | 409 | goto error; |
@@ -418,16 +472,48 @@ out: | |||
418 | return err; | 472 | return err; |
419 | } | 473 | } |
420 | 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 | |||
421 | 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) |
422 | { | 508 | { |
423 | struct xfrm_state *x; | 509 | struct xfrm_state *x; |
424 | int err; | 510 | int err = -ESRCH; |
425 | struct km_event c; | 511 | struct km_event c; |
426 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); | 512 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); |
427 | 513 | ||
428 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | 514 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); |
429 | if (x == NULL) | 515 | if (x == NULL) |
430 | return -ESRCH; | 516 | return err; |
431 | 517 | ||
432 | if ((err = security_xfrm_state_delete(x)) != 0) | 518 | if ((err = security_xfrm_state_delete(x)) != 0) |
433 | goto out; | 519 | goto out; |
@@ -521,6 +607,13 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) | |||
521 | uctx->ctx_len = x->security->ctx_len; | 607 | uctx->ctx_len = x->security->ctx_len; |
522 | memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); | 608 | memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); |
523 | } | 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 | |||
524 | nlh->nlmsg_len = skb->tail - b; | 617 | nlh->nlmsg_len = skb->tail - b; |
525 | out: | 618 | out: |
526 | sp->this_idx++; | 619 | sp->this_idx++; |
@@ -542,7 +635,7 @@ static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) | |||
542 | info.nlmsg_flags = NLM_F_MULTI; | 635 | info.nlmsg_flags = NLM_F_MULTI; |
543 | info.this_idx = 0; | 636 | info.this_idx = 0; |
544 | info.start_idx = cb->args[0]; | 637 | info.start_idx = cb->args[0]; |
545 | (void) xfrm_state_walk(IPSEC_PROTO_ANY, dump_one_state, &info); | 638 | (void) xfrm_state_walk(0, dump_one_state, &info); |
546 | cb->args[0] = info.this_idx; | 639 | cb->args[0] = info.this_idx; |
547 | 640 | ||
548 | return skb->len; | 641 | return skb->len; |
@@ -578,10 +671,9 @@ static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | |||
578 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); | 671 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); |
579 | struct xfrm_state *x; | 672 | struct xfrm_state *x; |
580 | struct sk_buff *resp_skb; | 673 | struct sk_buff *resp_skb; |
581 | int err; | 674 | int err = -ESRCH; |
582 | 675 | ||
583 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | 676 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); |
584 | err = -ESRCH; | ||
585 | if (x == NULL) | 677 | if (x == NULL) |
586 | goto out_noput; | 678 | goto out_noput; |
587 | 679 | ||
@@ -694,6 +786,22 @@ static int verify_policy_dir(__u8 dir) | |||
694 | return 0; | 786 | return 0; |
695 | } | 787 | } |
696 | 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 | |||
697 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) | 805 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) |
698 | { | 806 | { |
699 | switch (p->share) { | 807 | switch (p->share) { |
@@ -787,6 +895,29 @@ static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) | |||
787 | return 0; | 895 | return 0; |
788 | } | 896 | } |
789 | 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 | |||
790 | 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) |
791 | { | 922 | { |
792 | xp->priority = p->priority; | 923 | xp->priority = p->priority; |
@@ -825,16 +956,20 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, | |||
825 | 956 | ||
826 | copy_from_user_policy(xp, p); | 957 | copy_from_user_policy(xp, p); |
827 | 958 | ||
959 | err = copy_from_user_policy_type(&xp->type, xfrma); | ||
960 | if (err) | ||
961 | goto error; | ||
962 | |||
828 | if (!(err = copy_from_user_tmpl(xp, xfrma))) | 963 | if (!(err = copy_from_user_tmpl(xp, xfrma))) |
829 | err = copy_from_user_sec_ctx(xp, xfrma); | 964 | err = copy_from_user_sec_ctx(xp, xfrma); |
830 | 965 | if (err) | |
831 | if (err) { | 966 | goto error; |
832 | *errp = err; | ||
833 | kfree(xp); | ||
834 | xp = NULL; | ||
835 | } | ||
836 | 967 | ||
837 | return xp; | 968 | return xp; |
969 | error: | ||
970 | *errp = err; | ||
971 | kfree(xp); | ||
972 | return NULL; | ||
838 | } | 973 | } |
839 | 974 | ||
840 | 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) |
@@ -911,27 +1046,63 @@ rtattr_failure: | |||
911 | return -1; | 1046 | return -1; |
912 | } | 1047 | } |
913 | 1048 | ||
914 | 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) |
915 | { | 1050 | { |
916 | if (xp->security) { | 1051 | int ctx_size = sizeof(struct xfrm_sec_ctx) + s->ctx_len; |
917 | int ctx_size = sizeof(struct xfrm_sec_ctx) + | 1052 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); |
918 | xp->security->ctx_len; | 1053 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); |
919 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); | 1054 | |
920 | 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; | ||
921 | 1062 | ||
922 | uctx->exttype = XFRMA_SEC_CTX; | 1063 | rtattr_failure: |
923 | uctx->len = ctx_size; | 1064 | return -1; |
924 | uctx->ctx_doi = xp->security->ctx_doi; | 1065 | } |
925 | uctx->ctx_alg = xp->security->ctx_alg; | 1066 | |
926 | 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) |
927 | memcpy(uctx + 1, xp->security->ctx_str, xp->security->ctx_len); | 1068 | { |
1069 | if (x->security) { | ||
1070 | return copy_sec_ctx(x->security, skb); | ||
928 | } | 1071 | } |
929 | return 0; | 1072 | return 0; |
1073 | } | ||
930 | 1074 | ||
931 | 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: | ||
932 | return -1; | 1096 | return -1; |
933 | } | 1097 | } |
934 | 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 | |||
935 | 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) |
936 | { | 1107 | { |
937 | struct xfrm_dump_info *sp = ptr; | 1108 | struct xfrm_dump_info *sp = ptr; |
@@ -955,6 +1126,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
955 | goto nlmsg_failure; | 1126 | goto nlmsg_failure; |
956 | if (copy_to_user_sec_ctx(xp, skb)) | 1127 | if (copy_to_user_sec_ctx(xp, skb)) |
957 | goto nlmsg_failure; | 1128 | goto nlmsg_failure; |
1129 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
1130 | goto nlmsg_failure; | ||
958 | 1131 | ||
959 | nlh->nlmsg_len = skb->tail - b; | 1132 | nlh->nlmsg_len = skb->tail - b; |
960 | out: | 1133 | out: |
@@ -976,7 +1149,10 @@ static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) | |||
976 | info.nlmsg_flags = NLM_F_MULTI; | 1149 | info.nlmsg_flags = NLM_F_MULTI; |
977 | info.this_idx = 0; | 1150 | info.this_idx = 0; |
978 | info.start_idx = cb->args[0]; | 1151 | info.start_idx = cb->args[0]; |
979 | (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 | ||
980 | cb->args[0] = info.this_idx; | 1156 | cb->args[0] = info.this_idx; |
981 | 1157 | ||
982 | return skb->len; | 1158 | return skb->len; |
@@ -1012,6 +1188,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
1012 | { | 1188 | { |
1013 | struct xfrm_policy *xp; | 1189 | struct xfrm_policy *xp; |
1014 | struct xfrm_userpolicy_id *p; | 1190 | struct xfrm_userpolicy_id *p; |
1191 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
1015 | int err; | 1192 | int err; |
1016 | struct km_event c; | 1193 | struct km_event c; |
1017 | int delete; | 1194 | int delete; |
@@ -1019,12 +1196,16 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
1019 | p = NLMSG_DATA(nlh); | 1196 | p = NLMSG_DATA(nlh); |
1020 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; | 1197 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; |
1021 | 1198 | ||
1199 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
1200 | if (err) | ||
1201 | return err; | ||
1202 | |||
1022 | err = verify_policy_dir(p->dir); | 1203 | err = verify_policy_dir(p->dir); |
1023 | if (err) | 1204 | if (err) |
1024 | return err; | 1205 | return err; |
1025 | 1206 | ||
1026 | if (p->index) | 1207 | if (p->index) |
1027 | xp = xfrm_policy_byid(p->dir, p->index, delete); | 1208 | xp = xfrm_policy_byid(type, p->dir, p->index, delete); |
1028 | else { | 1209 | else { |
1029 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | 1210 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
1030 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | 1211 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; |
@@ -1041,7 +1222,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
1041 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1222 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) |
1042 | return err; | 1223 | return err; |
1043 | } | 1224 | } |
1044 | 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); |
1045 | security_xfrm_policy_free(&tmp); | 1226 | security_xfrm_policy_free(&tmp); |
1046 | } | 1227 | } |
1047 | if (xp == NULL) | 1228 | if (xp == NULL) |
@@ -1224,9 +1405,16 @@ out: | |||
1224 | 1405 | ||
1225 | 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) |
1226 | { | 1407 | { |
1227 | 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; | ||
1228 | 1415 | ||
1229 | xfrm_policy_flush(); | 1416 | xfrm_policy_flush(type); |
1417 | c.data.type = type; | ||
1230 | c.event = nlh->nlmsg_type; | 1418 | c.event = nlh->nlmsg_type; |
1231 | c.seq = nlh->nlmsg_seq; | 1419 | c.seq = nlh->nlmsg_seq; |
1232 | c.pid = nlh->nlmsg_pid; | 1420 | c.pid = nlh->nlmsg_pid; |
@@ -1239,10 +1427,15 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void * | |||
1239 | struct xfrm_policy *xp; | 1427 | struct xfrm_policy *xp; |
1240 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); | 1428 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); |
1241 | struct xfrm_userpolicy_info *p = &up->pol; | 1429 | struct xfrm_userpolicy_info *p = &up->pol; |
1430 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
1242 | int err = -ENOENT; | 1431 | int err = -ENOENT; |
1243 | 1432 | ||
1433 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
1434 | if (err) | ||
1435 | return err; | ||
1436 | |||
1244 | if (p->index) | 1437 | if (p->index) |
1245 | xp = xfrm_policy_byid(p->dir, p->index, 0); | 1438 | xp = xfrm_policy_byid(type, p->dir, p->index, 0); |
1246 | else { | 1439 | else { |
1247 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | 1440 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
1248 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | 1441 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; |
@@ -1259,7 +1452,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void * | |||
1259 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1452 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) |
1260 | return err; | 1453 | return err; |
1261 | } | 1454 | } |
1262 | 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); |
1263 | security_xfrm_policy_free(&tmp); | 1456 | security_xfrm_policy_free(&tmp); |
1264 | } | 1457 | } |
1265 | 1458 | ||
@@ -1386,6 +1579,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | |||
1386 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), | 1579 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), |
1387 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | 1580 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), |
1388 | [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), | ||
1389 | }; | 1583 | }; |
1390 | 1584 | ||
1391 | #undef XMSGSIZE | 1585 | #undef XMSGSIZE |
@@ -1710,7 +1904,9 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, | |||
1710 | 1904 | ||
1711 | if (copy_to_user_tmpl(xp, skb) < 0) | 1905 | if (copy_to_user_tmpl(xp, skb) < 0) |
1712 | goto nlmsg_failure; | 1906 | goto nlmsg_failure; |
1713 | 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) | ||
1714 | goto nlmsg_failure; | 1910 | goto nlmsg_failure; |
1715 | 1911 | ||
1716 | nlh->nlmsg_len = skb->tail - b; | 1912 | nlh->nlmsg_len = skb->tail - b; |
@@ -1744,7 +1940,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, | |||
1744 | /* 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 |
1745 | * or more templates. | 1941 | * or more templates. |
1746 | */ | 1942 | */ |
1747 | static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | 1943 | static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, |
1748 | u8 *data, int len, int *dir) | 1944 | u8 *data, int len, int *dir) |
1749 | { | 1945 | { |
1750 | struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; | 1946 | struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; |
@@ -1752,7 +1948,7 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | |||
1752 | struct xfrm_policy *xp; | 1948 | struct xfrm_policy *xp; |
1753 | int nr; | 1949 | int nr; |
1754 | 1950 | ||
1755 | switch (family) { | 1951 | switch (sk->sk_family) { |
1756 | case AF_INET: | 1952 | case AF_INET: |
1757 | if (opt != IP_XFRM_POLICY) { | 1953 | if (opt != IP_XFRM_POLICY) { |
1758 | *dir = -EOPNOTSUPP; | 1954 | *dir = -EOPNOTSUPP; |
@@ -1792,8 +1988,18 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | |||
1792 | } | 1988 | } |
1793 | 1989 | ||
1794 | copy_from_user_policy(xp, p); | 1990 | copy_from_user_policy(xp, p); |
1991 | xp->type = XFRM_POLICY_TYPE_MAIN; | ||
1795 | copy_templates(xp, ut, nr); | 1992 | copy_templates(xp, ut, nr); |
1796 | 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 | |||
1797 | *dir = p->dir; | 2003 | *dir = p->dir; |
1798 | 2004 | ||
1799 | return xp; | 2005 | return xp; |
@@ -1816,6 +2022,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | |||
1816 | goto nlmsg_failure; | 2022 | goto nlmsg_failure; |
1817 | if (copy_to_user_sec_ctx(xp, skb)) | 2023 | if (copy_to_user_sec_ctx(xp, skb)) |
1818 | goto nlmsg_failure; | 2024 | goto nlmsg_failure; |
2025 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
2026 | goto nlmsg_failure; | ||
1819 | upe->hard = !!hard; | 2027 | upe->hard = !!hard; |
1820 | 2028 | ||
1821 | nlh->nlmsg_len = skb->tail - b; | 2029 | nlh->nlmsg_len = skb->tail - b; |
@@ -1887,6 +2095,8 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * | |||
1887 | copy_to_user_policy(xp, p, dir); | 2095 | copy_to_user_policy(xp, p, dir); |
1888 | if (copy_to_user_tmpl(xp, skb) < 0) | 2096 | if (copy_to_user_tmpl(xp, skb) < 0) |
1889 | goto nlmsg_failure; | 2097 | goto nlmsg_failure; |
2098 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
2099 | goto nlmsg_failure; | ||
1890 | 2100 | ||
1891 | nlh->nlmsg_len = skb->tail - b; | 2101 | nlh->nlmsg_len = skb->tail - b; |
1892 | 2102 | ||
@@ -1904,6 +2114,9 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
1904 | struct nlmsghdr *nlh; | 2114 | struct nlmsghdr *nlh; |
1905 | struct sk_buff *skb; | 2115 | struct sk_buff *skb; |
1906 | unsigned char *b; | 2116 | unsigned char *b; |
2117 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
2118 | struct xfrm_userpolicy_type upt; | ||
2119 | #endif | ||
1907 | int len = NLMSG_LENGTH(0); | 2120 | int len = NLMSG_LENGTH(0); |
1908 | 2121 | ||
1909 | skb = alloc_skb(len, GFP_ATOMIC); | 2122 | skb = alloc_skb(len, GFP_ATOMIC); |
@@ -1913,6 +2126,13 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
1913 | 2126 | ||
1914 | 2127 | ||
1915 | 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 | ||
1916 | 2136 | ||
1917 | nlh->nlmsg_len = skb->tail - b; | 2137 | nlh->nlmsg_len = skb->tail - b; |
1918 | 2138 | ||
@@ -1920,6 +2140,9 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
1920 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); | 2140 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); |
1921 | 2141 | ||
1922 | nlmsg_failure: | 2142 | nlmsg_failure: |
2143 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
2144 | rtattr_failure: | ||
2145 | #endif | ||
1923 | kfree_skb(skb); | 2146 | kfree_skb(skb); |
1924 | return -1; | 2147 | return -1; |
1925 | } | 2148 | } |
@@ -1944,19 +2167,64 @@ static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_ev | |||
1944 | 2167 | ||
1945 | } | 2168 | } |
1946 | 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 | |||
1947 | static struct xfrm_mgr netlink_mgr = { | 2214 | static struct xfrm_mgr netlink_mgr = { |
1948 | .id = "netlink", | 2215 | .id = "netlink", |
1949 | .notify = xfrm_send_state_notify, | 2216 | .notify = xfrm_send_state_notify, |
1950 | .acquire = xfrm_send_acquire, | 2217 | .acquire = xfrm_send_acquire, |
1951 | .compile_policy = xfrm_compile_policy, | 2218 | .compile_policy = xfrm_compile_policy, |
1952 | .notify_policy = xfrm_send_policy_notify, | 2219 | .notify_policy = xfrm_send_policy_notify, |
2220 | .report = xfrm_send_report, | ||
1953 | }; | 2221 | }; |
1954 | 2222 | ||
1955 | static int __init xfrm_user_init(void) | 2223 | static int __init xfrm_user_init(void) |
1956 | { | 2224 | { |
1957 | struct sock *nlsk; | 2225 | struct sock *nlsk; |
1958 | 2226 | ||
1959 | printk(KERN_INFO "Initializing IPsec netlink socket\n"); | 2227 | printk(KERN_INFO "Initializing XFRM netlink socket\n"); |
1960 | 2228 | ||
1961 | nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, | 2229 | nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, |
1962 | xfrm_netlink_rcv, THIS_MODULE); | 2230 | xfrm_netlink_rcv, THIS_MODULE); |