diff options
Diffstat (limited to 'net/xfrm/xfrm_user.c')
-rw-r--r-- | net/xfrm/xfrm_user.c | 134 |
1 files changed, 121 insertions, 13 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 7303b820bea4..c59a78d2923a 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -786,6 +786,22 @@ static int verify_policy_dir(__u8 dir) | |||
786 | return 0; | 786 | return 0; |
787 | } | 787 | } |
788 | 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 | |||
789 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) | 805 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) |
790 | { | 806 | { |
791 | switch (p->share) { | 807 | switch (p->share) { |
@@ -879,6 +895,29 @@ static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) | |||
879 | return 0; | 895 | return 0; |
880 | } | 896 | } |
881 | 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 | |||
882 | 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) |
883 | { | 922 | { |
884 | xp->priority = p->priority; | 923 | xp->priority = p->priority; |
@@ -917,16 +956,20 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, | |||
917 | 956 | ||
918 | copy_from_user_policy(xp, p); | 957 | copy_from_user_policy(xp, p); |
919 | 958 | ||
959 | err = copy_from_user_policy_type(&xp->type, xfrma); | ||
960 | if (err) | ||
961 | goto error; | ||
962 | |||
920 | if (!(err = copy_from_user_tmpl(xp, xfrma))) | 963 | if (!(err = copy_from_user_tmpl(xp, xfrma))) |
921 | err = copy_from_user_sec_ctx(xp, xfrma); | 964 | err = copy_from_user_sec_ctx(xp, xfrma); |
922 | 965 | if (err) | |
923 | if (err) { | 966 | goto error; |
924 | *errp = err; | ||
925 | kfree(xp); | ||
926 | xp = NULL; | ||
927 | } | ||
928 | 967 | ||
929 | return xp; | 968 | return xp; |
969 | error: | ||
970 | *errp = err; | ||
971 | kfree(xp); | ||
972 | return NULL; | ||
930 | } | 973 | } |
931 | 974 | ||
932 | 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) |
@@ -1037,6 +1080,29 @@ static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *s | |||
1037 | return 0; | 1080 | return 0; |
1038 | } | 1081 | } |
1039 | 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: | ||
1096 | return -1; | ||
1097 | } | ||
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 | |||
1040 | 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) |
1041 | { | 1107 | { |
1042 | struct xfrm_dump_info *sp = ptr; | 1108 | struct xfrm_dump_info *sp = ptr; |
@@ -1060,6 +1126,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
1060 | goto nlmsg_failure; | 1126 | goto nlmsg_failure; |
1061 | if (copy_to_user_sec_ctx(xp, skb)) | 1127 | if (copy_to_user_sec_ctx(xp, skb)) |
1062 | goto nlmsg_failure; | 1128 | goto nlmsg_failure; |
1129 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
1130 | goto nlmsg_failure; | ||
1063 | 1131 | ||
1064 | nlh->nlmsg_len = skb->tail - b; | 1132 | nlh->nlmsg_len = skb->tail - b; |
1065 | out: | 1133 | out: |
@@ -1081,7 +1149,10 @@ static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1081 | info.nlmsg_flags = NLM_F_MULTI; | 1149 | info.nlmsg_flags = NLM_F_MULTI; |
1082 | info.this_idx = 0; | 1150 | info.this_idx = 0; |
1083 | info.start_idx = cb->args[0]; | 1151 | info.start_idx = cb->args[0]; |
1084 | (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 | ||
1085 | cb->args[0] = info.this_idx; | 1156 | cb->args[0] = info.this_idx; |
1086 | 1157 | ||
1087 | return skb->len; | 1158 | return skb->len; |
@@ -1117,6 +1188,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
1117 | { | 1188 | { |
1118 | struct xfrm_policy *xp; | 1189 | struct xfrm_policy *xp; |
1119 | struct xfrm_userpolicy_id *p; | 1190 | struct xfrm_userpolicy_id *p; |
1191 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
1120 | int err; | 1192 | int err; |
1121 | struct km_event c; | 1193 | struct km_event c; |
1122 | int delete; | 1194 | int delete; |
@@ -1124,12 +1196,16 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
1124 | p = NLMSG_DATA(nlh); | 1196 | p = NLMSG_DATA(nlh); |
1125 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; | 1197 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; |
1126 | 1198 | ||
1199 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
1200 | if (err) | ||
1201 | return err; | ||
1202 | |||
1127 | err = verify_policy_dir(p->dir); | 1203 | err = verify_policy_dir(p->dir); |
1128 | if (err) | 1204 | if (err) |
1129 | return err; | 1205 | return err; |
1130 | 1206 | ||
1131 | if (p->index) | 1207 | if (p->index) |
1132 | xp = xfrm_policy_byid(p->dir, p->index, delete); | 1208 | xp = xfrm_policy_byid(type, p->dir, p->index, delete); |
1133 | else { | 1209 | else { |
1134 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | 1210 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
1135 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | 1211 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; |
@@ -1146,7 +1222,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
1146 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1222 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) |
1147 | return err; | 1223 | return err; |
1148 | } | 1224 | } |
1149 | 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); |
1150 | security_xfrm_policy_free(&tmp); | 1226 | security_xfrm_policy_free(&tmp); |
1151 | } | 1227 | } |
1152 | if (xp == NULL) | 1228 | if (xp == NULL) |
@@ -1329,9 +1405,16 @@ out: | |||
1329 | 1405 | ||
1330 | 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) |
1331 | { | 1407 | { |
1332 | 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; | ||
1333 | 1415 | ||
1334 | xfrm_policy_flush(); | 1416 | xfrm_policy_flush(type); |
1417 | c.data.type = type; | ||
1335 | c.event = nlh->nlmsg_type; | 1418 | c.event = nlh->nlmsg_type; |
1336 | c.seq = nlh->nlmsg_seq; | 1419 | c.seq = nlh->nlmsg_seq; |
1337 | c.pid = nlh->nlmsg_pid; | 1420 | c.pid = nlh->nlmsg_pid; |
@@ -1344,10 +1427,15 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void * | |||
1344 | struct xfrm_policy *xp; | 1427 | struct xfrm_policy *xp; |
1345 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); | 1428 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); |
1346 | struct xfrm_userpolicy_info *p = &up->pol; | 1429 | struct xfrm_userpolicy_info *p = &up->pol; |
1430 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
1347 | int err = -ENOENT; | 1431 | int err = -ENOENT; |
1348 | 1432 | ||
1433 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
1434 | if (err) | ||
1435 | return err; | ||
1436 | |||
1349 | if (p->index) | 1437 | if (p->index) |
1350 | xp = xfrm_policy_byid(p->dir, p->index, 0); | 1438 | xp = xfrm_policy_byid(type, p->dir, p->index, 0); |
1351 | else { | 1439 | else { |
1352 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | 1440 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
1353 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | 1441 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; |
@@ -1364,7 +1452,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void * | |||
1364 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1452 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) |
1365 | return err; | 1453 | return err; |
1366 | } | 1454 | } |
1367 | 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); |
1368 | security_xfrm_policy_free(&tmp); | 1456 | security_xfrm_policy_free(&tmp); |
1369 | } | 1457 | } |
1370 | 1458 | ||
@@ -1818,6 +1906,8 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, | |||
1818 | goto nlmsg_failure; | 1906 | goto nlmsg_failure; |
1819 | if (copy_to_user_state_sec_ctx(x, skb)) | 1907 | if (copy_to_user_state_sec_ctx(x, skb)) |
1820 | goto nlmsg_failure; | 1908 | goto nlmsg_failure; |
1909 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
1910 | goto nlmsg_failure; | ||
1821 | 1911 | ||
1822 | nlh->nlmsg_len = skb->tail - b; | 1912 | nlh->nlmsg_len = skb->tail - b; |
1823 | return skb->len; | 1913 | return skb->len; |
@@ -1898,6 +1988,7 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, | |||
1898 | } | 1988 | } |
1899 | 1989 | ||
1900 | copy_from_user_policy(xp, p); | 1990 | copy_from_user_policy(xp, p); |
1991 | xp->type = XFRM_POLICY_TYPE_MAIN; | ||
1901 | copy_templates(xp, ut, nr); | 1992 | copy_templates(xp, ut, nr); |
1902 | 1993 | ||
1903 | if (!xp->security) { | 1994 | if (!xp->security) { |
@@ -1931,6 +2022,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | |||
1931 | goto nlmsg_failure; | 2022 | goto nlmsg_failure; |
1932 | if (copy_to_user_sec_ctx(xp, skb)) | 2023 | if (copy_to_user_sec_ctx(xp, skb)) |
1933 | goto nlmsg_failure; | 2024 | goto nlmsg_failure; |
2025 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
2026 | goto nlmsg_failure; | ||
1934 | upe->hard = !!hard; | 2027 | upe->hard = !!hard; |
1935 | 2028 | ||
1936 | nlh->nlmsg_len = skb->tail - b; | 2029 | nlh->nlmsg_len = skb->tail - b; |
@@ -2002,6 +2095,8 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * | |||
2002 | copy_to_user_policy(xp, p, dir); | 2095 | copy_to_user_policy(xp, p, dir); |
2003 | if (copy_to_user_tmpl(xp, skb) < 0) | 2096 | if (copy_to_user_tmpl(xp, skb) < 0) |
2004 | goto nlmsg_failure; | 2097 | goto nlmsg_failure; |
2098 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
2099 | goto nlmsg_failure; | ||
2005 | 2100 | ||
2006 | nlh->nlmsg_len = skb->tail - b; | 2101 | nlh->nlmsg_len = skb->tail - b; |
2007 | 2102 | ||
@@ -2019,6 +2114,9 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
2019 | struct nlmsghdr *nlh; | 2114 | struct nlmsghdr *nlh; |
2020 | struct sk_buff *skb; | 2115 | struct sk_buff *skb; |
2021 | unsigned char *b; | 2116 | unsigned char *b; |
2117 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
2118 | struct xfrm_userpolicy_type upt; | ||
2119 | #endif | ||
2022 | int len = NLMSG_LENGTH(0); | 2120 | int len = NLMSG_LENGTH(0); |
2023 | 2121 | ||
2024 | skb = alloc_skb(len, GFP_ATOMIC); | 2122 | skb = alloc_skb(len, GFP_ATOMIC); |
@@ -2028,6 +2126,13 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
2028 | 2126 | ||
2029 | 2127 | ||
2030 | 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 | ||
2031 | 2136 | ||
2032 | nlh->nlmsg_len = skb->tail - b; | 2137 | nlh->nlmsg_len = skb->tail - b; |
2033 | 2138 | ||
@@ -2035,6 +2140,9 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
2035 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); | 2140 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); |
2036 | 2141 | ||
2037 | nlmsg_failure: | 2142 | nlmsg_failure: |
2143 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
2144 | rtattr_failure: | ||
2145 | #endif | ||
2038 | kfree_skb(skb); | 2146 | kfree_skb(skb); |
2039 | return -1; | 2147 | return -1; |
2040 | } | 2148 | } |