aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-03-03 15:58:43 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-03-03 15:58:43 -0500
commit530ede14cf63ef4a207b0003e14af2f750484180 (patch)
tree2849be2c8fd6d2d6a8a71447aebe5d7400317c8d /arch/s390
parent6977c6fc77b864dc1851e100c8528c2f3ed5bd9b (diff)
parent72a6b43e4bbb818ac1875a3a572cb2aa8c9af820 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull second set of s390 patches from Martin Schwidefsky: "The main part of this merge are Heikos uaccess patches. Together with commit 09884964335e ("mm: do not grow the stack vma just because of an overrun on preceding vma") the user string access is hopefully fixed for good. In addition some bug fixes and two cleanup patches." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390/module: fix compile warning qdio: remove unused parameters s390/uaccess: fix kernel ds access for page table walk s390/uaccess: fix strncpy_from_user string length check input: disable i8042 PC Keyboard controller for s390 s390/dis: Fix invalid array size s390/uaccess: remove pointless access_ok() checks s390/uaccess: fix strncpy_from_user/strnlen_user zero maxlen case s390/uaccess: shorten strncpy_from_user/strnlen_user s390/dasd: fix unresponsive device after all channel paths were lost s390/mm: ignore change bit for vmemmap s390/page table dumper: add support for change-recording override bit
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/include/asm/futex.h6
-rw-r--r--arch/s390/include/asm/pgtable.h2
-rw-r--r--arch/s390/include/asm/uaccess.h23
-rw-r--r--arch/s390/kernel/compat_signal.c14
-rw-r--r--arch/s390/kernel/dis.c4
-rw-r--r--arch/s390/kernel/module.c2
-rw-r--r--arch/s390/kernel/signal.c8
-rw-r--r--arch/s390/lib/uaccess_mvcos.c26
-rw-r--r--arch/s390/lib/uaccess_pt.c129
-rw-r--r--arch/s390/lib/uaccess_std.c48
-rw-r--r--arch/s390/mm/dump_pagetables.c25
-rw-r--r--arch/s390/mm/vmem.c3
12 files changed, 156 insertions, 134 deletions
diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
index 96bc83ea5c90..51bcaa0fdeef 100644
--- a/arch/s390/include/asm/futex.h
+++ b/arch/s390/include/asm/futex.h
@@ -16,9 +16,6 @@ static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
16 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) 16 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
17 oparg = 1 << oparg; 17 oparg = 1 << oparg;
18 18
19 if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
20 return -EFAULT;
21
22 pagefault_disable(); 19 pagefault_disable();
23 ret = uaccess.futex_atomic_op(op, uaddr, oparg, &oldval); 20 ret = uaccess.futex_atomic_op(op, uaddr, oparg, &oldval);
24 pagefault_enable(); 21 pagefault_enable();
@@ -40,9 +37,6 @@ static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
40static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 37static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
41 u32 oldval, u32 newval) 38 u32 oldval, u32 newval)
42{ 39{
43 if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
44 return -EFAULT;
45
46 return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval); 40 return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
47} 41}
48 42
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 97de1200c849..4a2930844d43 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -340,6 +340,8 @@ extern unsigned long MODULES_END;
340#define _REGION3_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INV) 340#define _REGION3_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INV)
341 341
342#define _REGION3_ENTRY_LARGE 0x400 /* RTTE-format control, large page */ 342#define _REGION3_ENTRY_LARGE 0x400 /* RTTE-format control, large page */
343#define _REGION3_ENTRY_RO 0x200 /* page protection bit */
344#define _REGION3_ENTRY_CO 0x100 /* change-recording override */
343 345
344/* Bits in the segment table entry */ 346/* Bits in the segment table entry */
345#define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */ 347#define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index 34268df959a3..9c33ed4e666f 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -252,9 +252,7 @@ static inline unsigned long __must_check
252copy_to_user(void __user *to, const void *from, unsigned long n) 252copy_to_user(void __user *to, const void *from, unsigned long n)
253{ 253{
254 might_fault(); 254 might_fault();
255 if (access_ok(VERIFY_WRITE, to, n)) 255 return __copy_to_user(to, from, n);
256 n = __copy_to_user(to, from, n);
257 return n;
258} 256}
259 257
260/** 258/**
@@ -315,11 +313,7 @@ copy_from_user(void *to, const void __user *from, unsigned long n)
315 copy_from_user_overflow(); 313 copy_from_user_overflow();
316 return n; 314 return n;
317 } 315 }
318 if (access_ok(VERIFY_READ, from, n)) 316 return __copy_from_user(to, from, n);
319 n = __copy_from_user(to, from, n);
320 else
321 memset(to, 0, n);
322 return n;
323} 317}
324 318
325static inline unsigned long __must_check 319static inline unsigned long __must_check
@@ -332,9 +326,7 @@ static inline unsigned long __must_check
332copy_in_user(void __user *to, const void __user *from, unsigned long n) 326copy_in_user(void __user *to, const void __user *from, unsigned long n)
333{ 327{
334 might_fault(); 328 might_fault();
335 if (__access_ok(from,n) && __access_ok(to,n)) 329 return __copy_in_user(to, from, n);
336 n = __copy_in_user(to, from, n);
337 return n;
338} 330}
339 331
340/* 332/*
@@ -343,11 +335,8 @@ copy_in_user(void __user *to, const void __user *from, unsigned long n)
343static inline long __must_check 335static inline long __must_check
344strncpy_from_user(char *dst, const char __user *src, long count) 336strncpy_from_user(char *dst, const char __user *src, long count)
345{ 337{
346 long res = -EFAULT;
347 might_fault(); 338 might_fault();
348 if (access_ok(VERIFY_READ, src, 1)) 339 return uaccess.strncpy_from_user(count, src, dst);
349 res = uaccess.strncpy_from_user(count, src, dst);
350 return res;
351} 340}
352 341
353static inline unsigned long 342static inline unsigned long
@@ -387,9 +376,7 @@ static inline unsigned long __must_check
387clear_user(void __user *to, unsigned long n) 376clear_user(void __user *to, unsigned long n)
388{ 377{
389 might_fault(); 378 might_fault();
390 if (access_ok(VERIFY_WRITE, to, n)) 379 return uaccess.clear_user(n, to);
391 n = uaccess.clear_user(n, to);
392 return n;
393} 380}
394 381
395extern int copy_to_user_real(void __user *dest, void *src, size_t count); 382extern int copy_to_user_real(void __user *dest, void *src, size_t count);
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index 3e71194c1902..6de049fbe62d 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -53,9 +53,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
53{ 53{
54 int err; 54 int err;
55 55
56 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
57 return -EFAULT;
58
59 /* If you change siginfo_t structure, please be sure 56 /* If you change siginfo_t structure, please be sure
60 this code is fixed accordingly. 57 this code is fixed accordingly.
61 It should never copy any pad contained in the structure 58 It should never copy any pad contained in the structure
@@ -110,9 +107,6 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
110 int err; 107 int err;
111 u32 tmp; 108 u32 tmp;
112 109
113 if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t)))
114 return -EFAULT;
115
116 err = __get_user(to->si_signo, &from->si_signo); 110 err = __get_user(to->si_signo, &from->si_signo);
117 err |= __get_user(to->si_errno, &from->si_errno); 111 err |= __get_user(to->si_errno, &from->si_errno);
118 err |= __get_user(to->si_code, &from->si_code); 112 err |= __get_user(to->si_code, &from->si_code);
@@ -244,8 +238,6 @@ asmlinkage long sys32_sigreturn(void)
244 sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15]; 238 sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
245 sigset_t set; 239 sigset_t set;
246 240
247 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
248 goto badframe;
249 if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32)) 241 if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
250 goto badframe; 242 goto badframe;
251 set_current_blocked(&set); 243 set_current_blocked(&set);
@@ -265,8 +257,6 @@ asmlinkage long sys32_rt_sigreturn(void)
265 rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15]; 257 rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
266 sigset_t set; 258 sigset_t set;
267 259
268 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
269 goto badframe;
270 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) 260 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
271 goto badframe; 261 goto badframe;
272 set_current_blocked(&set); 262 set_current_blocked(&set);
@@ -325,8 +315,6 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
325 sigset_t *set, struct pt_regs * regs) 315 sigset_t *set, struct pt_regs * regs)
326{ 316{
327 sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32)); 317 sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32));
328 if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32)))
329 goto give_sigsegv;
330 318
331 if (frame == (void __user *) -1UL) 319 if (frame == (void __user *) -1UL)
332 goto give_sigsegv; 320 goto give_sigsegv;
@@ -391,8 +379,6 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
391{ 379{
392 int err = 0; 380 int err = 0;
393 rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32)); 381 rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32));
394 if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32)))
395 goto give_sigsegv;
396 382
397 if (frame == (void __user *) -1UL) 383 if (frame == (void __user *) -1UL)
398 goto give_sigsegv; 384 goto give_sigsegv;
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index c50665fe9435..3ad5e9540160 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -1711,10 +1711,10 @@ int insn_to_mnemonic(unsigned char *instruction, char buf[8])
1711 if (!insn) 1711 if (!insn)
1712 return -ENOENT; 1712 return -ENOENT;
1713 if (insn->name[0] == '\0') 1713 if (insn->name[0] == '\0')
1714 snprintf(buf, sizeof(buf), "%s", 1714 snprintf(buf, 8, "%s",
1715 long_insn_name[(int) insn->name[1]]); 1715 long_insn_name[(int) insn->name[1]]);
1716 else 1716 else
1717 snprintf(buf, sizeof(buf), "%.5s", insn->name); 1717 snprintf(buf, 8, "%.5s", insn->name);
1718 return 0; 1718 return 0;
1719} 1719}
1720EXPORT_SYMBOL_GPL(insn_to_mnemonic); 1720EXPORT_SYMBOL_GPL(insn_to_mnemonic);
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index f750bd7bd2c2..7845e15a17df 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -222,7 +222,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
222 struct mod_arch_syminfo *info; 222 struct mod_arch_syminfo *info;
223 Elf_Addr loc, val; 223 Elf_Addr loc, val;
224 int r_type, r_sym; 224 int r_type, r_sym;
225 int rc; 225 int rc = -ENOEXEC;
226 226
227 /* This is where to make the change */ 227 /* This is where to make the change */
228 loc = base + rela->r_offset; 228 loc = base + rela->r_offset;
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 9c6e747a5e1e..c45becf82e01 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -116,8 +116,6 @@ SYSCALL_DEFINE0(sigreturn)
116 sigframe __user *frame = (sigframe __user *)regs->gprs[15]; 116 sigframe __user *frame = (sigframe __user *)regs->gprs[15];
117 sigset_t set; 117 sigset_t set;
118 118
119 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
120 goto badframe;
121 if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE)) 119 if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
122 goto badframe; 120 goto badframe;
123 set_current_blocked(&set); 121 set_current_blocked(&set);
@@ -135,8 +133,6 @@ SYSCALL_DEFINE0(rt_sigreturn)
135 rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15]; 133 rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15];
136 sigset_t set; 134 sigset_t set;
137 135
138 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
139 goto badframe;
140 if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set))) 136 if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
141 goto badframe; 137 goto badframe;
142 set_current_blocked(&set); 138 set_current_blocked(&set);
@@ -195,8 +191,6 @@ static int setup_frame(int sig, struct k_sigaction *ka,
195 sigframe __user *frame; 191 sigframe __user *frame;
196 192
197 frame = get_sigframe(ka, regs, sizeof(sigframe)); 193 frame = get_sigframe(ka, regs, sizeof(sigframe));
198 if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe)))
199 goto give_sigsegv;
200 194
201 if (frame == (void __user *) -1UL) 195 if (frame == (void __user *) -1UL)
202 goto give_sigsegv; 196 goto give_sigsegv;
@@ -264,8 +258,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
264 rt_sigframe __user *frame; 258 rt_sigframe __user *frame;
265 259
266 frame = get_sigframe(ka, regs, sizeof(rt_sigframe)); 260 frame = get_sigframe(ka, regs, sizeof(rt_sigframe));
267 if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe)))
268 goto give_sigsegv;
269 261
270 if (frame == (void __user *) -1UL) 262 if (frame == (void __user *) -1UL)
271 goto give_sigsegv; 263 goto give_sigsegv;
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
index 2443ae476e33..1829742bf479 100644
--- a/arch/s390/lib/uaccess_mvcos.c
+++ b/arch/s390/lib/uaccess_mvcos.c
@@ -162,19 +162,19 @@ static size_t clear_user_mvcos(size_t size, void __user *to)
162 162
163static size_t strnlen_user_mvcos(size_t count, const char __user *src) 163static size_t strnlen_user_mvcos(size_t count, const char __user *src)
164{ 164{
165 size_t done, len, offset, len_str;
165 char buf[256]; 166 char buf[256];
166 int rc;
167 size_t done, len, len_str;
168 167
169 done = 0; 168 done = 0;
170 do { 169 do {
171 len = min(count - done, (size_t) 256); 170 offset = (size_t)src & ~PAGE_MASK;
172 rc = uaccess.copy_from_user(len, src + done, buf); 171 len = min(256UL, PAGE_SIZE - offset);
173 if (unlikely(rc == len)) 172 len = min(count - done, len);
173 if (copy_from_user_mvcos(len, src, buf))
174 return 0; 174 return 0;
175 len -= rc;
176 len_str = strnlen(buf, len); 175 len_str = strnlen(buf, len);
177 done += len_str; 176 done += len_str;
177 src += len_str;
178 } while ((len_str == len) && (done < count)); 178 } while ((len_str == len) && (done < count));
179 return done + 1; 179 return done + 1;
180} 180}
@@ -182,18 +182,20 @@ static size_t strnlen_user_mvcos(size_t count, const char __user *src)
182static size_t strncpy_from_user_mvcos(size_t count, const char __user *src, 182static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
183 char *dst) 183 char *dst)
184{ 184{
185 int rc; 185 size_t done, len, offset, len_str;
186 size_t done, len, len_str;
187 186
187 if (unlikely(!count))
188 return 0;
188 done = 0; 189 done = 0;
189 do { 190 do {
190 len = min(count - done, (size_t) 4096); 191 offset = (size_t)src & ~PAGE_MASK;
191 rc = uaccess.copy_from_user(len, src + done, dst); 192 len = min(count - done, PAGE_SIZE - offset);
192 if (unlikely(rc == len)) 193 if (copy_from_user_mvcos(len, src, dst))
193 return -EFAULT; 194 return -EFAULT;
194 len -= rc;
195 len_str = strnlen(dst, len); 195 len_str = strnlen(dst, len);
196 done += len_str; 196 done += len_str;
197 src += len_str;
198 dst += len_str;
197 } while ((len_str == len) && (done < count)); 199 } while ((len_str == len) && (done < count));
198 return done; 200 return done;
199} 201}
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index a70ee84c0241..dff631d34b45 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -14,6 +14,63 @@
14#include <asm/futex.h> 14#include <asm/futex.h>
15#include "uaccess.h" 15#include "uaccess.h"
16 16
17#ifndef CONFIG_64BIT
18#define AHI "ahi"
19#define SLR "slr"
20#else
21#define AHI "aghi"
22#define SLR "slgr"
23#endif
24
25static size_t strnlen_kernel(size_t count, const char __user *src)
26{
27 register unsigned long reg0 asm("0") = 0UL;
28 unsigned long tmp1, tmp2;
29
30 asm volatile(
31 " la %2,0(%1)\n"
32 " la %3,0(%0,%1)\n"
33 " "SLR" %0,%0\n"
34 "0: srst %3,%2\n"
35 " jo 0b\n"
36 " la %0,1(%3)\n" /* strnlen_kernel results includes \0 */
37 " "SLR" %0,%1\n"
38 "1:\n"
39 EX_TABLE(0b,1b)
40 : "+a" (count), "+a" (src), "=a" (tmp1), "=a" (tmp2)
41 : "d" (reg0) : "cc", "memory");
42 return count;
43}
44
45static size_t copy_in_kernel(size_t count, void __user *to,
46 const void __user *from)
47{
48 unsigned long tmp1;
49
50 asm volatile(
51 " "AHI" %0,-1\n"
52 " jo 5f\n"
53 " bras %3,3f\n"
54 "0:"AHI" %0,257\n"
55 "1: mvc 0(1,%1),0(%2)\n"
56 " la %1,1(%1)\n"
57 " la %2,1(%2)\n"
58 " "AHI" %0,-1\n"
59 " jnz 1b\n"
60 " j 5f\n"
61 "2: mvc 0(256,%1),0(%2)\n"
62 " la %1,256(%1)\n"
63 " la %2,256(%2)\n"
64 "3:"AHI" %0,-256\n"
65 " jnm 2b\n"
66 "4: ex %0,1b-0b(%3)\n"
67 "5:"SLR" %0,%0\n"
68 "6:\n"
69 EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
70 : "+a" (count), "+a" (to), "+a" (from), "=a" (tmp1)
71 : : "cc", "memory");
72 return count;
73}
17 74
18/* 75/*
19 * Returns kernel address for user virtual address. If the returned address is 76 * Returns kernel address for user virtual address. If the returned address is
@@ -123,10 +180,8 @@ size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
123{ 180{
124 size_t rc; 181 size_t rc;
125 182
126 if (segment_eq(get_fs(), KERNEL_DS)) { 183 if (segment_eq(get_fs(), KERNEL_DS))
127 memcpy(to, (void __kernel __force *) from, n); 184 return copy_in_kernel(n, (void __user *) to, from);
128 return 0;
129 }
130 rc = __user_copy_pt((unsigned long) from, to, n, 0); 185 rc = __user_copy_pt((unsigned long) from, to, n, 0);
131 if (unlikely(rc)) 186 if (unlikely(rc))
132 memset(to + n - rc, 0, rc); 187 memset(to + n - rc, 0, rc);
@@ -135,30 +190,28 @@ size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
135 190
136size_t copy_to_user_pt(size_t n, void __user *to, const void *from) 191size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
137{ 192{
138 if (segment_eq(get_fs(), KERNEL_DS)) { 193 if (segment_eq(get_fs(), KERNEL_DS))
139 memcpy((void __kernel __force *) to, from, n); 194 return copy_in_kernel(n, to, (void __user *) from);
140 return 0;
141 }
142 return __user_copy_pt((unsigned long) to, (void *) from, n, 1); 195 return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
143} 196}
144 197
145static size_t clear_user_pt(size_t n, void __user *to) 198static size_t clear_user_pt(size_t n, void __user *to)
146{ 199{
200 void *zpage = &empty_zero_page;
147 long done, size, ret; 201 long done, size, ret;
148 202
149 if (segment_eq(get_fs(), KERNEL_DS)) {
150 memset((void __kernel __force *) to, 0, n);
151 return 0;
152 }
153 done = 0; 203 done = 0;
154 do { 204 do {
155 if (n - done > PAGE_SIZE) 205 if (n - done > PAGE_SIZE)
156 size = PAGE_SIZE; 206 size = PAGE_SIZE;
157 else 207 else
158 size = n - done; 208 size = n - done;
159 ret = __user_copy_pt((unsigned long) to + done, 209 if (segment_eq(get_fs(), KERNEL_DS))
160 &empty_zero_page, size, 1); 210 ret = copy_in_kernel(n, to, (void __user *) zpage);
211 else
212 ret = __user_copy_pt((unsigned long) to, zpage, size, 1);
161 done += size; 213 done += size;
214 to += size;
162 if (ret) 215 if (ret)
163 return ret + n - done; 216 return ret + n - done;
164 } while (done < n); 217 } while (done < n);
@@ -172,8 +225,10 @@ static size_t strnlen_user_pt(size_t count, const char __user *src)
172 unsigned long offset, done, len, kaddr; 225 unsigned long offset, done, len, kaddr;
173 size_t len_str; 226 size_t len_str;
174 227
228 if (unlikely(!count))
229 return 0;
175 if (segment_eq(get_fs(), KERNEL_DS)) 230 if (segment_eq(get_fs(), KERNEL_DS))
176 return strnlen((const char __kernel __force *) src, count) + 1; 231 return strnlen_kernel(count, src);
177 done = 0; 232 done = 0;
178retry: 233retry:
179 spin_lock(&mm->page_table_lock); 234 spin_lock(&mm->page_table_lock);
@@ -200,25 +255,27 @@ fault:
200static size_t strncpy_from_user_pt(size_t count, const char __user *src, 255static size_t strncpy_from_user_pt(size_t count, const char __user *src,
201 char *dst) 256 char *dst)
202{ 257{
203 size_t n = strnlen_user_pt(count, src); 258 size_t done, len, offset, len_str;
204 259
205 if (!n) 260 if (unlikely(!count))
206 return -EFAULT; 261 return 0;
207 if (n > count) 262 done = 0;
208 n = count; 263 do {
209 if (segment_eq(get_fs(), KERNEL_DS)) { 264 offset = (size_t)src & ~PAGE_MASK;
210 memcpy(dst, (const char __kernel __force *) src, n); 265 len = min(count - done, PAGE_SIZE - offset);
211 if (dst[n-1] == '\0') 266 if (segment_eq(get_fs(), KERNEL_DS)) {
212 return n-1; 267 if (copy_in_kernel(len, (void __user *) dst, src))
213 else 268 return -EFAULT;
214 return n; 269 } else {
215 } 270 if (__user_copy_pt((unsigned long) src, dst, len, 0))
216 if (__user_copy_pt((unsigned long) src, dst, n, 0)) 271 return -EFAULT;
217 return -EFAULT; 272 }
218 if (dst[n-1] == '\0') 273 len_str = strnlen(dst, len);
219 return n-1; 274 done += len_str;
220 else 275 src += len_str;
221 return n; 276 dst += len_str;
277 } while ((len_str == len) && (done < count));
278 return done;
222} 279}
223 280
224static size_t copy_in_user_pt(size_t n, void __user *to, 281static size_t copy_in_user_pt(size_t n, void __user *to,
@@ -231,10 +288,8 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
231 unsigned long kaddr_to, kaddr_from; 288 unsigned long kaddr_to, kaddr_from;
232 int write_user; 289 int write_user;
233 290
234 if (segment_eq(get_fs(), KERNEL_DS)) { 291 if (segment_eq(get_fs(), KERNEL_DS))
235 memcpy((void __force *) to, (void __force *) from, n); 292 return copy_in_kernel(n, to, from);
236 return 0;
237 }
238 done = 0; 293 done = 0;
239retry: 294retry:
240 spin_lock(&mm->page_table_lock); 295 spin_lock(&mm->page_table_lock);
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
index 6fbd06338270..4a75d475b06a 100644
--- a/arch/s390/lib/uaccess_std.c
+++ b/arch/s390/lib/uaccess_std.c
@@ -188,6 +188,8 @@ size_t strnlen_user_std(size_t size, const char __user *src)
188 register unsigned long reg0 asm("0") = 0UL; 188 register unsigned long reg0 asm("0") = 0UL;
189 unsigned long tmp1, tmp2; 189 unsigned long tmp1, tmp2;
190 190
191 if (unlikely(!size))
192 return 0;
191 asm volatile( 193 asm volatile(
192 " la %2,0(%1)\n" 194 " la %2,0(%1)\n"
193 " la %3,0(%0,%1)\n" 195 " la %3,0(%0,%1)\n"
@@ -204,38 +206,24 @@ size_t strnlen_user_std(size_t size, const char __user *src)
204 return size; 206 return size;
205} 207}
206 208
207size_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)
208{ 210{
209 register unsigned long reg0 asm("0") = 0UL; 211 size_t done, len, offset, len_str;
210 unsigned long tmp1, tmp2;
211 212
212 asm volatile( 213 if (unlikely(!count))
213 " la %3,0(%1)\n" 214 return 0;
214 " la %4,0(%0,%1)\n" 215 done = 0;
215 " sacf 256\n" 216 do {
216 "0: srst %4,%3\n" 217 offset = (size_t)src & ~PAGE_MASK;
217 " jo 0b\n" 218 len = min(count - done, PAGE_SIZE - offset);
218 " sacf 0\n" 219 if (copy_from_user_std(len, src, dst))
219 " la %0,0(%4)\n" 220 return -EFAULT;
220 " jh 1f\n" /* found \0 in string ? */ 221 len_str = strnlen(dst, len);
221 " "AHI" %4,1\n" /* include \0 in copy */ 222 done += len_str;
222 "1:"SLR" %0,%1\n" /* %0 = return length (without \0) */ 223 src += len_str;
223 " "SLR" %4,%1\n" /* %4 = copy length (including \0) */ 224 dst += len_str;
224 "2: mvcp 0(%4,%2),0(%1),%5\n" 225 } while ((len_str == len) && (done < count));
225 " jz 9f\n" 226 return done;
226 "3:"AHI" %4,-256\n"
227 " la %1,256(%1)\n"
228 " la %2,256(%2)\n"
229 "4: mvcp 0(%4,%2),0(%1),%5\n"
230 " jnz 3b\n"
231 " j 9f\n"
232 "7: sacf 0\n"
233 "8:"LHI" %0,%6\n"
234 "9:\n"
235 EX_TABLE(0b,7b) EX_TABLE(2b,8b) EX_TABLE(4b,8b)
236 : "+a" (size), "+a" (src), "+d" (dst), "=a" (tmp1), "=a" (tmp2)
237 : "d" (reg0), "K" (-EFAULT) : "cc", "memory");
238 return size;
239} 227}
240 228
241#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \ 229#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \
diff --git a/arch/s390/mm/dump_pagetables.c b/arch/s390/mm/dump_pagetables.c
index 04e4892247d2..3ad65b04ac15 100644
--- a/arch/s390/mm/dump_pagetables.c
+++ b/arch/s390/mm/dump_pagetables.c
@@ -49,10 +49,13 @@ static void print_prot(struct seq_file *m, unsigned int pr, int level)
49 { "ASCE", "PGD", "PUD", "PMD", "PTE" }; 49 { "ASCE", "PGD", "PUD", "PMD", "PTE" };
50 50
51 seq_printf(m, "%s ", level_name[level]); 51 seq_printf(m, "%s ", level_name[level]);
52 if (pr & _PAGE_INVALID) 52 if (pr & _PAGE_INVALID) {
53 seq_printf(m, "I\n"); 53 seq_printf(m, "I\n");
54 else 54 return;
55 seq_printf(m, "%s\n", pr & _PAGE_RO ? "RO" : "RW"); 55 }
56 seq_printf(m, "%s", pr & _PAGE_RO ? "RO " : "RW ");
57 seq_printf(m, "%s", pr & _PAGE_CO ? "CO " : " ");
58 seq_putc(m, '\n');
56} 59}
57 60
58static void note_page(struct seq_file *m, struct pg_state *st, 61static void note_page(struct seq_file *m, struct pg_state *st,
@@ -125,6 +128,12 @@ static void walk_pte_level(struct seq_file *m, struct pg_state *st,
125 } 128 }
126} 129}
127 130
131#ifdef CONFIG_64BIT
132#define _PMD_PROT_MASK (_SEGMENT_ENTRY_RO | _SEGMENT_ENTRY_CO)
133#else
134#define _PMD_PROT_MASK 0
135#endif
136
128static void walk_pmd_level(struct seq_file *m, struct pg_state *st, 137static void walk_pmd_level(struct seq_file *m, struct pg_state *st,
129 pud_t *pud, unsigned long addr) 138 pud_t *pud, unsigned long addr)
130{ 139{
@@ -137,7 +146,7 @@ static void walk_pmd_level(struct seq_file *m, struct pg_state *st,
137 pmd = pmd_offset(pud, addr); 146 pmd = pmd_offset(pud, addr);
138 if (!pmd_none(*pmd)) { 147 if (!pmd_none(*pmd)) {
139 if (pmd_large(*pmd)) { 148 if (pmd_large(*pmd)) {
140 prot = pmd_val(*pmd) & _SEGMENT_ENTRY_RO; 149 prot = pmd_val(*pmd) & _PMD_PROT_MASK;
141 note_page(m, st, prot, 3); 150 note_page(m, st, prot, 3);
142 } else 151 } else
143 walk_pte_level(m, st, pmd, addr); 152 walk_pte_level(m, st, pmd, addr);
@@ -147,6 +156,12 @@ static void walk_pmd_level(struct seq_file *m, struct pg_state *st,
147 } 156 }
148} 157}
149 158
159#ifdef CONFIG_64BIT
160#define _PUD_PROT_MASK (_REGION3_ENTRY_RO | _REGION3_ENTRY_CO)
161#else
162#define _PUD_PROT_MASK 0
163#endif
164
150static void walk_pud_level(struct seq_file *m, struct pg_state *st, 165static void walk_pud_level(struct seq_file *m, struct pg_state *st,
151 pgd_t *pgd, unsigned long addr) 166 pgd_t *pgd, unsigned long addr)
152{ 167{
@@ -159,7 +174,7 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st,
159 pud = pud_offset(pgd, addr); 174 pud = pud_offset(pgd, addr);
160 if (!pud_none(*pud)) 175 if (!pud_none(*pud))
161 if (pud_large(*pud)) { 176 if (pud_large(*pud)) {
162 prot = pud_val(*pud) & _PAGE_RO; 177 prot = pud_val(*pud) & _PUD_PROT_MASK;
163 note_page(m, st, prot, 2); 178 note_page(m, st, prot, 2);
164 } else 179 } else
165 walk_pmd_level(m, st, pud, addr); 180 walk_pmd_level(m, st, pud, addr);
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index e21aaf4f5cb6..ffab84db6907 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -236,7 +236,8 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
236 if (!new_page) 236 if (!new_page)
237 goto out; 237 goto out;
238 pmd_val(*pm_dir) = __pa(new_page) | 238 pmd_val(*pm_dir) = __pa(new_page) |
239 _SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE; 239 _SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE |
240 _SEGMENT_ENTRY_CO;
240 address = (address + PMD_SIZE) & PMD_MASK; 241 address = (address + PMD_SIZE) & PMD_MASK;
241 continue; 242 continue;
242 } 243 }