Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:23
erlang
0697-erts-Fix-use-after-free-for-send-delay-wri...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0697-erts-Fix-use-after-free-for-send-delay-write-error.patch of Package erlang
From baaa8f30d782a4b79828b84fcd6c0e92d47ac6c0 Mon Sep 17 00:00:00 2001 From: Lukas Larsson <lukas@erlang.org> Date: Wed, 13 Oct 2021 09:52:58 +0200 Subject: [PATCH] erts: Fix use after free for send-delay write error If a socket was in active mode and a write error happened when a send_delay was triggered the driver would read data from the deallocated tcp_description and crash. --- erts/emulator/drivers/common/inet_drv.c | 38 ++++++++++++++----------- lib/kernel/test/gen_tcp_misc_SUITE.erl | 10 +++++-- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index b69906b3e1..46e73c8b83 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1039,26 +1039,26 @@ typedef union { (1 + 2 + 4) : localaddrlen(data)) #endif +typedef int (MultiTimerFunction)(ErlDrvData drv_data, ErlDrvTermData caller); + typedef struct _multi_timer_data { ErlDrvTime when; ErlDrvTermData caller; - void (*timeout_function)(ErlDrvData drv_data, ErlDrvTermData caller); + MultiTimerFunction *timeout_function; struct _multi_timer_data *next; struct _multi_timer_data *prev; } MultiTimerData; static MultiTimerData *add_multi_timer(tcp_descriptor *desc, ErlDrvPort port, ErlDrvTermData caller, unsigned timeout, - void (*timeout_fun)(ErlDrvData drv_data, - ErlDrvTermData caller)); + MultiTimerFunction *timeout_fun); static void fire_multi_timers(tcp_descriptor *desc, ErlDrvPort port, ErlDrvData data); static void remove_multi_timer(tcp_descriptor *desc, ErlDrvPort port, MultiTimerData *p); static void cancel_multi_timer(tcp_descriptor *desc, ErlDrvPort port, - void (*timeout_fun)(ErlDrvData drv_data, - ErlDrvTermData caller)); + MultiTimerFunction *timeout_fun); -static void tcp_inet_multi_timeout(ErlDrvData e, ErlDrvTermData caller); +static int tcp_inet_multi_timeout(ErlDrvData e, ErlDrvTermData caller); static void clean_multi_timers(tcp_descriptor *desc, ErlDrvPort port); typedef struct { @@ -10131,13 +10131,14 @@ static void tcp_desc_close(tcp_descriptor* desc) erl_inet_close(INETP(desc)); } -static void tcp_inet_recv_timeout(ErlDrvData e, ErlDrvTermData dummy) +static int tcp_inet_recv_timeout(ErlDrvData e, ErlDrvTermData dummy) { tcp_descriptor* desc = (tcp_descriptor*)e; ASSERT(!desc->inet.active); sock_select(INETP(desc),(FD_READ|FD_CLOSE),0); desc->i_remain = 0; async_error_am(INETP(desc), am_timeout); + return 1; } /* TCP requests from Erlang */ @@ -10554,7 +10555,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, } -static void tcp_inet_send_timeout(ErlDrvData e, ErlDrvTermData dummy) +static int tcp_inet_send_timeout(ErlDrvData e, ErlDrvTermData dummy) { tcp_descriptor* desc = (tcp_descriptor*)e; ASSERT(IS_BUSY(INETP(desc))); @@ -10567,6 +10568,7 @@ static void tcp_inet_send_timeout(ErlDrvData e, ErlDrvTermData dummy) if (desc->send_timeout_close) { tcp_desc_close(desc); } + return 1; /* Q: Why not keep port busy as send queue may still be full (ERL-1390)? * * A: If kept busy, a following send call would hang without a timeout @@ -10616,14 +10618,14 @@ static void tcp_inet_timeout(ErlDrvData e) DEBUGF(("tcp_inet_timeout(%p) }\r\n", desc->inet.port)); } -static void tcp_inet_multi_timeout(ErlDrvData e, ErlDrvTermData caller) +static int tcp_inet_multi_timeout(ErlDrvData e, ErlDrvTermData caller) { tcp_descriptor* desc = (tcp_descriptor*)e; int id,req; ErlDrvMonitor monitor; if (remove_multi_op(desc, &id, &req, caller, NULL, &monitor) != 0) { - return; + return 1; } driver_demonitor_process(desc->inet.port, &monitor); if (desc->multi_first == NULL) { @@ -10631,6 +10633,7 @@ static void tcp_inet_multi_timeout(ErlDrvData e, ErlDrvTermData caller) desc->inet.state = INET_STATE_LISTENING; /* restore state */ } send_async_error(desc->inet.dport, id, caller, am_timeout); + return 1; } @@ -11605,10 +11608,10 @@ static int tcp_shutdown_error(tcp_descriptor* desc, int err) return tcp_send_or_shutdown_error(desc, err); } -static void tcp_inet_delay_send(ErlDrvData data, ErlDrvTermData dummy) +static int tcp_inet_delay_send(ErlDrvData data, ErlDrvTermData dummy) { tcp_descriptor *desc = (tcp_descriptor*)data; - (void)tcp_inet_output(desc, (HANDLE) INETP(desc)->s); + return tcp_inet_output(desc, (HANDLE) INETP(desc)->s); } /* @@ -13320,7 +13323,10 @@ static void fire_multi_timers(tcp_descriptor *desc, ErlDrvPort port, if (desc->mtd != NULL) desc->mtd->prev = NULL; - (*(save.timeout_function))(data,save.caller); + if ((*(save.timeout_function))(data,save.caller) < 0) + /* -1 means tcp_descriptor has been deallocated, + so we have to return as soon as possible */ + return; if (desc->mtd == NULL) return; @@ -13372,8 +13378,7 @@ static void remove_multi_timer(tcp_descriptor *desc, ErlDrvPort port, MultiTimer /* Cancel a timer based on the timeout_fun */ static void cancel_multi_timer(tcp_descriptor *desc, ErlDrvPort port, - void (*timeout_fun)(ErlDrvData drv_data, - ErlDrvTermData caller)) + MultiTimerFunction *timeout_fun) { MultiTimerData *timer = desc->mtd; while(timer && timer->timeout_function != timeout_fun) { @@ -13386,8 +13391,7 @@ static void cancel_multi_timer(tcp_descriptor *desc, ErlDrvPort port, static MultiTimerData *add_multi_timer(tcp_descriptor *desc, ErlDrvPort port, ErlDrvTermData caller, unsigned timeout, - void (*timeout_fun)(ErlDrvData drv_data, - ErlDrvTermData caller)) + MultiTimerFunction *timeout_fun) { MultiTimerData *mtd, *p, *s; diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 9f23ca5992..e6d875ca8d 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -6563,11 +6563,15 @@ delay_send_error(Config) -> ?LISTEN(Config, 0, [{reuseaddr, true}, {packet, 1}, {active, false}]), {ok,{{0,0,0,0},PortNum}}=inet:sockname(L), - ?P("try connect - with delay_send:true"), + + delay_send_error(Config, L, PortNum, false), + delay_send_error(Config, L, PortNum, true). +delay_send_error(Config, L, PortNum, Active) -> + ?P("try connect - with delay_send:true active:~p",[Active]), {ok, C} = ?CONNECT(Config, "localhost", PortNum, - [{packet, 1}, {active, false}, {delay_send, true}]), + [{packet, 1}, {active, Active}, {delay_send, true}]), ?P("try accept"), {ok, S} = gen_tcp:accept(L), %% Do a couple of sends first to see that it works @@ -6579,7 +6583,7 @@ delay_send_error(Config) -> ok = gen_tcp:send(C, "hello"), %% Close the receiver ?P("close receiver (accepted socket)"), - ok = gen_tcp:close(S), + ok = gen_tcp:shutdown(C, write), %% ?P("send data"), case gen_tcp:send(C, "hello") of -- 2.31.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor