summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorCatalin Marinas <catalin.marinas@arm.com>2016-11-02 00:43:25 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-11-10 17:34:56 +0300
commitfcd35857d66201b28b3ab158258e88ca7749fcb7 (patch)
tree4b78cdcb7fb7ea801260ae4b70bba47c918847dd /drivers/misc
parent052662cada1f2104dedfab68866e403a508e045c (diff)
downloadlinux-fcd35857d66201b28b3ab158258e88ca7749fcb7.tar.xz
lkdtm: Do not use flush_icache_range() on user addresses
The flush_icache_range() API is meant to be used on kernel addresses only as it may not have the infrastructure (exception entries) to handle user memory faults. The lkdtm execute_user_location() function tests the kernel execution of user space addresses by mmap'ing an anonymous page, copying some code together with cache maintenance and attempting to run it. However, the cache maintenance step may fail because of the incorrect API usage described above. The patch changes lkdtm to use access_process_vm() for copying the code into user space which would take care of the necessary cache maintenance. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> [kees: export access_process_vm() for module use] Signed-off-by: Kees Cook <keescook@chromium.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/lkdtm_perms.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/drivers/misc/lkdtm_perms.c b/drivers/misc/lkdtm_perms.c
index 45f1c0f96612..c7635a79341f 100644
--- a/drivers/misc/lkdtm_perms.c
+++ b/drivers/misc/lkdtm_perms.c
@@ -60,15 +60,18 @@ static noinline void execute_location(void *dst, bool write)
static void execute_user_location(void *dst)
{
+ int copied;
+
/* Intentionally crossing kernel/user memory boundary. */
void (*func)(void) = dst;
pr_info("attempting ok execution at %p\n", do_nothing);
do_nothing();
- if (copy_to_user((void __user *)dst, do_nothing, EXEC_SIZE))
+ copied = access_process_vm(current, (unsigned long)dst, do_nothing,
+ EXEC_SIZE, FOLL_WRITE);
+ if (copied < EXEC_SIZE)
return;
- flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE);
pr_info("attempting bad execution at %p\n", func);
func();
}