Back to home page

LXR

 
 

    


0001 /*
0002  * Access kernel memory without faulting.
0003  */
0004 #include <linux/export.h>
0005 #include <linux/mm.h>
0006 #include <linux/uaccess.h>
0007 
0008 /**
0009  * probe_kernel_read(): safely attempt to read from a location
0010  * @dst: pointer to the buffer that shall take the data
0011  * @src: address to read from
0012  * @size: size of the data chunk
0013  *
0014  * Safely read from address @src to the buffer at @dst.  If a kernel fault
0015  * happens, handle that and return -EFAULT.
0016  *
0017  * We ensure that the copy_from_user is executed in atomic context so that
0018  * do_page_fault() doesn't attempt to take mmap_sem.  This makes
0019  * probe_kernel_read() suitable for use within regions where the caller
0020  * already holds mmap_sem, or other locks which nest inside mmap_sem.
0021  */
0022 
0023 long __weak probe_kernel_read(void *dst, const void *src, size_t size)
0024     __attribute__((alias("__probe_kernel_read")));
0025 
0026 long __probe_kernel_read(void *dst, const void *src, size_t size)
0027 {
0028     long ret;
0029     mm_segment_t old_fs = get_fs();
0030 
0031     set_fs(KERNEL_DS);
0032     pagefault_disable();
0033     ret = __copy_from_user_inatomic(dst,
0034             (__force const void __user *)src, size);
0035     pagefault_enable();
0036     set_fs(old_fs);
0037 
0038     return ret ? -EFAULT : 0;
0039 }
0040 EXPORT_SYMBOL_GPL(probe_kernel_read);
0041 
0042 /**
0043  * probe_kernel_write(): safely attempt to write to a location
0044  * @dst: address to write to
0045  * @src: pointer to the data that shall be written
0046  * @size: size of the data chunk
0047  *
0048  * Safely write to address @dst from the buffer at @src.  If a kernel fault
0049  * happens, handle that and return -EFAULT.
0050  */
0051 long __weak probe_kernel_write(void *dst, const void *src, size_t size)
0052     __attribute__((alias("__probe_kernel_write")));
0053 
0054 long __probe_kernel_write(void *dst, const void *src, size_t size)
0055 {
0056     long ret;
0057     mm_segment_t old_fs = get_fs();
0058 
0059     set_fs(KERNEL_DS);
0060     pagefault_disable();
0061     ret = __copy_to_user_inatomic((__force void __user *)dst, src, size);
0062     pagefault_enable();
0063     set_fs(old_fs);
0064 
0065     return ret ? -EFAULT : 0;
0066 }
0067 EXPORT_SYMBOL_GPL(probe_kernel_write);
0068 
0069 /**
0070  * strncpy_from_unsafe: - Copy a NUL terminated string from unsafe address.
0071  * @dst:   Destination address, in kernel space.  This buffer must be at
0072  *         least @count bytes long.
0073  * @src:   Unsafe address.
0074  * @count: Maximum number of bytes to copy, including the trailing NUL.
0075  *
0076  * Copies a NUL-terminated string from unsafe address to kernel buffer.
0077  *
0078  * On success, returns the length of the string INCLUDING the trailing NUL.
0079  *
0080  * If access fails, returns -EFAULT (some data may have been copied
0081  * and the trailing NUL added).
0082  *
0083  * If @count is smaller than the length of the string, copies @count-1 bytes,
0084  * sets the last byte of @dst buffer to NUL and returns @count.
0085  */
0086 long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count)
0087 {
0088     mm_segment_t old_fs = get_fs();
0089     const void *src = unsafe_addr;
0090     long ret;
0091 
0092     if (unlikely(count <= 0))
0093         return 0;
0094 
0095     set_fs(KERNEL_DS);
0096     pagefault_disable();
0097 
0098     do {
0099         ret = __get_user(*dst++, (const char __user __force *)src++);
0100     } while (dst[-1] && ret == 0 && src - unsafe_addr < count);
0101 
0102     dst[-1] = '\0';
0103     pagefault_enable();
0104     set_fs(old_fs);
0105 
0106     return ret ? -EFAULT : src - unsafe_addr;
0107 }