Commit 7c478895 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar

x86/uaccess, sched/preempt: Verify access_ok() context

I recently encountered wreckage because access_ok() was used where it
should not be, add an explicit WARN when access_ok() is used wrongly.
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 0a21fc12
...@@ -68,6 +68,12 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un ...@@ -68,6 +68,12 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
__chk_range_not_ok((unsigned long __force)(addr), size, limit); \ __chk_range_not_ok((unsigned long __force)(addr), size, limit); \
}) })
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
# define WARN_ON_IN_IRQ() WARN_ON_ONCE(!in_task())
#else
# define WARN_ON_IN_IRQ()
#endif
/** /**
* access_ok: - Checks if a user space pointer is valid * access_ok: - Checks if a user space pointer is valid
* @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that
...@@ -88,8 +94,11 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un ...@@ -88,8 +94,11 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
* checks that the pointer is in the user space range - after calling * checks that the pointer is in the user space range - after calling
* this function, memory access functions may still return -EFAULT. * this function, memory access functions may still return -EFAULT.
*/ */
#define access_ok(type, addr, size) \ #define access_ok(type, addr, size) \
likely(!__range_not_ok(addr, size, user_addr_max())) ({ \
WARN_ON_IN_IRQ(); \
likely(!__range_not_ok(addr, size, user_addr_max())); \
})
/* /*
* These are the main single-value transfer routines. They automatically * These are the main single-value transfer routines. They automatically
......
...@@ -65,19 +65,24 @@ ...@@ -65,19 +65,24 @@
/* /*
* Are we doing bottom half or hardware interrupt processing? * Are we doing bottom half or hardware interrupt processing?
* Are we in a softirq context? Interrupt context? *
* in_softirq - Are we currently processing softirq or have bh disabled? * in_irq() - We're in (hard) IRQ context
* in_serving_softirq - Are we currently processing softirq? * in_softirq() - We have BH disabled, or are processing softirqs
* in_interrupt() - We're in NMI,IRQ,SoftIRQ context or have BH disabled
* in_serving_softirq() - We're in softirq context
* in_nmi() - We're in NMI context
* in_task() - We're in task context
*
* Note: due to the BH disabled confusion: in_softirq(),in_interrupt() really
* should not be used in new code.
*/ */
#define in_irq() (hardirq_count()) #define in_irq() (hardirq_count())
#define in_softirq() (softirq_count()) #define in_softirq() (softirq_count())
#define in_interrupt() (irq_count()) #define in_interrupt() (irq_count())
#define in_serving_softirq() (softirq_count() & SOFTIRQ_OFFSET) #define in_serving_softirq() (softirq_count() & SOFTIRQ_OFFSET)
#define in_nmi() (preempt_count() & NMI_MASK)
/* #define in_task() (!(preempt_count() & \
* Are we in NMI context? (NMI_MASK | HARDIRQ_MASK | SOFTIRQ_OFFSET)))
*/
#define in_nmi() (preempt_count() & NMI_MASK)
/* /*
* The preempt_count offset after preempt_disable(); * The preempt_count offset after preempt_disable();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment