Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(UAF): swap old/new l->config_ctx only when start success #257

Merged
merged 2 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion c_src/quicer_listener.c
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,6 @@ start_listener3(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
}

QuicerConfigCTX *old_config_ctx = l_ctx->config_resource;
l_ctx->config_resource = new_config_ctx;

#if defined(QUICER_USE_TRUSTED_STORE)
X509_STORE_free(l_ctx->trusted_store);
Expand Down Expand Up @@ -651,6 +650,7 @@ start_listener3(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
}
l_ctx->is_stopped = FALSE;

l_ctx->config_resource = new_config_ctx;
// the ongoing handshake will be completed with the old config
enif_release_resource(old_config_ctx);

Expand Down
85 changes: 84 additions & 1 deletion test/quicer_listener_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ end_per_group(_GroupName, _Config) ->
%% Reason = term()
%% @end
%%--------------------------------------------------------------------
init_per_testcase(tc_listener_conf_reload_listen_on_neg, Config) ->
{skip, "MacOs is able to listen on port 1"};
init_per_testcase(_TestCase, Config) ->
application:ensure_all_started(quicer),
quicer_test_lib:cleanup_msquic(),
Expand Down Expand Up @@ -557,7 +559,6 @@ tc_listener_conf_reload(Config) ->

tc_listener_conf_reload_listen_on(Config) ->
process_flag(trap_exit, true),
DataDir = ?config(data_dir, Config),
ServerConnCallback = example_server_connection,
ServerStreamCallback = example_server_stream,
Port = select_port(),
Expand Down Expand Up @@ -637,6 +638,88 @@ tc_listener_conf_reload_listen_on(Config) ->
gen_server:stop(ClientConnPid),
quicer_listener:stop_listener(QuicApp).

tc_listener_conf_reload_listen_on_neg(Config) ->
process_flag(trap_exit, true),
ServerConnCallback = example_server_connection,
ServerStreamCallback = example_server_stream,
Port = select_port(),
application:ensure_all_started(quicer),
ListenerOpts = [
{conn_acceptors, 32},
{peer_bidi_stream_count, 0},
{peer_unidi_stream_count, 1}
| default_listen_opts(Config)
],
ConnectionOpts = [
{conn_callback, ServerConnCallback},
{stream_acceptors, 2}
| default_conn_opts()
],
StreamOpts = [
{stream_callback, ServerStreamCallback}
| default_stream_opts()
],
Options = {ListenerOpts, ConnectionOpts, StreamOpts},

%% Given a QUIC connection between example client and example server
{ok, QuicApp} = quicer:spawn_listener(sample, Port, Options),
ClientConnOpts = default_conn_opts_verify(Config, ca),
{ok, ClientConnPid} = example_client_connection:start_link(
"localhost",
Port,
{ClientConnOpts, default_stream_opts()}
),

ct:pal("C1 status : ~p", [sys:get_status(ClientConnPid)]),
{ok, LHandle} = quicer_listener:get_handle(QuicApp, 5000),

%% WHEN: the listener is reloaded with ListenOn (new invalid bind address)
NewPort = 1,
%% THEN: We get error
{error, _, _} = quicer_listener:reload(QuicApp, NewPort, ListenerOpts),
%% THEN: the listener handle is unchanged
?assertEqual({ok, LHandle}, quicer_listener:get_handle(QuicApp, 5000)),

%% WHEN: we unlock it and start new connection
ok = quicer_listener:unlock(QuicApp, 3000),

%% THEN: the new connection shall be established with some reties
%% and traffic can be sent and received
{ok, Conn2} =
snabbkaffe:retry(
300,
10,
fun() ->
{ok, _} = quicer:connect(
"localhost",
Port,
default_conn_opts_verify(Config, 'ca'),
5000
)
end
),

{ok, Stream2} = quicer:start_stream(
Conn2,
#{open_flag => ?QUIC_STREAM_OPEN_FLAG_UNIDIRECTIONAL}
),
{ok, _} = quicer:send(Stream2, <<"ping_from_conn_2">>),

receive
{quic, new_stream, Stream2Remote, #{is_orphan := true}} ->
quicer:setopt(Stream2Remote, active, true),
ok
end,

receive
{quic, <<"ping_from_conn_2">>, Stream2Remote, _} -> ok
after 2000 ->
ct:fail("nothing from conn 2"),
quicer_test_lib:report_unhandled_messages()
Comment on lines +717 to +718
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the 2nd line is unreachable (maybe switch the order)

end,

quicer_listener:stop_listener(QuicApp).

tc_stop_close_listener(Config) ->
Port = select_port(),
{ok, L} = quicer:listen(Port, default_listen_opts(Config)),
Expand Down
Loading