pull request (net): ipsec 2018-01-11
Subsystems (3)
Steffen Klassert
maintainer1) 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.
Please pull or let me know if there are problems.
Thanks!
The following changes since commit 2758b3e3e630ba304fc4aca434d591e70e528298:
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net (2017-12-28 23:20:21 -0800)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec.git master
for you to fetch changes up to 76a4201191814a0061cb5c861fafb9ecaa764846:
xfrm: Fix a race in the xdst pcpu cache. (2018-01-10 12:14:28 +0100)
----------------------------------------------------------------
Eric Biggers (2):
af_key: fix buffer overread in verify_address_len()
af_key: fix buffer overread in parse_exthdrs()
Florian Westphal (2):
xfrm: skip policies marked as dead while rehashing
xfrm: don't call xfrm_policy_cache_flush while holding spinlock
Herbert Xu (3):
xfrm: Forbid state updates from changing encap type
xfrm: Use __skb_queue_tail in xfrm_trans_queue
xfrm: Return error on unknown encap_type in init_state
Sabrina Dubroca (1):
xfrm: fix rcu usage in xfrm_get_type_offload
Steffen Klassert (3):
esp: Fix GRO when the headers not fully in the linear part of the skb.
af_key: Fix memory leak in key_notify_policy.
xfrm: Fix a race in the xdst pcpu cache.
net/ipv4/esp4.c | 1 + net/ipv4/esp4_offload.c | 3 ++- net/ipv6/esp6.c | 3 +-- net/ipv6/esp6_offload.c | 3 ++- net/key/af_key.c | 12 +++++++++++- net/xfrm/xfrm_input.c | 2 +- net/xfrm/xfrm_policy.c | 15 +++++++++++---- net/xfrm/xfrm_state.c | 11 +++++++++-- 8 files changed, 38 insertions(+), 12 deletions(-)
Steffen Klassert
maintainerPATCH 1/11 xfrm: Forbid state updates from changing encap type
From: Herbert Xu <[email protected]>
Currently we allow state updates to competely replace the contents of x->encap. This is bad because on the user side ESP only sets up header lengths depending on encap_type once when the state is first created. This could result in the header lengths getting out of sync with the actual state configuration.
In practice key managers will never do a state update to change the encapsulation type. Only the port numbers need to be changed as the peer NAT entry is updated.
Therefore this patch adds a check in xfrm_state_update to forbid any changes to the encap_type.
--- net/xfrm/xfrm_state.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
net/xfrm/xfrm_state.c +7 -1
@@ -1534,8 +1534,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 +1556,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);
Signature · 1 line
2.14.1
Steffen Klassert
maintainerPATCH 2/11 xfrm: skip policies marked as dead while rehashing
In reply to Steffen KlassertFrom: Florian Westphal <[email protected]>
syzkaller triggered following KASAN splat:
BUG: KASAN: slab-out-of-bounds in xfrm_hash_rebuild+0xdbe/0xf00 net/xfrm/xfrm_policy.c:618 read of size 2 at addr ffff8801c8e92fe4 by task kworker/1:1/23 [..] Workqueue: events xfrm_hash_rebuild [..] __asan_report_load2_noabort+0x14/0x20 mm/kasan/report.c:428 xfrm_hash_rebuild+0xdbe/0xf00 net/xfrm/xfrm_policy.c:618 process_one_work+0xbbf/0x1b10 kernel/workqueue.c:2112 worker_thread+0x223/0x1990 kernel/workqueue.c:2246 [..]
The reproducer triggers:
1016 if (error) {
1017 list_move_tail(&walk->walk.all, &x->all);
1018 goto out;
1019 }
in xfrm_policy_walk() via pfkey (it sets tiny rcv space, dump callback returns -ENOBUFS).
In this case, *walk is located the pfkey socket struct, so this socket becomes visible in the global policy list.
It looks like this is intentional -- phony walker has walk.dead set to 1 and all other places skip such "policies".
Ccing original authors of the two commits that seem to expose this issue (first patch missed ->dead check, second patch adds pfkey sockets to policies dumper list).
--- net/xfrm/xfrm_policy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/xfrm/xfrm_policy.c +2 -1
@@ -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 ; }
Signature · 1 line
2.14.1
Steffen Klassert
maintainerPATCH 3/11 af_key: fix buffer overread in verify_address_len()
In reply to Steffen KlassertFrom: Eric Biggers <[email protected]>
If a message sent to a PF_KEY socket ended with one of the extensions that takes a 'struct sadb_address' but there were not enough bytes remaining in the message for the ->sa_family member of the 'struct sockaddr' which is supposed to follow, then verify_address_len() read past the end of the message, into uninitialized memory. Fix it by returning -EINVAL in this case.
This bug was found using syzkaller with KMSAN.
Reproducer:
#include <linux/pfkeyv2.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
int sock = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
char buf[24] = { 0 };
struct sadb_msg *msg = (void *)buf;
struct sadb_address *addr = (void *)(msg + 1);
msg->sadb_msg_version = PF_KEY_V2;
msg->sadb_msg_type = SADB_DELETE;
msg->sadb_msg_len = 3;
addr->sadb_address_len = 1;
addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
write(sock, buf, 24);
}--- net/key/af_key.c | 5 +++++ 1 file changed, 5 insertions(+)
net/key/af_key.c +5 -0
@@ -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 ));
Signature · 1 line
2.14.1
Steffen Klassert
maintainerPATCH 4/11 af_key: fix buffer overread in parse_exthdrs()
In reply to Steffen KlassertFrom: Eric Biggers <[email protected]>
If a message sent to a PF_KEY socket ended with an incomplete extension header (fewer than 4 bytes remaining), then parse_exthdrs() read past the end of the message, into uninitialized memory. Fix it by returning -EINVAL in this case.
Reproducer:
#include <linux/pfkeyv2.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
int sock = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
char buf[17] = { 0 };
struct sadb_msg *msg = (void *)buf;
msg->sadb_msg_version = PF_KEY_V2;
msg->sadb_msg_type = SADB_DELETE;
msg->sadb_msg_len = 2;
write(sock, buf, 17);
}--- net/key/af_key.c | 3 +++ 1 file changed, 3 insertions(+)
net/key/af_key.c +3 -0
@@ -516,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;
Signature · 1 line
2.14.1
Steffen Klassert
maintainerPATCH 5/11 xfrm: fix rcu usage in xfrm_get_type_offload
In reply to Steffen KlassertFrom: Sabrina Dubroca <[email protected]>
request_module can sleep, thus we cannot hold rcu_read_lock() while calling it. The function also jumps back and takes rcu_read_lock() again (in xfrm_state_get_afinfo()), resulting in an imbalance.
This codepath is triggered whenever a new offloaded state is created.
--- net/xfrm/xfrm_state.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/xfrm/xfrm_state.c +2 -1
@@ -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; }
Signature · 1 line
2.14.1
Steffen Klassert
maintainerPATCH 6/11 xfrm: Use __skb_queue_tail in xfrm_trans_queue
In reply to Steffen KlassertFrom: Herbert Xu <[email protected]>
We do not need locking in xfrm_trans_queue because it is designed to use per-CPU buffers. However, the original code incorrectly used skb_queue_tail which takes the lock. This patch switches it to __skb_queue_tail instead.
--- net/xfrm/xfrm_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/xfrm/xfrm_input.c +1 -1
@@ -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 ; }
Signature · 1 line
2.14.1
Steffen Klassert
maintainerPATCH 7/11 xfrm: Return error on unknown encap_type in init_state
In reply to Steffen KlassertFrom: Herbert Xu <[email protected]>
Currently esp will happily create an xfrm state with an unknown encap type for IPv4, without setting the necessary state parameters. This patch fixes it by returning -EINVAL.
There is a similar problem in IPv6 where if the mode is unknown we will skip initialisation while returning zero. However, this is harmless as the mode has already been checked further up the stack. This patch removes this anomaly by aligning the IPv6 behaviour with IPv4 and treating unknown modes (which cannot actually happen) as transport mode.
--- net/ipv4/esp4.c | 1 + net/ipv6/esp6.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-)
net/ipv4/esp4.c +1 -0
@@ -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 );
net/ipv6/esp6.c +1 -2
@@ -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 );
Signature · 1 line
2.14.1
Steffen Klassert
maintainerPATCH 8/11 xfrm: don't call xfrm_policy_cache_flush while holding spinlock
In reply to Steffen KlassertFrom: Florian Westphal <[email protected]>
xfrm_policy_cache_flush can sleep, so it cannot be called while holding a spinlock. We could release the lock first, but I don't see why we need to invoke this function here in first place, the packet path won't reuse an xdst entry unless its still valid.
While at it, add an annotation to xfrm_policy_cache_flush, it would have probably caught this bug sooner.
--- net/xfrm/xfrm_policy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/xfrm/xfrm_policy.c +2 -2
@@ -975,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;
@@ -1744,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) {
Signature · 1 line
2.14.1
Steffen Klassert
maintainerPATCH 9/11 esp: Fix GRO when the headers not fully in the linear part of the skb.
In reply to Steffen KlassertThe GRO layer does not necessarily pull the complete headers into the linear part of the skb, a part may remain on the first page fragment. This can lead to a crash if we try to pull the headers, so make sure we have them on the linear part before pulling.
--- net/ipv4/esp4_offload.c | 3 ++- net/ipv6/esp6_offload.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-)
net/ipv4/esp4_offload.c +2 -1
@@ -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;
net/ipv6/esp6_offload.c +2 -1
@@ -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;
Signature · 1 line
2.14.1
Steffen Klassert
maintainerPATCH 10/11 af_key: Fix memory leak in key_notify_policy.
In reply to Steffen KlassertWe leak the allocated out_skb in case pfkey_xfrm_policy2msg() fails. Fix this by freeing it on error.
--- net/key/af_key.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/key/af_key.c +3 -1
@@ -2202,8 +2202,10 @@ static int key_notify_policy(struct xfrm_policy *xp, int dir, const struct km_evreturn 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 ;
Signature · 1 line
2.14.1
Steffen Klassert
maintainerPATCH 11/11 xfrm: Fix a race in the xdst pcpu cache.
In reply to Steffen KlassertWe need to run xfrm_resolve_and_create_bundle() with bottom halves off. Otherwise we may reuse an already released dst_enty when the xfrm lookup functions are called from process context.
--- net/xfrm/xfrm_policy.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
net/xfrm/xfrm_policy.c +7 -1
@@ -2063,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 )
@@ -2151,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);
Signature · 1 line
2.14.1
David Miller
maintainerFrom: Steffen Klassert <[email protected]>
Date: Thu, 11 Jan 2018 12:37:35 +0100
Quoted 30 lines
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 inxfrm_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_modulecan sleep, so can't be used
underrcu_read_lock. From Sabrina Dubroca.5) Fix an uninitialized lock in
xfrm_trans_queue.
Use__skb_queue_tailinstead ofskb_queue_tail
inxfrm_trans_queueas 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.
Quoted 7 lines
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.Please pull or let me know if there are problems.
Pulled, thanks Steffen.