Skip to content

Commit

Permalink
netfilter: nf_tables: ensure proper initialization of nft_pktinfo fields
Browse files Browse the repository at this point in the history
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: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
Pablo Neira Ayuso committed Sep 12, 2016
1 parent dbd2be0 commit beac5af
Show file tree
Hide file tree
Showing 7 changed files with 29 additions and 5 deletions.
18 changes: 18 additions & 0 deletions include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
*
Expand Down
1 change: 1 addition & 0 deletions include/net/netfilter/nf_tables_ipv4.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions include/net/netfilter/nf_tables_ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions net/bridge/netfilter/nf_tables_bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/netfilter/nf_tables_arp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
4 changes: 3 additions & 1 deletion net/netfilter/nf_tables_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ nft_netdev_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
else if (len < thoff)
return;

pkt->tprot_set = true;
pkt->tprot = iph->protocol;
pkt->xt.thoff = thoff;
pkt->xt.fragoff = ntohs(iph->frag_off) & IP_OFFSET;
Expand Down Expand Up @@ -74,6 +75,7 @@ __nft_netdev_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
if (protohdr < 0)
return;

pkt->tprot_set = true;
pkt->tprot = protohdr;
pkt->xt.thoff = thoff;
pkt->xt.fragoff = frag_off;
Expand Down Expand Up @@ -102,7 +104,7 @@ nft_do_chain_netdev(void *priv, struct sk_buff *skb,
nft_netdev_set_pktinfo_ipv6(&pkt, skb, state);
break;
default:
nft_set_pktinfo(&pkt, skb, state);
nft_set_pktinfo_unspec(&pkt, skb, state);
break;
}

Expand Down
2 changes: 2 additions & 0 deletions net/netfilter/nft_meta.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ void nft_meta_get_eval(const struct nft_expr *expr,
*dest = pkt->pf;
break;
case NFT_META_L4PROTO:
if (!pkt->tprot_set)
goto err;
*dest = pkt->tprot;
break;
case NFT_META_PRIORITY:
Expand Down

0 comments on commit beac5af

Please sign in to comment.