diff options
author | Ingela Anderton Andin <[email protected]> | 2018-08-23 14:29:36 +0200 |
---|---|---|
committer | Ingela Anderton Andin <[email protected]> | 2018-08-27 15:22:45 +0200 |
commit | a508428df8af14437f1a4766ec68294d1d736915 (patch) | |
tree | 4c13500b01060c8f52f7d0d32d7352f9f9ebb8ff /lib/ssl/src/tls_connection.erl | |
parent | 0078ebf6c5311edc1a07be71fb7a127a175a60fa (diff) | |
download | otp-a508428df8af14437f1a4766ec68294d1d736915.tar.gz otp-a508428df8af14437f1a4766ec68294d1d736915.tar.bz2 otp-a508428df8af14437f1a4766ec68294d1d736915.zip |
ssl: Improve close handling
We want to make sure that the sender process that may get stuck in
prim_inet:send will die if the tls_connection process is
terminated. And we also like to make sure that it terminates as
gracefully as possible. So when the tls_connection process dies it
spawns a killer process that will brutaly kill the sender if it is
unresponsive and does not terminate due to its monitor of the
tls_connetion process triggering.
When the sender process also acts as distribution controller it
may also have other processess that it is linked with that it
should bring down or that could bring the connection down.
Diffstat (limited to 'lib/ssl/src/tls_connection.erl')
-rw-r--r-- | lib/ssl/src/tls_connection.erl | 44 |
1 files changed, 24 insertions, 20 deletions
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index 8277569281..6c7511d2b3 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -65,7 +65,7 @@ %% gen_statem state functions -export([init/3, error/3, downgrade/3, %% Initiation and take down states hello/3, user_hello/3, certify/3, cipher/3, abbreviated/3, %% Handshake states - connection/3, death_row/3]). + connection/3]). %% gen_statem callbacks -export([callback_mode/0, terminate/3, code_change/4, format_status/2]). @@ -135,7 +135,7 @@ init([Role, Sender, Host, Port, Socket, {SslOpts, _, _} = Options, User, CbInfo gen_statem:enter_loop(?MODULE, [], error, EState) end. -pids(#state{protocol_specific = #{sender := {_, Sender}}}) -> +pids(#state{protocol_specific = #{sender := Sender}}) -> [self(), Sender]. %%==================================================================== @@ -307,7 +307,7 @@ queue_change_cipher(Msg, #state{negotiated_version = Version, State0#state{connection_states = ConnectionStates, flight_buffer = Flight0 ++ [BinChangeCipher]}. -reinit(#state{protocol_specific = #{sender := {_,Sender}}, +reinit(#state{protocol_specific = #{sender := Sender}, negotiated_version = Version, connection_states = #{current_write := Write}} = State) -> tls_sender:update_connection_state(Sender, Write, Version), @@ -353,7 +353,7 @@ send_alert(Alert, #state{negotiated_version = Version, Connection:send(Transport, Socket, BinMsg), StateData0#state{connection_states = ConnectionStates}. -send_alert_in_connection(Alert, #state{protocol_specific = #{sender := {_, Sender}}}) -> +send_alert_in_connection(Alert, #state{protocol_specific = #{sender := Sender}}) -> tls_sender:send_alert(Sender, Alert). %% User closes or recursive call! @@ -597,7 +597,7 @@ connection(internal, #hello_request{}, connection(internal, #client_hello{} = Hello, #state{role = server, allow_renegotiate = true, connection_states = CS, %%protocol_cb = Connection, - protocol_specific = #{sender := {_, Sender}} + protocol_specific = #{sender := Sender} } = State0) -> %% Mitigate Computational DoS attack %% http://www.educatedguesswork.org/2011/10/ssltls_and_computational_dos.html @@ -622,13 +622,6 @@ connection(Type, Event, State) -> ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE). %%-------------------------------------------------------------------- --spec death_row(gen_statem:event_type(), term(), #state{}) -> - gen_statem:state_function_result(). -%%-------------------------------------------------------------------- -death_row(Type, Event, State) -> - ssl_connection:death_row(Type, Event, State, ?MODULE). - -%%-------------------------------------------------------------------- -spec downgrade(gen_statem:event_type(), term(), #state{}) -> gen_statem:state_function_result(). %%-------------------------------------------------------------------- @@ -642,6 +635,7 @@ callback_mode() -> state_functions. terminate(Reason, StateName, State) -> + ensure_sender_terminate(Reason, State), catch ssl_connection:terminate(Reason, StateName, State). format_status(Type, Data) -> @@ -668,7 +662,6 @@ initial_state(Role, Sender, Host, Port, Socket, {SSLOptions, SocketOptions, Trac end, UserMonitor = erlang:monitor(process, User), - SendMonitor = erlang:monitor(process, Sender), #state{socket_options = SocketOptions, ssl_options = SSLOptions, @@ -693,7 +686,7 @@ initial_state(Role, Sender, Host, Port, Socket, {SSLOptions, SocketOptions, Trac protocol_cb = ?MODULE, tracker = Tracker, flight_buffer = [], - protocol_specific = #{sender => {SendMonitor, Sender}} + protocol_specific = #{sender => Sender} }. erl_dist_data(true) -> @@ -711,7 +704,7 @@ initialize_tls_sender(#state{role = Role, negotiated_version = Version, ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}, connection_states = #{current_write := ConnectionWriteState}, - protocol_specific = #{sender := {_, Sender}}}) -> + protocol_specific = #{sender := Sender}}) -> Init = #{current_write => ConnectionWriteState, role => Role, socket => Socket, @@ -794,11 +787,9 @@ handle_info({CloseTag, Socket}, StateName, %% and then receive the final message. next_event(StateName, no_record, State) end; -handle_info({'DOWN', Mon, _, _, _}, _, #state{ssl_options = #ssl_options{erl_dist = true}, - protocol_specific = #{sender:= {Mon, _}}} = State) -> - ssl_connection:death_row(State, disconnect); -handle_info({'DOWN', Mon, _, _, Reason}, _, #state{protocol_specific = #{sender:= {Mon, _}}} = State) -> - {stop, {shudown, sender_died, Reason}, State}; +handle_info({'EXIT', Pid, Reason}, _, + #state{protocol_specific = Pid} = State) -> + {stop, {shutdown, sender_died, Reason}, State}; handle_info(Msg, StateName, State) -> ssl_connection:StateName(info, Msg, State, ?MODULE). @@ -888,3 +879,16 @@ assert_buffer_sanity(Bin, _) -> throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake_data)) end. + +ensure_sender_terminate(downgrade, _) -> + ok; %% Do not terminate sender during downgrade phase +ensure_sender_terminate(_, #state{protocol_specific = #{sender := Sender}}) -> + %% Make sure TLS sender dies when connection process is terminated normally + %% This is needed if the tls_sender is blocked in prim_inet:send + Kill = fun() -> + receive + after 5000 -> + catch (exit(Sender, kill)) + end + end, + spawn(Kill). |