diff options
-rw-r--r-- | include/net/xfrm.h | 1 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 55 |
2 files changed, 49 insertions, 7 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 13488e7ba68c..9ebbdc1dd471 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -273,6 +273,7 @@ struct xfrm_type | |||
273 | void (*destructor)(struct xfrm_state *); | 273 | void (*destructor)(struct xfrm_state *); |
274 | int (*input)(struct xfrm_state *, struct sk_buff *skb); | 274 | int (*input)(struct xfrm_state *, struct sk_buff *skb); |
275 | int (*output)(struct xfrm_state *, struct sk_buff *pskb); | 275 | int (*output)(struct xfrm_state *, struct sk_buff *pskb); |
276 | int (*reject)(struct xfrm_state *, struct sk_buff *, struct flowi *); | ||
276 | int (*hdr_offset)(struct xfrm_state *, struct sk_buff *, u8 **); | 277 | int (*hdr_offset)(struct xfrm_state *, struct sk_buff *, u8 **); |
277 | xfrm_address_t *(*local_addr)(struct xfrm_state *, xfrm_address_t *); | 278 | xfrm_address_t *(*local_addr)(struct xfrm_state *, xfrm_address_t *); |
278 | xfrm_address_t *(*remote_addr)(struct xfrm_state *, xfrm_address_t *); | 279 | xfrm_address_t *(*remote_addr)(struct xfrm_state *, xfrm_address_t *); |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index ad2a5cba1f5b..d125a2649037 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -988,6 +988,23 @@ error: | |||
988 | } | 988 | } |
989 | EXPORT_SYMBOL(xfrm_lookup); | 989 | EXPORT_SYMBOL(xfrm_lookup); |
990 | 990 | ||
991 | static inline int | ||
992 | xfrm_secpath_reject(int idx, struct sk_buff *skb, struct flowi *fl) | ||
993 | { | ||
994 | struct xfrm_state *x; | ||
995 | int err; | ||
996 | |||
997 | if (!skb->sp || idx < 0 || idx >= skb->sp->len) | ||
998 | return 0; | ||
999 | x = skb->sp->xvec[idx]; | ||
1000 | if (!x->type->reject) | ||
1001 | return 0; | ||
1002 | xfrm_state_hold(x); | ||
1003 | err = x->type->reject(x, skb, fl); | ||
1004 | xfrm_state_put(x); | ||
1005 | return err; | ||
1006 | } | ||
1007 | |||
991 | /* When skb is transformed back to its "native" form, we have to | 1008 | /* When skb is transformed back to its "native" form, we have to |
992 | * check policy restrictions. At the moment we make this in maximally | 1009 | * check policy restrictions. At the moment we make this in maximally |
993 | * stupid way. Shame on me. :-) Of course, connected sockets must | 1010 | * stupid way. Shame on me. :-) Of course, connected sockets must |
@@ -1010,6 +1027,13 @@ xfrm_state_ok(struct xfrm_tmpl *tmpl, struct xfrm_state *x, | |||
1010 | xfrm_state_addr_cmp(tmpl, x, family)); | 1027 | xfrm_state_addr_cmp(tmpl, x, family)); |
1011 | } | 1028 | } |
1012 | 1029 | ||
1030 | /* | ||
1031 | * 0 or more than 0 is returned when validation is succeeded (either bypass | ||
1032 | * because of optional transport mode, or next index of the mathced secpath | ||
1033 | * state with the template. | ||
1034 | * -1 is returned when no matching template is found. | ||
1035 | * Otherwise "-2 - errored_index" is returned. | ||
1036 | */ | ||
1013 | static inline int | 1037 | static inline int |
1014 | xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, | 1038 | xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, |
1015 | unsigned short family) | 1039 | unsigned short family) |
@@ -1024,8 +1048,11 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, | |||
1024 | for (; idx < sp->len; idx++) { | 1048 | for (; idx < sp->len; idx++) { |
1025 | if (xfrm_state_ok(tmpl, sp->xvec[idx], family)) | 1049 | if (xfrm_state_ok(tmpl, sp->xvec[idx], family)) |
1026 | return ++idx; | 1050 | return ++idx; |
1027 | if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) | 1051 | if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) { |
1052 | if (start == -1) | ||
1053 | start = -2-idx; | ||
1028 | break; | 1054 | break; |
1055 | } | ||
1029 | } | 1056 | } |
1030 | return start; | 1057 | return start; |
1031 | } | 1058 | } |
@@ -1046,11 +1073,14 @@ xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family | |||
1046 | } | 1073 | } |
1047 | EXPORT_SYMBOL(xfrm_decode_session); | 1074 | EXPORT_SYMBOL(xfrm_decode_session); |
1048 | 1075 | ||
1049 | static inline int secpath_has_nontransport(struct sec_path *sp, int k) | 1076 | static inline int secpath_has_nontransport(struct sec_path *sp, int k, int *idxp) |
1050 | { | 1077 | { |
1051 | for (; k < sp->len; k++) { | 1078 | for (; k < sp->len; k++) { |
1052 | if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) | 1079 | if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) { |
1080 | if (idxp) | ||
1081 | *idxp = k; | ||
1053 | return 1; | 1082 | return 1; |
1083 | } | ||
1054 | } | 1084 | } |
1055 | 1085 | ||
1056 | return 0; | 1086 | return 0; |
@@ -1062,6 +1092,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1062 | struct xfrm_policy *pol; | 1092 | struct xfrm_policy *pol; |
1063 | struct flowi fl; | 1093 | struct flowi fl; |
1064 | u8 fl_dir = policy_to_flow_dir(dir); | 1094 | u8 fl_dir = policy_to_flow_dir(dir); |
1095 | int xerr_idx = -1; | ||
1096 | int *xerr_idxp = &xerr_idx; | ||
1065 | 1097 | ||
1066 | if (xfrm_decode_session(skb, &fl, family) < 0) | 1098 | if (xfrm_decode_session(skb, &fl, family) < 0) |
1067 | return 0; | 1099 | return 0; |
@@ -1086,8 +1118,13 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1086 | pol = flow_cache_lookup(&fl, family, fl_dir, | 1118 | pol = flow_cache_lookup(&fl, family, fl_dir, |
1087 | xfrm_policy_lookup); | 1119 | xfrm_policy_lookup); |
1088 | 1120 | ||
1089 | if (!pol) | 1121 | if (!pol) { |
1090 | return !skb->sp || !secpath_has_nontransport(skb->sp, 0); | 1122 | if (skb->sp && secpath_has_nontransport(skb->sp, 0, xerr_idxp)) { |
1123 | xfrm_secpath_reject(xerr_idx, skb, &fl); | ||
1124 | return 0; | ||
1125 | } | ||
1126 | return 1; | ||
1127 | } | ||
1091 | 1128 | ||
1092 | pol->curlft.use_time = (unsigned long)xtime.tv_sec; | 1129 | pol->curlft.use_time = (unsigned long)xtime.tv_sec; |
1093 | 1130 | ||
@@ -1107,11 +1144,14 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1107 | */ | 1144 | */ |
1108 | for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) { | 1145 | for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) { |
1109 | k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family); | 1146 | k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family); |
1110 | if (k < 0) | 1147 | if (k < 0) { |
1148 | if (k < -1 && xerr_idxp) | ||
1149 | *xerr_idxp = -(2+k); | ||
1111 | goto reject; | 1150 | goto reject; |
1151 | } | ||
1112 | } | 1152 | } |
1113 | 1153 | ||
1114 | if (secpath_has_nontransport(sp, k)) | 1154 | if (secpath_has_nontransport(sp, k, xerr_idxp)) |
1115 | goto reject; | 1155 | goto reject; |
1116 | 1156 | ||
1117 | xfrm_pol_put(pol); | 1157 | xfrm_pol_put(pol); |
@@ -1119,6 +1159,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1119 | } | 1159 | } |
1120 | 1160 | ||
1121 | reject: | 1161 | reject: |
1162 | xfrm_secpath_reject(xerr_idx, skb, &fl); | ||
1122 | xfrm_pol_put(pol); | 1163 | xfrm_pol_put(pol); |
1123 | return 0; | 1164 | return 0; |
1124 | } | 1165 | } |