aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/include/asm/uaccess_32.h
diff options
context:
space:
mode:
authorArjan van de Ven <arjan@infradead.org>2009-09-26 08:33:01 -0400
committerIngo Molnar <mingo@elte.hu>2009-09-26 10:25:41 -0400
commit9f0cf4adb6aa0bfccf675c938124e68f7f06349d (patch)
tree2045a8fa0b207a8adb288eb144c593db7d1f2f0b /arch/x86/include/asm/uaccess_32.h
parent704daf55c7297e727021063cb5d8ba1c55b84426 (diff)
x86: Use __builtin_object_size() to validate the buffer size for copy_from_user()
gcc (4.x) supports the __builtin_object_size() builtin, which reports the size of an object that a pointer point to, when known at compile time. If the buffer size is not known at compile time, a constant -1 is returned. This patch uses this feature to add a sanity check to copy_from_user(); if the target buffer is known to be smaller than the copy size, the copy is aborted and a WARNing is emitted in memory debug mode. These extra checks compile away when the object size is not known, or if both the buffer size and the copy length are constants. Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> LKML-Reference: <20090926143301.2c396b94@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/include/asm/uaccess_32.h')
-rw-r--r--arch/x86/include/asm/uaccess_32.h19
1 files changed, 18 insertions, 1 deletions
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h
index 632fb44b4cb5..582d6aef7417 100644
--- a/arch/x86/include/asm/uaccess_32.h
+++ b/arch/x86/include/asm/uaccess_32.h
@@ -187,9 +187,26 @@ __copy_from_user_inatomic_nocache(void *to, const void __user *from,
187 187
188unsigned long __must_check copy_to_user(void __user *to, 188unsigned long __must_check copy_to_user(void __user *to,
189 const void *from, unsigned long n); 189 const void *from, unsigned long n);
190unsigned long __must_check copy_from_user(void *to, 190unsigned long __must_check _copy_from_user(void *to,
191 const void __user *from, 191 const void __user *from,
192 unsigned long n); 192 unsigned long n);
193
194static inline unsigned long __must_check copy_from_user(void *to,
195 const void __user *from,
196 unsigned long n)
197{
198 int sz = __compiletime_object_size(to);
199 int ret = -EFAULT;
200
201 if (likely(sz == -1 || sz >= n))
202 ret = _copy_from_user(to, from, n);
203#ifdef CONFIG_DEBUG_VM
204 else
205 WARN(1, "Buffer overflow detected!\n");
206#endif
207 return ret;
208}
209
193long __must_check strncpy_from_user(char *dst, const char __user *src, 210long __must_check strncpy_from_user(char *dst, const char __user *src,
194 long count); 211 long count);
195long __must_check __strncpy_from_user(char *dst, 212long __must_check __strncpy_from_user(char *dst,