mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 02:50:43 +00:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says: ==================== pull request (net): ipsec 2018-01-11 1) Don't allow to change the encap type on state updates. The encap type is set on state initialization and should not change anymore. From Herbert Xu. 2) Skip dead policies when rehashing to fix a slab-out-of-bounds bug in xfrm_hash_rebuild. From Florian Westphal. 3) Two buffer overread fixes in pfkey. From Eric Biggers. 4) Fix rcu usage in xfrm_get_type_offload, request_module can sleep, so can't be used under rcu_read_lock. From Sabrina Dubroca. 5) Fix an uninitialized lock in xfrm_trans_queue. Use __skb_queue_tail instead of skb_queue_tail in xfrm_trans_queue as we don't need the lock. From Herbert Xu. 6) Currently it is possible to create an xfrm state with an unknown encap type in ESP IPv4. Fix this by returning an error on unknown encap types. Also from Herbert Xu. 7) Fix sleeping inside a spinlock in xfrm_policy_cache_flush. From Florian Westphal. 8) Fix ESP GRO when the headers not fully in the linear part of the skb. We need to pull before we can access them. 9) Fix a skb leak on error in key_notify_policy. 10) Fix a race in the xdst pcpu cache, we need to run the resolver routines with bottom halfes off like the old flowcache did. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
9c70f1a7fa
8 changed files with 38 additions and 12 deletions
|
@ -981,6 +981,7 @@ static int esp_init_state(struct xfrm_state *x)
|
|||
|
||||
switch (encap->encap_type) {
|
||||
default:
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
case UDP_ENCAP_ESPINUDP:
|
||||
x->props.header_len += sizeof(struct udphdr);
|
||||
|
|
|
@ -38,7 +38,8 @@ static struct sk_buff **esp4_gro_receive(struct sk_buff **head,
|
|||
__be32 spi;
|
||||
int err;
|
||||
|
||||
skb_pull(skb, offset);
|
||||
if (!pskb_pull(skb, offset))
|
||||
return NULL;
|
||||
|
||||
if ((err = xfrm_parse_spi(skb, IPPROTO_ESP, &spi, &seq)) != 0)
|
||||
goto out;
|
||||
|
|
|
@ -890,13 +890,12 @@ static int esp6_init_state(struct xfrm_state *x)
|
|||
x->props.header_len += IPV4_BEET_PHMAXLEN +
|
||||
(sizeof(struct ipv6hdr) - sizeof(struct iphdr));
|
||||
break;
|
||||
default:
|
||||
case XFRM_MODE_TRANSPORT:
|
||||
break;
|
||||
case XFRM_MODE_TUNNEL:
|
||||
x->props.header_len += sizeof(struct ipv6hdr);
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
align = ALIGN(crypto_aead_blocksize(aead), 4);
|
||||
|
|
|
@ -60,7 +60,8 @@ static struct sk_buff **esp6_gro_receive(struct sk_buff **head,
|
|||
int nhoff;
|
||||
int err;
|
||||
|
||||
skb_pull(skb, offset);
|
||||
if (!pskb_pull(skb, offset))
|
||||
return NULL;
|
||||
|
||||
if ((err = xfrm_parse_spi(skb, IPPROTO_ESP, &spi, &seq)) != 0)
|
||||
goto out;
|
||||
|
|
|
@ -401,6 +401,11 @@ static int verify_address_len(const void *p)
|
|||
#endif
|
||||
int len;
|
||||
|
||||
if (sp->sadb_address_len <
|
||||
DIV_ROUND_UP(sizeof(*sp) + offsetofend(typeof(*addr), sa_family),
|
||||
sizeof(uint64_t)))
|
||||
return -EINVAL;
|
||||
|
||||
switch (addr->sa_family) {
|
||||
case AF_INET:
|
||||
len = DIV_ROUND_UP(sizeof(*sp) + sizeof(*sin), sizeof(uint64_t));
|
||||
|
@ -511,6 +516,9 @@ static int parse_exthdrs(struct sk_buff *skb, const struct sadb_msg *hdr, void *
|
|||
uint16_t ext_type;
|
||||
int ext_len;
|
||||
|
||||
if (len < sizeof(*ehdr))
|
||||
return -EINVAL;
|
||||
|
||||
ext_len = ehdr->sadb_ext_len;
|
||||
ext_len *= sizeof(uint64_t);
|
||||
ext_type = ehdr->sadb_ext_type;
|
||||
|
@ -2194,8 +2202,10 @@ static int key_notify_policy(struct xfrm_policy *xp, int dir, const struct km_ev
|
|||
return PTR_ERR(out_skb);
|
||||
|
||||
err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
kfree_skb(out_skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
out_hdr = (struct sadb_msg *) out_skb->data;
|
||||
out_hdr->sadb_msg_version = PF_KEY_V2;
|
||||
|
|
|
@ -518,7 +518,7 @@ int xfrm_trans_queue(struct sk_buff *skb,
|
|||
return -ENOBUFS;
|
||||
|
||||
XFRM_TRANS_SKB_CB(skb)->finish = finish;
|
||||
skb_queue_tail(&trans->queue, skb);
|
||||
__skb_queue_tail(&trans->queue, skb);
|
||||
tasklet_schedule(&trans->tasklet);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -609,7 +609,8 @@ static void xfrm_hash_rebuild(struct work_struct *work)
|
|||
|
||||
/* re-insert all policies by order of creation */
|
||||
list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) {
|
||||
if (xfrm_policy_id2dir(policy->index) >= XFRM_POLICY_MAX) {
|
||||
if (policy->walk.dead ||
|
||||
xfrm_policy_id2dir(policy->index) >= XFRM_POLICY_MAX) {
|
||||
/* skip socket policies */
|
||||
continue;
|
||||
}
|
||||
|
@ -974,8 +975,6 @@ int xfrm_policy_flush(struct net *net, u8 type, bool task_valid)
|
|||
}
|
||||
if (!cnt)
|
||||
err = -ESRCH;
|
||||
else
|
||||
xfrm_policy_cache_flush();
|
||||
out:
|
||||
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
|
||||
return err;
|
||||
|
@ -1743,6 +1742,8 @@ void xfrm_policy_cache_flush(void)
|
|||
bool found = 0;
|
||||
int cpu;
|
||||
|
||||
might_sleep();
|
||||
|
||||
local_bh_disable();
|
||||
rcu_read_lock();
|
||||
for_each_possible_cpu(cpu) {
|
||||
|
@ -2062,8 +2063,11 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
|
|||
if (num_xfrms <= 0)
|
||||
goto make_dummy_bundle;
|
||||
|
||||
local_bh_disable();
|
||||
xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family,
|
||||
xflo->dst_orig);
|
||||
xflo->dst_orig);
|
||||
local_bh_enable();
|
||||
|
||||
if (IS_ERR(xdst)) {
|
||||
err = PTR_ERR(xdst);
|
||||
if (err != -EAGAIN)
|
||||
|
@ -2150,9 +2154,12 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
|
|||
goto no_transform;
|
||||
}
|
||||
|
||||
local_bh_disable();
|
||||
xdst = xfrm_resolve_and_create_bundle(
|
||||
pols, num_pols, fl,
|
||||
family, dst_orig);
|
||||
local_bh_enable();
|
||||
|
||||
if (IS_ERR(xdst)) {
|
||||
xfrm_pols_put(pols, num_pols);
|
||||
err = PTR_ERR(xdst);
|
||||
|
|
|
@ -313,13 +313,14 @@ xfrm_get_type_offload(u8 proto, unsigned short family, bool try_load)
|
|||
if ((type && !try_module_get(type->owner)))
|
||||
type = NULL;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!type && try_load) {
|
||||
request_module("xfrm-offload-%d-%d", family, proto);
|
||||
try_load = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -1534,8 +1535,12 @@ int xfrm_state_update(struct xfrm_state *x)
|
|||
err = -EINVAL;
|
||||
spin_lock_bh(&x1->lock);
|
||||
if (likely(x1->km.state == XFRM_STATE_VALID)) {
|
||||
if (x->encap && x1->encap)
|
||||
if (x->encap && x1->encap &&
|
||||
x->encap->encap_type == x1->encap->encap_type)
|
||||
memcpy(x1->encap, x->encap, sizeof(*x1->encap));
|
||||
else if (x->encap || x1->encap)
|
||||
goto fail;
|
||||
|
||||
if (x->coaddr && x1->coaddr) {
|
||||
memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
|
||||
}
|
||||
|
@ -1552,6 +1557,8 @@ int xfrm_state_update(struct xfrm_state *x)
|
|||
x->km.state = XFRM_STATE_DEAD;
|
||||
__xfrm_state_put(x);
|
||||
}
|
||||
|
||||
fail:
|
||||
spin_unlock_bh(&x1->lock);
|
||||
|
||||
xfrm_state_put(x1);
|
||||
|
|
Loading…
Reference in a new issue