|
@@ -20,6 +20,8 @@
|
|
|
#include <linux/sched/task.h>
|
|
|
#include <linux/sched/task_stack.h>
|
|
|
#include <linux/thread_info.h>
|
|
|
+#include <linux/atomic.h>
|
|
|
+#include <linux/jump_label.h>
|
|
|
#include <asm/sections.h>
|
|
|
|
|
|
/*
|
|
@@ -240,6 +242,8 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static DEFINE_STATIC_KEY_FALSE_RO(bypass_usercopy_checks);
|
|
|
+
|
|
|
/*
|
|
|
* Validates that the given object is:
|
|
|
* - not bogus address
|
|
@@ -248,6 +252,9 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
|
|
|
*/
|
|
|
void __check_object_size(const void *ptr, unsigned long n, bool to_user)
|
|
|
{
|
|
|
+ if (static_branch_unlikely(&bypass_usercopy_checks))
|
|
|
+ return;
|
|
|
+
|
|
|
/* Skip all tests if size is zero. */
|
|
|
if (!n)
|
|
|
return;
|
|
@@ -279,3 +286,21 @@ void __check_object_size(const void *ptr, unsigned long n, bool to_user)
|
|
|
check_kernel_text_object((const unsigned long)ptr, n, to_user);
|
|
|
}
|
|
|
EXPORT_SYMBOL(__check_object_size);
|
|
|
+
|
|
|
+static bool enable_checks __initdata = true;
|
|
|
+
|
|
|
+static int __init parse_hardened_usercopy(char *str)
|
|
|
+{
|
|
|
+ return strtobool(str, &enable_checks);
|
|
|
+}
|
|
|
+
|
|
|
+__setup("hardened_usercopy=", parse_hardened_usercopy);
|
|
|
+
|
|
|
+static int __init set_hardened_usercopy(void)
|
|
|
+{
|
|
|
+ if (enable_checks == false)
|
|
|
+ static_branch_enable(&bypass_usercopy_checks);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+late_initcall(set_hardened_usercopy);
|