diff mbox series

[08/19] tcp: authopt: Disable via sysctl by default

Message ID b0abf2b789220708011a862a892c37b0fd76dc25.1632240523.git.cdleonard@gmail.com (mailing list archive)
State New
Headers show
Series tcp: Initial support for RFC5925 auth option | expand

Commit Message

Leonard Crestez Sept. 21, 2021, 4:14 p.m. UTC
This is mainly intended to protect against local privilege escalations
through a rarely used feature so it is deliberately not namespaced.

Enforcement is only at the setsockopt level, this should be enough to
ensure that the tcp_authopt_needed static key never turns on.

No effort is made to handle disabling when the feature is already in
use.

Signed-off-by: Leonard Crestez <cdleonard@gmail.com>
---
 Documentation/networking/ip-sysctl.rst |  6 ++++++
 include/net/tcp_authopt.h              |  1 +
 net/ipv4/sysctl_net_ipv4.c             | 10 ++++++++++
 net/ipv4/tcp_authopt.c                 | 11 +++++++++++
 4 files changed, 28 insertions(+)

Comments

David Ahern Sept. 25, 2021, 1:57 a.m. UTC | #1
On 9/21/21 10:14 AM, Leonard Crestez wrote:
> This is mainly intended to protect against local privilege escalations
> through a rarely used feature so it is deliberately not namespaced.
> 
> Enforcement is only at the setsockopt level, this should be enough to
> ensure that the tcp_authopt_needed static key never turns on.
> 
> No effort is made to handle disabling when the feature is already in
> use.
> 

MD5 does not require a sysctl to use it, so why should this auth mechanism?
Leonard Crestez Sept. 25, 2021, 2:14 p.m. UTC | #2
On 9/25/21 4:57 AM, David Ahern wrote:
> On 9/21/21 10:14 AM, Leonard Crestez wrote:
>> This is mainly intended to protect against local privilege escalations
>> through a rarely used feature so it is deliberately not namespaced.
>>
>> Enforcement is only at the setsockopt level, this should be enough to
>> ensure that the tcp_authopt_needed static key never turns on.
>>
>> No effort is made to handle disabling when the feature is already in
>> use.
>>
> 
> MD5 does not require a sysctl to use it, so why should this auth mechanism?

I think it would make sense for both these features to be off by 
default. They interact with TCP in complex ways and are available to all 
unprivileged users but their real usecases are actually very limited.

Having to flip a few sysctls is very reasonable in the context of 
setting up a router.

My concern is that this feature ends up in distro kernels and somebody 
finds a way to use it for privilege escalation.

It also seems reasonable for "experimental" features to be off by default.

--
Regards,
Leonard
diff mbox series

Patch

diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst
index d91ab28718d4..16e34268ecb4 100644
--- a/Documentation/networking/ip-sysctl.rst
+++ b/Documentation/networking/ip-sysctl.rst
@@ -995,10 +995,16 @@  tcp_rx_skb_cache - BOOLEAN
 	on systems with a lot of TCP sockets, since it increases
 	memory usage.
 
 	Default: 0 (disabled)
 
+tcp_authopt - BOOLEAN
+	Enable the TCP Authentication Option (RFC5925), a replacement for TCP
+	MD5 Signatures (RFC2835).
+
+	Default: 0
+
 UDP variables
 =============
 
 udp_l3mdev_accept - BOOLEAN
 	Enabling this option allows a "global" bound socket to work
diff --git a/include/net/tcp_authopt.h b/include/net/tcp_authopt.h
index 263f98c3a1a8..422f0034d32b 100644
--- a/include/net/tcp_authopt.h
+++ b/include/net/tcp_authopt.h
@@ -51,10 +51,11 @@  struct tcp_authopt_info {
 	u32 src_isn;
 	u32 dst_isn;
 };
 
 #ifdef CONFIG_TCP_AUTHOPT
+extern int sysctl_tcp_authopt;
 DECLARE_STATIC_KEY_FALSE(tcp_authopt_needed);
 
 void tcp_authopt_free(struct sock *sk, struct tcp_authopt_info *info);
 void tcp_authopt_clear(struct sock *sk);
 int tcp_set_authopt(struct sock *sk, sockptr_t optval, unsigned int optlen);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 4680268f2e59..365466fbca8b 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -17,10 +17,11 @@ 
 #include <net/udp.h>
 #include <net/cipso_ipv4.h>
 #include <net/ping.h>
 #include <net/protocol.h>
 #include <net/netevent.h>
+#include <net/tcp_authopt.h>
 
 static int two = 2;
 static int three __maybe_unused = 3;
 static int four = 4;
 static int thousand = 1000;
@@ -595,10 +596,19 @@  static struct ctl_table ipv4_table[] = {
 		.procname	= "tcp_tx_skb_cache",
 		.data		= &tcp_tx_skb_cache_key.key,
 		.mode		= 0644,
 		.proc_handler	= proc_do_static_key,
 	},
+#ifdef CONFIG_TCP_AUTHOPT
+	{
+		.procname	= "tcp_authopt",
+		.data		= &sysctl_tcp_authopt,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
+#endif
 	{ }
 };
 
 static struct ctl_table ipv4_net_table[] = {
 	{
diff --git a/net/ipv4/tcp_authopt.c b/net/ipv4/tcp_authopt.c
index 0c32b8fb1d41..41f844d5d49a 100644
--- a/net/ipv4/tcp_authopt.c
+++ b/net/ipv4/tcp_authopt.c
@@ -3,10 +3,15 @@ 
 #include <linux/kernel.h>
 #include <net/tcp.h>
 #include <net/tcp_authopt.h>
 #include <crypto/hash.h>
 
+/* This is mainly intended to protect against local privilege escalations through
+ * a rarely used feature so it is deliberately not namespaced.
+ */
+int sysctl_tcp_authopt;
+
 /* This is enabled when first struct tcp_authopt_info is allocated and never released */
 DEFINE_STATIC_KEY_FALSE(tcp_authopt_needed);
 /* only for CONFIG_IPV6=m */
 EXPORT_SYMBOL(tcp_authopt_needed);
 
@@ -361,10 +366,12 @@  int tcp_set_authopt(struct sock *sk, sockptr_t optval, unsigned int optlen)
 	struct tcp_authopt opt;
 	struct tcp_authopt_info *info;
 	int err;
 
 	sock_owned_by_me(sk);
+	if (!sysctl_tcp_authopt)
+		return -EPERM;
 
 	err = _copy_from_sockptr_tolerant((u8*)&opt, sizeof(opt), optval, optlen);
 	if (err)
 		return err;
 
@@ -384,10 +391,12 @@  int tcp_get_authopt_val(struct sock *sk, struct tcp_authopt *opt)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct tcp_authopt_info *info;
 
 	sock_owned_by_me(sk);
+	if (!sysctl_tcp_authopt)
+		return -EPERM;
 
 	memset(opt, 0, sizeof(*opt));
 	info = rcu_dereference_check(tp->authopt_info, lockdep_sock_is_held(sk));
 	if (!info)
 		return -ENOENT;
@@ -452,10 +461,12 @@  int tcp_set_authopt_key(struct sock *sk, sockptr_t optval, unsigned int optlen)
 	struct tcp_authopt_key_info *key_info, *old_key_info;
 	struct tcp_authopt_alg_imp *alg;
 	int err;
 
 	sock_owned_by_me(sk);
+	if (!sysctl_tcp_authopt)
+		return -EPERM;
 
 	err = _copy_from_sockptr_tolerant((u8*)&opt, sizeof(opt), optval, optlen);
 	if (err)
 		return err;