--- /dev/null
+From d76f3351cea2d927fdf70dd7c06898235035e84e Mon Sep 17 00:00:00 2001
+From: Tim Froidcoeur <tim.froidcoeur@tessares.net>
+Date: Tue, 11 Aug 2020 20:33:24 +0200
+Subject: net: initialize fastreuse on inet_inherit_port
+
+From: Tim Froidcoeur <tim.froidcoeur@tessares.net>
+
+commit d76f3351cea2d927fdf70dd7c06898235035e84e upstream.
+
+In the case of TPROXY, bind_conflict optimizations for SO_REUSEADDR or
+SO_REUSEPORT are broken, possibly resulting in O(n) instead of O(1) bind
+behaviour or in the incorrect reuse of a bind.
+
+the kernel keeps track for each bind_bucket if all sockets in the
+bind_bucket support SO_REUSEADDR or SO_REUSEPORT in two fastreuse flags.
+These flags allow skipping the costly bind_conflict check when possible
+(meaning when all sockets have the proper SO_REUSE option).
+
+For every socket added to a bind_bucket, these flags need to be updated.
+As soon as a socket that does not support reuse is added, the flag is
+set to false and will never go back to true, unless the bind_bucket is
+deleted.
+
+Note that there is no mechanism to re-evaluate these flags when a socket
+is removed (this might make sense when removing a socket that would not
+allow reuse; this leaves room for a future patch).
+
+For this optimization to work, it is mandatory that these flags are
+properly initialized and updated.
+
+When a child socket is created from a listen socket in
+__inet_inherit_port, the TPROXY case could create a new bind bucket
+without properly initializing these flags, thus preventing the
+optimization to work. Alternatively, a socket not allowing reuse could
+be added to an existing bind bucket without updating the flags, causing
+bind_conflict to never be called as it should.
+
+Call inet_csk_update_fastreuse when __inet_inherit_port decides to create
+a new bind_bucket or use a different bind_bucket than the one of the
+listen socket.
+
+Fixes: 093d282321da ("tproxy: fix hash locking issue when using port redirection in __inet_inherit_port()")
+Acked-by: Matthieu Baerts <matthieu.baerts@tessares.net>
+Signed-off-by: Tim Froidcoeur <tim.froidcoeur@tessares.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Tim Froidcoeur <tim.froidcoeur@tessares.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/inet_hashtables.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/net/ipv4/inet_hashtables.c
++++ b/net/ipv4/inet_hashtables.c
+@@ -160,6 +160,7 @@ int __inet_inherit_port(const struct soc
+ return -ENOMEM;
+ }
+ }
++ inet_csk_update_fastreuse(tb, child);
+ }
+ inet_bind_hash(child, tb, port);
+ spin_unlock(&head->lock);
--- /dev/null
+From 62ffc589abb176821662efc4525ee4ac0b9c3894 Mon Sep 17 00:00:00 2001
+From: Tim Froidcoeur <tim.froidcoeur@tessares.net>
+Date: Tue, 11 Aug 2020 20:33:23 +0200
+Subject: net: refactor bind_bucket fastreuse into helper
+
+From: Tim Froidcoeur <tim.froidcoeur@tessares.net>
+
+commit 62ffc589abb176821662efc4525ee4ac0b9c3894 upstream.
+
+Refactor the fastreuse update code in inet_csk_get_port into a small
+helper function that can be called from other places.
+
+Acked-by: Matthieu Baerts <matthieu.baerts@tessares.net>
+Signed-off-by: Tim Froidcoeur <tim.froidcoeur@tessares.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Tim Froidcoeur <tim.froidcoeur@tessares.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/inet_connection_sock.h | 4 +++
+ net/ipv4/inet_connection_sock.c | 46 ++++++++++++++++++++++---------------
+ 2 files changed, 32 insertions(+), 18 deletions(-)
+
+--- a/include/net/inet_connection_sock.h
++++ b/include/net/inet_connection_sock.h
+@@ -319,5 +319,9 @@ int inet_csk_compat_getsockopt(struct so
+ int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, unsigned int optlen);
+
++/* update the fast reuse flag when adding a socket */
++void inet_csk_update_fastreuse(struct inet_bind_bucket *tb,
++ struct sock *sk);
++
+ struct dst_entry *inet_csk_update_pmtu(struct sock *sk, u32 mtu);
+ #endif /* _INET_CONNECTION_SOCK_H */
+--- a/net/ipv4/inet_connection_sock.c
++++ b/net/ipv4/inet_connection_sock.c
+@@ -87,6 +87,31 @@ int inet_csk_bind_conflict(const struct
+ }
+ EXPORT_SYMBOL_GPL(inet_csk_bind_conflict);
+
++void inet_csk_update_fastreuse(struct inet_bind_bucket *tb,
++ struct sock *sk)
++{
++ kuid_t uid = sock_i_uid(sk);
++
++ if (hlist_empty(&tb->owners)) {
++ if (sk->sk_reuse && sk->sk_state != TCP_LISTEN)
++ tb->fastreuse = 1;
++ else
++ tb->fastreuse = 0;
++ if (sk->sk_reuseport) {
++ tb->fastreuseport = 1;
++ tb->fastuid = uid;
++ } else
++ tb->fastreuseport = 0;
++ } else {
++ if (tb->fastreuse &&
++ (!sk->sk_reuse || sk->sk_state == TCP_LISTEN))
++ tb->fastreuse = 0;
++ if (tb->fastreuseport &&
++ (!sk->sk_reuseport || !uid_eq(tb->fastuid, uid)))
++ tb->fastreuseport = 0;
++ }
++}
++
+ /* Obtain a reference to a local port for the given sock,
+ * if snum is zero it means select any available local port.
+ */
+@@ -216,24 +241,9 @@ tb_not_found:
+ if (!tb && (tb = inet_bind_bucket_create(hashinfo->bind_bucket_cachep,
+ net, head, snum)) == NULL)
+ goto fail_unlock;
+- if (hlist_empty(&tb->owners)) {
+- if (sk->sk_reuse && sk->sk_state != TCP_LISTEN)
+- tb->fastreuse = 1;
+- else
+- tb->fastreuse = 0;
+- if (sk->sk_reuseport) {
+- tb->fastreuseport = 1;
+- tb->fastuid = uid;
+- } else
+- tb->fastreuseport = 0;
+- } else {
+- if (tb->fastreuse &&
+- (!sk->sk_reuse || sk->sk_state == TCP_LISTEN))
+- tb->fastreuse = 0;
+- if (tb->fastreuseport &&
+- (!sk->sk_reuseport || !uid_eq(tb->fastuid, uid)))
+- tb->fastreuseport = 0;
+- }
++
++ inet_csk_update_fastreuse(tb, sk);
++
+ success:
+ if (!inet_csk(sk)->icsk_bind_hash)
+ inet_bind_hash(sk, tb, snum);