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

Commit beac5afa authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files

netfilter: nf_tables: ensure proper initialization of nft_pktinfo fields



This patch introduces nft_set_pktinfo_unspec() that ensures proper
initialization all of pktinfo fields for non-IP traffic. This is used
by the bridge, netdev and arp families.

This new function relies on nft_set_pktinfo_proto_unspec() to set a new
tprot_set field that indicates if transport protocol information is
available. Remain fields are zeroed.

The meta expression has been also updated to check to tprot_set in first
place given that zero is a valid tprot value. Even a handcrafted packet
may come with the IPPROTO_RAW (255) protocol number so we can't rely on
this value as tprot unset.

Reported-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent dbd2be06
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ struct nft_pktinfo {
	const struct net_device		*out;
	u8				pf;
	u8				hook;
	bool				tprot_set;
	u8				tprot;
	/* for x_tables compatibility */
	struct xt_action_param		xt;
@@ -36,6 +37,23 @@ static inline void nft_set_pktinfo(struct nft_pktinfo *pkt,
	pkt->pf = pkt->xt.family = state->pf;
}

static inline void nft_set_pktinfo_proto_unspec(struct nft_pktinfo *pkt,
						struct sk_buff *skb)
{
	pkt->tprot_set = false;
	pkt->tprot = 0;
	pkt->xt.thoff = 0;
	pkt->xt.fragoff = 0;
}

static inline void nft_set_pktinfo_unspec(struct nft_pktinfo *pkt,
					  struct sk_buff *skb,
					  const struct nf_hook_state *state)
{
	nft_set_pktinfo(pkt, skb, state);
	nft_set_pktinfo_proto_unspec(pkt, skb);
}

/**
 * 	struct nft_verdict - nf_tables verdict
 *
+1 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
	nft_set_pktinfo(pkt, skb, state);

	ip = ip_hdr(pkt->skb);
	pkt->tprot_set = true;
	pkt->tprot = ip->protocol;
	pkt->xt.thoff = ip_hdrlen(pkt->skb);
	pkt->xt.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
+1 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
	if (protohdr < 0)
		return -1;

	pkt->tprot_set = true;
	pkt->tprot = protohdr;
	pkt->xt.thoff = thoff;
	pkt->xt.fragoff = frag_off;
+3 −3
Original line number Diff line number Diff line
@@ -71,7 +71,7 @@ static inline void nft_bridge_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
	if (nft_bridge_iphdr_validate(skb))
		nft_set_pktinfo_ipv4(pkt, skb, state);
	else
		nft_set_pktinfo(pkt, skb, state);
		nft_set_pktinfo_unspec(pkt, skb, state);
}

static inline void nft_bridge_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
@@ -83,7 +83,7 @@ static inline void nft_bridge_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
	    nft_set_pktinfo_ipv6(pkt, skb, state) == 0)
		return;
#endif
	nft_set_pktinfo(pkt, skb, state);
	nft_set_pktinfo_unspec(pkt, skb, state);
}

static unsigned int
@@ -101,7 +101,7 @@ nft_do_chain_bridge(void *priv,
		nft_bridge_set_pktinfo_ipv6(&pkt, skb, state);
		break;
	default:
		nft_set_pktinfo(&pkt, skb, state);
		nft_set_pktinfo_unspec(&pkt, skb, state);
		break;
	}

+1 −1
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ nft_do_chain_arp(void *priv,
{
	struct nft_pktinfo pkt;

	nft_set_pktinfo(&pkt, skb, state);
	nft_set_pktinfo_unspec(&pkt, skb, state);

	return nft_do_chain(&pkt, priv);
}
Loading