Skip to content

Commit ad8c619

Browse files
Peter Zijlstragregkh
authored andcommitted
x86/uaccess, sched/preempt: Verify access_ok() context
commit 7c4788950ba5922fde976d80b72baf46f14dee8d upstream. 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: Peter 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: Ingo Molnar <mingo@kernel.org> [add include/preempt.h to fix build error - gregkh] Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 44e0e2b commit ad8c619

2 files changed

Lines changed: 25 additions & 10 deletions

File tree

arch/x86/include/asm/uaccess.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/compiler.h>
88
#include <linux/thread_info.h>
99
#include <linux/string.h>
10+
#include <linux/preempt.h>
1011
#include <asm/asm.h>
1112
#include <asm/page.h>
1213
#include <asm/smap.h>
@@ -66,6 +67,12 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
6667
__chk_range_not_ok((unsigned long __force)(addr), size, limit); \
6768
})
6869

70+
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
71+
# define WARN_ON_IN_IRQ() WARN_ON_ONCE(!in_task())
72+
#else
73+
# define WARN_ON_IN_IRQ()
74+
#endif
75+
6976
/**
7077
* access_ok: - Checks if a user space pointer is valid
7178
* @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that
@@ -86,8 +93,11 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
8693
* checks that the pointer is in the user space range - after calling
8794
* this function, memory access functions may still return -EFAULT.
8895
*/
89-
#define access_ok(type, addr, size) \
90-
likely(!__range_not_ok(addr, size, user_addr_max()))
96+
#define access_ok(type, addr, size) \
97+
({ \
98+
WARN_ON_IN_IRQ(); \
99+
likely(!__range_not_ok(addr, size, user_addr_max())); \
100+
})
91101

92102
/*
93103
* The exception table consists of pairs of addresses relative to the

include/linux/preempt.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,24 @@
6565

6666
/*
6767
* Are we doing bottom half or hardware interrupt processing?
68-
* Are we in a softirq context? Interrupt context?
69-
* in_softirq - Are we currently processing softirq or have bh disabled?
70-
* in_serving_softirq - Are we currently processing softirq?
68+
*
69+
* in_irq() - We're in (hard) IRQ context
70+
* in_softirq() - We have BH disabled, or are processing softirqs
71+
* in_interrupt() - We're in NMI,IRQ,SoftIRQ context or have BH disabled
72+
* in_serving_softirq() - We're in softirq context
73+
* in_nmi() - We're in NMI context
74+
* in_task() - We're in task context
75+
*
76+
* Note: due to the BH disabled confusion: in_softirq(),in_interrupt() really
77+
* should not be used in new code.
7178
*/
7279
#define in_irq() (hardirq_count())
7380
#define in_softirq() (softirq_count())
7481
#define in_interrupt() (irq_count())
7582
#define in_serving_softirq() (softirq_count() & SOFTIRQ_OFFSET)
76-
77-
/*
78-
* Are we in NMI context?
79-
*/
80-
#define in_nmi() (preempt_count() & NMI_MASK)
83+
#define in_nmi() (preempt_count() & NMI_MASK)
84+
#define in_task() (!(preempt_count() & \
85+
(NMI_MASK | HARDIRQ_MASK | SOFTIRQ_OFFSET)))
8186

8287
/*
8388
* The preempt_count offset after preempt_disable();

0 commit comments

Comments
 (0)