LCOV - code coverage report
Current view: top level - lib - strncpy_from_user.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 38 41 92.7 %
Date: 2022-03-28 13:20:08 Functions: 2 2 100.0 %
Branches: 12 20 60.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : #include <linux/compiler.h>
       3                 :            : #include <linux/export.h>
       4                 :            : #include <linux/kasan-checks.h>
       5                 :            : #include <linux/thread_info.h>
       6                 :            : #include <linux/uaccess.h>
       7                 :            : #include <linux/kernel.h>
       8                 :            : #include <linux/errno.h>
       9                 :            : #include <linux/mm.h>
      10                 :            : 
      11                 :            : #include <asm/byteorder.h>
      12                 :            : #include <asm/word-at-a-time.h>
      13                 :            : 
      14                 :            : #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
      15                 :            : #define IS_UNALIGNED(src, dst)  0
      16                 :            : #else
      17                 :            : #define IS_UNALIGNED(src, dst)  \
      18                 :            :         (((long) dst | (long) src) & (sizeof(long) - 1))
      19                 :            : #endif
      20                 :            : 
      21                 :            : /*
      22                 :            :  * Do a strncpy, return length of string without final '\0'.
      23                 :            :  * 'count' is the user-supplied count (return 'count' if we
      24                 :            :  * hit it), 'max' is the address space maximum (and we return
      25                 :            :  * -EFAULT if we hit it).
      26                 :            :  */
      27                 :    4378493 : static inline long do_strncpy_from_user(char *dst, const char __user *src,
      28                 :            :                                         unsigned long count, unsigned long max)
      29                 :            : {
      30                 :    4378493 :         const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
      31                 :    4378493 :         unsigned long res = 0;
      32                 :            : 
      33                 :    4378493 :         if (IS_UNALIGNED(src, dst))
      34                 :            :                 goto byte_at_a_time;
      35                 :            : 
      36         [ +  + ]:   16196921 :         while (max >= sizeof(unsigned long)) {
      37                 :   16195805 :                 unsigned long c, data;
      38                 :            : 
      39                 :            :                 /* Fall back to byte-at-a-time if we get a page fault */
      40         [ -  + ]:   16195805 :                 unsafe_get_user(c, (unsigned long __user *)(src+res), byte_at_a_time);
      41                 :            : 
      42                 :   16195805 :                 *(unsigned long *)(dst+res) = c;
      43         [ +  + ]:   16195805 :                 if (has_zero(c, &data, &constants)) {
      44                 :    4377377 :                         data = prep_zero_mask(c, data, &constants);
      45                 :    4377377 :                         data = create_zero_mask(data);
      46                 :    4377377 :                         return res + find_zero(data);
      47                 :            :                 }
      48                 :   11818428 :                 res += sizeof(unsigned long);
      49                 :   11818428 :                 max -= sizeof(unsigned long);
      50                 :            :         }
      51                 :            : 
      52                 :       1116 : byte_at_a_time:
      53         [ +  - ]:       3048 :         while (max) {
      54                 :       3048 :                 char c;
      55                 :            : 
      56         [ -  + ]:       3048 :                 unsafe_get_user(c,src+res, efault);
      57                 :       3048 :                 dst[res] = c;
      58         [ +  + ]:       3048 :                 if (!c)
      59                 :       1116 :                         return res;
      60                 :       1932 :                 res++;
      61                 :       1932 :                 max--;
      62                 :            :         }
      63                 :            : 
      64                 :            :         /*
      65                 :            :          * Uhhuh. We hit 'max'. But was that the user-specified maximum
      66                 :            :          * too? If so, that's ok - we got as much as the user asked for.
      67                 :            :          */
      68         [ #  # ]:          0 :         if (res >= count)
      69                 :          0 :                 return res;
      70                 :            : 
      71                 :            :         /*
      72                 :            :          * Nope: we hit the address space limit, and we still had more
      73                 :            :          * characters the caller would have wanted. That's an EFAULT.
      74                 :            :          */
      75                 :          0 : efault:
      76                 :            :         return -EFAULT;
      77                 :            : }
      78                 :            : 
      79                 :            : /**
      80                 :            :  * strncpy_from_user: - Copy a NUL terminated string from userspace.
      81                 :            :  * @dst:   Destination address, in kernel space.  This buffer must be at
      82                 :            :  *         least @count bytes long.
      83                 :            :  * @src:   Source address, in user space.
      84                 :            :  * @count: Maximum number of bytes to copy, including the trailing NUL.
      85                 :            :  *
      86                 :            :  * Copies a NUL-terminated string from userspace to kernel space.
      87                 :            :  *
      88                 :            :  * On success, returns the length of the string (not including the trailing
      89                 :            :  * NUL).
      90                 :            :  *
      91                 :            :  * If access to userspace fails, returns -EFAULT (some data may have been
      92                 :            :  * copied).
      93                 :            :  *
      94                 :            :  * If @count is smaller than the length of the string, copies @count bytes
      95                 :            :  * and returns @count.
      96                 :            :  */
      97                 :    4378493 : long strncpy_from_user(char *dst, const char __user *src, long count)
      98                 :            : {
      99                 :    4378493 :         unsigned long max_addr, src_addr;
     100                 :            : 
     101         [ +  - ]:    4378493 :         if (unlikely(count <= 0))
     102                 :            :                 return 0;
     103                 :            : 
     104         [ +  - ]:    4378493 :         max_addr = user_addr_max();
     105                 :    4378493 :         src_addr = (unsigned long)untagged_addr(src);
     106         [ +  - ]:    4378493 :         if (likely(src_addr < max_addr)) {
     107                 :    4378493 :                 unsigned long max = max_addr - src_addr;
     108                 :    4378493 :                 long retval;
     109                 :            : 
     110                 :            :                 /*
     111                 :            :                  * Truncate 'max' to the user-specified limit, so that
     112                 :            :                  * we only have one limit we need to check in the loop
     113                 :            :                  */
     114                 :    4378493 :                 if (max > count)
     115                 :            :                         max = count;
     116                 :            : 
     117                 :    4378493 :                 kasan_check_write(dst, count);
     118                 :    4378493 :                 check_object_size(dst, count, false);
     119                 :    4378493 :                 if (user_access_begin(src, max)) {
     120                 :    4378493 :                         retval = do_strncpy_from_user(dst, src, count, max);
     121                 :    4378493 :                         user_access_end();
     122                 :    4378493 :                         return retval;
     123                 :            :                 }
     124                 :            :         }
     125                 :            :         return -EFAULT;
     126                 :            : }
     127                 :            : EXPORT_SYMBOL(strncpy_from_user);

Generated by: LCOV version 1.14