diff options
author | David S. Miller <davem@davemloft.net> | 2014-02-27 16:19:41 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-02-27 16:19:41 -0500 |
commit | 23187212e7c3664f6a0d8ccd83b6d32c05aeafcb (patch) | |
tree | 68e3c4c32c1295bb65da6f936be890290670c992 | |
parent | bf439b3154ce49d81a79b14f9fab18af99018ae2 (diff) | |
parent | 3a9016f97fdc8bfbb26ff36ba8f3dc9162eb691b (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says:
====================
1) Build fix for ip_vti when NET_IP_TUNNEL is not set.
We need this set to have ip_tunnel_get_stats64()
available.
2) Fix a NULL pointer dereference on sub policy usage.
We try to access a xfrm_state from the wrong array.
3) Take xfrm_state_lock in xfrm_migrate_state_find(),
we need it to traverse through the state lists.
4) Clone states properly on migration, otherwise we crash
when we migrate a state with aead algorithm attached.
5) Fix unlink race when between thread context and timer
when policies are deleted.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/xfrm.h | 11 | ||||
-rw-r--r-- | net/ipv6/Kconfig | 1 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 2 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 23 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 5 |
5 files changed, 30 insertions, 12 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index afa5730fb3bd..fb5654a8ca3c 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -1648,6 +1648,11 @@ static inline int xfrm_aevent_is_on(struct net *net) | |||
1648 | } | 1648 | } |
1649 | #endif | 1649 | #endif |
1650 | 1650 | ||
1651 | static inline int aead_len(struct xfrm_algo_aead *alg) | ||
1652 | { | ||
1653 | return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); | ||
1654 | } | ||
1655 | |||
1651 | static inline int xfrm_alg_len(const struct xfrm_algo *alg) | 1656 | static inline int xfrm_alg_len(const struct xfrm_algo *alg) |
1652 | { | 1657 | { |
1653 | return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); | 1658 | return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); |
@@ -1686,6 +1691,12 @@ static inline int xfrm_replay_clone(struct xfrm_state *x, | |||
1686 | return 0; | 1691 | return 0; |
1687 | } | 1692 | } |
1688 | 1693 | ||
1694 | static inline struct xfrm_algo_aead *xfrm_algo_aead_clone(struct xfrm_algo_aead *orig) | ||
1695 | { | ||
1696 | return kmemdup(orig, aead_len(orig), GFP_KERNEL); | ||
1697 | } | ||
1698 | |||
1699 | |||
1689 | static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig) | 1700 | static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig) |
1690 | { | 1701 | { |
1691 | return kmemdup(orig, xfrm_alg_len(orig), GFP_KERNEL); | 1702 | return kmemdup(orig, xfrm_alg_len(orig), GFP_KERNEL); |
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index d92e5586783e..438a73aa777c 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
@@ -138,6 +138,7 @@ config INET6_XFRM_MODE_ROUTEOPTIMIZATION | |||
138 | config IPV6_VTI | 138 | config IPV6_VTI |
139 | tristate "Virtual (secure) IPv6: tunneling" | 139 | tristate "Virtual (secure) IPv6: tunneling" |
140 | select IPV6_TUNNEL | 140 | select IPV6_TUNNEL |
141 | select NET_IP_TUNNEL | ||
141 | depends on INET6_XFRM_MODE_TUNNEL | 142 | depends on INET6_XFRM_MODE_TUNNEL |
142 | ---help--- | 143 | ---help--- |
143 | Tunneling means encapsulating data of one protocol type within | 144 | Tunneling means encapsulating data of one protocol type within |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 4b98b25793c5..1d5c7bf29938 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -1158,7 +1158,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | |||
1158 | if (hlist_unhashed(&pol->bydst)) | 1158 | if (hlist_unhashed(&pol->bydst)) |
1159 | return NULL; | 1159 | return NULL; |
1160 | 1160 | ||
1161 | hlist_del(&pol->bydst); | 1161 | hlist_del_init(&pol->bydst); |
1162 | hlist_del(&pol->byidx); | 1162 | hlist_del(&pol->byidx); |
1163 | list_del(&pol->walk.all); | 1163 | list_del(&pol->walk.all); |
1164 | net->xfrm.policy_count[dir]--; | 1164 | net->xfrm.policy_count[dir]--; |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index a26b7aa79475..40f1b3e92e78 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -1159,6 +1159,11 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
1159 | } | 1159 | } |
1160 | x->props.aalgo = orig->props.aalgo; | 1160 | x->props.aalgo = orig->props.aalgo; |
1161 | 1161 | ||
1162 | if (orig->aead) { | ||
1163 | x->aead = xfrm_algo_aead_clone(orig->aead); | ||
1164 | if (!x->aead) | ||
1165 | goto error; | ||
1166 | } | ||
1162 | if (orig->ealg) { | 1167 | if (orig->ealg) { |
1163 | x->ealg = xfrm_algo_clone(orig->ealg); | 1168 | x->ealg = xfrm_algo_clone(orig->ealg); |
1164 | if (!x->ealg) | 1169 | if (!x->ealg) |
@@ -1201,6 +1206,9 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
1201 | x->props.flags = orig->props.flags; | 1206 | x->props.flags = orig->props.flags; |
1202 | x->props.extra_flags = orig->props.extra_flags; | 1207 | x->props.extra_flags = orig->props.extra_flags; |
1203 | 1208 | ||
1209 | x->tfcpad = orig->tfcpad; | ||
1210 | x->replay_maxdiff = orig->replay_maxdiff; | ||
1211 | x->replay_maxage = orig->replay_maxage; | ||
1204 | x->curlft.add_time = orig->curlft.add_time; | 1212 | x->curlft.add_time = orig->curlft.add_time; |
1205 | x->km.state = orig->km.state; | 1213 | x->km.state = orig->km.state; |
1206 | x->km.seq = orig->km.seq; | 1214 | x->km.seq = orig->km.seq; |
@@ -1215,11 +1223,12 @@ out: | |||
1215 | return NULL; | 1223 | return NULL; |
1216 | } | 1224 | } |
1217 | 1225 | ||
1218 | /* net->xfrm.xfrm_state_lock is held */ | ||
1219 | struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net) | 1226 | struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net) |
1220 | { | 1227 | { |
1221 | unsigned int h; | 1228 | unsigned int h; |
1222 | struct xfrm_state *x; | 1229 | struct xfrm_state *x = NULL; |
1230 | |||
1231 | spin_lock_bh(&net->xfrm.xfrm_state_lock); | ||
1223 | 1232 | ||
1224 | if (m->reqid) { | 1233 | if (m->reqid) { |
1225 | h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr, | 1234 | h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr, |
@@ -1236,7 +1245,7 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n | |||
1236 | m->old_family)) | 1245 | m->old_family)) |
1237 | continue; | 1246 | continue; |
1238 | xfrm_state_hold(x); | 1247 | xfrm_state_hold(x); |
1239 | return x; | 1248 | break; |
1240 | } | 1249 | } |
1241 | } else { | 1250 | } else { |
1242 | h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr, | 1251 | h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr, |
@@ -1251,11 +1260,13 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n | |||
1251 | m->old_family)) | 1260 | m->old_family)) |
1252 | continue; | 1261 | continue; |
1253 | xfrm_state_hold(x); | 1262 | xfrm_state_hold(x); |
1254 | return x; | 1263 | break; |
1255 | } | 1264 | } |
1256 | } | 1265 | } |
1257 | 1266 | ||
1258 | return NULL; | 1267 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
1268 | |||
1269 | return x; | ||
1259 | } | 1270 | } |
1260 | EXPORT_SYMBOL(xfrm_migrate_state_find); | 1271 | EXPORT_SYMBOL(xfrm_migrate_state_find); |
1261 | 1272 | ||
@@ -1451,7 +1462,7 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, | |||
1451 | { | 1462 | { |
1452 | int err = 0; | 1463 | int err = 0; |
1453 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); | 1464 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); |
1454 | struct net *net = xs_net(*dst); | 1465 | struct net *net = xs_net(*src); |
1455 | 1466 | ||
1456 | if (!afinfo) | 1467 | if (!afinfo) |
1457 | return -EAFNOSUPPORT; | 1468 | return -EAFNOSUPPORT; |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 1ae3ec7c18b0..c274179d60a2 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -32,11 +32,6 @@ | |||
32 | #include <linux/in6.h> | 32 | #include <linux/in6.h> |
33 | #endif | 33 | #endif |
34 | 34 | ||
35 | static inline int aead_len(struct xfrm_algo_aead *alg) | ||
36 | { | ||
37 | return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); | ||
38 | } | ||
39 | |||
40 | static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) | 35 | static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) |
41 | { | 36 | { |
42 | struct nlattr *rt = attrs[type]; | 37 | struct nlattr *rt = attrs[type]; |