aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_policy.c55
1 files changed, 48 insertions, 7 deletions
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}
989EXPORT_SYMBOL(xfrm_lookup); 989EXPORT_SYMBOL(xfrm_lookup);
990 990
991static inline int
992xfrm_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 */
1013static inline int 1037static inline int
1014xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, 1038xfrm_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}
1047EXPORT_SYMBOL(xfrm_decode_session); 1074EXPORT_SYMBOL(xfrm_decode_session);
1048 1075
1049static inline int secpath_has_nontransport(struct sec_path *sp, int k) 1076static 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
1121reject: 1161reject:
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}