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

Generated by: LCOV version 1.14