diff options
Diffstat (limited to 'arch/x86/kernel/sys_x86_64.c')
-rw-r--r-- | arch/x86/kernel/sys_x86_64.c | 30 |
1 files changed, 27 insertions, 3 deletions
diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index 30277e27431a..10e0272d789a 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c | |||
@@ -34,10 +34,26 @@ static unsigned long get_align_mask(void) | |||
34 | return va_align.mask; | 34 | return va_align.mask; |
35 | } | 35 | } |
36 | 36 | ||
37 | /* | ||
38 | * To avoid aliasing in the I$ on AMD F15h, the bits defined by the | ||
39 | * va_align.bits, [12:upper_bit), are set to a random value instead of | ||
40 | * zeroing them. This random value is computed once per boot. This form | ||
41 | * of ASLR is known as "per-boot ASLR". | ||
42 | * | ||
43 | * To achieve this, the random value is added to the info.align_offset | ||
44 | * value before calling vm_unmapped_area() or ORed directly to the | ||
45 | * address. | ||
46 | */ | ||
47 | static unsigned long get_align_bits(void) | ||
48 | { | ||
49 | return va_align.bits & get_align_mask(); | ||
50 | } | ||
51 | |||
37 | unsigned long align_vdso_addr(unsigned long addr) | 52 | unsigned long align_vdso_addr(unsigned long addr) |
38 | { | 53 | { |
39 | unsigned long align_mask = get_align_mask(); | 54 | unsigned long align_mask = get_align_mask(); |
40 | return (addr + align_mask) & ~align_mask; | 55 | addr = (addr + align_mask) & ~align_mask; |
56 | return addr | get_align_bits(); | ||
41 | } | 57 | } |
42 | 58 | ||
43 | static int __init control_va_addr_alignment(char *str) | 59 | static int __init control_va_addr_alignment(char *str) |
@@ -135,8 +151,12 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, | |||
135 | info.length = len; | 151 | info.length = len; |
136 | info.low_limit = begin; | 152 | info.low_limit = begin; |
137 | info.high_limit = end; | 153 | info.high_limit = end; |
138 | info.align_mask = filp ? get_align_mask() : 0; | 154 | info.align_mask = 0; |
139 | info.align_offset = pgoff << PAGE_SHIFT; | 155 | info.align_offset = pgoff << PAGE_SHIFT; |
156 | if (filp) { | ||
157 | info.align_mask = get_align_mask(); | ||
158 | info.align_offset += get_align_bits(); | ||
159 | } | ||
140 | return vm_unmapped_area(&info); | 160 | return vm_unmapped_area(&info); |
141 | } | 161 | } |
142 | 162 | ||
@@ -174,8 +194,12 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, | |||
174 | info.length = len; | 194 | info.length = len; |
175 | info.low_limit = PAGE_SIZE; | 195 | info.low_limit = PAGE_SIZE; |
176 | info.high_limit = mm->mmap_base; | 196 | info.high_limit = mm->mmap_base; |
177 | info.align_mask = filp ? get_align_mask() : 0; | 197 | info.align_mask = 0; |
178 | info.align_offset = pgoff << PAGE_SHIFT; | 198 | info.align_offset = pgoff << PAGE_SHIFT; |
199 | if (filp) { | ||
200 | info.align_mask = get_align_mask(); | ||
201 | info.align_offset += get_align_bits(); | ||
202 | } | ||
179 | addr = vm_unmapped_area(&info); | 203 | addr = vm_unmapped_area(&info); |
180 | if (!(addr & ~PAGE_MASK)) | 204 | if (!(addr & ~PAGE_MASK)) |
181 | return addr; | 205 | return addr; |