Commit 2922585b93294d47172a765115e0dbc1bfe1be19

Authored by David S. Miller
1 parent 446969084d

lib: Sparc's strncpy_from_user is generic enough, move under lib/

To use this, an architecture simply needs to:

1) Provide a user_addr_max() implementation via asm/uaccess.h

2) Add "select GENERIC_STRNCPY_FROM_USER" to their arch Kcnfig

3) Remove the existing strncpy_from_user() implementation and symbol
   exports their architecture had.

Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: David Howells <dhowells@redhat.com>

Showing 5 changed files with 152 additions and 144 deletions Side-by-side Diff

... ... @@ -32,6 +32,7 @@
32 32 select HAVE_NMI_WATCHDOG if SPARC64
33 33 select HAVE_BPF_JIT
34 34 select GENERIC_SMP_IDLE_THREAD
  35 + select GENERIC_STRNCPY_FROM_USER
35 36  
36 37 config SPARC32
37 38 def_bool !64BIT
arch/sparc/lib/usercopy.c
1 1 #include <linux/module.h>
2   -#include <linux/uaccess.h>
3 2 #include <linux/kernel.h>
4   -#include <linux/errno.h>
5 3 #include <linux/bug.h>
6 4  
7   -#include <asm/byteorder.h>
8   -
9 5 void copy_from_user_overflow(void)
10 6 {
11 7 WARN(1, "Buffer overflow detected!\n");
12 8 }
13 9 EXPORT_SYMBOL(copy_from_user_overflow);
14   -
15   -static inline long find_zero(unsigned long mask)
16   -{
17   - long byte = 0;
18   -
19   -#ifdef __BIG_ENDIAN
20   -#ifdef CONFIG_64BIT
21   - if (mask >> 32)
22   - mask >>= 32;
23   - else
24   - byte = 4;
25   -#endif
26   - if (mask >> 16)
27   - mask >>= 16;
28   - else
29   - byte += 2;
30   - return (mask >> 8) ? byte : byte + 1;
31   -#else
32   -#ifdef CONFIG_64BIT
33   - if (!((unsigned int) mask)) {
34   - mask >>= 32;
35   - byte = 4;
36   - }
37   -#endif
38   - if (!(mask & 0xffff)) {
39   - mask >>= 16;
40   - byte += 2;
41   - }
42   - return (mask & 0xff) ? byte : byte + 1;
43   -#endif
44   -}
45   -
46   -#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
47   -#define IS_UNALIGNED(src, dst) 0
48   -#else
49   -#define IS_UNALIGNED(src, dst) \
50   - (((long) dst | (long) src) & (sizeof(long) - 1))
51   -#endif
52   -
53   -/*
54   - * Do a strncpy, return length of string without final '\0'.
55   - * 'count' is the user-supplied count (return 'count' if we
56   - * hit it), 'max' is the address space maximum (and we return
57   - * -EFAULT if we hit it).
58   - */
59   -static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max)
60   -{
61   - const unsigned long high_bits = REPEAT_BYTE(0xfe) + 1;
62   - const unsigned long low_bits = REPEAT_BYTE(0x7f);
63   - long res = 0;
64   -
65   - /*
66   - * Truncate 'max' to the user-specified limit, so that
67   - * we only have one limit we need to check in the loop
68   - */
69   - if (max > count)
70   - max = count;
71   -
72   - if (IS_UNALIGNED(src, dst))
73   - goto byte_at_a_time;
74   -
75   - while (max >= sizeof(unsigned long)) {
76   - unsigned long c, v, rhs;
77   -
78   - /* Fall back to byte-at-a-time if we get a page fault */
79   - if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
80   - break;
81   - rhs = c | low_bits;
82   - v = (c + high_bits) & ~rhs;
83   - *(unsigned long *)(dst+res) = c;
84   - if (v) {
85   - v = (c & low_bits) + low_bits;
86   - v = ~(v | rhs);
87   - return res + find_zero(v);
88   - }
89   - res += sizeof(unsigned long);
90   - max -= sizeof(unsigned long);
91   - }
92   -
93   -byte_at_a_time:
94   - while (max) {
95   - char c;
96   -
97   - if (unlikely(__get_user(c,src+res)))
98   - return -EFAULT;
99   - dst[res] = c;
100   - if (!c)
101   - return res;
102   - res++;
103   - max--;
104   - }
105   -
106   - /*
107   - * Uhhuh. We hit 'max'. But was that the user-specified maximum
108   - * too? If so, that's ok - we got as much as the user asked for.
109   - */
110   - if (res >= count)
111   - return res;
112   -
113   - /*
114   - * Nope: we hit the address space limit, and we still had more
115   - * characters the caller would have wanted. That's an EFAULT.
116   - */
117   - return -EFAULT;
118   -}
119   -
120   -/**
121   - * strncpy_from_user: - Copy a NUL terminated string from userspace.
122   - * @dst: Destination address, in kernel space. This buffer must be at
123   - * least @count bytes long.
124   - * @src: Source address, in user space.
125   - * @count: Maximum number of bytes to copy, including the trailing NUL.
126   - *
127   - * Copies a NUL-terminated string from userspace to kernel space.
128   - *
129   - * On success, returns the length of the string (not including the trailing
130   - * NUL).
131   - *
132   - * If access to userspace fails, returns -EFAULT (some data may have been
133   - * copied).
134   - *
135   - * If @count is smaller than the length of the string, copies @count bytes
136   - * and returns @count.
137   - */
138   -long strncpy_from_user(char *dst, const char __user *src, long count)
139   -{
140   - unsigned long max_addr, src_addr;
141   -
142   - if (unlikely(count <= 0))
143   - return 0;
144   -
145   - max_addr = user_addr_max();
146   - src_addr = (unsigned long)src;
147   - if (likely(src_addr < max_addr)) {
148   - unsigned long max = max_addr - src_addr;
149   - return do_strncpy_from_user(dst, src, count, max);
150   - }
151   - return -EFAULT;
152   -}
153   -EXPORT_SYMBOL(strncpy_from_user);
... ... @@ -16,6 +16,9 @@
16 16 config RATIONAL
17 17 boolean
18 18  
  19 +config GENERIC_STRNCPY_FROM_USER
  20 + bool
  21 +
19 22 config GENERIC_FIND_FIRST_BIT
20 23 bool
21 24  
... ... @@ -123,6 +123,8 @@
123 123  
124 124 obj-$(CONFIG_CLZ_TAB) += clz_tab.o
125 125  
  126 +obj-$(CONFIG_GENERIC_STRNCPY_FROM_USER) += strncpy_from_user.o
  127 +
126 128 hostprogs-y := gen_crc32table
127 129 clean-files := crc32table.h
128 130  
lib/strncpy_from_user.c
  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 +
  8 +static inline long find_zero(unsigned long mask)
  9 +{
  10 + long byte = 0;
  11 +
  12 +#ifdef __BIG_ENDIAN
  13 +#ifdef CONFIG_64BIT
  14 + if (mask >> 32)
  15 + mask >>= 32;
  16 + else
  17 + byte = 4;
  18 +#endif
  19 + if (mask >> 16)
  20 + mask >>= 16;
  21 + else
  22 + byte += 2;
  23 + return (mask >> 8) ? byte : byte + 1;
  24 +#else
  25 +#ifdef CONFIG_64BIT
  26 + if (!((unsigned int) mask)) {
  27 + mask >>= 32;
  28 + byte = 4;
  29 + }
  30 +#endif
  31 + if (!(mask & 0xffff)) {
  32 + mask >>= 16;
  33 + byte += 2;
  34 + }
  35 + return (mask & 0xff) ? byte : byte + 1;
  36 +#endif
  37 +}
  38 +
  39 +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
  40 +#define IS_UNALIGNED(src, dst) 0
  41 +#else
  42 +#define IS_UNALIGNED(src, dst) \
  43 + (((long) dst | (long) src) & (sizeof(long) - 1))
  44 +#endif
  45 +
  46 +/*
  47 + * Do a strncpy, return length of string without final '\0'.
  48 + * 'count' is the user-supplied count (return 'count' if we
  49 + * hit it), 'max' is the address space maximum (and we return
  50 + * -EFAULT if we hit it).
  51 + */
  52 +static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max)
  53 +{
  54 + const unsigned long high_bits = REPEAT_BYTE(0xfe) + 1;
  55 + const unsigned long low_bits = REPEAT_BYTE(0x7f);
  56 + long res = 0;
  57 +
  58 + /*
  59 + * Truncate 'max' to the user-specified limit, so that
  60 + * we only have one limit we need to check in the loop
  61 + */
  62 + if (max > count)
  63 + max = count;
  64 +
  65 + if (IS_UNALIGNED(src, dst))
  66 + goto byte_at_a_time;
  67 +
  68 + while (max >= sizeof(unsigned long)) {
  69 + unsigned long c, v, rhs;
  70 +
  71 + /* Fall back to byte-at-a-time if we get a page fault */
  72 + if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
  73 + break;
  74 + rhs = c | low_bits;
  75 + v = (c + high_bits) & ~rhs;
  76 + *(unsigned long *)(dst+res) = c;
  77 + if (v) {
  78 + v = (c & low_bits) + low_bits;
  79 + v = ~(v | rhs);
  80 + return res + find_zero(v);
  81 + }
  82 + res += sizeof(unsigned long);
  83 + max -= sizeof(unsigned long);
  84 + }
  85 +
  86 +byte_at_a_time:
  87 + while (max) {
  88 + char c;
  89 +
  90 + if (unlikely(__get_user(c,src+res)))
  91 + return -EFAULT;
  92 + dst[res] = c;
  93 + if (!c)
  94 + return res;
  95 + res++;
  96 + max--;
  97 + }
  98 +
  99 + /*
  100 + * Uhhuh. We hit 'max'. But was that the user-specified maximum
  101 + * too? If so, that's ok - we got as much as the user asked for.
  102 + */
  103 + if (res >= count)
  104 + return res;
  105 +
  106 + /*
  107 + * Nope: we hit the address space limit, and we still had more
  108 + * characters the caller would have wanted. That's an EFAULT.
  109 + */
  110 + return -EFAULT;
  111 +}
  112 +
  113 +/**
  114 + * strncpy_from_user: - Copy a NUL terminated string from userspace.
  115 + * @dst: Destination address, in kernel space. This buffer must be at
  116 + * least @count bytes long.
  117 + * @src: Source address, in user space.
  118 + * @count: Maximum number of bytes to copy, including the trailing NUL.
  119 + *
  120 + * Copies a NUL-terminated string from userspace to kernel space.
  121 + *
  122 + * On success, returns the length of the string (not including the trailing
  123 + * NUL).
  124 + *
  125 + * If access to userspace fails, returns -EFAULT (some data may have been
  126 + * copied).
  127 + *
  128 + * If @count is smaller than the length of the string, copies @count bytes
  129 + * and returns @count.
  130 + */
  131 +long strncpy_from_user(char *dst, const char __user *src, long count)
  132 +{
  133 + unsigned long max_addr, src_addr;
  134 +
  135 + if (unlikely(count <= 0))
  136 + return 0;
  137 +
  138 + max_addr = user_addr_max();
  139 + src_addr = (unsigned long)src;
  140 + if (likely(src_addr < max_addr)) {
  141 + unsigned long max = max_addr - src_addr;
  142 + return do_strncpy_from_user(dst, src, count, max);
  143 + }
  144 + return -EFAULT;
  145 +}
  146 +EXPORT_SYMBOL(strncpy_from_user);