ANDROID: dm-user: Fix the list walk-and-delete code

This needs list_for_each_safe, without which we have a use-after-free
bug when updating the next pointer.

Fixes: 83bf345abc0b ("ANDROID: dm: dm-user: New target that proxies BIOs to userspace")
Suggested-by: Akilesh Kailash <akailash@google.com>
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
Change-Id: I510ac12e2206a836ae6659bd7d96c0542960b26a
(cherry picked from commit 35f9e6bee13168655141057f8187b8b34c7543d9)
This commit is contained in:
Palmer Dabbelt 2021-01-19 16:47:34 -08:00
parent ea0aa59740
commit 9bd91249d2

View File

@ -507,11 +507,11 @@ static struct message *msg_get_to_user(struct target *t)
static struct message *msg_get_from_user(struct channel *c, u64 seq)
{
struct message *m;
struct list_head *cur;
struct list_head *cur, *tmp;
lockdep_assert_held(&c->lock);
list_for_each (cur, &c->from_user) {
list_for_each_safe (cur, tmp, &c->from_user) {
m = list_entry(cur, struct message, from_user);
if (m->msg.seq == seq) {
list_del(&m->from_user);
@ -544,14 +544,14 @@ static int target_poll(struct target *t)
static void target_release(struct kref *ref)
{
struct target *t = container_of(ref, struct target, references);
struct list_head *cur;
struct list_head *cur, *tmp;
/*
* There may be outstanding BIOs that have not yet been given to
* userspace. At this point there's nothing we can do about them, as
* there are and will never be any channels.
*/
list_for_each (cur, &t->to_user) {
list_for_each_safe (cur, tmp, &t->to_user) {
message_kill(list_entry(cur, struct message, to_user),
&t->message_pool);
}
@ -595,7 +595,7 @@ static struct channel *channel_alloc(struct target *t)
static void channel_free(struct channel *c)
{
struct list_head *cur;
struct list_head *cur, *tmp;
lockdep_assert_held(&c->lock);
@ -616,7 +616,7 @@ static void channel_free(struct channel *c)
message_kill(c->cur_to_user, &c->target->message_pool);
if (c->cur_from_user != &c->scratch_message_from_user)
message_kill(c->cur_from_user, &c->target->message_pool);
list_for_each (cur, &c->from_user)
list_for_each_safe (cur, tmp, &c->from_user)
message_kill(list_entry(cur, struct message, from_user),
&c->target->message_pool);