kernel: fix dst reference leak in flow offload

Fixes a significant amount of leaked memory with lots of connections

Signed-off-by: Felix Fietkau <nbd@nbd.name>
master
Felix Fietkau 4 years ago
parent 07ce940b77
commit c6c4701def

@ -98,7 +98,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
--- /dev/null --- /dev/null
+++ b/net/netfilter/xt_FLOWOFFLOAD.c +++ b/net/netfilter/xt_FLOWOFFLOAD.c
@@ -0,0 +1,421 @@ @@ -0,0 +1,422 @@
+/* +/*
+ * Copyright (C) 2018 Felix Fietkau <nbd@nbd.name> + * Copyright (C) 2018 Felix Fietkau <nbd@nbd.name>
+ * + *
@ -330,15 +330,16 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ +
+ this_dst = xt_flowoffload_dst(ct, !dir, par, xt_out(par)->ifindex); + this_dst = xt_flowoffload_dst(ct, !dir, par, xt_out(par)->ifindex);
+ other_dst = xt_flowoffload_dst(ct, dir, par, xt_in(par)->ifindex); + other_dst = xt_flowoffload_dst(ct, dir, par, xt_in(par)->ifindex);
+
+ route->tuple[dir].dst = this_dst;
+ route->tuple[!dir].dst = other_dst;
+
+ if (!this_dst || !other_dst) + if (!this_dst || !other_dst)
+ return -ENOENT; + return -ENOENT;
+ +
+ if (dst_xfrm(this_dst) || dst_xfrm(other_dst)) + if (dst_xfrm(this_dst) || dst_xfrm(other_dst))
+ return -EINVAL; + return -EINVAL;
+ +
+ route->tuple[dir].dst = this_dst;
+ route->tuple[!dir].dst = other_dst;
+
+ return 0; + return 0;
+} +}
+ +
@ -350,7 +351,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ enum ip_conntrack_info ctinfo; + enum ip_conntrack_info ctinfo;
+ enum ip_conntrack_dir dir; + enum ip_conntrack_dir dir;
+ struct nf_flow_route route; + struct nf_flow_route route;
+ struct flow_offload *flow; + struct flow_offload *flow = NULL;
+ struct nf_conn *ct; + struct nf_conn *ct;
+ struct net *net; + struct net *net;
+ +
@ -392,12 +393,14 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ +
+ dir = CTINFO2DIR(ctinfo); + dir = CTINFO2DIR(ctinfo);
+ +
+ if (xt_flowoffload_route(skb, ct, par, &route, dir) < 0) + if (xt_flowoffload_route(skb, ct, par, &route, dir) == 0)
+ goto err_flow_route; + flow = flow_offload_alloc(ct, &route);
+
+ dst_release(route.tuple[dir].dst);
+ dst_release(route.tuple[!dir].dst);
+ +
+ flow = flow_offload_alloc(ct, &route);
+ if (!flow) + if (!flow)
+ goto err_flow_alloc; + goto err_flow_route;
+ +
+ if (tcph) { + if (tcph) {
+ ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL; + ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
@ -421,8 +424,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ +
+err_flow_add: +err_flow_add:
+ flow_offload_free(flow); + flow_offload_free(flow);
+err_flow_alloc:
+ dst_release(route.tuple[!dir].dst);
+err_flow_route: +err_flow_route:
+ clear_bit(IPS_OFFLOAD_BIT, &ct->status); + clear_bit(IPS_OFFLOAD_BIT, &ct->status);
+ return XT_CONTINUE; + return XT_CONTINUE;

@ -98,7 +98,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
--- /dev/null --- /dev/null
+++ b/net/netfilter/xt_FLOWOFFLOAD.c +++ b/net/netfilter/xt_FLOWOFFLOAD.c
@@ -0,0 +1,421 @@ @@ -0,0 +1,422 @@
+/* +/*
+ * Copyright (C) 2018 Felix Fietkau <nbd@nbd.name> + * Copyright (C) 2018 Felix Fietkau <nbd@nbd.name>
+ * + *
@ -330,15 +330,16 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ +
+ this_dst = xt_flowoffload_dst(ct, !dir, par, xt_out(par)->ifindex); + this_dst = xt_flowoffload_dst(ct, !dir, par, xt_out(par)->ifindex);
+ other_dst = xt_flowoffload_dst(ct, dir, par, xt_in(par)->ifindex); + other_dst = xt_flowoffload_dst(ct, dir, par, xt_in(par)->ifindex);
+
+ route->tuple[dir].dst = this_dst;
+ route->tuple[!dir].dst = other_dst;
+
+ if (!this_dst || !other_dst) + if (!this_dst || !other_dst)
+ return -ENOENT; + return -ENOENT;
+ +
+ if (dst_xfrm(this_dst) || dst_xfrm(other_dst)) + if (dst_xfrm(this_dst) || dst_xfrm(other_dst))
+ return -EINVAL; + return -EINVAL;
+ +
+ route->tuple[dir].dst = this_dst;
+ route->tuple[!dir].dst = other_dst;
+
+ return 0; + return 0;
+} +}
+ +
@ -350,7 +351,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ enum ip_conntrack_info ctinfo; + enum ip_conntrack_info ctinfo;
+ enum ip_conntrack_dir dir; + enum ip_conntrack_dir dir;
+ struct nf_flow_route route; + struct nf_flow_route route;
+ struct flow_offload *flow; + struct flow_offload *flow = NULL;
+ struct nf_conn *ct; + struct nf_conn *ct;
+ struct net *net; + struct net *net;
+ +
@ -392,12 +393,14 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ +
+ dir = CTINFO2DIR(ctinfo); + dir = CTINFO2DIR(ctinfo);
+ +
+ if (xt_flowoffload_route(skb, ct, par, &route, dir) < 0) + if (xt_flowoffload_route(skb, ct, par, &route, dir) == 0)
+ goto err_flow_route; + flow = flow_offload_alloc(ct, &route);
+
+ dst_release(route.tuple[dir].dst);
+ dst_release(route.tuple[!dir].dst);
+ +
+ flow = flow_offload_alloc(ct, &route);
+ if (!flow) + if (!flow)
+ goto err_flow_alloc; + goto err_flow_route;
+ +
+ if (tcph) { + if (tcph) {
+ ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL; + ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
@ -421,8 +424,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ +
+err_flow_add: +err_flow_add:
+ flow_offload_free(flow); + flow_offload_free(flow);
+err_flow_alloc:
+ dst_release(route.tuple[!dir].dst);
+err_flow_route: +err_flow_route:
+ clear_bit(IPS_OFFLOAD_BIT, &ct->status); + clear_bit(IPS_OFFLOAD_BIT, &ct->status);
+ return XT_CONTINUE; + return XT_CONTINUE;

Loading…
Cancel
Save