linux/lib/strncpy_from_user.c
<<
>>
Prefs
   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 */
  22static 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        if (max > count)
  32                max = count;
  33
  34        if (IS_UNALIGNED(src, dst))
  35                goto byte_at_a_time;
  36
  37        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                if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
  42                        break;
  43                *(unsigned long *)(dst+res) = c;
  44                if (has_zero(c, &data, &constants)) {
  45                        data = prep_zero_mask(c, data, &constants);
  46                        data = create_zero_mask(data);
  47                        return res + find_zero(data);
  48                }
  49                res += sizeof(unsigned long);
  50                max -= sizeof(unsigned long);
  51        }
  52
  53byte_at_a_time:
  54        while (max) {
  55                char c;
  56
  57                if (unlikely(__get_user(c,src+res)))
  58                        return -EFAULT;
  59                dst[res] = c;
  60                if (!c)
  61                        return res;
  62                res++;
  63                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        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 */
  98long strncpy_from_user(char *dst, const char __user *src, long count)
  99{
 100        unsigned long max_addr, src_addr;
 101
 102        if (unlikely(count <= 0))
 103                return 0;
 104
 105        max_addr = user_addr_max();
 106        src_addr = (unsigned long)src;
 107        if (likely(src_addr < max_addr)) {
 108                unsigned long max = max_addr - src_addr;
 109                return do_strncpy_from_user(dst, src, count, max);
 110        }
 111        return -EFAULT;
 112}
 113EXPORT_SYMBOL(strncpy_from_user);
 114
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.