Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says: ==================== pull request (net): ipsec 2022-03-09 1) Fix IPv6 PMTU discovery for xfrm interfaces. From Lina Wang. 2) Revert failing for policies and states that are configured with XFRMA_IF_ID 0. It broke a user configuration. From Kai Lueke. 3) Fix a possible buffer overflow in the ESP output path. 4) Fix ESP GSO for tunnel and BEET mode on inter address family tunnels. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
cc7e2f596e
|
@ -4602,6 +4602,8 @@ int skb_csum_hwoffload_help(struct sk_buff *skb,
|
|||
|
||||
struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
|
||||
netdev_features_t features, bool tx_path);
|
||||
struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb,
|
||||
netdev_features_t features, __be16 type);
|
||||
struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
|
||||
netdev_features_t features);
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#define ESP_SKB_FRAG_MAXSIZE (PAGE_SIZE << SKB_FRAG_PAGE_ORDER)
|
||||
|
||||
struct ip_esp_hdr;
|
||||
|
||||
static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb)
|
||||
|
|
|
@ -92,6 +92,31 @@ void dev_remove_offload(struct packet_offload *po)
|
|||
}
|
||||
EXPORT_SYMBOL(dev_remove_offload);
|
||||
|
||||
/**
|
||||
* skb_eth_gso_segment - segmentation handler for ethernet protocols.
|
||||
* @skb: buffer to segment
|
||||
* @features: features for the output path (see dev->features)
|
||||
* @type: Ethernet Protocol ID
|
||||
*/
|
||||
struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb,
|
||||
netdev_features_t features, __be16 type)
|
||||
{
|
||||
struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
|
||||
struct packet_offload *ptype;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(ptype, &offload_base, list) {
|
||||
if (ptype->type == type && ptype->callbacks.gso_segment) {
|
||||
segs = ptype->callbacks.gso_segment(skb, features);
|
||||
break;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return segs;
|
||||
}
|
||||
EXPORT_SYMBOL(skb_eth_gso_segment);
|
||||
|
||||
/**
|
||||
* skb_mac_gso_segment - mac layer segmentation handler.
|
||||
* @skb: buffer to segment
|
||||
|
|
|
@ -446,6 +446,7 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
|
|||
struct page *page;
|
||||
struct sk_buff *trailer;
|
||||
int tailen = esp->tailen;
|
||||
unsigned int allocsz;
|
||||
|
||||
/* this is non-NULL only with TCP/UDP Encapsulation */
|
||||
if (x->encap) {
|
||||
|
@ -455,6 +456,10 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
|
|||
return err;
|
||||
}
|
||||
|
||||
allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES);
|
||||
if (allocsz > ESP_SKB_FRAG_MAXSIZE)
|
||||
goto cow;
|
||||
|
||||
if (!skb_cloned(skb)) {
|
||||
if (tailen <= skb_tailroom(skb)) {
|
||||
nfrags = 1;
|
||||
|
|
|
@ -110,8 +110,7 @@ static struct sk_buff *xfrm4_tunnel_gso_segment(struct xfrm_state *x,
|
|||
struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
__skb_push(skb, skb->mac_len);
|
||||
return skb_mac_gso_segment(skb, features);
|
||||
return skb_eth_gso_segment(skb, features, htons(ETH_P_IP));
|
||||
}
|
||||
|
||||
static struct sk_buff *xfrm4_transport_gso_segment(struct xfrm_state *x,
|
||||
|
@ -160,6 +159,9 @@ static struct sk_buff *xfrm4_beet_gso_segment(struct xfrm_state *x,
|
|||
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;
|
||||
}
|
||||
|
||||
if (proto == IPPROTO_IPV6)
|
||||
skb_shinfo(skb)->gso_type |= SKB_GSO_IPXIP4;
|
||||
|
||||
__skb_pull(skb, skb_transport_offset(skb));
|
||||
ops = rcu_dereference(inet_offloads[proto]);
|
||||
if (likely(ops && ops->callbacks.gso_segment))
|
||||
|
|
|
@ -482,6 +482,7 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
|
|||
struct page *page;
|
||||
struct sk_buff *trailer;
|
||||
int tailen = esp->tailen;
|
||||
unsigned int allocsz;
|
||||
|
||||
if (x->encap) {
|
||||
int err = esp6_output_encap(x, skb, esp);
|
||||
|
@ -490,6 +491,10 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
|
|||
return err;
|
||||
}
|
||||
|
||||
allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES);
|
||||
if (allocsz > ESP_SKB_FRAG_MAXSIZE)
|
||||
goto cow;
|
||||
|
||||
if (!skb_cloned(skb)) {
|
||||
if (tailen <= skb_tailroom(skb)) {
|
||||
nfrags = 1;
|
||||
|
|
|
@ -145,8 +145,7 @@ static struct sk_buff *xfrm6_tunnel_gso_segment(struct xfrm_state *x,
|
|||
struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
__skb_push(skb, skb->mac_len);
|
||||
return skb_mac_gso_segment(skb, features);
|
||||
return skb_eth_gso_segment(skb, features, htons(ETH_P_IPV6));
|
||||
}
|
||||
|
||||
static struct sk_buff *xfrm6_transport_gso_segment(struct xfrm_state *x,
|
||||
|
@ -199,6 +198,9 @@ static struct sk_buff *xfrm6_beet_gso_segment(struct xfrm_state *x,
|
|||
ipv6_skip_exthdr(skb, 0, &proto, &frag);
|
||||
}
|
||||
|
||||
if (proto == IPPROTO_IPIP)
|
||||
skb_shinfo(skb)->gso_type |= SKB_GSO_IPXIP6;
|
||||
|
||||
__skb_pull(skb, skb_transport_offset(skb));
|
||||
ops = rcu_dereference(inet6_offloads[proto]);
|
||||
if (likely(ops && ops->callbacks.gso_segment))
|
||||
|
|
|
@ -45,6 +45,19 @@ static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buf
|
|||
return xfrm_output(sk, skb);
|
||||
}
|
||||
|
||||
static int xfrm6_noneed_fragment(struct sk_buff *skb)
|
||||
{
|
||||
struct frag_hdr *fh;
|
||||
u8 prevhdr = ipv6_hdr(skb)->nexthdr;
|
||||
|
||||
if (prevhdr != NEXTHDR_FRAGMENT)
|
||||
return 0;
|
||||
fh = (struct frag_hdr *)(skb->data + sizeof(struct ipv6hdr));
|
||||
if (fh->nexthdr == NEXTHDR_ESP || fh->nexthdr == NEXTHDR_AUTH)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
|
@ -73,6 +86,9 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
|||
xfrm6_local_rxpmtu(skb, mtu);
|
||||
kfree_skb(skb);
|
||||
return -EMSGSIZE;
|
||||
} else if (toobig && xfrm6_noneed_fragment(skb)) {
|
||||
skb->ignore_df = 1;
|
||||
goto skip_frag;
|
||||
} else if (!skb->ignore_df && toobig && skb->sk) {
|
||||
xfrm_local_error(skb, mtu);
|
||||
kfree_skb(skb);
|
||||
|
|
|
@ -304,7 +304,10 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
|
|||
if (mtu < IPV6_MIN_MTU)
|
||||
mtu = IPV6_MIN_MTU;
|
||||
|
||||
icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
|
||||
if (skb->len > 1280)
|
||||
icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
|
||||
else
|
||||
goto xmit;
|
||||
} else {
|
||||
if (!(ip_hdr(skb)->frag_off & htons(IP_DF)))
|
||||
goto xmit;
|
||||
|
|
|
@ -630,13 +630,8 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
|
|||
|
||||
xfrm_smark_init(attrs, &x->props.smark);
|
||||
|
||||
if (attrs[XFRMA_IF_ID]) {
|
||||
if (attrs[XFRMA_IF_ID])
|
||||
x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
||||
if (!x->if_id) {
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]);
|
||||
if (err)
|
||||
|
@ -1432,13 +1427,8 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
|
||||
mark = xfrm_mark_get(attrs, &m);
|
||||
|
||||
if (attrs[XFRMA_IF_ID]) {
|
||||
if (attrs[XFRMA_IF_ID])
|
||||
if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
||||
if (!if_id) {
|
||||
err = -EINVAL;
|
||||
goto out_noput;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->info.seq) {
|
||||
x = xfrm_find_acq_byseq(net, mark, p->info.seq);
|
||||
|
@ -1751,13 +1741,8 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_us
|
|||
|
||||
xfrm_mark_get(attrs, &xp->mark);
|
||||
|
||||
if (attrs[XFRMA_IF_ID]) {
|
||||
if (attrs[XFRMA_IF_ID])
|
||||
xp->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
||||
if (!xp->if_id) {
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return xp;
|
||||
error:
|
||||
|
|
Loading…
Reference in New Issue