On Thu, Mar 26, 2020 at 3:44 PM Andrey Konovalov <andreyknvl@xxxxxxxxxx> wrote: > > If vmalloc() fails in kcov_remote_start() we'll access remote->kcov > without holding kcov_remote_lock, so remote might potentially be freed > at that point. Cache kcov pointer in a local variable. > > Signed-off-by: Andrey Konovalov <andreyknvl@xxxxxxxxxx> Reviewed-by: Dmitry Vyukov <dvyukov@xxxxxxxxxx> > --- > kernel/kcov.c | 14 ++++++++------ > 1 file changed, 8 insertions(+), 6 deletions(-) > > diff --git a/kernel/kcov.c b/kernel/kcov.c > index f6bd119c9419..cc5900ac2467 100644 > --- a/kernel/kcov.c > +++ b/kernel/kcov.c > @@ -748,6 +748,7 @@ static const struct file_operations kcov_fops = { > void kcov_remote_start(u64 handle) > { > struct kcov_remote *remote; > + struct kcov *kcov; > void *area; > struct task_struct *t; > unsigned int size; > @@ -774,16 +775,17 @@ void kcov_remote_start(u64 handle) > spin_unlock(&kcov_remote_lock); > return; > } > + kcov = remote->kcov; > /* Put in kcov_remote_stop(). */ > - kcov_get(remote->kcov); > - t->kcov = remote->kcov; > + kcov_get(kcov); > + t->kcov = kcov; > /* > * Read kcov fields before unlock to prevent races with > * KCOV_DISABLE / kcov_remote_reset(). > */ > - size = remote->kcov->remote_size; > - mode = remote->kcov->mode; > - sequence = remote->kcov->sequence; > + size = kcov->remote_size; > + mode = kcov->mode; > + sequence = kcov->sequence; > area = kcov_remote_area_get(size); > spin_unlock(&kcov_remote_lock); > > @@ -791,7 +793,7 @@ void kcov_remote_start(u64 handle) > area = vmalloc(size * sizeof(unsigned long)); > if (!area) { > t->kcov = NULL; > - kcov_put(remote->kcov); > + kcov_put(kcov); > return; > } > } > -- > 2.26.0.rc2.310.g2932bb562d-goog >