diff options
author | Karsten Graul <kgraul@linux.ibm.com> | 2020-10-14 19:43:27 +0200 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2020-10-15 09:54:43 -0700 |
commit | d535ca1367787ddc8bff22d679a11f864c8228bc (patch) | |
tree | d2993ff8994afb8d39cda0e156b0a669364b6f0c /net/smc/smc_llc.c | |
parent | 1d273fcc2c29343e59658276b77b02e5897a3123 (diff) | |
download | linux-d535ca1367787ddc8bff22d679a11f864c8228bc.tar.gz linux-d535ca1367787ddc8bff22d679a11f864c8228bc.tar.bz2 linux-d535ca1367787ddc8bff22d679a11f864c8228bc.zip |
net/smc: fix use-after-free of delayed events
When a delayed event is enqueued then the event worker will send this
event the next time it is running and no other flow is currently
active. The event handler is called for the delayed event, and the
pointer to the event keeps set in lgr->delayed_event. This pointer is
cleared later in the processing by smc_llc_flow_start().
This can lead to a use-after-free condition when the processing does not
reach smc_llc_flow_start(), but frees the event because of an error
situation. Then the delayed_event pointer is still set but the event is
freed.
Fix this by always clearing the delayed event pointer when the event is
provided to the event handler for processing, and remove the code to
clear it in smc_llc_flow_start().
Fixes: 555da9af827d ("net/smc: add event-based llc_flow framework")
Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/smc/smc_llc.c')
-rw-r--r-- | net/smc/smc_llc.c | 13 |
1 files changed, 5 insertions, 8 deletions
diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c index f5f6487bb847..5e86926c83a1 100644 --- a/net/smc/smc_llc.c +++ b/net/smc/smc_llc.c @@ -233,8 +233,6 @@ static bool smc_llc_flow_start(struct smc_llc_flow *flow, default: flow->type = SMC_LLC_FLOW_NONE; } - if (qentry == lgr->delayed_event) - lgr->delayed_event = NULL; smc_llc_flow_qentry_set(flow, qentry); spin_unlock_bh(&lgr->llc_flow_lock); return true; @@ -1603,13 +1601,12 @@ static void smc_llc_event_work(struct work_struct *work) struct smc_llc_qentry *qentry; if (!lgr->llc_flow_lcl.type && lgr->delayed_event) { - if (smc_link_usable(lgr->delayed_event->link)) { - smc_llc_event_handler(lgr->delayed_event); - } else { - qentry = lgr->delayed_event; - lgr->delayed_event = NULL; + qentry = lgr->delayed_event; + lgr->delayed_event = NULL; + if (smc_link_usable(qentry->link)) + smc_llc_event_handler(qentry); + else kfree(qentry); - } } again: |