Wed, 2 Sep 2020 13:26:50 -0700 > From: Tom Rix <trix@xxxxxxxxxx> > > 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@xxxxxxxxxx> > Reviewed-by: Nick Desaulniers <ndesaulniers@xxxxxxxxxx> > Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@xxxxxxxxxxxxxxx> > --- > 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);