162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <linux/uaccess.h>
462306a36Sopenharmony_ci#include <linux/kernel.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <asm/vsyscall.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#ifdef CONFIG_X86_64
962306a36Sopenharmony_cibool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size)
1062306a36Sopenharmony_ci{
1162306a36Sopenharmony_ci	unsigned long vaddr = (unsigned long)unsafe_src;
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci	/*
1462306a36Sopenharmony_ci	 * Do not allow userspace addresses.  This disallows
1562306a36Sopenharmony_ci	 * normal userspace and the userspace guard page:
1662306a36Sopenharmony_ci	 */
1762306a36Sopenharmony_ci	if (vaddr < TASK_SIZE_MAX + PAGE_SIZE)
1862306a36Sopenharmony_ci		return false;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	/*
2162306a36Sopenharmony_ci	 * Reading from the vsyscall page may cause an unhandled fault in
2262306a36Sopenharmony_ci	 * certain cases.  Though it is at an address above TASK_SIZE_MAX, it is
2362306a36Sopenharmony_ci	 * usually considered as a user space address.
2462306a36Sopenharmony_ci	 */
2562306a36Sopenharmony_ci	if (is_vsyscall_vaddr(vaddr))
2662306a36Sopenharmony_ci		return false;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	/*
2962306a36Sopenharmony_ci	 * Allow everything during early boot before 'x86_virt_bits'
3062306a36Sopenharmony_ci	 * is initialized.  Needed for instruction decoding in early
3162306a36Sopenharmony_ci	 * exception handlers.
3262306a36Sopenharmony_ci	 */
3362306a36Sopenharmony_ci	if (!boot_cpu_data.x86_virt_bits)
3462306a36Sopenharmony_ci		return true;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	return __is_canonical_address(vaddr, boot_cpu_data.x86_virt_bits);
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci#else
3962306a36Sopenharmony_cibool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	return (unsigned long)unsafe_src >= TASK_SIZE_MAX;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci#endif
44