diff options
author | Nick Piggin <npiggin@suse.de> | 2008-09-10 07:37:17 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-09-11 03:44:21 -0400 |
commit | 3ee1afa308f2a38e5d1e2ad3752ad7abcf480da1 (patch) | |
tree | 914e0f3bbd32a387cf6095c6955369fa8da7ebf6 | |
parent | c10d38dda1774ed4540380333cabd229eff37094 (diff) |
x86: some lock annotations for user copy paths, v2
- introduce might_fault()
- handle the atomic user copy paths correctly
[ mingo@elte.hu: move might_sleep() outside of in_atomic(). ]
Signed-off-by: Nick Piggin <npiggin@suse.de>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/lib/usercopy_32.c | 12 | ||||
-rw-r--r-- | arch/x86/lib/usercopy_64.c | 8 | ||||
-rw-r--r-- | include/asm-x86/uaccess.h | 18 | ||||
-rw-r--r-- | include/asm-x86/uaccess_32.h | 12 | ||||
-rw-r--r-- | include/asm-x86/uaccess_64.h | 12 | ||||
-rw-r--r-- | include/linux/kernel.h | 9 | ||||
-rw-r--r-- | mm/memory.c | 15 |
7 files changed, 39 insertions, 47 deletions
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c index 8eedde2a9cac..7393152a252e 100644 --- a/arch/x86/lib/usercopy_32.c +++ b/arch/x86/lib/usercopy_32.c | |||
@@ -32,9 +32,7 @@ static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned lon | |||
32 | #define __do_strncpy_from_user(dst, src, count, res) \ | 32 | #define __do_strncpy_from_user(dst, src, count, res) \ |
33 | do { \ | 33 | do { \ |
34 | int __d0, __d1, __d2; \ | 34 | int __d0, __d1, __d2; \ |
35 | might_sleep(); \ | 35 | might_fault(); \ |
36 | if (current->mm) \ | ||
37 | might_lock_read(¤t->mm->mmap_sem); \ | ||
38 | __asm__ __volatile__( \ | 36 | __asm__ __volatile__( \ |
39 | " testl %1,%1\n" \ | 37 | " testl %1,%1\n" \ |
40 | " jz 2f\n" \ | 38 | " jz 2f\n" \ |
@@ -121,9 +119,7 @@ EXPORT_SYMBOL(strncpy_from_user); | |||
121 | #define __do_clear_user(addr,size) \ | 119 | #define __do_clear_user(addr,size) \ |
122 | do { \ | 120 | do { \ |
123 | int __d0; \ | 121 | int __d0; \ |
124 | might_sleep(); \ | 122 | might_fault(); \ |
125 | if (current->mm) \ | ||
126 | might_lock_read(¤t->mm->mmap_sem); \ | ||
127 | __asm__ __volatile__( \ | 123 | __asm__ __volatile__( \ |
128 | "0: rep; stosl\n" \ | 124 | "0: rep; stosl\n" \ |
129 | " movl %2,%0\n" \ | 125 | " movl %2,%0\n" \ |
@@ -193,9 +189,7 @@ long strnlen_user(const char __user *s, long n) | |||
193 | unsigned long mask = -__addr_ok(s); | 189 | unsigned long mask = -__addr_ok(s); |
194 | unsigned long res, tmp; | 190 | unsigned long res, tmp; |
195 | 191 | ||
196 | might_sleep(); | 192 | might_fault(); |
197 | if (current->mm) | ||
198 | might_lock_read(¤t->mm->mmap_sem); | ||
199 | 193 | ||
200 | __asm__ __volatile__( | 194 | __asm__ __volatile__( |
201 | " testl %0, %0\n" | 195 | " testl %0, %0\n" |
diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index 847d12945998..64d6c84e6353 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c | |||
@@ -15,9 +15,7 @@ | |||
15 | #define __do_strncpy_from_user(dst,src,count,res) \ | 15 | #define __do_strncpy_from_user(dst,src,count,res) \ |
16 | do { \ | 16 | do { \ |
17 | long __d0, __d1, __d2; \ | 17 | long __d0, __d1, __d2; \ |
18 | might_sleep(); \ | 18 | might_fault(); \ |
19 | if (current->mm) \ | ||
20 | might_lock_read(¤t->mm->mmap_sem); \ | ||
21 | __asm__ __volatile__( \ | 19 | __asm__ __volatile__( \ |
22 | " testq %1,%1\n" \ | 20 | " testq %1,%1\n" \ |
23 | " jz 2f\n" \ | 21 | " jz 2f\n" \ |
@@ -66,9 +64,7 @@ EXPORT_SYMBOL(strncpy_from_user); | |||
66 | unsigned long __clear_user(void __user *addr, unsigned long size) | 64 | unsigned long __clear_user(void __user *addr, unsigned long size) |
67 | { | 65 | { |
68 | long __d0; | 66 | long __d0; |
69 | might_sleep(); | 67 | might_fault(); |
70 | if (current->mm) | ||
71 | might_lock_read(¤t->mm->mmap_sem); | ||
72 | /* no memory constraint because it doesn't change any memory gcc knows | 68 | /* no memory constraint because it doesn't change any memory gcc knows |
73 | about */ | 69 | about */ |
74 | asm volatile( | 70 | asm volatile( |
diff --git a/include/asm-x86/uaccess.h b/include/asm-x86/uaccess.h index ad29752a1713..39f8420c75d9 100644 --- a/include/asm-x86/uaccess.h +++ b/include/asm-x86/uaccess.h | |||
@@ -8,8 +8,6 @@ | |||
8 | #include <linux/thread_info.h> | 8 | #include <linux/thread_info.h> |
9 | #include <linux/prefetch.h> | 9 | #include <linux/prefetch.h> |
10 | #include <linux/string.h> | 10 | #include <linux/string.h> |
11 | #include <linux/lockdep.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <asm/asm.h> | 11 | #include <asm/asm.h> |
14 | #include <asm/page.h> | 12 | #include <asm/page.h> |
15 | 13 | ||
@@ -159,9 +157,7 @@ extern int __get_user_bad(void); | |||
159 | int __ret_gu; \ | 157 | int __ret_gu; \ |
160 | unsigned long __val_gu; \ | 158 | unsigned long __val_gu; \ |
161 | __chk_user_ptr(ptr); \ | 159 | __chk_user_ptr(ptr); \ |
162 | might_sleep(); \ | 160 | might_fault(); \ |
163 | if (current->mm) \ | ||
164 | might_lock_read(¤t->mm->mmap_sem); \ | ||
165 | switch (sizeof(*(ptr))) { \ | 161 | switch (sizeof(*(ptr))) { \ |
166 | case 1: \ | 162 | case 1: \ |
167 | __get_user_x(1, __ret_gu, __val_gu, ptr); \ | 163 | __get_user_x(1, __ret_gu, __val_gu, ptr); \ |
@@ -246,9 +242,7 @@ extern void __put_user_8(void); | |||
246 | int __ret_pu; \ | 242 | int __ret_pu; \ |
247 | __typeof__(*(ptr)) __pu_val; \ | 243 | __typeof__(*(ptr)) __pu_val; \ |
248 | __chk_user_ptr(ptr); \ | 244 | __chk_user_ptr(ptr); \ |
249 | might_sleep(); \ | 245 | might_fault(); \ |
250 | if (current->mm) \ | ||
251 | might_lock_read(¤t->mm->mmap_sem); \ | ||
252 | __pu_val = x; \ | 246 | __pu_val = x; \ |
253 | switch (sizeof(*(ptr))) { \ | 247 | switch (sizeof(*(ptr))) { \ |
254 | case 1: \ | 248 | case 1: \ |
@@ -273,9 +267,7 @@ extern void __put_user_8(void); | |||
273 | #define __put_user_size(x, ptr, size, retval, errret) \ | 267 | #define __put_user_size(x, ptr, size, retval, errret) \ |
274 | do { \ | 268 | do { \ |
275 | retval = 0; \ | 269 | retval = 0; \ |
276 | might_sleep(); \ | 270 | might_fault(); \ |
277 | if (current->mm) \ | ||
278 | might_lock_read(¤t->mm->mmap_sem); \ | ||
279 | __chk_user_ptr(ptr); \ | 271 | __chk_user_ptr(ptr); \ |
280 | switch (size) { \ | 272 | switch (size) { \ |
281 | case 1: \ | 273 | case 1: \ |
@@ -328,9 +320,7 @@ do { \ | |||
328 | #define __get_user_size(x, ptr, size, retval, errret) \ | 320 | #define __get_user_size(x, ptr, size, retval, errret) \ |
329 | do { \ | 321 | do { \ |
330 | retval = 0; \ | 322 | retval = 0; \ |
331 | might_sleep(); \ | 323 | might_fault(); \ |
332 | if (current->mm) \ | ||
333 | might_lock_read(¤t->mm->mmap_sem); \ | ||
334 | __chk_user_ptr(ptr); \ | 324 | __chk_user_ptr(ptr); \ |
335 | switch (size) { \ | 325 | switch (size) { \ |
336 | case 1: \ | 326 | case 1: \ |
diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index d725e2d703f7..d10e842ec3ee 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h | |||
@@ -82,9 +82,7 @@ __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n) | |||
82 | static __always_inline unsigned long __must_check | 82 | static __always_inline unsigned long __must_check |
83 | __copy_to_user(void __user *to, const void *from, unsigned long n) | 83 | __copy_to_user(void __user *to, const void *from, unsigned long n) |
84 | { | 84 | { |
85 | might_sleep(); | 85 | might_fault(); |
86 | if (current->mm) | ||
87 | might_lock_read(¤t->mm->mmap_sem); | ||
88 | return __copy_to_user_inatomic(to, from, n); | 86 | return __copy_to_user_inatomic(to, from, n); |
89 | } | 87 | } |
90 | 88 | ||
@@ -139,9 +137,7 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n) | |||
139 | static __always_inline unsigned long | 137 | static __always_inline unsigned long |
140 | __copy_from_user(void *to, const void __user *from, unsigned long n) | 138 | __copy_from_user(void *to, const void __user *from, unsigned long n) |
141 | { | 139 | { |
142 | might_sleep(); | 140 | might_fault(); |
143 | if (current->mm) | ||
144 | might_lock_read(¤t->mm->mmap_sem); | ||
145 | if (__builtin_constant_p(n)) { | 141 | if (__builtin_constant_p(n)) { |
146 | unsigned long ret; | 142 | unsigned long ret; |
147 | 143 | ||
@@ -163,9 +159,7 @@ __copy_from_user(void *to, const void __user *from, unsigned long n) | |||
163 | static __always_inline unsigned long __copy_from_user_nocache(void *to, | 159 | static __always_inline unsigned long __copy_from_user_nocache(void *to, |
164 | const void __user *from, unsigned long n) | 160 | const void __user *from, unsigned long n) |
165 | { | 161 | { |
166 | might_sleep(); | 162 | might_fault(); |
167 | if (current->mm) | ||
168 | might_lock_read(¤t->mm->mmap_sem); | ||
169 | if (__builtin_constant_p(n)) { | 163 | if (__builtin_constant_p(n)) { |
170 | unsigned long ret; | 164 | unsigned long ret; |
171 | 165 | ||
diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index 40a7205fe576..13fd56fbc3ab 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h | |||
@@ -29,9 +29,7 @@ int __copy_from_user(void *dst, const void __user *src, unsigned size) | |||
29 | { | 29 | { |
30 | int ret = 0; | 30 | int ret = 0; |
31 | 31 | ||
32 | might_sleep(); | 32 | might_fault(); |
33 | if (current->mm) | ||
34 | might_lock_read(¤t->mm->mmap_sem); | ||
35 | if (!__builtin_constant_p(size)) | 33 | if (!__builtin_constant_p(size)) |
36 | return copy_user_generic(dst, (__force void *)src, size); | 34 | return copy_user_generic(dst, (__force void *)src, size); |
37 | switch (size) { | 35 | switch (size) { |
@@ -75,9 +73,7 @@ int __copy_to_user(void __user *dst, const void *src, unsigned size) | |||
75 | { | 73 | { |
76 | int ret = 0; | 74 | int ret = 0; |
77 | 75 | ||
78 | might_sleep(); | 76 | might_fault(); |
79 | if (current->mm) | ||
80 | might_lock_read(¤t->mm->mmap_sem); | ||
81 | if (!__builtin_constant_p(size)) | 77 | if (!__builtin_constant_p(size)) |
82 | return copy_user_generic((__force void *)dst, src, size); | 78 | return copy_user_generic((__force void *)dst, src, size); |
83 | switch (size) { | 79 | switch (size) { |
@@ -121,9 +117,7 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size) | |||
121 | { | 117 | { |
122 | int ret = 0; | 118 | int ret = 0; |
123 | 119 | ||
124 | might_sleep(); | 120 | might_fault(); |
125 | if (current->mm) | ||
126 | might_lock_read(¤t->mm->mmap_sem); | ||
127 | if (!__builtin_constant_p(size)) | 121 | if (!__builtin_constant_p(size)) |
128 | return copy_user_generic((__force void *)dst, | 122 | return copy_user_generic((__force void *)dst, |
129 | (__force void *)src, size); | 123 | (__force void *)src, size); |
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 2651f805ba6d..e580ec095765 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
@@ -140,6 +140,15 @@ extern int _cond_resched(void); | |||
140 | (__x < 0) ? -__x : __x; \ | 140 | (__x < 0) ? -__x : __x; \ |
141 | }) | 141 | }) |
142 | 142 | ||
143 | #ifdef CONFIG_PROVE_LOCKING | ||
144 | void might_fault(void); | ||
145 | #else | ||
146 | static inline void might_fault(void) | ||
147 | { | ||
148 | might_sleep(); | ||
149 | } | ||
150 | #endif | ||
151 | |||
143 | extern struct atomic_notifier_head panic_notifier_list; | 152 | extern struct atomic_notifier_head panic_notifier_list; |
144 | extern long (*panic_blink)(long time); | 153 | extern long (*panic_blink)(long time); |
145 | NORET_TYPE void panic(const char * fmt, ...) | 154 | NORET_TYPE void panic(const char * fmt, ...) |
diff --git a/mm/memory.c b/mm/memory.c index 1002f473f497..b8fdf4e5e65b 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -3016,3 +3016,18 @@ void print_vma_addr(char *prefix, unsigned long ip) | |||
3016 | } | 3016 | } |
3017 | up_read(¤t->mm->mmap_sem); | 3017 | up_read(¤t->mm->mmap_sem); |
3018 | } | 3018 | } |
3019 | |||
3020 | #ifdef CONFIG_PROVE_LOCKING | ||
3021 | void might_fault(void) | ||
3022 | { | ||
3023 | might_sleep(); | ||
3024 | /* | ||
3025 | * it would be nicer only to annotate paths which are not under | ||
3026 | * pagefault_disable, however that requires a larger audit and | ||
3027 | * providing helpers like get_user_atomic. | ||
3028 | */ | ||
3029 | if (!in_atomic() && current->mm) | ||
3030 | might_lock_read(¤t->mm->mmap_sem); | ||
3031 | } | ||
3032 | EXPORT_SYMBOL(might_fault); | ||
3033 | #endif | ||