LCOV - code coverage report
Current view: top level - lib - strncpy_from_user.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 21 22 95.5 %
Date: 2015-04-12 14:34:49 Functions: 1 1 100.0 %

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

Generated by: LCOV version 1.11