From 06ccfa10c86f166c0a76475cc8ef2ea0baa87eec Mon Sep 17 00:00:00 2001 From: Palmer Dabbelt Date: Tue, 19 Jan 2021 16:47:34 -0800 Subject: [PATCH] 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 Signed-off-by: Palmer Dabbelt Change-Id: I510ac12e2206a836ae6659bd7d96c0542960b26a (cherry picked from commit 35f9e6bee13168655141057f8187b8b34c7543d9) --- drivers/md/dm-user.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/md/dm-user.c b/drivers/md/dm-user.c index b08fef011082..98fad9e9dd75 100644 --- a/drivers/md/dm-user.c +++ b/drivers/md/dm-user.c @@ -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 @@ int target_poll(struct target *t) 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 @@ struct channel *channel_alloc(struct target *t) void channel_free(struct channel *c) { - struct list_head *cur; + struct list_head *cur, *tmp; lockdep_assert_held(&c->lock); @@ -616,7 +616,7 @@ 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);