[PATCH v5 4/4] net: diag: Support destroying TCP sockets.
This implements SOCK_DESTROY for TCP sockets. It causes all blocking calls on the socket to fail fast with ECONNABORTED and causes a protocol close of the socket. It informs the other end of the connection by sending a RST, i.e., initiating a TCP ABORT as per RFC 793. ECONNABORTED was chosen for consistency with FreeBSD. Signed-off-by: Lorenzo Colitti--- include/net/tcp.h | 4 net/ipv4/Kconfig| 13 + net/ipv4/tcp.c | 34 ++ net/ipv4/tcp_diag.c | 19 +++ net/ipv4/tcp_ipv4.c | 3 +++ net/ipv6/tcp_ipv6.c | 3 +++ 6 files changed, 76 insertions(+) diff --git a/include/net/tcp.h b/include/net/tcp.h index f80e74c..505cef5 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1170,6 +1170,10 @@ void tcp_set_state(struct sock *sk, int state); void tcp_done(struct sock *sk); +#if CONFIG_INET_DIAG_DESTROY +int tcp_abort(struct sock *sk); +#endif + static inline void tcp_sack_reset(struct tcp_options_received *rx_opt) { rx_opt->dsack = 0; diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 416dfa0..31c4496 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -436,6 +436,19 @@ config INET_UDP_DIAG Support for UDP socket monitoring interface used by the ss tool. If unsure, say Y. +config INET_DIAG_DESTROY + bool "INET: allow privileged process to administratively close sockets" + depends on INET_DIAG && (IPV6 || IPV6=n) + default n + ---help--- + Provides a SOCK_DESTROY operation that allows privileged processes + (e.g., a connection manager or a network administration tool such as + ss) to close sockets opened by other processes. Closing a socket in + this way interrupts any blocking read/writes/connect operations on + the socket and causes future socket calls to behave as if the socket + had been disconnected. + If unsure, say N. + menuconfig TCP_CONG_ADVANCED bool "TCP: advanced congestion control" ---help--- diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c82cca1..fc5068d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3080,6 +3080,40 @@ void tcp_done(struct sock *sk) } EXPORT_SYMBOL_GPL(tcp_done); +#ifdef CONFIG_INET_DIAG_DESTROY +int tcp_abort(struct sock *sk) +{ + if (!sk_fullsock(sk)) { + sock_gen_put(sk); + return -EOPNOTSUPP; + } + + /* Don't race with userspace socket closes such as tcp_close. */ + lock_sock(sk); + + /* Don't race with BH socket closes such as inet_csk_listen_stop. */ + local_bh_disable(); + bh_lock_sock(sk); + + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_err = ECONNABORTED; + /* This barrier is coupled with smp_rmb() in tcp_poll() */ + smp_wmb(); + sk->sk_error_report(sk); + if (tcp_need_reset(sk->sk_state)) + tcp_send_active_reset(sk, GFP_ATOMIC); + tcp_done(sk); + } + + bh_unlock_sock(sk); + local_bh_enable(); + release_sock(sk); + sock_put(sk); + return 0; +} +EXPORT_SYMBOL_GPL(tcp_abort); +#endif + extern struct tcp_congestion_ops tcp_reno; static __initdata unsigned long thash_entries; diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index b316040..8d435f17 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -10,6 +10,8 @@ */ #include +#include +#include #include #include @@ -46,12 +48,29 @@ static int tcp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh, return inet_diag_dump_one_icsk(_hashinfo, in_skb, nlh, req); } +#ifdef CONFIG_INET_DIAG_DESTROY +static int tcp_diag_destroy(struct sk_buff *in_skb, + const struct inet_diag_req_v2 *req) +{ + struct net *net = sock_net(in_skb->sk); + struct sock *sk = inet_diag_find_one_icsk(net, _hashinfo, req); + + if (IS_ERR(sk)) + return PTR_ERR(sk); + + return sock_diag_destroy(sk); +} +#endif + static const struct inet_diag_handler tcp_diag_handler = { .dump= tcp_diag_dump, .dump_one= tcp_diag_dump_one, .idiag_get_info = tcp_diag_get_info, .idiag_type = IPPROTO_TCP, .idiag_info_size = sizeof(struct tcp_info), +#ifdef CONFIG_INET_DIAG_DESTROY + .destroy = tcp_diag_destroy, +#endif }; static int __init tcp_diag_init(void) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index db00343..5e28bf1 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2342,6 +2342,9 @@ struct proto tcp_prot = { .destroy_cgroup = tcp_destroy_cgroup, .proto_cgroup = tcp_proto_cgroup, #endif +#ifdef CONFIG_INET_DIAG_DESTROY + .diag_destroy = tcp_abort, +#endif }; EXPORT_SYMBOL(tcp_prot); diff --git a/net/ipv6/tcp_ipv6.c
Re: [PATCH v5 4/4] net: diag: Support destroying TCP sockets.
From: Lorenzo ColittiDate: Tue, 15 Dec 2015 02:29:57 +0900 > +#if CONFIG_INET_DIAG_DESTROY Config symbols are to be checked with "ifdef" not "if". > +config INET_DIAG_DESTROY > + bool "INET: allow privileged process to administratively close sockets" > + depends on INET_DIAG && (IPV6 || IPV6=n) > + default n As Eric Dumazet stated, this "(X || X=n)" construct only makes sense for tristate Kconfig entries. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v5 4/4] net: diag: Support destroying TCP sockets.
Hi Lorenzo, [auto build test WARNING on net/master] [also build test WARNING on v4.4-rc5] [cannot apply to next-20151214] url: https://github.com/0day-ci/linux/commits/Lorenzo-Colitti/net-diag-Add-the-ability-to-destroy-a-socket/20151215-013254 config: x86_64-randconfig-x013-12141150 (attached as .config) reproduce: # save the attached .config to linux build tree make ARCH=x86_64 All warnings (new ones prefixed by >>): In file included from net/ipv4/route.c:103:0: >> include/net/tcp.h:1173:5: warning: "CONFIG_INET_DIAG_DESTROY" is not defined >> [-Wundef] #if CONFIG_INET_DIAG_DESTROY ^ In file included from net/ipv4/route.c:103:0: >> include/net/tcp.h:1173:5: warning: "CONFIG_INET_DIAG_DESTROY" is not defined >> [-Wundef] #if CONFIG_INET_DIAG_DESTROY ^ -- In file included from net/ipv4/ip_forward.c:31:0: >> include/net/tcp.h:1173:5: warning: "CONFIG_INET_DIAG_DESTROY" is not defined >> [-Wundef] #if CONFIG_INET_DIAG_DESTROY ^ vim +/CONFIG_INET_DIAG_DESTROY +1173 include/net/tcp.h 1157 1158 bool tcp_prequeue(struct sock *sk, struct sk_buff *skb); 1159 1160 #undef STATE_TRACE 1161 1162 #ifdef STATE_TRACE 1163 static const char *statename[]={ 1164 "Unused","Established","Syn Sent","Syn Recv", 1165 "Fin Wait 1","Fin Wait 2","Time Wait", "Close", 1166 "Close Wait","Last ACK","Listen","Closing" 1167 }; 1168 #endif 1169 void tcp_set_state(struct sock *sk, int state); 1170 1171 void tcp_done(struct sock *sk); 1172 > 1173 #if CONFIG_INET_DIAG_DESTROY 1174 int tcp_abort(struct sock *sk); 1175 #endif 1176 1177 static inline void tcp_sack_reset(struct tcp_options_received *rx_opt) 1178 { 1179 rx_opt->dsack = 0; 1180 rx_opt->num_sacks = 0; 1181 } --- 0-DAY kernel test infrastructureOpen Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation .config.gz Description: Binary data
Re: [PATCH v5 4/4] net: diag: Support destroying TCP sockets.
On Mon, Dec 14, 2015 at 9:29 AM, Lorenzo Colittiwrote: > This implements SOCK_DESTROY for TCP sockets. It causes all > blocking calls on the socket to fail fast with ECONNABORTED and > causes a protocol close of the socket. It informs the other end > of the connection by sending a RST, i.e., initiating a TCP ABORT > as per RFC 793. ECONNABORTED was chosen for consistency with > FreeBSD. > > Signed-off-by: Lorenzo Colitti > --- > include/net/tcp.h | 4 > net/ipv4/Kconfig| 13 + > net/ipv4/tcp.c | 34 ++ > net/ipv4/tcp_diag.c | 19 +++ > net/ipv4/tcp_ipv4.c | 3 +++ > net/ipv6/tcp_ipv6.c | 3 +++ > 6 files changed, 76 insertions(+) > > diff --git a/include/net/tcp.h b/include/net/tcp.h > index f80e74c..505cef5 100644 > --- a/include/net/tcp.h > +++ b/include/net/tcp.h > @@ -1170,6 +1170,10 @@ void tcp_set_state(struct sock *sk, int state); > > void tcp_done(struct sock *sk); > > +#if CONFIG_INET_DIAG_DESTROY > +int tcp_abort(struct sock *sk); > +#endif > + > static inline void tcp_sack_reset(struct tcp_options_received *rx_opt) > { > rx_opt->dsack = 0; > diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig > index 416dfa0..31c4496 100644 > --- a/net/ipv4/Kconfig > +++ b/net/ipv4/Kconfig > @@ -436,6 +436,19 @@ config INET_UDP_DIAG > Support for UDP socket monitoring interface used by the ss tool. > If unsure, say Y. > > +config INET_DIAG_DESTROY > + bool "INET: allow privileged process to administratively close > sockets" > + depends on INET_DIAG && (IPV6 || IPV6=n) > + default n > + ---help--- > + Provides a SOCK_DESTROY operation that allows privileged processes > + (e.g., a connection manager or a network administration tool such as > + ss) to close sockets opened by other processes. Closing a socket in > + this way interrupts any blocking read/writes/connect operations on > + the socket and causes future socket calls to behave as if the socket > + had been disconnected. > + If unsure, say N. > + > menuconfig TCP_CONG_ADVANCED > bool "TCP: advanced congestion control" > ---help--- > diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c > index c82cca1..fc5068d 100644 > --- a/net/ipv4/tcp.c > +++ b/net/ipv4/tcp.c > @@ -3080,6 +3080,40 @@ void tcp_done(struct sock *sk) > } > EXPORT_SYMBOL_GPL(tcp_done); > > +#ifdef CONFIG_INET_DIAG_DESTROY This is a general use function it should not be under a CONFIG. > +int tcp_abort(struct sock *sk) Please add an err argument for setting sk->err. A value of zero could mean to use the default value (ECONNABORTED). > +{ > + if (!sk_fullsock(sk)) { > + sock_gen_put(sk); > + return -EOPNOTSUPP; > + } > + > + /* Don't race with userspace socket closes such as tcp_close. */ > + lock_sock(sk); > + > + /* Don't race with BH socket closes such as inet_csk_listen_stop. */ > + local_bh_disable(); > + bh_lock_sock(sk); > + > + if (!sock_flag(sk, SOCK_DEAD)) { > + sk->sk_err = ECONNABORTED; > + /* This barrier is coupled with smp_rmb() in tcp_poll() */ > + smp_wmb(); > + sk->sk_error_report(sk); > + if (tcp_need_reset(sk->sk_state)) > + tcp_send_active_reset(sk, GFP_ATOMIC); > + tcp_done(sk); > + } > + > + bh_unlock_sock(sk); > + local_bh_enable(); > + release_sock(sk); > + sock_put(sk); > + return 0; > +} > +EXPORT_SYMBOL_GPL(tcp_abort); > +#endif > + > extern struct tcp_congestion_ops tcp_reno; > > static __initdata unsigned long thash_entries; > diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c > index b316040..8d435f17 100644 > --- a/net/ipv4/tcp_diag.c > +++ b/net/ipv4/tcp_diag.c > @@ -10,6 +10,8 @@ > */ > > #include > +#include > +#include > #include > > #include > @@ -46,12 +48,29 @@ static int tcp_diag_dump_one(struct sk_buff *in_skb, > const struct nlmsghdr *nlh, > return inet_diag_dump_one_icsk(_hashinfo, in_skb, nlh, req); > } > > +#ifdef CONFIG_INET_DIAG_DESTROY > +static int tcp_diag_destroy(struct sk_buff *in_skb, > + const struct inet_diag_req_v2 *req) > +{ > + struct net *net = sock_net(in_skb->sk); > + struct sock *sk = inet_diag_find_one_icsk(net, _hashinfo, req); > + > + if (IS_ERR(sk)) > + return PTR_ERR(sk); > + > + return sock_diag_destroy(sk); > +} > +#endif > + > static const struct inet_diag_handler tcp_diag_handler = { > .dump= tcp_diag_dump, > .dump_one= tcp_diag_dump_one, > .idiag_get_info = tcp_diag_get_info, > .idiag_type = IPPROTO_TCP, > .idiag_info_size = sizeof(struct tcp_info), > +#ifdef CONFIG_INET_DIAG_DESTROY > + .destroy =
Re: [PATCH v5 4/4] net: diag: Support destroying TCP sockets.
On Tue, 2015-12-15 at 02:29 +0900, Lorenzo Colitti wrote: > +config INET_DIAG_DESTROY > + bool "INET: allow privileged process to administratively close sockets" > + depends on INET_DIAG && (IPV6 || IPV6=n) > + default n I can see the effect of (IPV6 || IPv6=n) for a tristate, but what is the intent for a bool ? It seems INET_DIAG_DESTROY can be selected regardless of IPV6 being off, on, or a module ? -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html