LCOV - code coverage report
Current view: top level - mm - maccess.c (source / functions) Hit Total Coverage
Test: Real Lines: 12 40 30.0 %
Date: 2020-10-17 15:46:43 Functions: 0 7 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Access kernel memory without faulting.
       4                 :            :  */
       5                 :            : #include <linux/export.h>
       6                 :            : #include <linux/mm.h>
       7                 :            : #include <linux/uaccess.h>
       8                 :            : 
       9                 :            : static __always_inline long
      10                 :            : probe_read_common(void *dst, const void __user *src, size_t size)
      11                 :            : {
      12                 :            :         long ret;
      13                 :            : 
      14                 :          3 :         pagefault_disable();
      15                 :            :         ret = __copy_from_user_inatomic(dst, src, size);
      16                 :          3 :         pagefault_enable();
      17                 :            : 
      18                 :          3 :         return ret ? -EFAULT : 0;
      19                 :            : }
      20                 :            : 
      21                 :            : static __always_inline long
      22                 :            : probe_write_common(void __user *dst, const void *src, size_t size)
      23                 :            : {
      24                 :            :         long ret;
      25                 :            : 
      26                 :          3 :         pagefault_disable();
      27                 :            :         ret = __copy_to_user_inatomic(dst, src, size);
      28                 :          3 :         pagefault_enable();
      29                 :            : 
      30                 :          3 :         return ret ? -EFAULT : 0;
      31                 :            : }
      32                 :            : 
      33                 :            : /**
      34                 :            :  * probe_kernel_read(): safely attempt to read from a kernel-space location
      35                 :            :  * @dst: pointer to the buffer that shall take the data
      36                 :            :  * @src: address to read from
      37                 :            :  * @size: size of the data chunk
      38                 :            :  *
      39                 :            :  * Safely read from address @src to the buffer at @dst.  If a kernel fault
      40                 :            :  * happens, handle that and return -EFAULT.
      41                 :            :  *
      42                 :            :  * We ensure that the copy_from_user is executed in atomic context so that
      43                 :            :  * do_page_fault() doesn't attempt to take mmap_sem.  This makes
      44                 :            :  * probe_kernel_read() suitable for use within regions where the caller
      45                 :            :  * already holds mmap_sem, or other locks which nest inside mmap_sem.
      46                 :            :  */
      47                 :            : 
      48                 :            : long __weak probe_kernel_read(void *dst, const void *src, size_t size)
      49                 :            :     __attribute__((alias("__probe_kernel_read")));
      50                 :            : 
      51                 :          3 : long __probe_kernel_read(void *dst, const void *src, size_t size)
      52                 :            : {
      53                 :            :         long ret;
      54                 :          3 :         mm_segment_t old_fs = get_fs();
      55                 :            : 
      56                 :            :         set_fs(KERNEL_DS);
      57                 :            :         ret = probe_read_common(dst, (__force const void __user *)src, size);
      58                 :            :         set_fs(old_fs);
      59                 :            : 
      60                 :          3 :         return ret;
      61                 :            : }
      62                 :            : EXPORT_SYMBOL_GPL(probe_kernel_read);
      63                 :            : 
      64                 :            : /**
      65                 :            :  * probe_user_read(): safely attempt to read from a user-space location
      66                 :            :  * @dst: pointer to the buffer that shall take the data
      67                 :            :  * @src: address to read from. This must be a user address.
      68                 :            :  * @size: size of the data chunk
      69                 :            :  *
      70                 :            :  * Safely read from user address @src to the buffer at @dst. If a kernel fault
      71                 :            :  * happens, handle that and return -EFAULT.
      72                 :            :  */
      73                 :            : 
      74                 :            : long __weak probe_user_read(void *dst, const void __user *src, size_t size)
      75                 :            :     __attribute__((alias("__probe_user_read")));
      76                 :            : 
      77                 :          0 : long __probe_user_read(void *dst, const void __user *src, size_t size)
      78                 :            : {
      79                 :            :         long ret = -EFAULT;
      80                 :          0 :         mm_segment_t old_fs = get_fs();
      81                 :            : 
      82                 :            :         set_fs(USER_DS);
      83                 :          0 :         if (access_ok(src, size))
      84                 :            :                 ret = probe_read_common(dst, src, size);
      85                 :            :         set_fs(old_fs);
      86                 :            : 
      87                 :          0 :         return ret;
      88                 :            : }
      89                 :            : EXPORT_SYMBOL_GPL(probe_user_read);
      90                 :            : 
      91                 :            : /**
      92                 :            :  * probe_kernel_write(): safely attempt to write to a location
      93                 :            :  * @dst: address to write to
      94                 :            :  * @src: pointer to the data that shall be written
      95                 :            :  * @size: size of the data chunk
      96                 :            :  *
      97                 :            :  * Safely write to address @dst from the buffer at @src.  If a kernel fault
      98                 :            :  * happens, handle that and return -EFAULT.
      99                 :            :  */
     100                 :            : 
     101                 :            : long __weak probe_kernel_write(void *dst, const void *src, size_t size)
     102                 :            :     __attribute__((alias("__probe_kernel_write")));
     103                 :            : 
     104                 :          3 : long __probe_kernel_write(void *dst, const void *src, size_t size)
     105                 :            : {
     106                 :            :         long ret;
     107                 :          3 :         mm_segment_t old_fs = get_fs();
     108                 :            : 
     109                 :            :         set_fs(KERNEL_DS);
     110                 :            :         ret = probe_write_common((__force void __user *)dst, src, size);
     111                 :            :         set_fs(old_fs);
     112                 :            : 
     113                 :          3 :         return ret;
     114                 :            : }
     115                 :            : EXPORT_SYMBOL_GPL(probe_kernel_write);
     116                 :            : 
     117                 :            : /**
     118                 :            :  * probe_user_write(): safely attempt to write to a user-space location
     119                 :            :  * @dst: address to write to
     120                 :            :  * @src: pointer to the data that shall be written
     121                 :            :  * @size: size of the data chunk
     122                 :            :  *
     123                 :            :  * Safely write to address @dst from the buffer at @src.  If a kernel fault
     124                 :            :  * happens, handle that and return -EFAULT.
     125                 :            :  */
     126                 :            : 
     127                 :            : long __weak probe_user_write(void __user *dst, const void *src, size_t size)
     128                 :            :     __attribute__((alias("__probe_user_write")));
     129                 :            : 
     130                 :          0 : long __probe_user_write(void __user *dst, const void *src, size_t size)
     131                 :            : {
     132                 :            :         long ret = -EFAULT;
     133                 :          0 :         mm_segment_t old_fs = get_fs();
     134                 :            : 
     135                 :            :         set_fs(USER_DS);
     136                 :          0 :         if (access_ok(dst, size))
     137                 :            :                 ret = probe_write_common(dst, src, size);
     138                 :            :         set_fs(old_fs);
     139                 :            : 
     140                 :          0 :         return ret;
     141                 :            : }
     142                 :            : EXPORT_SYMBOL_GPL(probe_user_write);
     143                 :            : 
     144                 :            : /**
     145                 :            :  * strncpy_from_unsafe: - Copy a NUL terminated string from unsafe address.
     146                 :            :  * @dst:   Destination address, in kernel space.  This buffer must be at
     147                 :            :  *         least @count bytes long.
     148                 :            :  * @unsafe_addr: Unsafe address.
     149                 :            :  * @count: Maximum number of bytes to copy, including the trailing NUL.
     150                 :            :  *
     151                 :            :  * Copies a NUL-terminated string from unsafe address to kernel buffer.
     152                 :            :  *
     153                 :            :  * On success, returns the length of the string INCLUDING the trailing NUL.
     154                 :            :  *
     155                 :            :  * If access fails, returns -EFAULT (some data may have been copied
     156                 :            :  * and the trailing NUL added).
     157                 :            :  *
     158                 :            :  * If @count is smaller than the length of the string, copies @count-1 bytes,
     159                 :            :  * sets the last byte of @dst buffer to NUL and returns @count.
     160                 :            :  */
     161                 :          0 : long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count)
     162                 :            : {
     163                 :          0 :         mm_segment_t old_fs = get_fs();
     164                 :            :         const void *src = unsafe_addr;
     165                 :            :         long ret;
     166                 :            : 
     167                 :          0 :         if (unlikely(count <= 0))
     168                 :            :                 return 0;
     169                 :            : 
     170                 :            :         set_fs(KERNEL_DS);
     171                 :            :         pagefault_disable();
     172                 :            : 
     173                 :            :         do {
     174                 :          0 :                 ret = __get_user(*dst++, (const char __user __force *)src++);
     175                 :          0 :         } while (dst[-1] && ret == 0 && src - unsafe_addr < count);
     176                 :            : 
     177                 :          0 :         dst[-1] = '\0';
     178                 :            :         pagefault_enable();
     179                 :            :         set_fs(old_fs);
     180                 :            : 
     181                 :          0 :         return ret ? -EFAULT : src - unsafe_addr;
     182                 :            : }
     183                 :            : 
     184                 :            : /**
     185                 :            :  * strncpy_from_unsafe_user: - Copy a NUL terminated string from unsafe user
     186                 :            :  *                              address.
     187                 :            :  * @dst:   Destination address, in kernel space.  This buffer must be at
     188                 :            :  *         least @count bytes long.
     189                 :            :  * @unsafe_addr: Unsafe user address.
     190                 :            :  * @count: Maximum number of bytes to copy, including the trailing NUL.
     191                 :            :  *
     192                 :            :  * Copies a NUL-terminated string from unsafe user address to kernel buffer.
     193                 :            :  *
     194                 :            :  * On success, returns the length of the string INCLUDING the trailing NUL.
     195                 :            :  *
     196                 :            :  * If access fails, returns -EFAULT (some data may have been copied
     197                 :            :  * and the trailing NUL added).
     198                 :            :  *
     199                 :            :  * If @count is smaller than the length of the string, copies @count-1 bytes,
     200                 :            :  * sets the last byte of @dst buffer to NUL and returns @count.
     201                 :            :  */
     202                 :          0 : long strncpy_from_unsafe_user(char *dst, const void __user *unsafe_addr,
     203                 :            :                               long count)
     204                 :            : {
     205                 :          0 :         mm_segment_t old_fs = get_fs();
     206                 :            :         long ret;
     207                 :            : 
     208                 :          0 :         if (unlikely(count <= 0))
     209                 :            :                 return 0;
     210                 :            : 
     211                 :            :         set_fs(USER_DS);
     212                 :            :         pagefault_disable();
     213                 :          0 :         ret = strncpy_from_user(dst, unsafe_addr, count);
     214                 :            :         pagefault_enable();
     215                 :            :         set_fs(old_fs);
     216                 :            : 
     217                 :          0 :         if (ret >= count) {
     218                 :            :                 ret = count;
     219                 :          0 :                 dst[ret - 1] = '\0';
     220                 :          0 :         } else if (ret > 0) {
     221                 :          0 :                 ret++;
     222                 :            :         }
     223                 :            : 
     224                 :          0 :         return ret;
     225                 :            : }
     226                 :            : 
     227                 :            : /**
     228                 :            :  * strnlen_unsafe_user: - Get the size of a user string INCLUDING final NUL.
     229                 :            :  * @unsafe_addr: The string to measure.
     230                 :            :  * @count: Maximum count (including NUL)
     231                 :            :  *
     232                 :            :  * Get the size of a NUL-terminated string in user space without pagefault.
     233                 :            :  *
     234                 :            :  * Returns the size of the string INCLUDING the terminating NUL.
     235                 :            :  *
     236                 :            :  * If the string is too long, returns a number larger than @count. User
     237                 :            :  * has to check the return value against "> count".
     238                 :            :  * On exception (or invalid count), returns 0.
     239                 :            :  *
     240                 :            :  * Unlike strnlen_user, this can be used from IRQ handler etc. because
     241                 :            :  * it disables pagefaults.
     242                 :            :  */
     243                 :          0 : long strnlen_unsafe_user(const void __user *unsafe_addr, long count)
     244                 :            : {
     245                 :          0 :         mm_segment_t old_fs = get_fs();
     246                 :            :         int ret;
     247                 :            : 
     248                 :            :         set_fs(USER_DS);
     249                 :            :         pagefault_disable();
     250                 :          0 :         ret = strnlen_user(unsafe_addr, count);
     251                 :            :         pagefault_enable();
     252                 :            :         set_fs(old_fs);
     253                 :            : 
     254                 :          0 :         return ret;
     255                 :            : }
    

Generated by: LCOV version 1.14