Changes in 4.9.236 HID: core: Correctly handle ReportSize being zero HID: core: Sanitize event code and type when mapping input perf record/stat: Explicitly call out event modifiers in the documentation hwmon: (applesmc) check status earlier. nvmet: Disable keep-alive timer when kato is cleared to 0h ceph: don't allow setlease on cephfs s390: don't trace preemption in percpu macros xen/xenbus: Fix granting of vmalloc'd memory dmaengine: of-dma: Fix of_dma_router_xlate's of_dma_xlate handling batman-adv: Avoid uninitialized chaddr when handling DHCP batman-adv: bla: use netif_rx_ni when not in interrupt context dmaengine: at_hdmac: check return value of of_find_device_by_node() in at_dma_xlate() MIPS: mm: BMIPS5000 has inclusive physical caches MIPS: BMIPS: Also call bmips_cpu_setup() for secondary cores netfilter: nf_tables: add NFTA_SET_USERDATA if not null netfilter: nf_tables: incorrect enum nft_list_attributes definition netfilter: nf_tables: fix destination register zeroing net: hns: Fix memleak in hns_nic_dev_probe ravb: Fixed to be able to unload modules net: arc_emac: Fix memleak in arc_mdio_probe dmaengine: pl330: Fix burst length if burst size is smaller than bus width bnxt_en: Check for zero dir entries in NVRAM. bnxt_en: Fix PCI AER error recovery flow fix regression in "epoll: Keep a reference on files added to the check list" tg3: Fix soft lockup when tg3_reset_task() fails. iommu/vt-d: Serialize IOMMU GCMD register modifications thermal: ti-soc-thermal: Fix bogus thermal shutdowns for omap4430 include/linux/log2.h: add missing () around n in roundup_pow_of_two() btrfs: drop path before adding new uuid tree entry btrfs: Remove redundant extent_buffer_get in get_old_root btrfs: Remove extraneous extent_buffer_get from tree_mod_log_rewind btrfs: set the lockdep class for log tree extent buffers uaccess: Add non-pagefault user-space read functions uaccess: Add non-pagefault user-space write function btrfs: fix potential deadlock in the search ioctl net: usb: qmi_wwan: add Telit 0x1050 composition drivers: net: usb: qmi_wwan: add QMI_QUIRK_SET_DTR for Telit PID 0x1201 qmi_wwan: new Telewell and Sierra device IDs usb: qmi_wwan: add D-Link DWM-222 A2 device ID ALSA: ca0106: fix error code handling ALSA: pcm: oss: Remove superfluous WARN_ON() for mulaw sanity check ALSA: firewire-digi00x: exclude Avid Adrenaline from detection block: allow for_each_bvec to support zero len bvec block: Move SECTOR_SIZE and SECTOR_SHIFT definitions into <linux/blkdev.h> libata: implement ATA_HORKAGE_MAX_TRIM_128M and apply to Sandisks dm cache metadata: Avoid returning cmd->bm wild pointer on error dm thin metadata: Avoid returning cmd->bm wild pointer on error mm: slub: fix conversion of freelist_corrupted() vfio/type1: Support faulting PFNMAP vmas vfio-pci: Fault mmaps to enable vma tracking vfio-pci: Invalidate mmaps and block MMIO access on disabled memory KVM: arm64: Add kvm_extable for vaxorcism code KVM: arm64: Defer guest entry when an asynchronous exception is pending KVM: arm64: Survive synchronous exceptions caused by AT instructions KVM: arm64: Set HCR_EL2.PTW to prevent AT taking synchronous exception net: refactor bind_bucket fastreuse into helper net: initialize fastreuse on inet_inherit_port vfio/pci: Fix SR-IOV VF handling with MMIO blocking checkpatch: fix the usage of capture group ( ... ) mm/hugetlb: fix a race between hugetlb sysctl handlers cfg80211: regulatory: reject invalid hints net: usb: Fix uninit-was-stored issue in asix_read_phy_addr() ALSA; firewire-tascam: exclude Tascam FE-8 from detection fs/affs: use octal for permissions affs: fix basic permission bits to actually work net: ethernet: mlx4: Fix memory allocation in mlx4_buddy_init() bnxt: don't enable NAPI until rings are ready netlabel: fix problems with mapping removal sctp: not disable bh in the whole sctp_get_port_local() net: disable netpoll on fresh napis Linux 4.9.236 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I707909fadc45a09f6ecdacb81a294421af163664
255 lines
6.8 KiB
C
255 lines
6.8 KiB
C
/*
|
|
* Access kernel memory without faulting.
|
|
*/
|
|
#include <linux/export.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/uaccess.h>
|
|
|
|
static __always_inline long
|
|
probe_read_common(void *dst, const void __user *src, size_t size)
|
|
{
|
|
long ret;
|
|
|
|
pagefault_disable();
|
|
ret = __copy_from_user_inatomic(dst, src, size);
|
|
pagefault_enable();
|
|
|
|
return ret ? -EFAULT : 0;
|
|
}
|
|
|
|
static __always_inline long
|
|
probe_write_common(void __user *dst, const void *src, size_t size)
|
|
{
|
|
long ret;
|
|
|
|
pagefault_disable();
|
|
ret = __copy_to_user_inatomic(dst, src, size);
|
|
pagefault_enable();
|
|
|
|
return ret ? -EFAULT : 0;
|
|
}
|
|
|
|
/**
|
|
* probe_kernel_read(): safely attempt to read from a kernel-space location
|
|
* @dst: pointer to the buffer that shall take the data
|
|
* @src: address to read from
|
|
* @size: size of the data chunk
|
|
*
|
|
* Safely read from address @src to the buffer at @dst. If a kernel fault
|
|
* happens, handle that and return -EFAULT.
|
|
*
|
|
* We ensure that the copy_from_user is executed in atomic context so that
|
|
* do_page_fault() doesn't attempt to take mmap_sem. This makes
|
|
* probe_kernel_read() suitable for use within regions where the caller
|
|
* already holds mmap_sem, or other locks which nest inside mmap_sem.
|
|
*/
|
|
|
|
long __weak probe_kernel_read(void *dst, const void *src, size_t size)
|
|
__attribute__((alias("__probe_kernel_read")));
|
|
|
|
long __probe_kernel_read(void *dst, const void *src, size_t size)
|
|
{
|
|
long ret;
|
|
mm_segment_t old_fs = get_fs();
|
|
|
|
set_fs(KERNEL_DS);
|
|
ret = probe_read_common(dst, (__force const void __user *)src, size);
|
|
set_fs(old_fs);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(probe_kernel_read);
|
|
|
|
/**
|
|
* probe_user_read(): safely attempt to read from a user-space location
|
|
* @dst: pointer to the buffer that shall take the data
|
|
* @src: address to read from. This must be a user address.
|
|
* @size: size of the data chunk
|
|
*
|
|
* Safely read from user address @src to the buffer at @dst. If a kernel fault
|
|
* happens, handle that and return -EFAULT.
|
|
*/
|
|
|
|
long __weak probe_user_read(void *dst, const void __user *src, size_t size)
|
|
__attribute__((alias("__probe_user_read")));
|
|
|
|
long __probe_user_read(void *dst, const void __user *src, size_t size)
|
|
{
|
|
long ret = -EFAULT;
|
|
mm_segment_t old_fs = get_fs();
|
|
|
|
set_fs(USER_DS);
|
|
if (access_ok(VERIFY_READ, src, size))
|
|
ret = probe_read_common(dst, src, size);
|
|
set_fs(old_fs);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(probe_user_read);
|
|
|
|
/**
|
|
* probe_kernel_write(): safely attempt to write to a location
|
|
* @dst: address to write to
|
|
* @src: pointer to the data that shall be written
|
|
* @size: size of the data chunk
|
|
*
|
|
* Safely write to address @dst from the buffer at @src. If a kernel fault
|
|
* happens, handle that and return -EFAULT.
|
|
*/
|
|
|
|
long __weak probe_kernel_write(void *dst, const void *src, size_t size)
|
|
__attribute__((alias("__probe_kernel_write")));
|
|
|
|
long __probe_kernel_write(void *dst, const void *src, size_t size)
|
|
{
|
|
long ret;
|
|
mm_segment_t old_fs = get_fs();
|
|
|
|
set_fs(KERNEL_DS);
|
|
ret = probe_write_common((__force void __user *)dst, src, size);
|
|
set_fs(old_fs);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(probe_kernel_write);
|
|
|
|
/**
|
|
* probe_user_write(): safely attempt to write to a user-space location
|
|
* @dst: address to write to
|
|
* @src: pointer to the data that shall be written
|
|
* @size: size of the data chunk
|
|
*
|
|
* Safely write to address @dst from the buffer at @src. If a kernel fault
|
|
* happens, handle that and return -EFAULT.
|
|
*/
|
|
|
|
long __weak probe_user_write(void __user *dst, const void *src, size_t size)
|
|
__attribute__((alias("__probe_user_write")));
|
|
|
|
long __probe_user_write(void __user *dst, const void *src, size_t size)
|
|
{
|
|
long ret = -EFAULT;
|
|
mm_segment_t old_fs = get_fs();
|
|
|
|
set_fs(USER_DS);
|
|
if (access_ok(VERIFY_WRITE, dst, size))
|
|
ret = probe_write_common(dst, src, size);
|
|
set_fs(old_fs);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(probe_user_write);
|
|
|
|
/**
|
|
* strncpy_from_unsafe: - Copy a NUL terminated string from unsafe address.
|
|
* @dst: Destination address, in kernel space. This buffer must be at
|
|
* least @count bytes long.
|
|
* @src: Unsafe address.
|
|
* @count: Maximum number of bytes to copy, including the trailing NUL.
|
|
*
|
|
* Copies a NUL-terminated string from unsafe address to kernel buffer.
|
|
*
|
|
* On success, returns the length of the string INCLUDING the trailing NUL.
|
|
*
|
|
* If access fails, returns -EFAULT (some data may have been copied
|
|
* and the trailing NUL added).
|
|
*
|
|
* If @count is smaller than the length of the string, copies @count-1 bytes,
|
|
* sets the last byte of @dst buffer to NUL and returns @count.
|
|
*/
|
|
long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count)
|
|
{
|
|
mm_segment_t old_fs = get_fs();
|
|
const void *src = unsafe_addr;
|
|
long ret;
|
|
|
|
if (unlikely(count <= 0))
|
|
return 0;
|
|
|
|
set_fs(KERNEL_DS);
|
|
pagefault_disable();
|
|
|
|
do {
|
|
ret = __get_user(*dst++, (const char __user __force *)src++);
|
|
} while (dst[-1] && ret == 0 && src - unsafe_addr < count);
|
|
|
|
dst[-1] = '\0';
|
|
pagefault_enable();
|
|
set_fs(old_fs);
|
|
|
|
return ret ? -EFAULT : src - unsafe_addr;
|
|
}
|
|
|
|
/**
|
|
* strncpy_from_unsafe_user: - Copy a NUL terminated string from unsafe user
|
|
* address.
|
|
* @dst: Destination address, in kernel space. This buffer must be at
|
|
* least @count bytes long.
|
|
* @unsafe_addr: Unsafe user address.
|
|
* @count: Maximum number of bytes to copy, including the trailing NUL.
|
|
*
|
|
* Copies a NUL-terminated string from unsafe user address to kernel buffer.
|
|
*
|
|
* On success, returns the length of the string INCLUDING the trailing NUL.
|
|
*
|
|
* If access fails, returns -EFAULT (some data may have been copied
|
|
* and the trailing NUL added).
|
|
*
|
|
* If @count is smaller than the length of the string, copies @count-1 bytes,
|
|
* sets the last byte of @dst buffer to NUL and returns @count.
|
|
*/
|
|
long strncpy_from_unsafe_user(char *dst, const void __user *unsafe_addr,
|
|
long count)
|
|
{
|
|
mm_segment_t old_fs = get_fs();
|
|
long ret;
|
|
|
|
if (unlikely(count <= 0))
|
|
return 0;
|
|
|
|
set_fs(USER_DS);
|
|
pagefault_disable();
|
|
ret = strncpy_from_user(dst, unsafe_addr, count);
|
|
pagefault_enable();
|
|
set_fs(old_fs);
|
|
|
|
if (ret >= count) {
|
|
ret = count;
|
|
dst[ret - 1] = '\0';
|
|
} else if (ret > 0) {
|
|
ret++;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* strnlen_unsafe_user: - Get the size of a user string INCLUDING final NUL.
|
|
* @unsafe_addr: The string to measure.
|
|
* @count: Maximum count (including NUL)
|
|
*
|
|
* Get the size of a NUL-terminated string in user space without pagefault.
|
|
*
|
|
* Returns the size of the string INCLUDING the terminating NUL.
|
|
*
|
|
* If the string is too long, returns a number larger than @count. User
|
|
* has to check the return value against "> count".
|
|
* On exception (or invalid count), returns 0.
|
|
*
|
|
* Unlike strnlen_user, this can be used from IRQ handler etc. because
|
|
* it disables pagefaults.
|
|
*/
|
|
long strnlen_unsafe_user(const void __user *unsafe_addr, long count)
|
|
{
|
|
mm_segment_t old_fs = get_fs();
|
|
int ret;
|
|
|
|
set_fs(USER_DS);
|
|
pagefault_disable();
|
|
ret = strnlen_user(unsafe_addr, count);
|
|
pagefault_enable();
|
|
set_fs(old_fs);
|
|
|
|
return ret;
|
|
}
|