mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 06:12:08 +00:00
[IPSEC]: Fix BEET output
The IPv6 BEET output function is incorrectly including the inner header in the payload to be protected. This causes a crash as the packet doesn't actually have that many bytes for a second header. The IPv4 BEET output on the other hand is broken when it comes to handling an inner IPv6 header since it always assumes an inner IPv4 header. This patch fixes both by making sure that neither BEET output function touches the inner header at all. All access is now done through the protocol-independent cb structure. Two new attributes are added to make this work, the IP header length and the IPv4 option length. They're filled in by the inner mode's output function. Thanks to Joakim Koskela for finding this problem. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0e5606e4f4
commit
732c8bd590
@ -552,6 +552,9 @@ struct xfrm_mode_skb_cb {
|
||||
__be16 id;
|
||||
__be16 frag_off;
|
||||
|
||||
/* IP header length (excluding options or extension headers). */
|
||||
u8 ihl;
|
||||
|
||||
/* TOS for IPv4, class for IPv6. */
|
||||
u8 tos;
|
||||
|
||||
@ -561,6 +564,9 @@ struct xfrm_mode_skb_cb {
|
||||
/* Protocol for IPv4, NH for IPv6. */
|
||||
u8 protocol;
|
||||
|
||||
/* Option length for IPv4, zero for IPv6. */
|
||||
u8 optlen;
|
||||
|
||||
/* Used by IPv6 only, zero for IPv4. */
|
||||
u8 flow_lbl[3];
|
||||
};
|
||||
|
@ -39,13 +39,11 @@ static void xfrm4_beet_make_header(struct sk_buff *skb)
|
||||
static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
|
||||
{
|
||||
struct ip_beet_phdr *ph;
|
||||
struct iphdr *iph, *top_iph;
|
||||
struct iphdr *top_iph;
|
||||
int hdrlen, optlen;
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
|
||||
hdrlen = 0;
|
||||
optlen = iph->ihl * 4 - sizeof(*iph);
|
||||
optlen = XFRM_MODE_SKB_CB(skb)->optlen;
|
||||
if (unlikely(optlen))
|
||||
hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
|
||||
|
||||
@ -53,11 +51,12 @@ static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
|
||||
hdrlen);
|
||||
skb->mac_header = skb->network_header +
|
||||
offsetof(struct iphdr, protocol);
|
||||
skb->transport_header = skb->network_header + sizeof(*iph);
|
||||
skb->transport_header = skb->network_header + sizeof(*top_iph);
|
||||
|
||||
xfrm4_beet_make_header(skb);
|
||||
|
||||
ph = (struct ip_beet_phdr *)__skb_pull(skb, sizeof(*iph) - hdrlen);
|
||||
ph = (struct ip_beet_phdr *)
|
||||
__skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdrlen);
|
||||
|
||||
top_iph = ip_hdr(skb);
|
||||
|
||||
|
@ -52,10 +52,12 @@ int xfrm4_extract_header(struct sk_buff *skb)
|
||||
{
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
|
||||
XFRM_MODE_SKB_CB(skb)->ihl = sizeof(*iph);
|
||||
XFRM_MODE_SKB_CB(skb)->id = iph->id;
|
||||
XFRM_MODE_SKB_CB(skb)->frag_off = iph->frag_off;
|
||||
XFRM_MODE_SKB_CB(skb)->tos = iph->tos;
|
||||
XFRM_MODE_SKB_CB(skb)->ttl = iph->ttl;
|
||||
XFRM_MODE_SKB_CB(skb)->optlen = iph->ihl * 4 - sizeof(*iph);
|
||||
memset(XFRM_MODE_SKB_CB(skb)->flow_lbl, 0,
|
||||
sizeof(XFRM_MODE_SKB_CB(skb)->flow_lbl));
|
||||
|
||||
|
@ -45,6 +45,7 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
|
||||
skb->mac_header = skb->network_header +
|
||||
offsetof(struct ipv6hdr, nexthdr);
|
||||
skb->transport_header = skb->network_header + sizeof(*top_iph);
|
||||
__skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl);
|
||||
|
||||
xfrm6_beet_make_header(skb);
|
||||
|
||||
|
@ -174,10 +174,12 @@ int xfrm6_extract_header(struct sk_buff *skb)
|
||||
{
|
||||
struct ipv6hdr *iph = ipv6_hdr(skb);
|
||||
|
||||
XFRM_MODE_SKB_CB(skb)->ihl = sizeof(*iph);
|
||||
XFRM_MODE_SKB_CB(skb)->id = 0;
|
||||
XFRM_MODE_SKB_CB(skb)->frag_off = htons(IP_DF);
|
||||
XFRM_MODE_SKB_CB(skb)->tos = ipv6_get_dsfield(iph);
|
||||
XFRM_MODE_SKB_CB(skb)->ttl = iph->hop_limit;
|
||||
XFRM_MODE_SKB_CB(skb)->optlen = 0;
|
||||
memcpy(XFRM_MODE_SKB_CB(skb)->flow_lbl, iph->flow_lbl,
|
||||
sizeof(XFRM_MODE_SKB_CB(skb)->flow_lbl));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user