Commit e15e5027 authored by Florian Westphal's avatar Florian Westphal
Browse files

netfilter: xt_mangle: only check verdict part of return value



These checks assume that the caller only returns NF_DROP without
any errno embedded in the upper bits.

This is fine right now, but followup patches will start to propagate
such errors to allow kfree_skb_drop_reason() in the called functions,
those would then indicate 'errno << 8 | NF_STOLEN'.

To not break things we have to mask those parts out.

Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
parent a0a86022
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -36,12 +36,12 @@ static const struct xt_table packet_mangler = {
static unsigned int
ipt_mangle_out(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
	unsigned int ret;
	unsigned int ret, verdict;
	const struct iphdr *iph;
	u_int8_t tos;
	__be32 saddr, daddr;
	u_int32_t mark;
	u32 mark;
	int err;
	u8 tos;

	/* Save things which could affect route */
	mark = skb->mark;
@@ -51,8 +51,9 @@ ipt_mangle_out(void *priv, struct sk_buff *skb, const struct nf_hook_state *stat
	tos = iph->tos;

	ret = ipt_do_table(priv, skb, state);
	verdict = ret & NF_VERDICT_MASK;
	/* Reroute for ANY change. */
	if (ret != NF_DROP && ret != NF_STOLEN) {
	if (verdict != NF_DROP && verdict != NF_STOLEN) {
		iph = ip_hdr(skb);

		if (iph->saddr != saddr ||
+5 −4
Original line number Diff line number Diff line
@@ -31,10 +31,10 @@ static const struct xt_table packet_mangler = {
static unsigned int
ip6t_mangle_out(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
	unsigned int ret;
	struct in6_addr saddr, daddr;
	u_int8_t hop_limit;
	u_int32_t flowlabel, mark;
	unsigned int ret, verdict;
	u32 flowlabel, mark;
	u8 hop_limit;
	int err;

	/* save source/dest address, mark, hoplimit, flowlabel, priority,  */
@@ -47,8 +47,9 @@ ip6t_mangle_out(void *priv, struct sk_buff *skb, const struct nf_hook_state *sta
	flowlabel = *((u_int32_t *)ipv6_hdr(skb));

	ret = ip6t_do_table(priv, skb, state);
	verdict = ret & NF_VERDICT_MASK;

	if (ret != NF_DROP && ret != NF_STOLEN &&
	if (verdict != NF_DROP && verdict != NF_STOLEN &&
	    (!ipv6_addr_equal(&ipv6_hdr(skb)->saddr, &saddr) ||
	     !ipv6_addr_equal(&ipv6_hdr(skb)->daddr, &daddr) ||
	     skb->mark != mark ||