diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2005-09-29 00:06:47 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-09-29 00:06:47 -0400 |
commit | efdc1e2083e04cc70721d55803889b346c1a3de2 (patch) | |
tree | 9f24fab33f795a69bb2dc43a8f3613392762ff02 /arch/sparc64/lib | |
parent | 5fd29752f09cabff582f65c0ce35518db4c64937 (diff) |
[SPARC64]: Simplify user fault fixup handling.
Instead of doing byte-at-a-time user accesses to figure
out where the fault occurred, read the saved fault_address
from the current thread structure.
For the sake of defensive programming, if the fault_address
does not fall into the user buffer range, simply assume the
whole area faulted. This will cause the fixup for
copy_from_user() to clear the entire kernel side buffer.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/lib')
-rw-r--r-- | arch/sparc64/lib/user_fixup.c | 63 |
1 files changed, 29 insertions, 34 deletions
diff --git a/arch/sparc64/lib/user_fixup.c b/arch/sparc64/lib/user_fixup.c index 0278e34125db..19d1fdb17d0e 100644 --- a/arch/sparc64/lib/user_fixup.c +++ b/arch/sparc64/lib/user_fixup.c | |||
@@ -11,61 +11,56 @@ | |||
11 | 11 | ||
12 | /* Calculating the exact fault address when using | 12 | /* Calculating the exact fault address when using |
13 | * block loads and stores can be very complicated. | 13 | * block loads and stores can be very complicated. |
14 | * | ||
14 | * Instead of trying to be clever and handling all | 15 | * Instead of trying to be clever and handling all |
15 | * of the cases, just fix things up simply here. | 16 | * of the cases, just fix things up simply here. |
16 | */ | 17 | */ |
17 | 18 | ||
18 | unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size) | 19 | static unsigned long compute_size(unsigned long start, unsigned long size, unsigned long *offset) |
19 | { | 20 | { |
20 | char *dst = to; | 21 | unsigned long fault_addr = current_thread_info()->fault_address; |
21 | const char __user *src = from; | 22 | unsigned long end = start + size; |
22 | 23 | ||
23 | while (size) { | 24 | if (fault_addr < start || fault_addr >= end) { |
24 | if (__get_user(*dst, src)) | 25 | *offset = 0; |
25 | break; | 26 | } else { |
26 | dst++; | 27 | *offset = start - fault_addr; |
27 | src++; | 28 | size = end - fault_addr; |
28 | size--; | ||
29 | } | 29 | } |
30 | return size; | ||
31 | } | ||
30 | 32 | ||
31 | if (size) | 33 | unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size) |
32 | memset(dst, 0, size); | 34 | { |
35 | unsigned long offset; | ||
36 | |||
37 | size = compute_size((unsigned long) from, size, &offset); | ||
38 | if (likely(size)) | ||
39 | memset(to + offset, 0, size); | ||
33 | 40 | ||
34 | return size; | 41 | return size; |
35 | } | 42 | } |
36 | 43 | ||
37 | unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size) | 44 | unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size) |
38 | { | 45 | { |
39 | char __user *dst = to; | 46 | unsigned long offset; |
40 | const char *src = from; | ||
41 | |||
42 | while (size) { | ||
43 | if (__put_user(*src, dst)) | ||
44 | break; | ||
45 | dst++; | ||
46 | src++; | ||
47 | size--; | ||
48 | } | ||
49 | 47 | ||
50 | return size; | 48 | return compute_size((unsigned long) to, size, &offset); |
51 | } | 49 | } |
52 | 50 | ||
53 | unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size) | 51 | unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size) |
54 | { | 52 | { |
55 | char __user *dst = to; | 53 | unsigned long fault_addr = current_thread_info()->fault_address; |
56 | char __user *src = from; | 54 | unsigned long start = (unsigned long) to; |
55 | unsigned long end = start + size; | ||
57 | 56 | ||
58 | while (size) { | 57 | if (fault_addr >= start && fault_addr < end) |
59 | char tmp; | 58 | return end - fault_addr; |
60 | 59 | ||
61 | if (__get_user(tmp, src)) | 60 | start = (unsigned long) from; |
62 | break; | 61 | end = start + size; |
63 | if (__put_user(tmp, dst)) | 62 | if (fault_addr >= start && fault_addr < end) |
64 | break; | 63 | return end - fault_addr; |
65 | dst++; | ||
66 | src++; | ||
67 | size--; | ||
68 | } | ||
69 | 64 | ||
70 | return size; | 65 | return size; |
71 | } | 66 | } |