mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
inet: frags: prevent acceptance of partially authenticated reassembly
A reassembled skb retains the secpath from its first fragment, which
makes it possible for the final policy check to accept bytes that were
not covered by the transform recorded on the skb. This can affect IPsec
tunnel traffic, including AH and ESP, and allow a packet to be accepted
even though only part of its payload was authenticated.
Reject a fragment when its secpath differs from the fragments already
in the queue, and keep overlap statistics limited to actual overlaps.
Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
This commit is contained in:
parent
22dd6bb2ba
commit
6fb4e32f2c
|
|
@ -171,6 +171,7 @@ extern const u8 ip_frag_ecn_table[16];
|
|||
#define IPFRAG_OK 0
|
||||
#define IPFRAG_DUP 1
|
||||
#define IPFRAG_OVERLAP 2
|
||||
#define IPFRAG_MIXED_SECPATH 3
|
||||
int inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb,
|
||||
int offset, int end);
|
||||
void *inet_frag_reasm_prepare(struct inet_frag_queue *q, struct sk_buff *skb,
|
||||
|
|
|
|||
|
|
@ -1201,6 +1201,23 @@ secpath_reset(struct sk_buff *skb)
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline bool
|
||||
secpath_equal(const struct sk_buff *skb1, const struct sk_buff *skb2)
|
||||
{
|
||||
const struct sec_path *sp1 = skb_sec_path(skb1);
|
||||
const struct sec_path *sp2 = skb_sec_path(skb2);
|
||||
int i;
|
||||
|
||||
if (!sp1 || !sp2)
|
||||
return sp1 == sp2;
|
||||
if (sp1->len != sp2->len)
|
||||
return false;
|
||||
for (i = 0; i < sp1->len; i++)
|
||||
if (sp1->xvec[i] != sp2->xvec[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xfrm_addr_any(const xfrm_address_t *addr, unsigned short family)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <net/inet_ecn.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/xfrm.h>
|
||||
|
||||
/* Use skb->cb to track consecutive/adjacent fragments coming at
|
||||
* the end of the queue. Nodes in the rb-tree queue will
|
||||
|
|
@ -441,6 +442,10 @@ int inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb,
|
|||
{
|
||||
struct sk_buff *last = q->fragments_tail;
|
||||
|
||||
/* The reassembled skb keeps the first fragment's secpath. */
|
||||
if (last && !secpath_equal(last, skb))
|
||||
return IPFRAG_MIXED_SECPATH;
|
||||
|
||||
/* An IP fragment is never a GSO packet, but an untrusted source
|
||||
* (virtio_net_hdr) may have attached GSO metadata to it. Do not let
|
||||
* that reach the reassembled skb, whose head keeps the first
|
||||
|
|
|
|||
|
|
@ -378,8 +378,9 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb, int *refs)
|
|||
err = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
if (err == IPFRAG_OVERLAP)
|
||||
__IP_INC_STATS(net, IPSTATS_MIB_REASM_OVERLAPS);
|
||||
err = -EINVAL;
|
||||
__IP_INC_STATS(net, IPSTATS_MIB_REASM_OVERLAPS);
|
||||
discard_qp:
|
||||
inet_frag_kill(&qp->q, refs);
|
||||
__IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS);
|
||||
|
|
|
|||
|
|
@ -241,8 +241,9 @@ static int ip6_frag_queue(struct net *net,
|
|||
err = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
if (err == IPFRAG_OVERLAP)
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_REASM_OVERLAPS);
|
||||
err = -EINVAL;
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_REASM_OVERLAPS);
|
||||
discard_fq:
|
||||
inet_frag_kill(&fq->q, refs);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_REASMFAILS);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user