Skip to content

Commit d5ed10b

Browse files
committed
Merge branch 'x86-uaccess-cleanup': x86 uaccess header cleanups
Merge my x86 uaccess updates branch. The LAM ("Linear Address Masking") updates in this release made me unhappy about how "access_ok()" was done, and it actually turned out to have a couple of small bugs in it too. This is my cleanup of the code: - use the sign bit of the __user pointer rather than masking the address and checking it against the TASK_SIZE range. We already did this part for the get/put_user() side, but 'access_ok()' did the naïve "mask and range check" thing, which not only generates nasty code, but also ended up meaning that __access_ok itself didn't do a good job, and so copy_from_user_nmi() didn't get the check right. - move all the code that is 64-bit only into the 64-bit version of the header file, so that we don't unnecessarily pollute the shared x86 code and make it look like LAM might work in 32-bit too. - fix a bug in the address masking (that doesn't end up mattering: in this case the fix was to just remove the buggy code entirely). - a couple of trivial cleanups and added commentary about the access_ok() rules. * x86-uaccess-cleanup: x86-64: mm: clarify the 'positive addresses' user address rules x86: mm: remove 'sign' games from LAM untagged_addr*() macros x86: uaccess: move 32-bit and 64-bit parts into proper <asm/uaccess_N.h> header x86: mm: remove architecture-specific 'access_ok()' define x86-64: make access_ok() independent of LAM
2 parents 982365a + 798dec3 commit d5ed10b

File tree

5 files changed

+124
-94
lines changed

5 files changed

+124
-94
lines changed

arch/x86/include/asm/uaccess.h

Lines changed: 3 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -16,88 +16,12 @@
1616
#include <asm/extable.h>
1717
#include <asm/tlbflush.h>
1818

19-
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
20-
static inline bool pagefault_disabled(void);
21-
# define WARN_ON_IN_IRQ() \
22-
WARN_ON_ONCE(!in_task() && !pagefault_disabled())
23-
#else
24-
# define WARN_ON_IN_IRQ()
25-
#endif
26-
27-
#ifdef CONFIG_ADDRESS_MASKING
28-
/*
29-
* Mask out tag bits from the address.
30-
*
31-
* Magic with the 'sign' allows to untag userspace pointer without any branches
32-
* while leaving kernel addresses intact.
33-
*/
34-
static inline unsigned long __untagged_addr(unsigned long addr)
35-
{
36-
long sign;
37-
38-
/*
39-
* Refer tlbstate_untag_mask directly to avoid RIP-relative relocation
40-
* in alternative instructions. The relocation gets wrong when gets
41-
* copied to the target place.
42-
*/
43-
asm (ALTERNATIVE("",
44-
"sar $63, %[sign]\n\t" /* user_ptr ? 0 : -1UL */
45-
"or %%gs:tlbstate_untag_mask, %[sign]\n\t"
46-
"and %[sign], %[addr]\n\t", X86_FEATURE_LAM)
47-
: [addr] "+r" (addr), [sign] "=r" (sign)
48-
: "m" (tlbstate_untag_mask), "[sign]" (addr));
49-
50-
return addr;
51-
}
52-
53-
#define untagged_addr(addr) ({ \
54-
unsigned long __addr = (__force unsigned long)(addr); \
55-
(__force __typeof__(addr))__untagged_addr(__addr); \
56-
})
57-
58-
static inline unsigned long __untagged_addr_remote(struct mm_struct *mm,
59-
unsigned long addr)
60-
{
61-
long sign = addr >> 63;
62-
63-
mmap_assert_locked(mm);
64-
addr &= (mm)->context.untag_mask | sign;
65-
66-
return addr;
67-
}
68-
69-
#define untagged_addr_remote(mm, addr) ({ \
70-
unsigned long __addr = (__force unsigned long)(addr); \
71-
(__force __typeof__(addr))__untagged_addr_remote(mm, __addr); \
72-
})
73-
19+
#ifdef CONFIG_X86_32
20+
# include <asm/uaccess_32.h>
7421
#else
75-
#define untagged_addr(addr) (addr)
22+
# include <asm/uaccess_64.h>
7623
#endif
7724

78-
/**
79-
* access_ok - Checks if a user space pointer is valid
80-
* @addr: User space pointer to start of block to check
81-
* @size: Size of block to check
82-
*
83-
* Context: User context only. This function may sleep if pagefaults are
84-
* enabled.
85-
*
86-
* Checks if a pointer to a block of memory in user space is valid.
87-
*
88-
* Note that, depending on architecture, this function probably just
89-
* checks that the pointer is in the user space range - after calling
90-
* this function, memory access functions may still return -EFAULT.
91-
*
92-
* Return: true (nonzero) if the memory block may be valid, false (zero)
93-
* if it is definitely invalid.
94-
*/
95-
#define access_ok(addr, size) \
96-
({ \
97-
WARN_ON_IN_IRQ(); \
98-
likely(__access_ok(untagged_addr(addr), size)); \
99-
})
100-
10125
#include <asm-generic/access_ok.h>
10226

10327
extern int __get_user_1(void);
@@ -586,14 +510,6 @@ extern struct movsl_mask {
586510

587511
#define ARCH_HAS_NOCACHE_UACCESS 1
588512

589-
#ifdef CONFIG_X86_32
590-
unsigned long __must_check clear_user(void __user *mem, unsigned long len);
591-
unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
592-
# include <asm/uaccess_32.h>
593-
#else
594-
# include <asm/uaccess_64.h>
595-
#endif
596-
597513
/*
598514
* The "unsafe" user accesses aren't really "unsafe", but the naming
599515
* is a big fat warning: you have to not only do the access_ok()

arch/x86/include/asm/uaccess_32.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,7 @@ __copy_from_user_inatomic_nocache(void *to, const void __user *from,
3333
return __copy_from_user_ll_nocache_nozero(to, from, n);
3434
}
3535

36+
unsigned long __must_check clear_user(void __user *mem, unsigned long len);
37+
unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
38+
3639
#endif /* _ASM_X86_UACCESS_32_H */

arch/x86/include/asm/uaccess_64.h

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,87 @@
1212
#include <asm/cpufeatures.h>
1313
#include <asm/page.h>
1414

15+
#ifdef CONFIG_ADDRESS_MASKING
16+
/*
17+
* Mask out tag bits from the address.
18+
*/
19+
static inline unsigned long __untagged_addr(unsigned long addr)
20+
{
21+
/*
22+
* Refer tlbstate_untag_mask directly to avoid RIP-relative relocation
23+
* in alternative instructions. The relocation gets wrong when gets
24+
* copied to the target place.
25+
*/
26+
asm (ALTERNATIVE("",
27+
"and %%gs:tlbstate_untag_mask, %[addr]\n\t", X86_FEATURE_LAM)
28+
: [addr] "+r" (addr) : "m" (tlbstate_untag_mask));
29+
30+
return addr;
31+
}
32+
33+
#define untagged_addr(addr) ({ \
34+
unsigned long __addr = (__force unsigned long)(addr); \
35+
(__force __typeof__(addr))__untagged_addr(__addr); \
36+
})
37+
38+
static inline unsigned long __untagged_addr_remote(struct mm_struct *mm,
39+
unsigned long addr)
40+
{
41+
mmap_assert_locked(mm);
42+
return addr & (mm)->context.untag_mask;
43+
}
44+
45+
#define untagged_addr_remote(mm, addr) ({ \
46+
unsigned long __addr = (__force unsigned long)(addr); \
47+
(__force __typeof__(addr))__untagged_addr_remote(mm, __addr); \
48+
})
49+
50+
#endif
51+
52+
/*
53+
* The virtual address space space is logically divided into a kernel
54+
* half and a user half. When cast to a signed type, user pointers
55+
* are positive and kernel pointers are negative.
56+
*/
57+
#define valid_user_address(x) ((long)(x) >= 0)
58+
59+
/*
60+
* User pointers can have tag bits on x86-64. This scheme tolerates
61+
* arbitrary values in those bits rather then masking them off.
62+
*
63+
* Enforce two rules:
64+
* 1. 'ptr' must be in the user half of the address space
65+
* 2. 'ptr+size' must not overflow into kernel addresses
66+
*
67+
* Note that addresses around the sign change are not valid addresses,
68+
* and will GP-fault even with LAM enabled if the sign bit is set (see
69+
* "CR3.LAM_SUP" that can narrow the canonicality check if we ever
70+
* enable it, but not remove it entirely).
71+
*
72+
* So the "overflow into kernel addresses" does not imply some sudden
73+
* exact boundary at the sign bit, and we can allow a lot of slop on the
74+
* size check.
75+
*
76+
* In fact, we could probably remove the size check entirely, since
77+
* any kernel accesses will be in increasing address order starting
78+
* at 'ptr', and even if the end might be in kernel space, we'll
79+
* hit the GP faults for non-canonical accesses before we ever get
80+
* there.
81+
*
82+
* That's a separate optimization, for now just handle the small
83+
* constant case.
84+
*/
85+
static inline bool __access_ok(const void __user *ptr, unsigned long size)
86+
{
87+
if (__builtin_constant_p(size <= PAGE_SIZE) && size <= PAGE_SIZE) {
88+
return valid_user_address(ptr);
89+
} else {
90+
unsigned long sum = size + (unsigned long)ptr;
91+
return valid_user_address(sum) && sum >= (unsigned long)ptr;
92+
}
93+
}
94+
#define __access_ok __access_ok
95+
1596
/*
1697
* Copy To/From Userspace
1798
*/
@@ -106,7 +187,7 @@ static __always_inline __must_check unsigned long __clear_user(void __user *addr
106187

107188
static __always_inline unsigned long clear_user(void __user *to, unsigned long n)
108189
{
109-
if (access_ok(to, n))
190+
if (__access_ok(to, n))
110191
return __clear_user(to, n);
111192
return n;
112193
}

arch/x86/mm/extable.c

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,36 @@ static bool ex_handler_fprestore(const struct exception_table_entry *fixup,
130130
return true;
131131
}
132132

133+
/*
134+
* On x86-64, we end up being imprecise with 'access_ok()', and allow
135+
* non-canonical user addresses to make the range comparisons simpler,
136+
* and to not have to worry about LAM being enabled.
137+
*
138+
* In fact, we allow up to one page of "slop" at the sign boundary,
139+
* which means that we can do access_ok() by just checking the sign
140+
* of the pointer for the common case of having a small access size.
141+
*/
142+
static bool gp_fault_address_ok(unsigned long fault_address)
143+
{
144+
#ifdef CONFIG_X86_64
145+
/* Is it in the "user space" part of the non-canonical space? */
146+
if (valid_user_address(fault_address))
147+
return true;
148+
149+
/* .. or just above it? */
150+
fault_address -= PAGE_SIZE;
151+
if (valid_user_address(fault_address))
152+
return true;
153+
#endif
154+
return false;
155+
}
156+
133157
static bool ex_handler_uaccess(const struct exception_table_entry *fixup,
134-
struct pt_regs *regs, int trapnr)
158+
struct pt_regs *regs, int trapnr,
159+
unsigned long fault_address)
135160
{
136-
WARN_ONCE(trapnr == X86_TRAP_GP, "General protection fault in user access. Non-canonical address?");
161+
WARN_ONCE(trapnr == X86_TRAP_GP && !gp_fault_address_ok(fault_address),
162+
"General protection fault in user access. Non-canonical address?");
137163
return ex_handler_default(fixup, regs);
138164
}
139165

@@ -189,10 +215,12 @@ static bool ex_handler_imm_reg(const struct exception_table_entry *fixup,
189215
}
190216

191217
static bool ex_handler_ucopy_len(const struct exception_table_entry *fixup,
192-
struct pt_regs *regs, int trapnr, int reg, int imm)
218+
struct pt_regs *regs, int trapnr,
219+
unsigned long fault_address,
220+
int reg, int imm)
193221
{
194222
regs->cx = imm * regs->cx + *pt_regs_nr(regs, reg);
195-
return ex_handler_uaccess(fixup, regs, trapnr);
223+
return ex_handler_uaccess(fixup, regs, trapnr, fault_address);
196224
}
197225

198226
int ex_get_fixup_type(unsigned long ip)
@@ -238,7 +266,7 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code,
238266
case EX_TYPE_FAULT_MCE_SAFE:
239267
return ex_handler_fault(e, regs, trapnr);
240268
case EX_TYPE_UACCESS:
241-
return ex_handler_uaccess(e, regs, trapnr);
269+
return ex_handler_uaccess(e, regs, trapnr, fault_addr);
242270
case EX_TYPE_COPY:
243271
return ex_handler_copy(e, regs, trapnr);
244272
case EX_TYPE_CLEAR_FS:
@@ -269,7 +297,7 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code,
269297
case EX_TYPE_FAULT_SGX:
270298
return ex_handler_sgx(e, regs, trapnr);
271299
case EX_TYPE_UCOPY_LEN:
272-
return ex_handler_ucopy_len(e, regs, trapnr, reg, imm);
300+
return ex_handler_ucopy_len(e, regs, trapnr, fault_addr, reg, imm);
273301
case EX_TYPE_ZEROPAD:
274302
return ex_handler_zeropad(e, regs, fault_addr);
275303
}

mm/gup.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2970,6 +2970,8 @@ static int internal_get_user_pages_fast(unsigned long start,
29702970
len = nr_pages << PAGE_SHIFT;
29712971
if (check_add_overflow(start, len, &end))
29722972
return 0;
2973+
if (end > TASK_SIZE_MAX)
2974+
return -EFAULT;
29732975
if (unlikely(!access_ok((void __user *)start, len)))
29742976
return -EFAULT;
29752977

0 commit comments

Comments
 (0)