From: Greg Kroah-Hartman Date: Tue, 17 Nov 2020 09:40:00 +0000 (+0100) Subject: 4.14-stable patches X-Git-Tag: v4.4.244~30 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=28063a22724419862724d9ba2d7b602c01c2d556;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches added patches: ipv6-set-sit-tunnel-hard_header_len-to-zero.patch net-af_iucv-fix-null-pointer-dereference-on-shutdown.patch net-update-window_clamp-if-sock_rcvbuf-is-set.patch net-x25-fix-null-ptr-deref-in-x25_connect.patch r8169-fix-potential-skb-double-free-in-an-error-path.patch vrf-fix-fast-path-output-packet-handling-with-async-netfilter-rules.patch --- diff --git a/queue-4.14/btrfs-fix-potential-overflow-in-cluster_pages_for_defrag-on-32bit-arch.patch b/queue-4.14/btrfs-fix-potential-overflow-in-cluster_pages_for_defrag-on-32bit-arch.patch deleted file mode 100644 index c1b5c377282..00000000000 --- a/queue-4.14/btrfs-fix-potential-overflow-in-cluster_pages_for_defrag-on-32bit-arch.patch +++ /dev/null @@ -1,66 +0,0 @@ -From a1fbc6750e212c5675a4e48d7f51d44607eb8756 Mon Sep 17 00:00:00 2001 -From: "Matthew Wilcox (Oracle)" -Date: Sun, 4 Oct 2020 19:04:26 +0100 -Subject: btrfs: fix potential overflow in cluster_pages_for_defrag on 32bit arch - -From: Matthew Wilcox (Oracle) - -commit a1fbc6750e212c5675a4e48d7f51d44607eb8756 upstream. - -On 32-bit systems, this shift will overflow for files larger than 4GB as -start_index is unsigned long while the calls to btrfs_delalloc_*_space -expect u64. - -CC: stable@vger.kernel.org # 4.4+ -Fixes: df480633b891 ("btrfs: extent-tree: Switch to new delalloc space reserve and release") -Reviewed-by: Josef Bacik -Signed-off-by: Matthew Wilcox (Oracle) -Reviewed-by: David Sterba -[ define the variable instead of repeating the shift ] -Signed-off-by: David Sterba -Signed-off-by: Greg Kroah-Hartman - - - -diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c -index 63394b450afc..4e3b71ec7492 100644 ---- a/fs/btrfs/ioctl.c -+++ b/fs/btrfs/ioctl.c -@@ -1255,6 +1255,7 @@ static int cluster_pages_for_defrag(struct inode *inode, - u64 page_start; - u64 page_end; - u64 page_cnt; -+ u64 start = (u64)start_index << PAGE_SHIFT; - int ret; - int i; - int i_done; -@@ -1271,8 +1272,7 @@ static int cluster_pages_for_defrag(struct inode *inode, - page_cnt = min_t(u64, (u64)num_pages, (u64)file_end - start_index + 1); - - ret = btrfs_delalloc_reserve_space(inode, &data_reserved, -- start_index << PAGE_SHIFT, -- page_cnt << PAGE_SHIFT); -+ start, page_cnt << PAGE_SHIFT); - if (ret) - return ret; - i_done = 0; -@@ -1361,8 +1361,7 @@ static int cluster_pages_for_defrag(struct inode *inode, - btrfs_mod_outstanding_extents(BTRFS_I(inode), 1); - spin_unlock(&BTRFS_I(inode)->lock); - btrfs_delalloc_release_space(inode, data_reserved, -- start_index << PAGE_SHIFT, -- (page_cnt - i_done) << PAGE_SHIFT, true); -+ start, (page_cnt - i_done) << PAGE_SHIFT, true); - } - - -@@ -1389,8 +1388,7 @@ static int cluster_pages_for_defrag(struct inode *inode, - put_page(pages[i]); - } - btrfs_delalloc_release_space(inode, data_reserved, -- start_index << PAGE_SHIFT, -- page_cnt << PAGE_SHIFT, true); -+ start, page_cnt << PAGE_SHIFT, true); - btrfs_delalloc_release_extents(BTRFS_I(inode), page_cnt << PAGE_SHIFT); - extent_changeset_free(data_reserved); - return ret; diff --git a/queue-4.14/ipv6-set-sit-tunnel-hard_header_len-to-zero.patch b/queue-4.14/ipv6-set-sit-tunnel-hard_header_len-to-zero.patch new file mode 100644 index 00000000000..b3e73a76c87 --- /dev/null +++ b/queue-4.14/ipv6-set-sit-tunnel-hard_header_len-to-zero.patch @@ -0,0 +1,52 @@ +From foo@baz Tue Nov 17 10:36:22 AM CET 2020 +From: Oliver Herms +Date: Tue, 3 Nov 2020 11:41:33 +0100 +Subject: IPv6: Set SIT tunnel hard_header_len to zero + +From: Oliver Herms + +[ Upstream commit 8ef9ba4d666614497a057d09b0a6eafc1e34eadf ] + +Due to the legacy usage of hard_header_len for SIT tunnels while +already using infrastructure from net/ipv4/ip_tunnel.c the +calculation of the path MTU in tnl_update_pmtu is incorrect. +This leads to unnecessary creation of MTU exceptions for any +flow going over a SIT tunnel. + +As SIT tunnels do not have a header themsevles other than their +transport (L3, L2) headers we're leaving hard_header_len set to zero +as tnl_update_pmtu is already taking care of the transport headers +sizes. + +This will also help avoiding unnecessary IPv6 GC runs and spinlock +contention seen when using SIT tunnels and for more than +net.ipv6.route.gc_thresh flows. + +Fixes: c54419321455 ("GRE: Refactor GRE tunneling code.") +Signed-off-by: Oliver Herms +Acked-by: Willem de Bruijn +Link: https://lore.kernel.org/r/20201103104133.GA1573211@tws +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/sit.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -1073,7 +1073,6 @@ static void ipip6_tunnel_bind_dev(struct + if (tdev && !netif_is_l3_master(tdev)) { + int t_hlen = tunnel->hlen + sizeof(struct iphdr); + +- dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); + dev->mtu = tdev->mtu - t_hlen; + if (dev->mtu < IPV6_MIN_MTU) + dev->mtu = IPV6_MIN_MTU; +@@ -1363,7 +1362,6 @@ static void ipip6_tunnel_setup(struct ne + dev->priv_destructor = ipip6_dev_free; + + dev->type = ARPHRD_SIT; +- dev->hard_header_len = LL_MAX_HEADER + t_hlen; + dev->mtu = ETH_DATA_LEN - t_hlen; + dev->min_mtu = IPV6_MIN_MTU; + dev->max_mtu = IP6_MAX_MTU - t_hlen; diff --git a/queue-4.14/net-af_iucv-fix-null-pointer-dereference-on-shutdown.patch b/queue-4.14/net-af_iucv-fix-null-pointer-dereference-on-shutdown.patch new file mode 100644 index 00000000000..c27943e2b73 --- /dev/null +++ b/queue-4.14/net-af_iucv-fix-null-pointer-dereference-on-shutdown.patch @@ -0,0 +1,61 @@ +From foo@baz Tue Nov 17 10:36:22 AM CET 2020 +From: Ursula Braun +Date: Mon, 9 Nov 2020 08:57:05 +0100 +Subject: net/af_iucv: fix null pointer dereference on shutdown + +From: Ursula Braun + +[ Upstream commit 4031eeafa71eaf22ae40a15606a134ae86345daf ] + +syzbot reported the following KASAN finding: + +BUG: KASAN: nullptr-dereference in iucv_send_ctrl+0x390/0x3f0 net/iucv/af_iucv.c:385 +Read of size 2 at addr 000000000000021e by task syz-executor907/519 + +CPU: 0 PID: 519 Comm: syz-executor907 Not tainted 5.9.0-syzkaller-07043-gbcf9877ad213 #0 +Hardware name: IBM 3906 M04 701 (KVM/Linux) +Call Trace: + [<00000000c576af60>] unwind_start arch/s390/include/asm/unwind.h:65 [inline] + [<00000000c576af60>] show_stack+0x180/0x228 arch/s390/kernel/dumpstack.c:135 + [<00000000c9dcd1f8>] __dump_stack lib/dump_stack.c:77 [inline] + [<00000000c9dcd1f8>] dump_stack+0x268/0x2f0 lib/dump_stack.c:118 + [<00000000c5fed016>] print_address_description.constprop.0+0x5e/0x218 mm/kasan/report.c:383 + [<00000000c5fec82a>] __kasan_report mm/kasan/report.c:517 [inline] + [<00000000c5fec82a>] kasan_report+0x11a/0x168 mm/kasan/report.c:534 + [<00000000c98b5b60>] iucv_send_ctrl+0x390/0x3f0 net/iucv/af_iucv.c:385 + [<00000000c98b6262>] iucv_sock_shutdown+0x44a/0x4c0 net/iucv/af_iucv.c:1457 + [<00000000c89d3a54>] __sys_shutdown+0x12c/0x1c8 net/socket.c:2204 + [<00000000c89d3b70>] __do_sys_shutdown net/socket.c:2212 [inline] + [<00000000c89d3b70>] __s390x_sys_shutdown+0x38/0x48 net/socket.c:2210 + [<00000000c9e36eac>] system_call+0xe0/0x28c arch/s390/kernel/entry.S:415 + +There is nothing to shutdown if a connection has never been established. +Besides that iucv->hs_dev is not yet initialized if a socket is in +IUCV_OPEN state and iucv->path is not yet initialized if socket is in +IUCV_BOUND state. +So, just skip the shutdown calls for a socket in these states. + +Fixes: eac3731bd04c ("[S390]: Add AF_IUCV socket support") +Fixes: 82492a355fac ("af_iucv: add shutdown for HS transport") +Reviewed-by: Vasily Gorbik +Signed-off-by: Ursula Braun +[jwi: correct one Fixes tag] +Signed-off-by: Julian Wiedmann +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/iucv/af_iucv.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -1552,7 +1552,8 @@ static int iucv_sock_shutdown(struct soc + break; + } + +- if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) { ++ if ((how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) && ++ sk->sk_state == IUCV_CONNECTED) { + if (iucv->transport == AF_IUCV_TRANS_IUCV) { + txmsg.class = 0; + txmsg.tag = 0; diff --git a/queue-4.14/net-update-window_clamp-if-sock_rcvbuf-is-set.patch b/queue-4.14/net-update-window_clamp-if-sock_rcvbuf-is-set.patch new file mode 100644 index 00000000000..86b7ca8513b --- /dev/null +++ b/queue-4.14/net-update-window_clamp-if-sock_rcvbuf-is-set.patch @@ -0,0 +1,82 @@ +From foo@baz Tue Nov 17 10:36:22 AM CET 2020 +From: Mao Wenan +Date: Tue, 10 Nov 2020 08:16:31 +0800 +Subject: net: Update window_clamp if SOCK_RCVBUF is set + +From: Mao Wenan + +[ Upstream commit 909172a149749242990a6e64cb55d55460d4e417 ] + +When net.ipv4.tcp_syncookies=1 and syn flood is happened, +cookie_v4_check or cookie_v6_check tries to redo what +tcp_v4_send_synack or tcp_v6_send_synack did, +rsk_window_clamp will be changed if SOCK_RCVBUF is set, +which will make rcv_wscale is different, the client +still operates with initial window scale and can overshot +granted window, the client use the initial scale but local +server use new scale to advertise window value, and session +work abnormally. + +Fixes: e88c64f0a425 ("tcp: allow effective reduction of TCP's rcv-buffer via setsockopt") +Signed-off-by: Mao Wenan +Signed-off-by: Eric Dumazet +Link: https://lore.kernel.org/r/1604967391-123737-1-git-send-email-wenan.mao@linux.alibaba.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/syncookies.c | 9 +++++++-- + net/ipv6/syncookies.c | 10 ++++++++-- + 2 files changed, 15 insertions(+), 4 deletions(-) + +--- a/net/ipv4/syncookies.c ++++ b/net/ipv4/syncookies.c +@@ -296,7 +296,7 @@ struct sock *cookie_v4_check(struct sock + __u32 cookie = ntohl(th->ack_seq) - 1; + struct sock *ret = sk; + struct request_sock *req; +- int mss; ++ int full_space, mss; + struct rtable *rt; + __u8 rcv_wscale; + struct flowi4 fl4; +@@ -389,8 +389,13 @@ struct sock *cookie_v4_check(struct sock + + /* Try to redo what tcp_v4_send_synack did. */ + req->rsk_window_clamp = tp->window_clamp ? :dst_metric(&rt->dst, RTAX_WINDOW); ++ /* limit the window selection if the user enforce a smaller rx buffer */ ++ full_space = tcp_full_space(sk); ++ if (sk->sk_userlocks & SOCK_RCVBUF_LOCK && ++ (req->rsk_window_clamp > full_space || req->rsk_window_clamp == 0)) ++ req->rsk_window_clamp = full_space; + +- tcp_select_initial_window(tcp_full_space(sk), req->mss, ++ tcp_select_initial_window(full_space, req->mss, + &req->rsk_rcv_wnd, &req->rsk_window_clamp, + ireq->wscale_ok, &rcv_wscale, + dst_metric(&rt->dst, RTAX_INITRWND)); +--- a/net/ipv6/syncookies.c ++++ b/net/ipv6/syncookies.c +@@ -141,7 +141,7 @@ struct sock *cookie_v6_check(struct sock + __u32 cookie = ntohl(th->ack_seq) - 1; + struct sock *ret = sk; + struct request_sock *req; +- int mss; ++ int full_space, mss; + struct dst_entry *dst; + __u8 rcv_wscale; + u32 tsoff = 0; +@@ -244,7 +244,13 @@ struct sock *cookie_v6_check(struct sock + } + + req->rsk_window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); +- tcp_select_initial_window(tcp_full_space(sk), req->mss, ++ /* limit the window selection if the user enforce a smaller rx buffer */ ++ full_space = tcp_full_space(sk); ++ if (sk->sk_userlocks & SOCK_RCVBUF_LOCK && ++ (req->rsk_window_clamp > full_space || req->rsk_window_clamp == 0)) ++ req->rsk_window_clamp = full_space; ++ ++ tcp_select_initial_window(full_space, req->mss, + &req->rsk_rcv_wnd, &req->rsk_window_clamp, + ireq->wscale_ok, &rcv_wscale, + dst_metric(dst, RTAX_INITRWND)); diff --git a/queue-4.14/net-x25-fix-null-ptr-deref-in-x25_connect.patch b/queue-4.14/net-x25-fix-null-ptr-deref-in-x25_connect.patch new file mode 100644 index 00000000000..0c66236f665 --- /dev/null +++ b/queue-4.14/net-x25-fix-null-ptr-deref-in-x25_connect.patch @@ -0,0 +1,39 @@ +From foo@baz Tue Nov 17 10:36:22 AM CET 2020 +From: Martin Schiller +Date: Mon, 9 Nov 2020 07:54:49 +0100 +Subject: net/x25: Fix null-ptr-deref in x25_connect + +From: Martin Schiller + +[ Upstream commit 361182308766a265b6c521879b34302617a8c209 ] + +This fixes a regression for blocking connects introduced by commit +4becb7ee5b3d ("net/x25: Fix x25_neigh refcnt leak when x25 disconnect"). + +The x25->neighbour is already set to "NULL" by x25_disconnect() now, +while a blocking connect is waiting in +x25_wait_for_connection_establishment(). Therefore x25->neighbour must +not be accessed here again and x25->state is also already set to +X25_STATE_0 by x25_disconnect(). + +Fixes: 4becb7ee5b3d ("net/x25: Fix x25_neigh refcnt leak when x25 disconnect") +Signed-off-by: Martin Schiller +Reviewed-by: Xie He +Link: https://lore.kernel.org/r/20201109065449.9014-1-ms@dev.tdt.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/x25/af_x25.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/x25/af_x25.c ++++ b/net/x25/af_x25.c +@@ -823,7 +823,7 @@ static int x25_connect(struct socket *so + sock->state = SS_CONNECTED; + rc = 0; + out_put_neigh: +- if (rc) { ++ if (rc && x25->neighbour) { + read_lock_bh(&x25_list_lock); + x25_neigh_put(x25->neighbour); + x25->neighbour = NULL; diff --git a/queue-4.14/r8169-fix-potential-skb-double-free-in-an-error-path.patch b/queue-4.14/r8169-fix-potential-skb-double-free-in-an-error-path.patch new file mode 100644 index 00000000000..9eec7c441c4 --- /dev/null +++ b/queue-4.14/r8169-fix-potential-skb-double-free-in-an-error-path.patch @@ -0,0 +1,36 @@ +From foo@baz Tue Nov 17 10:23:12 AM CET 2020 +From: Heiner Kallweit +Date: Thu, 5 Nov 2020 15:28:42 +0100 +Subject: r8169: fix potential skb double free in an error path + +From: Heiner Kallweit + +[ Upstream commit cc6528bc9a0c901c83b8220a2e2617f3354d6dd9 ] + +The caller of rtl8169_tso_csum_v2() frees the skb if false is returned. +eth_skb_pad() internally frees the skb on error what would result in a +double free. Therefore use __skb_put_padto() directly and instruct it +to not free the skb on error. + +Fixes: b423e9ae49d7 ("r8169: fix offloaded tx checksum for small packets.") +Reported-by: Jakub Kicinski +Signed-off-by: Heiner Kallweit +Link: https://lore.kernel.org/r/f7e68191-acff-9ded-4263-c016428a8762@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/realtek/r8169.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/realtek/r8169.c ++++ b/drivers/net/ethernet/realtek/r8169.c +@@ -7143,7 +7143,8 @@ static bool rtl8169_tso_csum_v2(struct r + opts[1] |= transport_offset << TCPHO_SHIFT; + } else { + if (unlikely(rtl_test_hw_pad_bug(tp, skb))) +- return !eth_skb_pad(skb); ++ /* eth_skb_pad would free the skb on error */ ++ return !__skb_put_padto(skb, ETH_ZLEN, false); + } + + return true; diff --git a/queue-4.14/series b/queue-4.14/series index fdc799cd966..9a2235346bc 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -55,4 +55,9 @@ drm-gma500-fix-out-of-bounds-access-to-struct-drm_device.vblank.patch pinctrl-amd-use-higher-precision-for-512-rtcclk.patch pinctrl-amd-fix-incorrect-way-to-disable-debounce-filter.patch swiotlb-fix-x86-don-t-panic-if-can-not-alloc-buffer-for-swiotlb.patch -btrfs-fix-potential-overflow-in-cluster_pages_for_defrag-on-32bit-arch.patch +ipv6-set-sit-tunnel-hard_header_len-to-zero.patch +net-af_iucv-fix-null-pointer-dereference-on-shutdown.patch +net-x25-fix-null-ptr-deref-in-x25_connect.patch +vrf-fix-fast-path-output-packet-handling-with-async-netfilter-rules.patch +r8169-fix-potential-skb-double-free-in-an-error-path.patch +net-update-window_clamp-if-sock_rcvbuf-is-set.patch diff --git a/queue-4.14/vrf-fix-fast-path-output-packet-handling-with-async-netfilter-rules.patch b/queue-4.14/vrf-fix-fast-path-output-packet-handling-with-async-netfilter-rules.patch new file mode 100644 index 00000000000..e4f3eb87baa --- /dev/null +++ b/queue-4.14/vrf-fix-fast-path-output-packet-handling-with-async-netfilter-rules.patch @@ -0,0 +1,192 @@ +From foo@baz Tue Nov 17 10:23:12 AM CET 2020 +From: Martin Willi +Date: Fri, 6 Nov 2020 08:30:30 +0100 +Subject: vrf: Fix fast path output packet handling with async Netfilter rules + +From: Martin Willi + +[ Upstream commit 9e2b7fa2df4365e99934901da4fb4af52d81e820 ] + +VRF devices use an optimized direct path on output if a default qdisc +is involved, calling Netfilter hooks directly. This path, however, does +not consider Netfilter rules completing asynchronously, such as with +NFQUEUE. The Netfilter okfn() is called for asynchronously accepted +packets, but the VRF never passes that packet down the stack to send +it out over the slave device. Using the slower redirect path for this +seems not feasible, as we do not know beforehand if a Netfilter hook +has asynchronously completing rules. + +Fix the use of asynchronously completing Netfilter rules in OUTPUT and +POSTROUTING by using a special completion function that additionally +calls dst_output() to pass the packet down the stack. Also, slightly +adjust the use of nf_reset_ct() so that is called in the asynchronous +case, too. + +Fixes: dcdd43c41e60 ("net: vrf: performance improvements for IPv4") +Fixes: a9ec54d1b0cd ("net: vrf: performance improvements for IPv6") +Signed-off-by: Martin Willi +Link: https://lore.kernel.org/r/20201106073030.3974927-1-martin@strongswan.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/vrf.c | 92 ++++++++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 69 insertions(+), 23 deletions(-) + +--- a/drivers/net/vrf.c ++++ b/drivers/net/vrf.c +@@ -334,8 +334,7 @@ static netdev_tx_t vrf_xmit(struct sk_bu + return ret; + } + +-static int vrf_finish_direct(struct net *net, struct sock *sk, +- struct sk_buff *skb) ++static void vrf_finish_direct(struct sk_buff *skb) + { + struct net_device *vrf_dev = skb->dev; + +@@ -354,7 +353,8 @@ static int vrf_finish_direct(struct net + skb_pull(skb, ETH_HLEN); + } + +- return 1; ++ /* reset skb device */ ++ nf_reset(skb); + } + + #if IS_ENABLED(CONFIG_IPV6) +@@ -433,15 +433,41 @@ static struct sk_buff *vrf_ip6_out_redir + return skb; + } + ++static int vrf_output6_direct_finish(struct net *net, struct sock *sk, ++ struct sk_buff *skb) ++{ ++ vrf_finish_direct(skb); ++ ++ return vrf_ip6_local_out(net, sk, skb); ++} ++ + static int vrf_output6_direct(struct net *net, struct sock *sk, + struct sk_buff *skb) + { ++ int err = 1; ++ + skb->protocol = htons(ETH_P_IPV6); + +- return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, +- net, sk, skb, NULL, skb->dev, +- vrf_finish_direct, +- !(IPCB(skb)->flags & IPSKB_REROUTED)); ++ if (!(IPCB(skb)->flags & IPSKB_REROUTED)) ++ err = nf_hook(NFPROTO_IPV6, NF_INET_POST_ROUTING, net, sk, skb, ++ NULL, skb->dev, vrf_output6_direct_finish); ++ ++ if (likely(err == 1)) ++ vrf_finish_direct(skb); ++ ++ return err; ++} ++ ++static int vrf_ip6_out_direct_finish(struct net *net, struct sock *sk, ++ struct sk_buff *skb) ++{ ++ int err; ++ ++ err = vrf_output6_direct(net, sk, skb); ++ if (likely(err == 1)) ++ err = vrf_ip6_local_out(net, sk, skb); ++ ++ return err; + } + + static struct sk_buff *vrf_ip6_out_direct(struct net_device *vrf_dev, +@@ -454,18 +480,15 @@ static struct sk_buff *vrf_ip6_out_direc + skb->dev = vrf_dev; + + err = nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk, +- skb, NULL, vrf_dev, vrf_output6_direct); ++ skb, NULL, vrf_dev, vrf_ip6_out_direct_finish); + + if (likely(err == 1)) + err = vrf_output6_direct(net, sk, skb); + +- /* reset skb device */ + if (likely(err == 1)) +- nf_reset(skb); +- else +- skb = NULL; ++ return skb; + +- return skb; ++ return NULL; + } + + static struct sk_buff *vrf_ip6_out(struct net_device *vrf_dev, +@@ -649,15 +672,41 @@ static struct sk_buff *vrf_ip_out_redire + return skb; + } + ++static int vrf_output_direct_finish(struct net *net, struct sock *sk, ++ struct sk_buff *skb) ++{ ++ vrf_finish_direct(skb); ++ ++ return vrf_ip_local_out(net, sk, skb); ++} ++ + static int vrf_output_direct(struct net *net, struct sock *sk, + struct sk_buff *skb) + { ++ int err = 1; ++ + skb->protocol = htons(ETH_P_IP); + +- return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, +- net, sk, skb, NULL, skb->dev, +- vrf_finish_direct, +- !(IPCB(skb)->flags & IPSKB_REROUTED)); ++ if (!(IPCB(skb)->flags & IPSKB_REROUTED)) ++ err = nf_hook(NFPROTO_IPV4, NF_INET_POST_ROUTING, net, sk, skb, ++ NULL, skb->dev, vrf_output_direct_finish); ++ ++ if (likely(err == 1)) ++ vrf_finish_direct(skb); ++ ++ return err; ++} ++ ++static int vrf_ip_out_direct_finish(struct net *net, struct sock *sk, ++ struct sk_buff *skb) ++{ ++ int err; ++ ++ err = vrf_output_direct(net, sk, skb); ++ if (likely(err == 1)) ++ err = vrf_ip_local_out(net, sk, skb); ++ ++ return err; + } + + static struct sk_buff *vrf_ip_out_direct(struct net_device *vrf_dev, +@@ -670,18 +719,15 @@ static struct sk_buff *vrf_ip_out_direct + skb->dev = vrf_dev; + + err = nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, net, sk, +- skb, NULL, vrf_dev, vrf_output_direct); ++ skb, NULL, vrf_dev, vrf_ip_out_direct_finish); + + if (likely(err == 1)) + err = vrf_output_direct(net, sk, skb); + +- /* reset skb device */ + if (likely(err == 1)) +- nf_reset(skb); +- else +- skb = NULL; ++ return skb; + +- return skb; ++ return NULL; + } + + static struct sk_buff *vrf_ip_out(struct net_device *vrf_dev,