diff options
author | Andrey Konovalov <[email protected]> | 2020-06-04 16:45:51 -0700 |
---|---|---|
committer | Linus Torvalds <[email protected]> | 2020-06-04 19:06:20 -0700 |
commit | 67b3d3cca385507c4c8b6ad97b823415e038e3c8 (patch) | |
tree | c5ccb706f67e0ebb63d978e30e0be771b31dcd47 | |
parent | 3c61df3885e91f8737bbbbaba79b908da0e1919f (diff) |
kcov: fix potential use-after-free in kcov_remote_start
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 <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Reviewed-by: Dmitry Vyukov <[email protected]>
Cc: Alan Stern <[email protected]>
Cc: Alexander Potapenko <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Marco Elver <[email protected]>
Cc: Andrey Konovalov <[email protected]>
Link: http://lkml.kernel.org/r/9d9134359725a965627b7e8f2652069f86f1d1fa.1585233617.git.andreyknvl@google.com
Link: http://lkml.kernel.org/r/de0d3d30ff90776a2a509cc34c7c1c7521bda125.1584655448.git.andreyknvl@google.com
Signed-off-by: Linus Torvalds <[email protected]>
-rw-r--r-- | kernel/kcov.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/kernel/kcov.c b/kernel/kcov.c index e6bb2b50569f..14e7208c5291 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; } } |