aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2013-02-25 01:24:20 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-02-28 03:37:11 -0500
commit225cf8d69c768f4472d2fd9f54bba2b69a588193 (patch)
tree72bb482ba7c226991712e0cf466e6155b85a7821 /arch/s390
parent832a998190400563a69677b30d5f306e45cc3aff (diff)
s390/uaccess: fix strncpy_from_user string length check
The "standard" and page table walk variants of strncpy_from_user() first check the length of the to be copied string in userspace. The string is then copied to kernel space and the length returned to the caller. However userspace can modify the string at any time while the kernel checks for the length of the string or copies the string. In result the returned length of the string is not necessarily correct. Fix this by copying in a loop which mimics the mvcos variant of strncpy_from_user(), which handles this correctly. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/lib/uaccess_pt.c34
-rw-r--r--arch/s390/lib/uaccess_std.c46
2 files changed, 34 insertions, 46 deletions
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index c1aaf22c326b..304e07086ab3 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -202,27 +202,29 @@ fault:
202static size_t strncpy_from_user_pt(size_t count, const char __user *src, 202static size_t strncpy_from_user_pt(size_t count, const char __user *src,
203 char *dst) 203 char *dst)
204{ 204{
205 size_t n = strnlen_user_pt(count, src); 205 size_t done, len, offset, len_str;
206 206
207 if (unlikely(!count)) 207 if (unlikely(!count))
208 return 0; 208 return 0;
209 if (!n)
210 return -EFAULT;
211 if (n > count)
212 n = count;
213 if (segment_eq(get_fs(), KERNEL_DS)) { 209 if (segment_eq(get_fs(), KERNEL_DS)) {
214 memcpy(dst, (const char __kernel __force *) src, n); 210 len = strnlen((const char __kernel __force *) src, count) + 1;
215 if (dst[n-1] == '\0') 211 if (len > count)
216 return n-1; 212 len = count;
217 else 213 memcpy(dst, (const char __kernel __force *) src, len);
218 return n; 214 return (dst[len - 1] == '\0') ? len - 1 : len;
219 } 215 }
220 if (__user_copy_pt((unsigned long) src, dst, n, 0)) 216 done = 0;
221 return -EFAULT; 217 do {
222 if (dst[n-1] == '\0') 218 offset = (size_t)src & ~PAGE_MASK;
223 return n-1; 219 len = min(count - done, PAGE_SIZE - offset);
224 else 220 if (__user_copy_pt((unsigned long) src, dst, len, 0))
225 return n; 221 return -EFAULT;
222 len_str = strnlen(dst, len);
223 done += len_str;
224 src += len_str;
225 dst += len_str;
226 } while ((len_str == len) && (done < count));
227 return done;
226} 228}
227 229
228static size_t copy_in_user_pt(size_t n, void __user *to, 230static size_t copy_in_user_pt(size_t n, void __user *to,
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
index 79c6c7d76e08..4a75d475b06a 100644
--- a/arch/s390/lib/uaccess_std.c
+++ b/arch/s390/lib/uaccess_std.c
@@ -206,38 +206,24 @@ size_t strnlen_user_std(size_t size, const char __user *src)
206 return size; 206 return size;
207} 207}
208 208
209size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst) 209size_t strncpy_from_user_std(size_t count, const char __user *src, char *dst)
210{ 210{
211 register unsigned long reg0 asm("0") = 0UL; 211 size_t done, len, offset, len_str;
212 unsigned long tmp1, tmp2;
213 212
214 asm volatile( 213 if (unlikely(!count))
215 " la %3,0(%1)\n" 214 return 0;
216 " la %4,0(%0,%1)\n" 215 done = 0;
217 " sacf 256\n" 216 do {
218 "0: srst %4,%3\n" 217 offset = (size_t)src & ~PAGE_MASK;
219 " jo 0b\n" 218 len = min(count - done, PAGE_SIZE - offset);
220 " sacf 0\n" 219 if (copy_from_user_std(len, src, dst))
221 " la %0,0(%4)\n" 220 return -EFAULT;
222 " jh 1f\n" /* found \0 in string ? */ 221 len_str = strnlen(dst, len);
223 " "AHI" %4,1\n" /* include \0 in copy */ 222 done += len_str;
224 "1:"SLR" %0,%1\n" /* %0 = return length (without \0) */ 223 src += len_str;
225 " "SLR" %4,%1\n" /* %4 = copy length (including \0) */ 224 dst += len_str;
226 "2: mvcp 0(%4,%2),0(%1),%5\n" 225 } while ((len_str == len) && (done < count));
227 " jz 9f\n" 226 return done;
228 "3:"AHI" %4,-256\n"
229 " la %1,256(%1)\n"
230 " la %2,256(%2)\n"
231 "4: mvcp 0(%4,%2),0(%1),%5\n"
232 " jnz 3b\n"
233 " j 9f\n"
234 "7: sacf 0\n"
235 "8:"LHI" %0,%6\n"
236 "9:\n"
237 EX_TABLE(0b,7b) EX_TABLE(2b,8b) EX_TABLE(4b,8b)
238 : "+a" (size), "+a" (src), "+d" (dst), "=a" (tmp1), "=a" (tmp2)
239 : "d" (reg0), "K" (-EFAULT) : "cc", "memory");
240 return size;
241} 227}
242 228
243#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \ 229#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \