LCOV - code coverage report
Current view: top level - mm - maccess.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 71 0.0 %
Date: 2023-04-06 08:38:28 Functions: 0 9 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : /*
       3             :  * Access kernel or user memory without faulting.
       4             :  */
       5             : #include <linux/export.h>
       6             : #include <linux/mm.h>
       7             : #include <linux/uaccess.h>
       8             : 
       9           0 : bool __weak copy_from_kernel_nofault_allowed(const void *unsafe_src,
      10             :                 size_t size)
      11             : {
      12           0 :         return true;
      13             : }
      14             : 
      15             : #define copy_from_kernel_nofault_loop(dst, src, len, type, err_label)   \
      16             :         while (len >= sizeof(type)) {                                        \
      17             :                 __get_kernel_nofault(dst, src, type, err_label);                \
      18             :                 dst += sizeof(type);                                    \
      19             :                 src += sizeof(type);                                    \
      20             :                 len -= sizeof(type);                                    \
      21             :         }
      22             : 
      23           0 : long copy_from_kernel_nofault(void *dst, const void *src, size_t size)
      24             : {
      25           0 :         unsigned long align = 0;
      26             : 
      27             :         if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
      28           0 :                 align = (unsigned long)dst | (unsigned long)src;
      29             : 
      30           0 :         if (!copy_from_kernel_nofault_allowed(src, size))
      31             :                 return -ERANGE;
      32             : 
      33           0 :         pagefault_disable();
      34           0 :         if (!(align & 7))
      35           0 :                 copy_from_kernel_nofault_loop(dst, src, size, u64, Efault);
      36           0 :         if (!(align & 3))
      37           0 :                 copy_from_kernel_nofault_loop(dst, src, size, u32, Efault);
      38           0 :         if (!(align & 1))
      39           0 :                 copy_from_kernel_nofault_loop(dst, src, size, u16, Efault);
      40           0 :         copy_from_kernel_nofault_loop(dst, src, size, u8, Efault);
      41           0 :         pagefault_enable();
      42           0 :         return 0;
      43             : Efault:
      44             :         pagefault_enable();
      45             :         return -EFAULT;
      46             : }
      47             : EXPORT_SYMBOL_GPL(copy_from_kernel_nofault);
      48             : 
      49             : #define copy_to_kernel_nofault_loop(dst, src, len, type, err_label)     \
      50             :         while (len >= sizeof(type)) {                                        \
      51             :                 __put_kernel_nofault(dst, src, type, err_label);                \
      52             :                 dst += sizeof(type);                                    \
      53             :                 src += sizeof(type);                                    \
      54             :                 len -= sizeof(type);                                    \
      55             :         }
      56             : 
      57           0 : long copy_to_kernel_nofault(void *dst, const void *src, size_t size)
      58             : {
      59           0 :         unsigned long align = 0;
      60             : 
      61             :         if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
      62           0 :                 align = (unsigned long)dst | (unsigned long)src;
      63             : 
      64           0 :         pagefault_disable();
      65           0 :         if (!(align & 7))
      66           0 :                 copy_to_kernel_nofault_loop(dst, src, size, u64, Efault);
      67           0 :         if (!(align & 3))
      68           0 :                 copy_to_kernel_nofault_loop(dst, src, size, u32, Efault);
      69           0 :         if (!(align & 1))
      70           0 :                 copy_to_kernel_nofault_loop(dst, src, size, u16, Efault);
      71           0 :         copy_to_kernel_nofault_loop(dst, src, size, u8, Efault);
      72           0 :         pagefault_enable();
      73             :         return 0;
      74             : Efault:
      75             :         pagefault_enable();
      76             :         return -EFAULT;
      77             : }
      78             : 
      79           0 : long strncpy_from_kernel_nofault(char *dst, const void *unsafe_addr, long count)
      80             : {
      81           0 :         const void *src = unsafe_addr;
      82             : 
      83           0 :         if (unlikely(count <= 0))
      84             :                 return 0;
      85           0 :         if (!copy_from_kernel_nofault_allowed(unsafe_addr, count))
      86             :                 return -ERANGE;
      87             : 
      88             :         pagefault_disable();
      89             :         do {
      90           0 :                 __get_kernel_nofault(dst, src, u8, Efault);
      91           0 :                 dst++;
      92           0 :                 src++;
      93           0 :         } while (dst[-1] && src - unsafe_addr < count);
      94           0 :         pagefault_enable();
      95             : 
      96           0 :         dst[-1] = '\0';
      97           0 :         return src - unsafe_addr;
      98             : Efault:
      99             :         pagefault_enable();
     100             :         dst[0] = '\0';
     101             :         return -EFAULT;
     102             : }
     103             : 
     104             : /**
     105             :  * copy_from_user_nofault(): safely attempt to read from a user-space location
     106             :  * @dst: pointer to the buffer that shall take the data
     107             :  * @src: address to read from. This must be a user address.
     108             :  * @size: size of the data chunk
     109             :  *
     110             :  * Safely read from user address @src to the buffer at @dst. If a kernel fault
     111             :  * happens, handle that and return -EFAULT.
     112             :  */
     113           0 : long copy_from_user_nofault(void *dst, const void __user *src, size_t size)
     114             : {
     115           0 :         long ret = -EFAULT;
     116           0 :         if (access_ok(src, size)) {
     117           0 :                 pagefault_disable();
     118           0 :                 ret = __copy_from_user_inatomic(dst, src, size);
     119             :                 pagefault_enable();
     120             :         }
     121             : 
     122           0 :         if (ret)
     123             :                 return -EFAULT;
     124           0 :         return 0;
     125             : }
     126             : EXPORT_SYMBOL_GPL(copy_from_user_nofault);
     127             : 
     128             : /**
     129             :  * copy_to_user_nofault(): safely attempt to write to a user-space location
     130             :  * @dst: address to write to
     131             :  * @src: pointer to the data that shall be written
     132             :  * @size: size of the data chunk
     133             :  *
     134             :  * Safely write to address @dst from the buffer at @src.  If a kernel fault
     135             :  * happens, handle that and return -EFAULT.
     136             :  */
     137           0 : long copy_to_user_nofault(void __user *dst, const void *src, size_t size)
     138             : {
     139           0 :         long ret = -EFAULT;
     140             : 
     141           0 :         if (access_ok(dst, size)) {
     142           0 :                 pagefault_disable();
     143           0 :                 ret = __copy_to_user_inatomic(dst, src, size);
     144             :                 pagefault_enable();
     145             :         }
     146             : 
     147           0 :         if (ret)
     148             :                 return -EFAULT;
     149           0 :         return 0;
     150             : }
     151             : EXPORT_SYMBOL_GPL(copy_to_user_nofault);
     152             : 
     153             : /**
     154             :  * strncpy_from_user_nofault: - Copy a NUL terminated string from unsafe user
     155             :  *                              address.
     156             :  * @dst:   Destination address, in kernel space.  This buffer must be at
     157             :  *         least @count bytes long.
     158             :  * @unsafe_addr: Unsafe user address.
     159             :  * @count: Maximum number of bytes to copy, including the trailing NUL.
     160             :  *
     161             :  * Copies a NUL-terminated string from unsafe user address to kernel buffer.
     162             :  *
     163             :  * On success, returns the length of the string INCLUDING the trailing NUL.
     164             :  *
     165             :  * If access fails, returns -EFAULT (some data may have been copied
     166             :  * and the trailing NUL added).
     167             :  *
     168             :  * If @count is smaller than the length of the string, copies @count-1 bytes,
     169             :  * sets the last byte of @dst buffer to NUL and returns @count.
     170             :  */
     171           0 : long strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
     172             :                               long count)
     173             : {
     174             :         long ret;
     175             : 
     176           0 :         if (unlikely(count <= 0))
     177             :                 return 0;
     178             : 
     179           0 :         pagefault_disable();
     180           0 :         ret = strncpy_from_user(dst, unsafe_addr, count);
     181           0 :         pagefault_enable();
     182             : 
     183           0 :         if (ret >= count) {
     184           0 :                 ret = count;
     185           0 :                 dst[ret - 1] = '\0';
     186           0 :         } else if (ret > 0) {
     187           0 :                 ret++;
     188             :         }
     189             : 
     190             :         return ret;
     191             : }
     192             : 
     193             : /**
     194             :  * strnlen_user_nofault: - Get the size of a user string INCLUDING final NUL.
     195             :  * @unsafe_addr: The string to measure.
     196             :  * @count: Maximum count (including NUL)
     197             :  *
     198             :  * Get the size of a NUL-terminated string in user space without pagefault.
     199             :  *
     200             :  * Returns the size of the string INCLUDING the terminating NUL.
     201             :  *
     202             :  * If the string is too long, returns a number larger than @count. User
     203             :  * has to check the return value against "> count".
     204             :  * On exception (or invalid count), returns 0.
     205             :  *
     206             :  * Unlike strnlen_user, this can be used from IRQ handler etc. because
     207             :  * it disables pagefaults.
     208             :  */
     209           0 : long strnlen_user_nofault(const void __user *unsafe_addr, long count)
     210             : {
     211             :         int ret;
     212             : 
     213           0 :         pagefault_disable();
     214           0 :         ret = strnlen_user(unsafe_addr, count);
     215           0 :         pagefault_enable();
     216             : 
     217           0 :         return ret;
     218             : }
     219             : 
     220           0 : void __copy_overflow(int size, unsigned long count)
     221             : {
     222           0 :         WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count);
     223           0 : }
     224             : EXPORT_SYMBOL(__copy_overflow);

Generated by: LCOV version 1.14