summaryrefslogtreecommitdiffstats
path: root/net/smc
diff options
context:
space:
mode:
authorKarsten Graul <kgraul@linux.ibm.com>2020-10-14 19:43:27 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-10-29 10:10:51 +0100
commit3d1b5d3c4da7426dcc11ae9a9ea1247dec255bfb (patch)
treea69938b9609d33091249be9d810852c68ea5bd23 /net/smc
parentea4f9b89ca785d702c403f6f1621d7e427190d3a (diff)
downloadlinux-stable-3d1b5d3c4da7426dcc11ae9a9ea1247dec255bfb.tar.gz
linux-stable-3d1b5d3c4da7426dcc11ae9a9ea1247dec255bfb.tar.bz2
linux-stable-3d1b5d3c4da7426dcc11ae9a9ea1247dec255bfb.zip
net/smc: fix use-after-free of delayed events
[ Upstream commit d535ca1367787ddc8bff22d679a11f864c8228bc ] 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net/smc')
-rw-r--r--net/smc/smc_llc.c13
1 files changed, 5 insertions, 8 deletions
diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c
index 3ea33466ebe9..da9332de26c5 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: