diff options
author | Alexei Starovoitov <ast@kernel.org> | 2019-11-02 12:39:13 -0700 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2019-11-02 12:45:15 -0700 |
commit | 358fdb456288d48874d44a064a82bfb0d9963fa0 (patch) | |
tree | 59237fefc66616b1656f1ade555b2365e8d89d88 /arch/x86/mm/maccess.c | |
parent | e1cb7d2d60d536baf24d2f0fd58786324ce92331 (diff) | |
parent | fa553d9b57d4a98a160d1926b4e263e7a78c0cf3 (diff) | |
download | linux-358fdb456288d48874d44a064a82bfb0d9963fa0.tar.gz linux-358fdb456288d48874d44a064a82bfb0d9963fa0.tar.bz2 linux-358fdb456288d48874d44a064a82bfb0d9963fa0.zip |
Merge branch 'bpf_probe_read_user'
Daniel Borkmann says:
====================
This set adds probe_read_{user,kernel}(), probe_read_str_{user,kernel}()
helpers, fixes probe_write_user() helper and selftests. For details please
see individual patches.
Thanks!
v2 -> v3:
- noticed two more things that are fixed in here:
- bpf uapi helper description used 'int size' for *_str helpers, now u32
- we need TASK_SIZE_MAX + guard page on x86-64 in patch 2 otherwise
we'll trigger the 00c42373d397 warn as well, so full range covered now
v1 -> v2:
- standardize unsafe_ptr terminology in uapi header comment (Andrii)
- probe_read_{user,kernel}[_str] naming scheme (Andrii)
- use global data in last test case, remove relaxed_maps (Andrii)
- add strict non-pagefault kernel read funcs to avoid warning in
kernel probe read helpers (Alexei)
====================
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'arch/x86/mm/maccess.c')
-rw-r--r-- | arch/x86/mm/maccess.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/arch/x86/mm/maccess.c b/arch/x86/mm/maccess.c new file mode 100644 index 000000000000..f5b85bdc0535 --- /dev/null +++ b/arch/x86/mm/maccess.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/uaccess.h> +#include <linux/kernel.h> + +#ifdef CONFIG_X86_64 +static __always_inline u64 canonical_address(u64 vaddr, u8 vaddr_bits) +{ + return ((s64)vaddr << (64 - vaddr_bits)) >> (64 - vaddr_bits); +} + +static __always_inline bool invalid_probe_range(u64 vaddr) +{ + /* + * Range covering the highest possible canonical userspace address + * as well as non-canonical address range. For the canonical range + * we also need to include the userspace guard page. + */ + return vaddr < TASK_SIZE_MAX + PAGE_SIZE || + canonical_address(vaddr, boot_cpu_data.x86_virt_bits) != vaddr; +} +#else +static __always_inline bool invalid_probe_range(u64 vaddr) +{ + return vaddr < TASK_SIZE_MAX; +} +#endif + +long probe_kernel_read_strict(void *dst, const void *src, size_t size) +{ + if (unlikely(invalid_probe_range((unsigned long)src))) + return -EFAULT; + + return __probe_kernel_read(dst, src, size); +} + +long strncpy_from_unsafe_strict(char *dst, const void *unsafe_addr, long count) +{ + if (unlikely(invalid_probe_range((unsigned long)unsafe_addr))) + return -EFAULT; + + return __strncpy_from_unsafe(dst, unsafe_addr, count); +} |