Bug#917533: linux-image-4.9.0-8-marvell: nfs-kernel-server leaks ports and triggers rkhunter/unhide-tcp
On Fri, 2018-12-28 at 09:58 +0000, Ian Campbell wrote:
> I'm next going to reboot into my locally built kernel with the (likely/hopeful)
> fix applied. I'll follow up in a few days (maybe a week to be sure) if I don't
> see this issue recurring. If it is looking positive at that point I'll also
> ping davem and Trond to requests upstream backports.
It's been a week and I've not had recurrence of the issue, previously I
was seeing it every 2-3 days.
I'm attaching the patch I was using which I described earlier as:
> pkg-kernel git's stretch branch at d9cfad89feb2 ('Revert
> "tracing: Use strlcpy() instead of strcpy() in
> __trace_find_cmdline()"') plus backports of:
>
> 8d1b8c62e080 SUNRPC: Refactor TCP socket timeout code into a helper function
> 3ffbc1d65583 net/sunrpc/xprt_sock: fix regression in connection error reporting.
> 9b30889c548a SUNRPC: Ensure we always close the socket after a connection shuts down
I'll also ping upstream about a possible stable backport shortly.
Ian.
From 3f47e65ec1a5b9c456cda19655759d43ec476988 Mon Sep 17 00:00:00 2001
From: Ian Campbell <ijc@hellion.org.uk>
Date: Tue, 25 Dec 2018 09:28:51 +0000
Subject: [PATCH] Backport patches to stop NFS kernel server leak
This tweaks rkhunters hidden port checks
---
debian/changelog | 3 +
...-always-close-the-socket-after-a-con.patch | 82 +++++++++++++++++
...TCP-socket-timeout-code-into-a-helpe.patch | 88 +++++++++++++++++++
...sock-fix-regression-in-connection-er.patch | 50 +++++++++++
debian/patches/series | 3 +
5 files changed, 226 insertions(+)
create mode 100644 debian/patches/bugfix/all/SUNRPC-Ensure-we-always-close-the-socket-after-a-con.patch
create mode 100644 debian/patches/bugfix/all/SUNRPC-Refactor-TCP-socket-timeout-code-into-a-helpe.patch
create mode 100644 debian/patches/bugfix/all/net-sunrpc-xprt_sock-fix-regression-in-connection-er.patch
diff --git a/debian/changelog b/debian/changelog
index da70135267ba..1c6b7e88734a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -734,6 +734,9 @@ linux (4.9.144-1) UNRELEASED; urgency=medium
* Refresh inet-frags-avoid-abi-change-in-4.9.134.patch for context changes
in 4.9.142
+ [ Ian Campbell ]
+ * Backport NFS fixes to not trigger rkhunter hidden port scan.
+
-- Ben Hutchings <ben@decadent.org.uk> Sat, 08 Dec 2018 20:53:57 +0000
linux (4.9.135-1) stretch; urgency=medium
diff --git a/debian/patches/bugfix/all/SUNRPC-Ensure-we-always-close-the-socket-after-a-con.patch b/debian/patches/bugfix/all/SUNRPC-Ensure-we-always-close-the-socket-after-a-con.patch
new file mode 100644
index 000000000000..5e99fe42a090
--- /dev/null
+++ b/debian/patches/bugfix/all/SUNRPC-Ensure-we-always-close-the-socket-after-a-con.patch
@@ -0,0 +1,82 @@
+From b0494c706325fdd1ec6b4fdef1d1f0cc12f4f4ad Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+Date: Mon, 5 Feb 2018 10:20:06 -0500
+Subject: [PATCH 3/3] SUNRPC: Ensure we always close the socket after a
+ connection shuts down
+
+Ensure that we release the TCP socket once it is in the TCP_CLOSE or
+TCP_TIME_WAIT state (and only then) so that we don't confuse rkhunter
+and its ilk.
+
+Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
+(cherry picked from commit 9b30889c548a4d45bfe6226e58de32504c1d682f)
+---
+ net/sunrpc/xprtsock.c | 23 ++++++++++-------------
+ 1 file changed, 10 insertions(+), 13 deletions(-)
+
+diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
+index d5422d479a22..5be417ed1311 100644
+--- a/net/sunrpc/xprtsock.c
++++ b/net/sunrpc/xprtsock.c
+@@ -798,13 +798,6 @@ static void xs_sock_reset_connection_flags(struct rpc_xprt *xprt)
+ smp_mb__after_atomic();
+ }
+
+-static void xs_sock_mark_closed(struct rpc_xprt *xprt)
+-{
+- xs_sock_reset_connection_flags(xprt);
+- /* Mark transport as closed and wake up all pending tasks */
+- xprt_disconnect_done(xprt);
+-}
+-
+ /**
+ * xs_error_report - callback to handle TCP socket state errors
+ * @sk: socket
+@@ -824,9 +817,6 @@ static void xs_error_report(struct sock *sk)
+ err = -sk->sk_err;
+ if (err == 0)
+ goto out;
+- /* Is this a reset event? */
+- if (sk->sk_state == TCP_CLOSE)
+- xs_sock_mark_closed(xprt);
+ dprintk("RPC: xs_error_report client %p, error=%d...\n",
+ xprt, -err);
+ trace_rpc_socket_error(xprt, sk->sk_socket, err);
+@@ -1619,9 +1609,11 @@ static void xs_tcp_state_change(struct sock *sk)
+ if (test_and_clear_bit(XPRT_SOCK_CONNECTING,
+ &transport->sock_state))
+ xprt_clear_connecting(xprt);
++ clear_bit(XPRT_CLOSING, &xprt->state);
+ if (sk->sk_err)
+ xprt_wake_pending_tasks(xprt, -sk->sk_err);
+- xs_sock_mark_closed(xprt);
++ /* Trigger the socket release */
++ xs_tcp_force_close(xprt);
+ }
+ out:
+ read_unlock_bh(&sk->sk_callback_lock);
+@@ -2227,14 +2219,19 @@ static void xs_tcp_shutdown(struct rpc_xprt *xprt)
+ {
+ struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+ struct socket *sock = transport->sock;
++ int skst = transport->inet ? transport->inet->sk_state : TCP_CLOSE;
+
+ if (sock == NULL)
+ return;
+- if (xprt_connected(xprt)) {
++ switch (skst) {
++ default:
+ kernel_sock_shutdown(sock, SHUT_RDWR);
+ trace_rpc_socket_shutdown(xprt, sock);
+- } else
++ break;
++ case TCP_CLOSE:
++ case TCP_TIME_WAIT:
+ xs_reset_transport(transport);
++ }
+ }
+
+ static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt,
+--
+2.19.2
+
diff --git a/debian/patches/bugfix/all/SUNRPC-Refactor-TCP-socket-timeout-code-into-a-helpe.patch b/debian/patches/bugfix/all/SUNRPC-Refactor-TCP-socket-timeout-code-into-a-helpe.patch
new file mode 100644
index 000000000000..6c340ac30cc1
--- /dev/null
+++ b/debian/patches/bugfix/all/SUNRPC-Refactor-TCP-socket-timeout-code-into-a-helpe.patch
@@ -0,0 +1,88 @@
+From d85eb2e56e66f56207d8d55972d456891b45b1ec Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+Date: Wed, 8 Feb 2017 11:17:53 -0500
+Subject: [PATCH 1/3] SUNRPC: Refactor TCP socket timeout code into a helper
+ function
+
+Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
+Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
+(cherry picked from commit 8d1b8c62e0805af7df900ef121389778d2126997)
+---
+ net/sunrpc/xprtsock.c | 45 +++++++++++++++++++++++++------------------
+ 1 file changed, 26 insertions(+), 19 deletions(-)
+
+diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
+index 1bf9153004cd..f2b769891b2b 100644
+--- a/net/sunrpc/xprtsock.c
++++ b/net/sunrpc/xprtsock.c
+@@ -2235,6 +2235,31 @@ static void xs_tcp_shutdown(struct rpc_xprt *xprt)
+ xs_reset_transport(transport);
+ }
+
++static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt,
++ struct socket *sock)
++{
++ unsigned int keepidle = DIV_ROUND_UP(xprt->timeout->to_initval, HZ);
++ unsigned int keepcnt = xprt->timeout->to_retries + 1;
++ unsigned int opt_on = 1;
++ unsigned int timeo;
++
++ /* TCP Keepalive options */
++ kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
++ (char *)&opt_on, sizeof(opt_on));
++ kernel_setsockopt(sock, SOL_TCP, TCP_KEEPIDLE,
++ (char *)&keepidle, sizeof(keepidle));
++ kernel_setsockopt(sock, SOL_TCP, TCP_KEEPINTVL,
++ (char *)&keepidle, sizeof(keepidle));
++ kernel_setsockopt(sock, SOL_TCP, TCP_KEEPCNT,
++ (char *)&keepcnt, sizeof(keepcnt));
++
++ /* TCP user timeout (see RFC5482) */
++ timeo = jiffies_to_msecs(xprt->timeout->to_initval) *
++ (xprt->timeout->to_retries + 1);
++ kernel_setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT,
++ (char *)&timeo, sizeof(timeo));
++}
++
+ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
+ {
+ struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+@@ -2242,22 +2267,8 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
+
+ if (!transport->inet) {
+ struct sock *sk = sock->sk;
+- unsigned int keepidle = xprt->timeout->to_initval / HZ;
+- unsigned int keepcnt = xprt->timeout->to_retries + 1;
+- unsigned int opt_on = 1;
+- unsigned int timeo;
+ unsigned int addr_pref = IPV6_PREFER_SRC_PUBLIC;
+
+- /* TCP Keepalive options */
+- kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
+- (char *)&opt_on, sizeof(opt_on));
+- kernel_setsockopt(sock, SOL_TCP, TCP_KEEPIDLE,
+- (char *)&keepidle, sizeof(keepidle));
+- kernel_setsockopt(sock, SOL_TCP, TCP_KEEPINTVL,
+- (char *)&keepidle, sizeof(keepidle));
+- kernel_setsockopt(sock, SOL_TCP, TCP_KEEPCNT,
+- (char *)&keepcnt, sizeof(keepcnt));
+-
+ /* Avoid temporary address, they are bad for long-lived
+ * connections such as NFS mounts.
+ * RFC4941, section 3.6 suggests that:
+@@ -2268,11 +2279,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
+ kernel_setsockopt(sock, SOL_IPV6, IPV6_ADDR_PREFERENCES,
+ (char *)&addr_pref, sizeof(addr_pref));
+
+- /* TCP user timeout (see RFC5482) */
+- timeo = jiffies_to_msecs(xprt->timeout->to_initval) *
+- (xprt->timeout->to_retries + 1);
+- kernel_setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT,
+- (char *)&timeo, sizeof(timeo));
++ xs_tcp_set_socket_timeouts(xprt, sock);
+
+ write_lock_bh(&sk->sk_callback_lock);
+
+--
+2.19.2
+
diff --git a/debian/patches/bugfix/all/net-sunrpc-xprt_sock-fix-regression-in-connection-er.patch b/debian/patches/bugfix/all/net-sunrpc-xprt_sock-fix-regression-in-connection-er.patch
new file mode 100644
index 000000000000..555a2aa0bb1e
--- /dev/null
+++ b/debian/patches/bugfix/all/net-sunrpc-xprt_sock-fix-regression-in-connection-er.patch
@@ -0,0 +1,50 @@
+From fe460ecd8dde88f9a6955420678b44e2f402995d Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.com>
+Date: Wed, 19 Jul 2017 14:05:01 +1000
+Subject: [PATCH 2/3] net/sunrpc/xprt_sock: fix regression in connection error
+ reporting.
+
+Commit 3d4762639dd3 ("tcp: remove poll() flakes when receiving
+RST") in v4.12 changed the order in which ->sk_state_change()
+and ->sk_error_report() are called when a socket is shut
+down - sk_state_change() is now called first.
+
+This causes xs_tcp_state_change() -> xs_sock_mark_closed() ->
+xprt_disconnect_done() to wake all pending tasked with -EAGAIN.
+When the ->sk_error_report() callback arrives, it is too late to
+pass the error on, and it is lost.
+
+As easy way to demonstrate the problem caused is to try to start
+rpc.nfsd while rcpbind isn't running.
+nfsd will attempt a tcp connection to rpcbind. A ECONNREFUSED
+error is returned, but sunrpc code loses the error and keeps
+retrying. If it saw the ECONNREFUSED, it would abort.
+
+To fix this, handle the sk->sk_err in the TCP_CLOSE branch of
+xs_tcp_state_change().
+
+Fixes: 3d4762639dd3 ("tcp: remove poll() flakes when receiving RST")
+Cc: stable@vger.kernel.org (v4.12)
+Signed-off-by: NeilBrown <neilb@suse.com>
+Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
+(cherry picked from commit 3ffbc1d65583394be12801655781dd2b079ce169)
+---
+ net/sunrpc/xprtsock.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
+index f2b769891b2b..d5422d479a22 100644
+--- a/net/sunrpc/xprtsock.c
++++ b/net/sunrpc/xprtsock.c
+@@ -1619,6 +1619,8 @@ static void xs_tcp_state_change(struct sock *sk)
+ if (test_and_clear_bit(XPRT_SOCK_CONNECTING,
+ &transport->sock_state))
+ xprt_clear_connecting(xprt);
++ if (sk->sk_err)
++ xprt_wake_pending_tasks(xprt, -sk->sk_err);
+ xs_sock_mark_closed(xprt);
+ }
+ out:
+--
+2.19.2
+
diff --git a/debian/patches/series b/debian/patches/series
index 95b0dfa575f3..c9abd00cccee 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -103,6 +103,9 @@ bugfix/x86/mmap-add-an-exception-to-the-stack-gap-for-hotspot-jvm.patch
bugfix/all/xen-time-do-not-decrease-steal-time-after-live-migra.patch
bugfix/all/nfsd-increase-DRC-cache-limit.patch
bugfix/all/netfilter-xt_hashlimit-fix-integer-divide-round-to-z.patch
+bugfix/all/SUNRPC-Refactor-TCP-socket-timeout-code-into-a-helpe.patch
+bugfix/all/net-sunrpc-xprt_sock-fix-regression-in-connection-er.patch
+bugfix/all/SUNRPC-Ensure-we-always-close-the-socket-after-a-con.patch
# Miscellaneous features
features/all/netfilter-nft_ct-add-notrack-support.patch
--
2.19.2
Reply to: