mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-29 15:14:18 +08:00
netfilter: fix crashes in bridge netfilter caused by fragment jumps
When fragments from bridge netfilter are passed to IPv4 or IPv6 conntrack and a reassembly queue with the same fragment key already exists from reassembling a similar packet received on a different device (f.i. with multicasted fragments), the reassembled packet might continue on a different codepath than where the head fragment originated. This can cause crashes in bridge netfilter when a fragment received on a non-bridge device (and thus with skb->nf_bridge == NULL) continues through the bridge netfilter code. Add a new reassembly identifier for packets originating from bridge netfilter and use it to put those packets in insolated queues. Fixes http://bugzilla.kernel.org/show_bug.cgi?id=14805 Reported-and-Tested-by: Chong Qiao <qiaochong@loongson.cn> Signed-off-by: Patrick McHardy <kaber@trash.net>
This commit is contained in:
parent
0b5ccb2ee2
commit
8fa9ff6849
@ -337,6 +337,7 @@ enum ip_defrag_users {
|
||||
IP_DEFRAG_CALL_RA_CHAIN,
|
||||
IP_DEFRAG_CONNTRACK_IN,
|
||||
IP_DEFRAG_CONNTRACK_OUT,
|
||||
IP_DEFRAG_CONNTRACK_BRIDGE_IN,
|
||||
IP_DEFRAG_VS_IN,
|
||||
IP_DEFRAG_VS_OUT,
|
||||
IP_DEFRAG_VS_FWD
|
||||
|
@ -354,6 +354,7 @@ enum ip6_defrag_users {
|
||||
IP6_DEFRAG_LOCAL_DELIVER,
|
||||
IP6_DEFRAG_CONNTRACK_IN,
|
||||
IP6_DEFRAG_CONNTRACK_OUT,
|
||||
IP6_DEFRAG_CONNTRACK_BRIDGE_IN,
|
||||
};
|
||||
|
||||
struct ip6_create_arg {
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <net/route.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
|
||||
|
||||
@ -34,6 +35,20 @@ static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
|
||||
return err;
|
||||
}
|
||||
|
||||
static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
if (skb->nf_bridge &&
|
||||
skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
|
||||
return IP_DEFRAG_CONNTRACK_BRIDGE_IN;
|
||||
#endif
|
||||
if (hooknum == NF_INET_PRE_ROUTING)
|
||||
return IP_DEFRAG_CONNTRACK_IN;
|
||||
else
|
||||
return IP_DEFRAG_CONNTRACK_OUT;
|
||||
}
|
||||
|
||||
static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
@ -50,10 +65,8 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
|
||||
#endif
|
||||
/* Gather fragments. */
|
||||
if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
|
||||
if (nf_ct_ipv4_gather_frags(skb,
|
||||
hooknum == NF_INET_PRE_ROUTING ?
|
||||
IP_DEFRAG_CONNTRACK_IN :
|
||||
IP_DEFRAG_CONNTRACK_OUT))
|
||||
enum ip_defrag_users user = nf_ct_defrag_user(hooknum, skb);
|
||||
if (nf_ct_ipv4_gather_frags(skb, user))
|
||||
return NF_STOLEN;
|
||||
}
|
||||
return NF_ACCEPT;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <net/ipv6.h>
|
||||
#include <net/inet_frag.h>
|
||||
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <net/netfilter/nf_conntrack_helper.h>
|
||||
@ -190,6 +191,11 @@ out:
|
||||
static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
if (skb->nf_bridge &&
|
||||
skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
|
||||
return IP6_DEFRAG_CONNTRACK_BRIDGE_IN;
|
||||
#endif
|
||||
if (hooknum == NF_INET_PRE_ROUTING)
|
||||
return IP6_DEFRAG_CONNTRACK_IN;
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user