Wed, 2 Sep 2020 13:26:50 -0700
From: Tom Rix trix@redhat.com
clang static analysis flags this problem
stream.c:844:9: warning: Use of memory after it is freed kfree(bus->defer_msg.msg->buf); ^~~~~~~~~~~~~~~~~~~~~~~
This happens in an error handler cleaning up memory allocated for elements in a list.
list_for_each_entry(m_rt, &stream->master_list, stream_node) { bus = m_rt->bus;
kfree(bus->defer_msg.msg->buf); kfree(bus->defer_msg.msg);
}
And is triggered when the call to sdw_bank_switch() fails. There are a two problems.
First, when sdw_bank_switch() fails, though it frees memory it does not clear bus's reference 'defer_msg.msg' to that memory.
The second problem is the freeing msg->buf. In some cases msg will be NULL so this will dereference a null pointer. Need to check before freeing.
Fixes: 99b8a5d608a6 ("soundwire: Add bank switch routine") Signed-off-by: Tom Rix trix@redhat.com Reviewed-by: Nick Desaulniers ndesaulniers@google.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com
v2 : change title, was 'soundwire: fix error handling'
drivers/soundwire/stream.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 37290a799023..6e36deb505b1 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -717,6 +717,7 @@ static int sdw_bank_switch(struct sdw_bus *bus, int m_rt_count) kfree(wbuf); error_1: kfree(wr_msg);
- bus->defer_msg.msg = NULL; return ret;
}
@@ -840,9 +841,10 @@ static int do_bank_switch(struct sdw_stream_runtime *stream) error: list_for_each_entry(m_rt, &stream->master_list, stream_node) { bus = m_rt->bus;
kfree(bus->defer_msg.msg->buf);
kfree(bus->defer_msg.msg);
if (bus->defer_msg.msg) {
kfree(bus->defer_msg.msg->buf);
kfree(bus->defer_msg.msg);
}}
msg_unlock:
2.18.1
Looks like it needs also to release the current buf before putting the new one into place.
--- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -665,6 +665,10 @@ static int sdw_bank_switch(struct sdw_bu if (!wr_msg) return -ENOMEM;
+ if (bus->defer_msg.msg) { + kfree(bus->defer_msg.msg->buf); + kfree(bus->defer_msg.msg); + } bus->defer_msg.msg = wr_msg;
wbuf = kzalloc(sizeof(*wbuf), GFP_KERNEL);