diff options
author | Arun Sharma <asharma@fb.com> | 2012-04-20 18:41:35 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-06-06 11:08:01 -0400 |
commit | bc6ca7b342d5ae15c3ba3081fd40271b8039fb25 (patch) | |
tree | c2fbb2f922b48a450df5b66c0dca13ba6fd51f98 | |
parent | 0b0d9cf6ec7bab91977da2d71c09157f110f7c2e (diff) |
perf/x86: Check if user fp is valid
Signed-off-by: Arun Sharma <asharma@fb.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1334961696-19580-4-git-send-email-asharma@fb.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/include/asm/uaccess.h | 12 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 12 |
2 files changed, 18 insertions, 6 deletions
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 04cd6882308e..e1f3a17034fc 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h | |||
@@ -33,9 +33,8 @@ | |||
33 | #define segment_eq(a, b) ((a).seg == (b).seg) | 33 | #define segment_eq(a, b) ((a).seg == (b).seg) |
34 | 34 | ||
35 | #define user_addr_max() (current_thread_info()->addr_limit.seg) | 35 | #define user_addr_max() (current_thread_info()->addr_limit.seg) |
36 | #define __addr_ok(addr) \ | 36 | #define __addr_ok(addr) \ |
37 | ((unsigned long __force)(addr) < \ | 37 | ((unsigned long __force)(addr) < user_addr_max()) |
38 | (current_thread_info()->addr_limit.seg)) | ||
39 | 38 | ||
40 | /* | 39 | /* |
41 | * Test whether a block of memory is a valid user space address. | 40 | * Test whether a block of memory is a valid user space address. |
@@ -47,14 +46,14 @@ | |||
47 | * This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry... | 46 | * This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry... |
48 | */ | 47 | */ |
49 | 48 | ||
50 | #define __range_not_ok(addr, size) \ | 49 | #define __range_not_ok(addr, size, limit) \ |
51 | ({ \ | 50 | ({ \ |
52 | unsigned long flag, roksum; \ | 51 | unsigned long flag, roksum; \ |
53 | __chk_user_ptr(addr); \ | 52 | __chk_user_ptr(addr); \ |
54 | asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \ | 53 | asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \ |
55 | : "=&r" (flag), "=r" (roksum) \ | 54 | : "=&r" (flag), "=r" (roksum) \ |
56 | : "1" (addr), "g" ((long)(size)), \ | 55 | : "1" (addr), "g" ((long)(size)), \ |
57 | "rm" (current_thread_info()->addr_limit.seg)); \ | 56 | "rm" (limit)); \ |
58 | flag; \ | 57 | flag; \ |
59 | }) | 58 | }) |
60 | 59 | ||
@@ -77,7 +76,8 @@ | |||
77 | * checks that the pointer is in the user space range - after calling | 76 | * checks that the pointer is in the user space range - after calling |
78 | * this function, memory access functions may still return -EFAULT. | 77 | * this function, memory access functions may still return -EFAULT. |
79 | */ | 78 | */ |
80 | #define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0)) | 79 | #define access_ok(type, addr, size) \ |
80 | (likely(__range_not_ok(addr, size, user_addr_max()) == 0)) | ||
81 | 81 | ||
82 | /* | 82 | /* |
83 | * The exception table consists of pairs of addresses relative to the | 83 | * The exception table consists of pairs of addresses relative to the |
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index e78bc256aea8..c4706cf9c011 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -1757,6 +1757,12 @@ perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs) | |||
1757 | dump_trace(NULL, regs, NULL, 0, &backtrace_ops, entry); | 1757 | dump_trace(NULL, regs, NULL, 0, &backtrace_ops, entry); |
1758 | } | 1758 | } |
1759 | 1759 | ||
1760 | static inline int | ||
1761 | valid_user_frame(const void __user *fp, unsigned long size) | ||
1762 | { | ||
1763 | return (__range_not_ok(fp, size, TASK_SIZE) == 0); | ||
1764 | } | ||
1765 | |||
1760 | #ifdef CONFIG_COMPAT | 1766 | #ifdef CONFIG_COMPAT |
1761 | 1767 | ||
1762 | #include <asm/compat.h> | 1768 | #include <asm/compat.h> |
@@ -1781,6 +1787,9 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry) | |||
1781 | if (bytes != sizeof(frame)) | 1787 | if (bytes != sizeof(frame)) |
1782 | break; | 1788 | break; |
1783 | 1789 | ||
1790 | if (!valid_user_frame(fp, sizeof(frame))) | ||
1791 | break; | ||
1792 | |||
1784 | perf_callchain_store(entry, frame.return_address); | 1793 | perf_callchain_store(entry, frame.return_address); |
1785 | fp = compat_ptr(frame.next_frame); | 1794 | fp = compat_ptr(frame.next_frame); |
1786 | } | 1795 | } |
@@ -1824,6 +1833,9 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) | |||
1824 | if (bytes != sizeof(frame)) | 1833 | if (bytes != sizeof(frame)) |
1825 | break; | 1834 | break; |
1826 | 1835 | ||
1836 | if (!valid_user_frame(fp, sizeof(frame))) | ||
1837 | break; | ||
1838 | |||
1827 | perf_callchain_store(entry, frame.return_address); | 1839 | perf_callchain_store(entry, frame.return_address); |
1828 | fp = frame.next_frame; | 1840 | fp = frame.next_frame; |
1829 | } | 1841 | } |