Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79f9ab7e authored by David S. Miller's avatar David S. Miller
Browse files


Steffen Klassert says:

====================
This pull request fixes some issues that arise when 6in4 or 4in6 tunnels
are used in combination with IPsec, all from Hannes Frederic Sowa and a
null pointer dereference when queueing packets to the policy hold queue.

1) We might access the local error handler of the wrong address family if
   6in4 or 4in6 tunnel is protected by ipsec. Fix this by addind a pointer
   to the correct local_error to xfrm_state_afinet.

2) Add a helper function to always refer to the correct interpretation
   of skb->sk.

3) Call skb_reset_inner_headers to record the position of the inner headers
   when adding a new one in various ipv6 tunnels. This is needed to identify
   the addresses where to send back errors in the xfrm layer.

4) Dereference inner ipv6 header if encapsulated to always call the
   right error handler.

5) Choose protocol family by skb protocol to not call the wrong
   xfrm{4,6}_local_error handler in case an ipv6 sockets is used
   in ipv4 mode.

6) Partly revert "xfrm: introduce helper for safe determination of mtu"
   because this introduced pmtu discovery problems.

7) Set skb->protocol on tcp, raw and ip6_append_data genereated skbs.
   We need this to get the correct mtu informations in xfrm.

8) Fix null pointer dereference in xdst_queue_output.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1f324e38 302a50bc
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -317,4 +317,12 @@ static inline int ip4_dst_hoplimit(const struct dst_entry *dst)
	return hoplimit;
}

static inline int ip_skb_dst_mtu(struct sk_buff *skb)
{
	struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL;

	return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ?
	       skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
}

#endif	/* _ROUTE_H */
+6 −0
Original line number Diff line number Diff line
@@ -341,10 +341,13 @@ struct xfrm_state_afinfo {
						  struct sk_buff *skb);
	int			(*transport_finish)(struct sk_buff *skb,
						    int async);
	void			(*local_error)(struct sk_buff *skb, u32 mtu);
};

extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo);
extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo);
extern struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
extern void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);

extern void xfrm_state_delete_tunnel(struct xfrm_state *x);

@@ -1477,6 +1480,7 @@ extern int xfrm_input_resume(struct sk_buff *skb, int nexthdr);
extern int xfrm_output_resume(struct sk_buff *skb, int err);
extern int xfrm_output(struct sk_buff *skb);
extern int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb);
extern void xfrm_local_error(struct sk_buff *skb, int mtu);
extern int xfrm4_extract_header(struct sk_buff *skb);
extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb);
extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
@@ -1497,6 +1501,7 @@ extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short fam
extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family);
extern int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel *handler);
extern int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel *handler);
extern void xfrm4_local_error(struct sk_buff *skb, u32 mtu);
extern int xfrm6_extract_header(struct sk_buff *skb);
extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb);
extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi);
@@ -1514,6 +1519,7 @@ extern int xfrm6_output(struct sk_buff *skb);
extern int xfrm6_output_finish(struct sk_buff *skb);
extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
				 u8 **prevhdr);
extern void xfrm6_local_error(struct sk_buff *skb, u32 mtu);

#ifdef CONFIG_XFRM
extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
+0 −8
Original line number Diff line number Diff line
@@ -211,14 +211,6 @@ static inline int ip_finish_output2(struct sk_buff *skb)
	return -EINVAL;
}

static inline int ip_skb_dst_mtu(struct sk_buff *skb)
{
	struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL;

	return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ?
	       skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
}

static int ip_finish_output(struct sk_buff *skb)
{
#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
+11 −5
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@
static int xfrm4_tunnel_check_size(struct sk_buff *skb)
{
	int mtu, ret = 0;
	struct dst_entry *dst;

	if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)
		goto out;
@@ -29,12 +28,10 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb)
	if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df)
		goto out;

	dst = skb_dst(skb);
	mtu = dst_mtu(dst);
	mtu = dst_mtu(skb_dst(skb));
	if (skb->len > mtu) {
		if (skb->sk)
			ip_local_error(skb->sk, EMSGSIZE, ip_hdr(skb)->daddr,
				       inet_sk(skb->sk)->inet_dport, mtu);
			xfrm_local_error(skb, mtu);
		else
			icmp_send(skb, ICMP_DEST_UNREACH,
				  ICMP_FRAG_NEEDED, htonl(mtu));
@@ -99,3 +96,12 @@ int xfrm4_output(struct sk_buff *skb)
			    x->outer_mode->afinfo->output_finish,
			    !(IPCB(skb)->flags & IPSKB_REROUTED));
}

void xfrm4_local_error(struct sk_buff *skb, u32 mtu)
{
	struct iphdr *hdr;

	hdr = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
	ip_local_error(skb->sk, EMSGSIZE, hdr->daddr,
		       inet_sk(skb->sk)->inet_dport, mtu);
}
+1 −0
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = {
	.extract_input		= xfrm4_extract_input,
	.extract_output		= xfrm4_extract_output,
	.transport_finish	= xfrm4_transport_finish,
	.local_error		= xfrm4_local_error,
};

void __init xfrm4_state_init(void)
Loading