Commit 64816aa7 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'ipv6-more-drop-reason'

Eric Dumazet says:

====================
ipv6: more drop reason

Add more drop reasons to IPv6:

 - IPV6_BAD_EXTHDR
 - IPV6_NDISC_FRAG
 - IPV6_NDISC_HOP_LIMIT
 - IPV6_NDISC_BAD_CODE
====================

Link: https://lore.kernel.org/r/20230210184708.2172562-1-edumazet@google.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 1a940b00 545dbcd1
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -2631,13 +2631,24 @@ void *skb_pull_data(struct sk_buff *skb, size_t len);

void *__pskb_pull_tail(struct sk_buff *skb, int delta);

static inline bool pskb_may_pull(struct sk_buff *skb, unsigned int len)
static inline enum skb_drop_reason
pskb_may_pull_reason(struct sk_buff *skb, unsigned int len)
{
	if (likely(len <= skb_headlen(skb)))
		return true;
		return SKB_NOT_DROPPED_YET;

	if (unlikely(len > skb->len))
		return false;
	return __pskb_pull_tail(skb, len - skb_headlen(skb)) != NULL;
		return SKB_DROP_REASON_PKT_TOO_SMALL;

	if (unlikely(!__pskb_pull_tail(skb, len - skb_headlen(skb))))
		return SKB_DROP_REASON_NOMEM;

	return SKB_NOT_DROPPED_YET;
}

static inline bool pskb_may_pull(struct sk_buff *skb, unsigned int len)
{
	return pskb_may_pull_reason(skb, len) == SKB_NOT_DROPPED_YET;
}

static inline void *pskb_pull(struct sk_buff *skb, unsigned int len)
+12 −0
Original line number Diff line number Diff line
@@ -72,6 +72,10 @@
	FN(FRAG_REASM_TIMEOUT)		\
	FN(FRAG_TOO_FAR)		\
	FN(TCP_MINTTL)			\
	FN(IPV6_BAD_EXTHDR)		\
	FN(IPV6_NDISC_FRAG)		\
	FN(IPV6_NDISC_HOP_LIMIT)	\
	FN(IPV6_NDISC_BAD_CODE)		\
	FNe(MAX)

/**
@@ -318,6 +322,14 @@ enum skb_drop_reason {
	 * the threshold (IP_MINTTL or IPV6_MINHOPCOUNT).
	 */
	SKB_DROP_REASON_TCP_MINTTL,
	/** @SKB_DROP_REASON_IPV6_BAD_EXTHDR: Bad IPv6 extension header. */
	SKB_DROP_REASON_IPV6_BAD_EXTHDR,
	/** @SKB_DROP_REASON_IPV6_NDISC_FRAG: invalid frag (suppress_frag_ndisc). */
	SKB_DROP_REASON_IPV6_NDISC_FRAG,
	/** @SKB_DROP_REASON_IPV6_NDISC_HOP_LIMIT: invalid hop limit. */
	SKB_DROP_REASON_IPV6_NDISC_HOP_LIMIT,
	/** @SKB_DROP_REASON_IPV6_NDISC_BAD_CODE: invalid NDISC icmp6 code. */
	SKB_DROP_REASON_IPV6_NDISC_BAD_CODE,
	/**
	 * @SKB_DROP_REASON_MAX: the maximum of drop reason, which shouldn't be
	 * used as a real 'reason'
+2 −1
Original line number Diff line number Diff line
@@ -436,7 +436,8 @@ static inline void fl6_sock_release(struct ip6_flowlabel *fl)
		atomic_dec(&fl->users);
}

void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info);
enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type,
				   u8 code, __be32 info);

void icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
				struct icmp6hdr *thdr, int len);
+1 −1
Original line number Diff line number Diff line
@@ -445,7 +445,7 @@ int ndisc_late_init(void);
void ndisc_late_cleanup(void);
void ndisc_cleanup(void);

int ndisc_rcv(struct sk_buff *skb);
enum skb_drop_reason ndisc_rcv(struct sk_buff *skb);

struct sk_buff *ndisc_ns_create(struct net_device *dev, const struct in6_addr *solicit,
				const struct in6_addr *saddr, u64 nonce);
+18 −9
Original line number Diff line number Diff line
@@ -813,16 +813,19 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
	local_bh_enable();
}

void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type,
				   u8 code, __be32 info)
{
	struct inet6_skb_parm *opt = IP6CB(skb);
	struct net *net = dev_net(skb->dev);
	const struct inet6_protocol *ipprot;
	enum skb_drop_reason reason;
	int inner_offset;
	__be16 frag_off;
	u8 nexthdr;
	struct net *net = dev_net(skb->dev);

	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
	reason = pskb_may_pull_reason(skb, sizeof(struct ipv6hdr));
	if (reason != SKB_NOT_DROPPED_YET)
		goto out;

	seg6_icmp_srh(skb, opt);
@@ -832,14 +835,17 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
		/* now skip over extension headers */
		inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
						&nexthdr, &frag_off);
		if (inner_offset < 0)
		if (inner_offset < 0) {
			SKB_DR_SET(reason, IPV6_BAD_EXTHDR);
			goto out;
		}
	} else {
		inner_offset = sizeof(struct ipv6hdr);
	}

	/* Checkin header including 8 bytes of inner protocol header. */
	if (!pskb_may_pull(skb, inner_offset+8))
	reason = pskb_may_pull_reason(skb, inner_offset + 8);
	if (reason != SKB_NOT_DROPPED_YET)
		goto out;

	/* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
@@ -854,10 +860,11 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
		ipprot->err_handler(skb, opt, type, code, inner_offset, info);

	raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info);
	return;
	return SKB_CONSUMED;

out:
	__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
	return reason;
}

/*
@@ -953,7 +960,8 @@ static int icmpv6_rcv(struct sk_buff *skb)
	case ICMPV6_DEST_UNREACH:
	case ICMPV6_TIME_EXCEED:
	case ICMPV6_PARAMPROB:
		icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
		reason = icmpv6_notify(skb, type, hdr->icmp6_code,
				       hdr->icmp6_mtu);
		break;

	case NDISC_ROUTER_SOLICITATION:
@@ -961,7 +969,7 @@ static int icmpv6_rcv(struct sk_buff *skb)
	case NDISC_NEIGHBOUR_SOLICITATION:
	case NDISC_NEIGHBOUR_ADVERTISEMENT:
	case NDISC_REDIRECT:
		ndisc_rcv(skb);
		reason = ndisc_rcv(skb);
		break;

	case ICMPV6_MGM_QUERY:
@@ -995,7 +1003,8 @@ static int icmpv6_rcv(struct sk_buff *skb)
		 * must pass to upper level
		 */

		icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
		reason = icmpv6_notify(skb, type, hdr->icmp6_code,
				       hdr->icmp6_mtu);
	}

	/* until the v6 path can be better sorted assume failure and
Loading