Merge branch 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/pti updates from Thomas Gleixner: "Yet another pile of melted spectrum related updates: - Drop native vsyscall support finally as it causes more trouble than benefit. - Make microcode loading more robust. There were a few issues especially related to late loading which are now surfacing because late loading of the IB* microcodes addressing spectre issues has become more widely used. - Simplify and robustify the syscall handling in the entry code - Prevent kprobes on the entry trampoline code which lead to kernel crashes when the probe hits before CR3 is updated - Don't check microcode versions when running on hypervisors as they are considered as lying anyway. - Fix the 32bit objtool build and a coment typo" * 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/kprobes: Fix kernel crash when probing .entry_trampoline code x86/pti: Fix a comment typo x86/microcode: Synchronize late microcode loading x86/microcode: Request microcode on the BSP x86/microcode/intel: Look into the patch cache first x86/microcode: Do not upload microcode if CPUs are offline x86/microcode/intel: Writeback and invalidate caches before updating microcode x86/microcode/intel: Check microcode revision before updating sibling threads x86/microcode: Get rid of struct apply_microcode_ctx x86/spectre_v2: Don't check microcode versions when running under hypervisors x86/vsyscall/64: Drop "native" vsyscalls x86/entry/64/compat: Save one instruction in entry_INT80_compat() x86/entry: Do not special-case clone(2) in compat entry x86/syscalls: Use COMPAT_SYSCALL_DEFINEx() macros for x86-only compat syscalls x86/syscalls: Use proper syscall definition for sys_ioperm() x86/entry: Remove stale syscall prototype x86/syscalls/32: Simplify $entry == $compat entries objtool: Fix 32-bit build
This commit is contained in:
commit
ed58d66f60
|
@ -2307,7 +2307,7 @@ choice
|
||||||
it can be used to assist security vulnerability exploitation.
|
it can be used to assist security vulnerability exploitation.
|
||||||
|
|
||||||
This setting can be changed at boot time via the kernel command
|
This setting can be changed at boot time via the kernel command
|
||||||
line parameter vsyscall=[native|emulate|none].
|
line parameter vsyscall=[emulate|none].
|
||||||
|
|
||||||
On a system with recent enough glibc (2.14 or newer) and no
|
On a system with recent enough glibc (2.14 or newer) and no
|
||||||
static binaries, you can say None without a performance penalty
|
static binaries, you can say None without a performance penalty
|
||||||
|
@ -2315,15 +2315,6 @@ choice
|
||||||
|
|
||||||
If unsure, select "Emulate".
|
If unsure, select "Emulate".
|
||||||
|
|
||||||
config LEGACY_VSYSCALL_NATIVE
|
|
||||||
bool "Native"
|
|
||||||
help
|
|
||||||
Actual executable code is located in the fixed vsyscall
|
|
||||||
address mapping, implementing time() efficiently. Since
|
|
||||||
this makes the mapping executable, it can be used during
|
|
||||||
security vulnerability exploitation (traditionally as
|
|
||||||
ROP gadgets). This configuration is not recommended.
|
|
||||||
|
|
||||||
config LEGACY_VSYSCALL_EMULATE
|
config LEGACY_VSYSCALL_EMULATE
|
||||||
bool "Emulate"
|
bool "Emulate"
|
||||||
help
|
help
|
||||||
|
|
|
@ -363,9 +363,7 @@ ENTRY(entry_INT80_compat)
|
||||||
pushq 2*8(%rdi) /* regs->ip */
|
pushq 2*8(%rdi) /* regs->ip */
|
||||||
pushq 1*8(%rdi) /* regs->orig_ax */
|
pushq 1*8(%rdi) /* regs->orig_ax */
|
||||||
|
|
||||||
movq (%rdi), %rdi /* restore %rdi */
|
pushq (%rdi) /* pt_regs->di */
|
||||||
|
|
||||||
pushq %rdi /* pt_regs->di */
|
|
||||||
pushq %rsi /* pt_regs->si */
|
pushq %rsi /* pt_regs->si */
|
||||||
pushq %rdx /* pt_regs->dx */
|
pushq %rdx /* pt_regs->dx */
|
||||||
pushq %rcx /* pt_regs->cx */
|
pushq %rcx /* pt_regs->cx */
|
||||||
|
@ -406,15 +404,3 @@ ENTRY(entry_INT80_compat)
|
||||||
TRACE_IRQS_ON
|
TRACE_IRQS_ON
|
||||||
jmp swapgs_restore_regs_and_return_to_usermode
|
jmp swapgs_restore_regs_and_return_to_usermode
|
||||||
END(entry_INT80_compat)
|
END(entry_INT80_compat)
|
||||||
|
|
||||||
ENTRY(stub32_clone)
|
|
||||||
/*
|
|
||||||
* The 32-bit clone ABI is: clone(..., int tls_val, int *child_tidptr).
|
|
||||||
* The 64-bit clone ABI is: clone(..., int *child_tidptr, int tls_val).
|
|
||||||
*
|
|
||||||
* The native 64-bit kernel's sys_clone() implements the latter,
|
|
||||||
* so we need to swap arguments here before calling it:
|
|
||||||
*/
|
|
||||||
xchg %r8, %rcx
|
|
||||||
jmp sys_clone
|
|
||||||
ENDPROC(stub32_clone)
|
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
#
|
#
|
||||||
0 i386 restart_syscall sys_restart_syscall
|
0 i386 restart_syscall sys_restart_syscall
|
||||||
1 i386 exit sys_exit
|
1 i386 exit sys_exit
|
||||||
2 i386 fork sys_fork sys_fork
|
2 i386 fork sys_fork
|
||||||
3 i386 read sys_read
|
3 i386 read sys_read
|
||||||
4 i386 write sys_write
|
4 i386 write sys_write
|
||||||
5 i386 open sys_open compat_sys_open
|
5 i386 open sys_open compat_sys_open
|
||||||
6 i386 close sys_close
|
6 i386 close sys_close
|
||||||
7 i386 waitpid sys_waitpid sys32_waitpid
|
7 i386 waitpid sys_waitpid compat_sys_x86_waitpid
|
||||||
8 i386 creat sys_creat
|
8 i386 creat sys_creat
|
||||||
9 i386 link sys_link
|
9 i386 link sys_link
|
||||||
10 i386 unlink sys_unlink
|
10 i386 unlink sys_unlink
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
69 i386 ssetmask sys_ssetmask
|
69 i386 ssetmask sys_ssetmask
|
||||||
70 i386 setreuid sys_setreuid16
|
70 i386 setreuid sys_setreuid16
|
||||||
71 i386 setregid sys_setregid16
|
71 i386 setregid sys_setregid16
|
||||||
72 i386 sigsuspend sys_sigsuspend sys_sigsuspend
|
72 i386 sigsuspend sys_sigsuspend
|
||||||
73 i386 sigpending sys_sigpending compat_sys_sigpending
|
73 i386 sigpending sys_sigpending compat_sys_sigpending
|
||||||
74 i386 sethostname sys_sethostname
|
74 i386 sethostname sys_sethostname
|
||||||
75 i386 setrlimit sys_setrlimit compat_sys_setrlimit
|
75 i386 setrlimit sys_setrlimit compat_sys_setrlimit
|
||||||
|
@ -96,7 +96,7 @@
|
||||||
87 i386 swapon sys_swapon
|
87 i386 swapon sys_swapon
|
||||||
88 i386 reboot sys_reboot
|
88 i386 reboot sys_reboot
|
||||||
89 i386 readdir sys_old_readdir compat_sys_old_readdir
|
89 i386 readdir sys_old_readdir compat_sys_old_readdir
|
||||||
90 i386 mmap sys_old_mmap sys32_mmap
|
90 i386 mmap sys_old_mmap compat_sys_x86_mmap
|
||||||
91 i386 munmap sys_munmap
|
91 i386 munmap sys_munmap
|
||||||
92 i386 truncate sys_truncate compat_sys_truncate
|
92 i386 truncate sys_truncate compat_sys_truncate
|
||||||
93 i386 ftruncate sys_ftruncate compat_sys_ftruncate
|
93 i386 ftruncate sys_ftruncate compat_sys_ftruncate
|
||||||
|
@ -126,7 +126,7 @@
|
||||||
117 i386 ipc sys_ipc compat_sys_ipc
|
117 i386 ipc sys_ipc compat_sys_ipc
|
||||||
118 i386 fsync sys_fsync
|
118 i386 fsync sys_fsync
|
||||||
119 i386 sigreturn sys_sigreturn sys32_sigreturn
|
119 i386 sigreturn sys_sigreturn sys32_sigreturn
|
||||||
120 i386 clone sys_clone stub32_clone
|
120 i386 clone sys_clone compat_sys_x86_clone
|
||||||
121 i386 setdomainname sys_setdomainname
|
121 i386 setdomainname sys_setdomainname
|
||||||
122 i386 uname sys_newuname
|
122 i386 uname sys_newuname
|
||||||
123 i386 modify_ldt sys_modify_ldt
|
123 i386 modify_ldt sys_modify_ldt
|
||||||
|
@ -186,8 +186,8 @@
|
||||||
177 i386 rt_sigtimedwait sys_rt_sigtimedwait compat_sys_rt_sigtimedwait
|
177 i386 rt_sigtimedwait sys_rt_sigtimedwait compat_sys_rt_sigtimedwait
|
||||||
178 i386 rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
|
178 i386 rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
|
||||||
179 i386 rt_sigsuspend sys_rt_sigsuspend
|
179 i386 rt_sigsuspend sys_rt_sigsuspend
|
||||||
180 i386 pread64 sys_pread64 sys32_pread
|
180 i386 pread64 sys_pread64 compat_sys_x86_pread
|
||||||
181 i386 pwrite64 sys_pwrite64 sys32_pwrite
|
181 i386 pwrite64 sys_pwrite64 compat_sys_x86_pwrite
|
||||||
182 i386 chown sys_chown16
|
182 i386 chown sys_chown16
|
||||||
183 i386 getcwd sys_getcwd
|
183 i386 getcwd sys_getcwd
|
||||||
184 i386 capget sys_capget
|
184 i386 capget sys_capget
|
||||||
|
@ -196,14 +196,14 @@
|
||||||
187 i386 sendfile sys_sendfile compat_sys_sendfile
|
187 i386 sendfile sys_sendfile compat_sys_sendfile
|
||||||
188 i386 getpmsg
|
188 i386 getpmsg
|
||||||
189 i386 putpmsg
|
189 i386 putpmsg
|
||||||
190 i386 vfork sys_vfork sys_vfork
|
190 i386 vfork sys_vfork
|
||||||
191 i386 ugetrlimit sys_getrlimit compat_sys_getrlimit
|
191 i386 ugetrlimit sys_getrlimit compat_sys_getrlimit
|
||||||
192 i386 mmap2 sys_mmap_pgoff
|
192 i386 mmap2 sys_mmap_pgoff
|
||||||
193 i386 truncate64 sys_truncate64 sys32_truncate64
|
193 i386 truncate64 sys_truncate64 compat_sys_x86_truncate64
|
||||||
194 i386 ftruncate64 sys_ftruncate64 sys32_ftruncate64
|
194 i386 ftruncate64 sys_ftruncate64 compat_sys_x86_ftruncate64
|
||||||
195 i386 stat64 sys_stat64 sys32_stat64
|
195 i386 stat64 sys_stat64 compat_sys_x86_stat64
|
||||||
196 i386 lstat64 sys_lstat64 sys32_lstat64
|
196 i386 lstat64 sys_lstat64 compat_sys_x86_lstat64
|
||||||
197 i386 fstat64 sys_fstat64 sys32_fstat64
|
197 i386 fstat64 sys_fstat64 compat_sys_x86_fstat64
|
||||||
198 i386 lchown32 sys_lchown
|
198 i386 lchown32 sys_lchown
|
||||||
199 i386 getuid32 sys_getuid
|
199 i386 getuid32 sys_getuid
|
||||||
200 i386 getgid32 sys_getgid
|
200 i386 getgid32 sys_getgid
|
||||||
|
@ -231,7 +231,7 @@
|
||||||
# 222 is unused
|
# 222 is unused
|
||||||
# 223 is unused
|
# 223 is unused
|
||||||
224 i386 gettid sys_gettid
|
224 i386 gettid sys_gettid
|
||||||
225 i386 readahead sys_readahead sys32_readahead
|
225 i386 readahead sys_readahead compat_sys_x86_readahead
|
||||||
226 i386 setxattr sys_setxattr
|
226 i386 setxattr sys_setxattr
|
||||||
227 i386 lsetxattr sys_lsetxattr
|
227 i386 lsetxattr sys_lsetxattr
|
||||||
228 i386 fsetxattr sys_fsetxattr
|
228 i386 fsetxattr sys_fsetxattr
|
||||||
|
@ -256,7 +256,7 @@
|
||||||
247 i386 io_getevents sys_io_getevents compat_sys_io_getevents
|
247 i386 io_getevents sys_io_getevents compat_sys_io_getevents
|
||||||
248 i386 io_submit sys_io_submit compat_sys_io_submit
|
248 i386 io_submit sys_io_submit compat_sys_io_submit
|
||||||
249 i386 io_cancel sys_io_cancel
|
249 i386 io_cancel sys_io_cancel
|
||||||
250 i386 fadvise64 sys_fadvise64 sys32_fadvise64
|
250 i386 fadvise64 sys_fadvise64 compat_sys_x86_fadvise64
|
||||||
# 251 is available for reuse (was briefly sys_set_zone_reclaim)
|
# 251 is available for reuse (was briefly sys_set_zone_reclaim)
|
||||||
252 i386 exit_group sys_exit_group
|
252 i386 exit_group sys_exit_group
|
||||||
253 i386 lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie
|
253 i386 lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie
|
||||||
|
@ -278,7 +278,7 @@
|
||||||
269 i386 fstatfs64 sys_fstatfs64 compat_sys_fstatfs64
|
269 i386 fstatfs64 sys_fstatfs64 compat_sys_fstatfs64
|
||||||
270 i386 tgkill sys_tgkill
|
270 i386 tgkill sys_tgkill
|
||||||
271 i386 utimes sys_utimes compat_sys_utimes
|
271 i386 utimes sys_utimes compat_sys_utimes
|
||||||
272 i386 fadvise64_64 sys_fadvise64_64 sys32_fadvise64_64
|
272 i386 fadvise64_64 sys_fadvise64_64 compat_sys_x86_fadvise64_64
|
||||||
273 i386 vserver
|
273 i386 vserver
|
||||||
274 i386 mbind sys_mbind
|
274 i386 mbind sys_mbind
|
||||||
275 i386 get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy
|
275 i386 get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy
|
||||||
|
@ -306,7 +306,7 @@
|
||||||
297 i386 mknodat sys_mknodat
|
297 i386 mknodat sys_mknodat
|
||||||
298 i386 fchownat sys_fchownat
|
298 i386 fchownat sys_fchownat
|
||||||
299 i386 futimesat sys_futimesat compat_sys_futimesat
|
299 i386 futimesat sys_futimesat compat_sys_futimesat
|
||||||
300 i386 fstatat64 sys_fstatat64 sys32_fstatat
|
300 i386 fstatat64 sys_fstatat64 compat_sys_x86_fstatat
|
||||||
301 i386 unlinkat sys_unlinkat
|
301 i386 unlinkat sys_unlinkat
|
||||||
302 i386 renameat sys_renameat
|
302 i386 renameat sys_renameat
|
||||||
303 i386 linkat sys_linkat
|
303 i386 linkat sys_linkat
|
||||||
|
@ -320,7 +320,7 @@
|
||||||
311 i386 set_robust_list sys_set_robust_list compat_sys_set_robust_list
|
311 i386 set_robust_list sys_set_robust_list compat_sys_set_robust_list
|
||||||
312 i386 get_robust_list sys_get_robust_list compat_sys_get_robust_list
|
312 i386 get_robust_list sys_get_robust_list compat_sys_get_robust_list
|
||||||
313 i386 splice sys_splice
|
313 i386 splice sys_splice
|
||||||
314 i386 sync_file_range sys_sync_file_range sys32_sync_file_range
|
314 i386 sync_file_range sys_sync_file_range compat_sys_x86_sync_file_range
|
||||||
315 i386 tee sys_tee
|
315 i386 tee sys_tee
|
||||||
316 i386 vmsplice sys_vmsplice compat_sys_vmsplice
|
316 i386 vmsplice sys_vmsplice compat_sys_vmsplice
|
||||||
317 i386 move_pages sys_move_pages compat_sys_move_pages
|
317 i386 move_pages sys_move_pages compat_sys_move_pages
|
||||||
|
@ -330,7 +330,7 @@
|
||||||
321 i386 signalfd sys_signalfd compat_sys_signalfd
|
321 i386 signalfd sys_signalfd compat_sys_signalfd
|
||||||
322 i386 timerfd_create sys_timerfd_create
|
322 i386 timerfd_create sys_timerfd_create
|
||||||
323 i386 eventfd sys_eventfd
|
323 i386 eventfd sys_eventfd
|
||||||
324 i386 fallocate sys_fallocate sys32_fallocate
|
324 i386 fallocate sys_fallocate compat_sys_x86_fallocate
|
||||||
325 i386 timerfd_settime sys_timerfd_settime compat_sys_timerfd_settime
|
325 i386 timerfd_settime sys_timerfd_settime compat_sys_timerfd_settime
|
||||||
326 i386 timerfd_gettime sys_timerfd_gettime compat_sys_timerfd_gettime
|
326 i386 timerfd_gettime sys_timerfd_gettime compat_sys_timerfd_gettime
|
||||||
327 i386 signalfd4 sys_signalfd4 compat_sys_signalfd4
|
327 i386 signalfd4 sys_signalfd4 compat_sys_signalfd4
|
||||||
|
|
|
@ -42,10 +42,8 @@
|
||||||
#define CREATE_TRACE_POINTS
|
#define CREATE_TRACE_POINTS
|
||||||
#include "vsyscall_trace.h"
|
#include "vsyscall_trace.h"
|
||||||
|
|
||||||
static enum { EMULATE, NATIVE, NONE } vsyscall_mode =
|
static enum { EMULATE, NONE } vsyscall_mode =
|
||||||
#if defined(CONFIG_LEGACY_VSYSCALL_NATIVE)
|
#ifdef CONFIG_LEGACY_VSYSCALL_NONE
|
||||||
NATIVE;
|
|
||||||
#elif defined(CONFIG_LEGACY_VSYSCALL_NONE)
|
|
||||||
NONE;
|
NONE;
|
||||||
#else
|
#else
|
||||||
EMULATE;
|
EMULATE;
|
||||||
|
@ -56,8 +54,6 @@ static int __init vsyscall_setup(char *str)
|
||||||
if (str) {
|
if (str) {
|
||||||
if (!strcmp("emulate", str))
|
if (!strcmp("emulate", str))
|
||||||
vsyscall_mode = EMULATE;
|
vsyscall_mode = EMULATE;
|
||||||
else if (!strcmp("native", str))
|
|
||||||
vsyscall_mode = NATIVE;
|
|
||||||
else if (!strcmp("none", str))
|
else if (!strcmp("none", str))
|
||||||
vsyscall_mode = NONE;
|
vsyscall_mode = NONE;
|
||||||
else
|
else
|
||||||
|
@ -139,10 +135,6 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
|
||||||
|
|
||||||
WARN_ON_ONCE(address != regs->ip);
|
WARN_ON_ONCE(address != regs->ip);
|
||||||
|
|
||||||
/* This should be unreachable in NATIVE mode. */
|
|
||||||
if (WARN_ON(vsyscall_mode == NATIVE))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (vsyscall_mode == NONE) {
|
if (vsyscall_mode == NONE) {
|
||||||
warn_bad_vsyscall(KERN_INFO, regs,
|
warn_bad_vsyscall(KERN_INFO, regs,
|
||||||
"vsyscall attempted with vsyscall=none");
|
"vsyscall attempted with vsyscall=none");
|
||||||
|
@ -370,9 +362,7 @@ void __init map_vsyscall(void)
|
||||||
|
|
||||||
if (vsyscall_mode != NONE) {
|
if (vsyscall_mode != NONE) {
|
||||||
__set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall,
|
__set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall,
|
||||||
vsyscall_mode == NATIVE
|
PAGE_KERNEL_VVAR);
|
||||||
? PAGE_KERNEL_VSYSCALL
|
|
||||||
: PAGE_KERNEL_VVAR);
|
|
||||||
set_vsyscall_pgtable_user_bits(swapper_pg_dir);
|
set_vsyscall_pgtable_user_bits(swapper_pg_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,15 +51,14 @@
|
||||||
#define AA(__x) ((unsigned long)(__x))
|
#define AA(__x) ((unsigned long)(__x))
|
||||||
|
|
||||||
|
|
||||||
asmlinkage long sys32_truncate64(const char __user *filename,
|
COMPAT_SYSCALL_DEFINE3(x86_truncate64, const char __user *, filename,
|
||||||
unsigned long offset_low,
|
unsigned long, offset_low, unsigned long, offset_high)
|
||||||
unsigned long offset_high)
|
|
||||||
{
|
{
|
||||||
return sys_truncate(filename, ((loff_t) offset_high << 32) | offset_low);
|
return sys_truncate(filename, ((loff_t) offset_high << 32) | offset_low);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long offset_low,
|
COMPAT_SYSCALL_DEFINE3(x86_ftruncate64, unsigned int, fd,
|
||||||
unsigned long offset_high)
|
unsigned long, offset_low, unsigned long, offset_high)
|
||||||
{
|
{
|
||||||
return sys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low);
|
return sys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low);
|
||||||
}
|
}
|
||||||
|
@ -96,8 +95,8 @@ static int cp_stat64(struct stat64 __user *ubuf, struct kstat *stat)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys32_stat64(const char __user *filename,
|
COMPAT_SYSCALL_DEFINE2(x86_stat64, const char __user *, filename,
|
||||||
struct stat64 __user *statbuf)
|
struct stat64 __user *, statbuf)
|
||||||
{
|
{
|
||||||
struct kstat stat;
|
struct kstat stat;
|
||||||
int ret = vfs_stat(filename, &stat);
|
int ret = vfs_stat(filename, &stat);
|
||||||
|
@ -107,8 +106,8 @@ asmlinkage long sys32_stat64(const char __user *filename,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys32_lstat64(const char __user *filename,
|
COMPAT_SYSCALL_DEFINE2(x86_lstat64, const char __user *, filename,
|
||||||
struct stat64 __user *statbuf)
|
struct stat64 __user *, statbuf)
|
||||||
{
|
{
|
||||||
struct kstat stat;
|
struct kstat stat;
|
||||||
int ret = vfs_lstat(filename, &stat);
|
int ret = vfs_lstat(filename, &stat);
|
||||||
|
@ -117,7 +116,8 @@ asmlinkage long sys32_lstat64(const char __user *filename,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf)
|
COMPAT_SYSCALL_DEFINE2(x86_fstat64, unsigned int, fd,
|
||||||
|
struct stat64 __user *, statbuf)
|
||||||
{
|
{
|
||||||
struct kstat stat;
|
struct kstat stat;
|
||||||
int ret = vfs_fstat(fd, &stat);
|
int ret = vfs_fstat(fd, &stat);
|
||||||
|
@ -126,8 +126,9 @@ asmlinkage long sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys32_fstatat(unsigned int dfd, const char __user *filename,
|
COMPAT_SYSCALL_DEFINE4(x86_fstatat, unsigned int, dfd,
|
||||||
struct stat64 __user *statbuf, int flag)
|
const char __user *, filename,
|
||||||
|
struct stat64 __user *, statbuf, int, flag)
|
||||||
{
|
{
|
||||||
struct kstat stat;
|
struct kstat stat;
|
||||||
int error;
|
int error;
|
||||||
|
@ -153,7 +154,7 @@ struct mmap_arg_struct32 {
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *arg)
|
COMPAT_SYSCALL_DEFINE1(x86_mmap, struct mmap_arg_struct32 __user *, arg)
|
||||||
{
|
{
|
||||||
struct mmap_arg_struct32 a;
|
struct mmap_arg_struct32 a;
|
||||||
|
|
||||||
|
@ -167,22 +168,22 @@ asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *arg)
|
||||||
a.offset>>PAGE_SHIFT);
|
a.offset>>PAGE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int __user *stat_addr,
|
COMPAT_SYSCALL_DEFINE3(x86_waitpid, compat_pid_t, pid, unsigned int __user *,
|
||||||
int options)
|
stat_addr, int, options)
|
||||||
{
|
{
|
||||||
return compat_sys_wait4(pid, stat_addr, options, NULL);
|
return compat_sys_wait4(pid, stat_addr, options, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* warning: next two assume little endian */
|
/* warning: next two assume little endian */
|
||||||
asmlinkage long sys32_pread(unsigned int fd, char __user *ubuf, u32 count,
|
COMPAT_SYSCALL_DEFINE5(x86_pread, unsigned int, fd, char __user *, ubuf,
|
||||||
u32 poslo, u32 poshi)
|
u32, count, u32, poslo, u32, poshi)
|
||||||
{
|
{
|
||||||
return sys_pread64(fd, ubuf, count,
|
return sys_pread64(fd, ubuf, count,
|
||||||
((loff_t)AA(poshi) << 32) | AA(poslo));
|
((loff_t)AA(poshi) << 32) | AA(poslo));
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys32_pwrite(unsigned int fd, const char __user *ubuf,
|
COMPAT_SYSCALL_DEFINE5(x86_pwrite, unsigned int, fd, const char __user *, ubuf,
|
||||||
u32 count, u32 poslo, u32 poshi)
|
u32, count, u32, poslo, u32, poshi)
|
||||||
{
|
{
|
||||||
return sys_pwrite64(fd, ubuf, count,
|
return sys_pwrite64(fd, ubuf, count,
|
||||||
((loff_t)AA(poshi) << 32) | AA(poslo));
|
((loff_t)AA(poshi) << 32) | AA(poslo));
|
||||||
|
@ -193,8 +194,9 @@ asmlinkage long sys32_pwrite(unsigned int fd, const char __user *ubuf,
|
||||||
* Some system calls that need sign extended arguments. This could be
|
* Some system calls that need sign extended arguments. This could be
|
||||||
* done by a generic wrapper.
|
* done by a generic wrapper.
|
||||||
*/
|
*/
|
||||||
long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high,
|
COMPAT_SYSCALL_DEFINE6(x86_fadvise64_64, int, fd, __u32, offset_low,
|
||||||
__u32 len_low, __u32 len_high, int advice)
|
__u32, offset_high, __u32, len_low, __u32, len_high,
|
||||||
|
int, advice)
|
||||||
{
|
{
|
||||||
return sys_fadvise64_64(fd,
|
return sys_fadvise64_64(fd,
|
||||||
(((u64)offset_high)<<32) | offset_low,
|
(((u64)offset_high)<<32) | offset_low,
|
||||||
|
@ -202,31 +204,43 @@ long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high,
|
||||||
advice);
|
advice);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage ssize_t sys32_readahead(int fd, unsigned off_lo, unsigned off_hi,
|
COMPAT_SYSCALL_DEFINE4(x86_readahead, int, fd, unsigned int, off_lo,
|
||||||
size_t count)
|
unsigned int, off_hi, size_t, count)
|
||||||
{
|
{
|
||||||
return sys_readahead(fd, ((u64)off_hi << 32) | off_lo, count);
|
return sys_readahead(fd, ((u64)off_hi << 32) | off_lo, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys32_sync_file_range(int fd, unsigned off_low, unsigned off_hi,
|
COMPAT_SYSCALL_DEFINE6(x86_sync_file_range, int, fd, unsigned int, off_low,
|
||||||
unsigned n_low, unsigned n_hi, int flags)
|
unsigned int, off_hi, unsigned int, n_low,
|
||||||
|
unsigned int, n_hi, int, flags)
|
||||||
{
|
{
|
||||||
return sys_sync_file_range(fd,
|
return sys_sync_file_range(fd,
|
||||||
((u64)off_hi << 32) | off_low,
|
((u64)off_hi << 32) | off_low,
|
||||||
((u64)n_hi << 32) | n_low, flags);
|
((u64)n_hi << 32) | n_low, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys32_fadvise64(int fd, unsigned offset_lo, unsigned offset_hi,
|
COMPAT_SYSCALL_DEFINE5(x86_fadvise64, int, fd, unsigned int, offset_lo,
|
||||||
size_t len, int advice)
|
unsigned int, offset_hi, size_t, len, int, advice)
|
||||||
{
|
{
|
||||||
return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo,
|
return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo,
|
||||||
len, advice);
|
len, advice);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo,
|
COMPAT_SYSCALL_DEFINE6(x86_fallocate, int, fd, int, mode,
|
||||||
unsigned offset_hi, unsigned len_lo,
|
unsigned int, offset_lo, unsigned int, offset_hi,
|
||||||
unsigned len_hi)
|
unsigned int, len_lo, unsigned int, len_hi)
|
||||||
{
|
{
|
||||||
return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
|
return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
|
||||||
((u64)len_hi << 32) | len_lo);
|
((u64)len_hi << 32) | len_lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The 32-bit clone ABI is CONFIG_CLONE_BACKWARDS
|
||||||
|
*/
|
||||||
|
COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags,
|
||||||
|
unsigned long, newsp, int __user *, parent_tidptr,
|
||||||
|
unsigned long, tls_val, int __user *, child_tidptr)
|
||||||
|
{
|
||||||
|
return sys_clone(clone_flags, newsp, parent_tidptr, child_tidptr,
|
||||||
|
tls_val);
|
||||||
|
}
|
||||||
|
|
|
@ -174,7 +174,6 @@ enum page_cache_mode {
|
||||||
#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW)
|
#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW)
|
||||||
#define __PAGE_KERNEL_RX (__PAGE_KERNEL_EXEC & ~_PAGE_RW)
|
#define __PAGE_KERNEL_RX (__PAGE_KERNEL_EXEC & ~_PAGE_RW)
|
||||||
#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_NOCACHE)
|
#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_NOCACHE)
|
||||||
#define __PAGE_KERNEL_VSYSCALL (__PAGE_KERNEL_RX | _PAGE_USER)
|
|
||||||
#define __PAGE_KERNEL_VVAR (__PAGE_KERNEL_RO | _PAGE_USER)
|
#define __PAGE_KERNEL_VVAR (__PAGE_KERNEL_RO | _PAGE_USER)
|
||||||
#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE)
|
#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE)
|
||||||
#define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE)
|
#define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE)
|
||||||
|
@ -206,7 +205,6 @@ enum page_cache_mode {
|
||||||
#define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE | _PAGE_ENC)
|
#define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE | _PAGE_ENC)
|
||||||
#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE | _PAGE_ENC)
|
#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE | _PAGE_ENC)
|
||||||
#define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC | _PAGE_ENC)
|
#define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC | _PAGE_ENC)
|
||||||
#define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL | _PAGE_ENC)
|
|
||||||
#define PAGE_KERNEL_VVAR __pgprot(__PAGE_KERNEL_VVAR | _PAGE_ENC)
|
#define PAGE_KERNEL_VVAR __pgprot(__PAGE_KERNEL_VVAR | _PAGE_ENC)
|
||||||
|
|
||||||
#define PAGE_KERNEL_IO __pgprot(__PAGE_KERNEL_IO)
|
#define PAGE_KERNEL_IO __pgprot(__PAGE_KERNEL_IO)
|
||||||
|
|
|
@ -10,6 +10,7 @@ extern struct exception_table_entry __stop___ex_table[];
|
||||||
|
|
||||||
#if defined(CONFIG_X86_64)
|
#if defined(CONFIG_X86_64)
|
||||||
extern char __end_rodata_hpage_align[];
|
extern char __end_rodata_hpage_align[];
|
||||||
|
extern char __entry_trampoline_start[], __entry_trampoline_end[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _ASM_X86_SECTIONS_H */
|
#endif /* _ASM_X86_SECTIONS_H */
|
||||||
|
|
|
@ -20,31 +20,43 @@
|
||||||
#include <asm/ia32.h>
|
#include <asm/ia32.h>
|
||||||
|
|
||||||
/* ia32/sys_ia32.c */
|
/* ia32/sys_ia32.c */
|
||||||
asmlinkage long sys32_truncate64(const char __user *, unsigned long, unsigned long);
|
asmlinkage long compat_sys_x86_truncate64(const char __user *, unsigned long,
|
||||||
asmlinkage long sys32_ftruncate64(unsigned int, unsigned long, unsigned long);
|
unsigned long);
|
||||||
|
asmlinkage long compat_sys_x86_ftruncate64(unsigned int, unsigned long,
|
||||||
|
unsigned long);
|
||||||
|
|
||||||
asmlinkage long sys32_stat64(const char __user *, struct stat64 __user *);
|
asmlinkage long compat_sys_x86_stat64(const char __user *,
|
||||||
asmlinkage long sys32_lstat64(const char __user *, struct stat64 __user *);
|
struct stat64 __user *);
|
||||||
asmlinkage long sys32_fstat64(unsigned int, struct stat64 __user *);
|
asmlinkage long compat_sys_x86_lstat64(const char __user *,
|
||||||
asmlinkage long sys32_fstatat(unsigned int, const char __user *,
|
struct stat64 __user *);
|
||||||
|
asmlinkage long compat_sys_x86_fstat64(unsigned int, struct stat64 __user *);
|
||||||
|
asmlinkage long compat_sys_x86_fstatat(unsigned int, const char __user *,
|
||||||
struct stat64 __user *, int);
|
struct stat64 __user *, int);
|
||||||
struct mmap_arg_struct32;
|
struct mmap_arg_struct32;
|
||||||
asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *);
|
asmlinkage long compat_sys_x86_mmap(struct mmap_arg_struct32 __user *);
|
||||||
|
|
||||||
asmlinkage long sys32_waitpid(compat_pid_t, unsigned int __user *, int);
|
asmlinkage long compat_sys_x86_waitpid(compat_pid_t, unsigned int __user *,
|
||||||
|
int);
|
||||||
|
|
||||||
asmlinkage long sys32_pread(unsigned int, char __user *, u32, u32, u32);
|
asmlinkage long compat_sys_x86_pread(unsigned int, char __user *, u32, u32,
|
||||||
asmlinkage long sys32_pwrite(unsigned int, const char __user *, u32, u32, u32);
|
u32);
|
||||||
|
asmlinkage long compat_sys_x86_pwrite(unsigned int, const char __user *, u32,
|
||||||
|
u32, u32);
|
||||||
|
|
||||||
long sys32_fadvise64_64(int, __u32, __u32, __u32, __u32, int);
|
asmlinkage long compat_sys_x86_fadvise64_64(int, __u32, __u32, __u32, __u32,
|
||||||
long sys32_vm86_warning(void);
|
int);
|
||||||
|
|
||||||
asmlinkage ssize_t sys32_readahead(int, unsigned, unsigned, size_t);
|
asmlinkage ssize_t compat_sys_x86_readahead(int, unsigned int, unsigned int,
|
||||||
asmlinkage long sys32_sync_file_range(int, unsigned, unsigned,
|
size_t);
|
||||||
unsigned, unsigned, int);
|
asmlinkage long compat_sys_x86_sync_file_range(int, unsigned int, unsigned int,
|
||||||
asmlinkage long sys32_fadvise64(int, unsigned, unsigned, size_t, int);
|
unsigned int, unsigned int,
|
||||||
asmlinkage long sys32_fallocate(int, int, unsigned,
|
int);
|
||||||
unsigned, unsigned, unsigned);
|
asmlinkage long compat_sys_x86_fadvise64(int, unsigned int, unsigned int,
|
||||||
|
size_t, int);
|
||||||
|
asmlinkage long compat_sys_x86_fallocate(int, int, unsigned int, unsigned int,
|
||||||
|
unsigned int, unsigned int);
|
||||||
|
asmlinkage long compat_sys_x86_clone(unsigned long, unsigned long, int __user *,
|
||||||
|
unsigned long, int __user *);
|
||||||
|
|
||||||
/* ia32/ia32_signal.c */
|
/* ia32/ia32_signal.c */
|
||||||
asmlinkage long sys32_sigreturn(void);
|
asmlinkage long sys32_sigreturn(void);
|
||||||
|
|
|
@ -144,6 +144,13 @@ static bool bad_spectre_microcode(struct cpuinfo_x86 *c)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We know that the hypervisor lie to us on the microcode version so
|
||||||
|
* we may as well hope that it is running the correct version.
|
||||||
|
*/
|
||||||
|
if (cpu_has(c, X86_FEATURE_HYPERVISOR))
|
||||||
|
return false;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(spectre_bad_microcodes); i++) {
|
for (i = 0; i < ARRAY_SIZE(spectre_bad_microcodes); i++) {
|
||||||
if (c->x86_model == spectre_bad_microcodes[i].model &&
|
if (c->x86_model == spectre_bad_microcodes[i].model &&
|
||||||
c->x86_stepping == spectre_bad_microcodes[i].stepping)
|
c->x86_stepping == spectre_bad_microcodes[i].stepping)
|
||||||
|
|
|
@ -22,13 +22,16 @@
|
||||||
#define pr_fmt(fmt) "microcode: " fmt
|
#define pr_fmt(fmt) "microcode: " fmt
|
||||||
|
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/stop_machine.h>
|
||||||
#include <linux/syscore_ops.h>
|
#include <linux/syscore_ops.h>
|
||||||
#include <linux/miscdevice.h>
|
#include <linux/miscdevice.h>
|
||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
|
#include <linux/nmi.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
|
|
||||||
|
@ -64,6 +67,11 @@ LIST_HEAD(microcode_cache);
|
||||||
*/
|
*/
|
||||||
static DEFINE_MUTEX(microcode_mutex);
|
static DEFINE_MUTEX(microcode_mutex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Serialize late loading so that CPUs get updated one-by-one.
|
||||||
|
*/
|
||||||
|
static DEFINE_SPINLOCK(update_lock);
|
||||||
|
|
||||||
struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
|
struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
|
||||||
|
|
||||||
struct cpu_info_ctx {
|
struct cpu_info_ctx {
|
||||||
|
@ -373,26 +381,23 @@ static int collect_cpu_info(int cpu)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct apply_microcode_ctx {
|
|
||||||
enum ucode_state err;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void apply_microcode_local(void *arg)
|
static void apply_microcode_local(void *arg)
|
||||||
{
|
{
|
||||||
struct apply_microcode_ctx *ctx = arg;
|
enum ucode_state *err = arg;
|
||||||
|
|
||||||
ctx->err = microcode_ops->apply_microcode(smp_processor_id());
|
*err = microcode_ops->apply_microcode(smp_processor_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apply_microcode_on_target(int cpu)
|
static int apply_microcode_on_target(int cpu)
|
||||||
{
|
{
|
||||||
struct apply_microcode_ctx ctx = { .err = 0 };
|
enum ucode_state err;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = smp_call_function_single(cpu, apply_microcode_local, &ctx, 1);
|
ret = smp_call_function_single(cpu, apply_microcode_local, &err, 1);
|
||||||
if (!ret)
|
if (!ret) {
|
||||||
ret = ctx.err;
|
if (err == UCODE_ERROR)
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,19 +494,100 @@ static void __exit microcode_dev_exit(void)
|
||||||
/* fake device for request_firmware */
|
/* fake device for request_firmware */
|
||||||
static struct platform_device *microcode_pdev;
|
static struct platform_device *microcode_pdev;
|
||||||
|
|
||||||
static enum ucode_state reload_for_cpu(int cpu)
|
/*
|
||||||
|
* Late loading dance. Why the heavy-handed stomp_machine effort?
|
||||||
|
*
|
||||||
|
* - HT siblings must be idle and not execute other code while the other sibling
|
||||||
|
* is loading microcode in order to avoid any negative interactions caused by
|
||||||
|
* the loading.
|
||||||
|
*
|
||||||
|
* - In addition, microcode update on the cores must be serialized until this
|
||||||
|
* requirement can be relaxed in the future. Right now, this is conservative
|
||||||
|
* and good.
|
||||||
|
*/
|
||||||
|
#define SPINUNIT 100 /* 100 nsec */
|
||||||
|
|
||||||
|
static int check_online_cpus(void)
|
||||||
{
|
{
|
||||||
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
|
if (num_online_cpus() == num_present_cpus())
|
||||||
enum ucode_state ustate;
|
return 0;
|
||||||
|
|
||||||
if (!uci->valid)
|
pr_err("Not all CPUs online, aborting microcode update.\n");
|
||||||
return UCODE_OK;
|
|
||||||
|
|
||||||
ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, true);
|
return -EINVAL;
|
||||||
if (ustate != UCODE_OK)
|
}
|
||||||
return ustate;
|
|
||||||
|
|
||||||
return apply_microcode_on_target(cpu);
|
static atomic_t late_cpus;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns:
|
||||||
|
* < 0 - on error
|
||||||
|
* 0 - no update done
|
||||||
|
* 1 - microcode was updated
|
||||||
|
*/
|
||||||
|
static int __reload_late(void *info)
|
||||||
|
{
|
||||||
|
unsigned int timeout = NSEC_PER_SEC;
|
||||||
|
int all_cpus = num_online_cpus();
|
||||||
|
int cpu = smp_processor_id();
|
||||||
|
enum ucode_state err;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
atomic_dec(&late_cpus);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for all CPUs to arrive. A load will not be attempted unless all
|
||||||
|
* CPUs show up.
|
||||||
|
* */
|
||||||
|
while (atomic_read(&late_cpus)) {
|
||||||
|
if (timeout < SPINUNIT) {
|
||||||
|
pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n",
|
||||||
|
atomic_read(&late_cpus));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ndelay(SPINUNIT);
|
||||||
|
timeout -= SPINUNIT;
|
||||||
|
|
||||||
|
touch_nmi_watchdog();
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock(&update_lock);
|
||||||
|
apply_microcode_local(&err);
|
||||||
|
spin_unlock(&update_lock);
|
||||||
|
|
||||||
|
if (err > UCODE_NFOUND) {
|
||||||
|
pr_warn("Error reloading microcode on CPU %d\n", cpu);
|
||||||
|
ret = -1;
|
||||||
|
} else if (err == UCODE_UPDATED) {
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_inc(&late_cpus);
|
||||||
|
|
||||||
|
while (atomic_read(&late_cpus) != all_cpus)
|
||||||
|
cpu_relax();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reload microcode late on all CPUs. Wait for a sec until they
|
||||||
|
* all gather together.
|
||||||
|
*/
|
||||||
|
static int microcode_reload_late(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
atomic_set(&late_cpus, num_online_cpus());
|
||||||
|
|
||||||
|
ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
else if (ret > 0)
|
||||||
|
microcode_check();
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t reload_store(struct device *dev,
|
static ssize_t reload_store(struct device *dev,
|
||||||
|
@ -509,10 +595,9 @@ static ssize_t reload_store(struct device *dev,
|
||||||
const char *buf, size_t size)
|
const char *buf, size_t size)
|
||||||
{
|
{
|
||||||
enum ucode_state tmp_ret = UCODE_OK;
|
enum ucode_state tmp_ret = UCODE_OK;
|
||||||
bool do_callback = false;
|
int bsp = boot_cpu_data.cpu_index;
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
int cpu;
|
|
||||||
|
|
||||||
ret = kstrtoul(buf, 0, &val);
|
ret = kstrtoul(buf, 0, &val);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -521,29 +606,24 @@ static ssize_t reload_store(struct device *dev,
|
||||||
if (val != 1)
|
if (val != 1)
|
||||||
return size;
|
return size;
|
||||||
|
|
||||||
|
tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev, true);
|
||||||
|
if (tmp_ret != UCODE_OK)
|
||||||
|
return size;
|
||||||
|
|
||||||
get_online_cpus();
|
get_online_cpus();
|
||||||
|
|
||||||
|
ret = check_online_cpus();
|
||||||
|
if (ret)
|
||||||
|
goto put;
|
||||||
|
|
||||||
mutex_lock(µcode_mutex);
|
mutex_lock(µcode_mutex);
|
||||||
for_each_online_cpu(cpu) {
|
ret = microcode_reload_late();
|
||||||
tmp_ret = reload_for_cpu(cpu);
|
|
||||||
if (tmp_ret > UCODE_NFOUND) {
|
|
||||||
pr_warn("Error reloading microcode on CPU %d\n", cpu);
|
|
||||||
|
|
||||||
/* set retval for the first encountered reload error */
|
|
||||||
if (!ret)
|
|
||||||
ret = -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tmp_ret == UCODE_UPDATED)
|
|
||||||
do_callback = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ret && do_callback)
|
|
||||||
microcode_check();
|
|
||||||
|
|
||||||
mutex_unlock(µcode_mutex);
|
mutex_unlock(µcode_mutex);
|
||||||
|
|
||||||
|
put:
|
||||||
put_online_cpus();
|
put_online_cpus();
|
||||||
|
|
||||||
if (!ret)
|
if (ret >= 0)
|
||||||
ret = size;
|
ret = size;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -589,6 +589,23 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
|
||||||
if (!mc)
|
if (!mc)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save us the MSR write below - which is a particular expensive
|
||||||
|
* operation - when the other hyperthread has updated the microcode
|
||||||
|
* already.
|
||||||
|
*/
|
||||||
|
rev = intel_get_microcode_revision();
|
||||||
|
if (rev >= mc->hdr.rev) {
|
||||||
|
uci->cpu_sig.rev = rev;
|
||||||
|
return UCODE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writeback and invalidate caches before updating microcode to avoid
|
||||||
|
* internal issues depending on what the microcode is updating.
|
||||||
|
*/
|
||||||
|
native_wbinvd();
|
||||||
|
|
||||||
/* write microcode via MSR 0x79 */
|
/* write microcode via MSR 0x79 */
|
||||||
native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
|
native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
|
||||||
|
|
||||||
|
@ -774,9 +791,9 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
|
||||||
|
|
||||||
static enum ucode_state apply_microcode_intel(int cpu)
|
static enum ucode_state apply_microcode_intel(int cpu)
|
||||||
{
|
{
|
||||||
|
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
|
||||||
|
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
||||||
struct microcode_intel *mc;
|
struct microcode_intel *mc;
|
||||||
struct ucode_cpu_info *uci;
|
|
||||||
struct cpuinfo_x86 *c;
|
|
||||||
static int prev_rev;
|
static int prev_rev;
|
||||||
u32 rev;
|
u32 rev;
|
||||||
|
|
||||||
|
@ -784,15 +801,32 @@ static enum ucode_state apply_microcode_intel(int cpu)
|
||||||
if (WARN_ON(raw_smp_processor_id() != cpu))
|
if (WARN_ON(raw_smp_processor_id() != cpu))
|
||||||
return UCODE_ERROR;
|
return UCODE_ERROR;
|
||||||
|
|
||||||
uci = ucode_cpu_info + cpu;
|
/* Look for a newer patch in our cache: */
|
||||||
mc = uci->mc;
|
mc = find_patch(uci);
|
||||||
if (!mc) {
|
if (!mc) {
|
||||||
/* Look for a newer patch in our cache: */
|
mc = uci->mc;
|
||||||
mc = find_patch(uci);
|
|
||||||
if (!mc)
|
if (!mc)
|
||||||
return UCODE_NFOUND;
|
return UCODE_NFOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save us the MSR write below - which is a particular expensive
|
||||||
|
* operation - when the other hyperthread has updated the microcode
|
||||||
|
* already.
|
||||||
|
*/
|
||||||
|
rev = intel_get_microcode_revision();
|
||||||
|
if (rev >= mc->hdr.rev) {
|
||||||
|
uci->cpu_sig.rev = rev;
|
||||||
|
c->microcode = rev;
|
||||||
|
return UCODE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writeback and invalidate caches before updating microcode to avoid
|
||||||
|
* internal issues depending on what the microcode is updating.
|
||||||
|
*/
|
||||||
|
native_wbinvd();
|
||||||
|
|
||||||
/* write microcode via MSR 0x79 */
|
/* write microcode via MSR 0x79 */
|
||||||
wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
|
wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
|
||||||
|
|
||||||
|
@ -813,8 +847,6 @@ static enum ucode_state apply_microcode_intel(int cpu)
|
||||||
prev_rev = rev;
|
prev_rev = rev;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = &cpu_data(cpu);
|
|
||||||
|
|
||||||
uci->cpu_sig.rev = rev;
|
uci->cpu_sig.rev = rev;
|
||||||
c->microcode = rev;
|
c->microcode = rev;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
/*
|
/*
|
||||||
* this changes the io permissions bitmap in the current task.
|
* this changes the io permissions bitmap in the current task.
|
||||||
*/
|
*/
|
||||||
asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
|
SYSCALL_DEFINE3(ioperm, unsigned long, from, unsigned long, num, int, turn_on)
|
||||||
{
|
{
|
||||||
struct thread_struct *t = ¤t->thread;
|
struct thread_struct *t = ¤t->thread;
|
||||||
struct tss_struct *tss;
|
struct tss_struct *tss;
|
||||||
|
|
|
@ -1168,10 +1168,18 @@ NOKPROBE_SYMBOL(longjmp_break_handler);
|
||||||
|
|
||||||
bool arch_within_kprobe_blacklist(unsigned long addr)
|
bool arch_within_kprobe_blacklist(unsigned long addr)
|
||||||
{
|
{
|
||||||
|
bool is_in_entry_trampoline_section = false;
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
is_in_entry_trampoline_section =
|
||||||
|
(addr >= (unsigned long)__entry_trampoline_start &&
|
||||||
|
addr < (unsigned long)__entry_trampoline_end);
|
||||||
|
#endif
|
||||||
return (addr >= (unsigned long)__kprobes_text_start &&
|
return (addr >= (unsigned long)__kprobes_text_start &&
|
||||||
addr < (unsigned long)__kprobes_text_end) ||
|
addr < (unsigned long)__kprobes_text_end) ||
|
||||||
(addr >= (unsigned long)__entry_text_start &&
|
(addr >= (unsigned long)__entry_text_start &&
|
||||||
addr < (unsigned long)__entry_text_end);
|
addr < (unsigned long)__entry_text_end) ||
|
||||||
|
is_in_entry_trampoline_section;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __init arch_init_kprobes(void)
|
int __init arch_init_kprobes(void)
|
||||||
|
|
|
@ -118,9 +118,11 @@ SECTIONS
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
. = ALIGN(PAGE_SIZE);
|
. = ALIGN(PAGE_SIZE);
|
||||||
|
VMLINUX_SYMBOL(__entry_trampoline_start) = .;
|
||||||
_entry_trampoline = .;
|
_entry_trampoline = .;
|
||||||
*(.entry_trampoline)
|
*(.entry_trampoline)
|
||||||
. = ALIGN(PAGE_SIZE);
|
. = ALIGN(PAGE_SIZE);
|
||||||
|
VMLINUX_SYMBOL(__entry_trampoline_end) = .;
|
||||||
ASSERT(. - _entry_trampoline == PAGE_SIZE, "entry trampoline is too big");
|
ASSERT(. - _entry_trampoline == PAGE_SIZE, "entry trampoline is too big");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -332,7 +332,7 @@ static void __init pti_clone_user_shared(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clone the ESPFIX P4D into the user space visinble page table
|
* Clone the ESPFIX P4D into the user space visible page table
|
||||||
*/
|
*/
|
||||||
static void __init pti_setup_espfix64(void)
|
static void __init pti_setup_espfix64(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1116,42 +1116,29 @@ static int read_unwind_hints(struct objtool_file *file)
|
||||||
|
|
||||||
static int read_retpoline_hints(struct objtool_file *file)
|
static int read_retpoline_hints(struct objtool_file *file)
|
||||||
{
|
{
|
||||||
struct section *sec, *relasec;
|
struct section *sec;
|
||||||
struct instruction *insn;
|
struct instruction *insn;
|
||||||
struct rela *rela;
|
struct rela *rela;
|
||||||
int i;
|
|
||||||
|
|
||||||
sec = find_section_by_name(file->elf, ".discard.retpoline_safe");
|
sec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe");
|
||||||
if (!sec)
|
if (!sec)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
relasec = sec->rela;
|
list_for_each_entry(rela, &sec->rela_list, list) {
|
||||||
if (!relasec) {
|
if (rela->sym->type != STT_SECTION) {
|
||||||
WARN("missing .rela.discard.retpoline_safe section");
|
WARN("unexpected relocation symbol type in %s", sec->name);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sec->len % sizeof(unsigned long)) {
|
|
||||||
WARN("retpoline_safe size mismatch: %d %ld", sec->len, sizeof(unsigned long));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < sec->len / sizeof(unsigned long); i++) {
|
|
||||||
rela = find_rela_by_dest(sec, i * sizeof(unsigned long));
|
|
||||||
if (!rela) {
|
|
||||||
WARN("can't find rela for retpoline_safe[%d]", i);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
insn = find_insn(file, rela->sym->sec, rela->addend);
|
insn = find_insn(file, rela->sym->sec, rela->addend);
|
||||||
if (!insn) {
|
if (!insn) {
|
||||||
WARN("can't find insn for retpoline_safe[%d]", i);
|
WARN("bad .discard.retpoline_safe entry");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (insn->type != INSN_JUMP_DYNAMIC &&
|
if (insn->type != INSN_JUMP_DYNAMIC &&
|
||||||
insn->type != INSN_CALL_DYNAMIC) {
|
insn->type != INSN_CALL_DYNAMIC) {
|
||||||
WARN_FUNC("retpoline_safe hint not a indirect jump/call",
|
WARN_FUNC("retpoline_safe hint not an indirect jump/call",
|
||||||
insn->sec, insn->offset);
|
insn->sec, insn->offset);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -450,7 +450,7 @@ static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
|
||||||
num_vsyscall_traps++;
|
num_vsyscall_traps++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_native_vsyscall(void)
|
static int test_emulation(void)
|
||||||
{
|
{
|
||||||
time_t tmp;
|
time_t tmp;
|
||||||
bool is_native;
|
bool is_native;
|
||||||
|
@ -458,7 +458,7 @@ static int test_native_vsyscall(void)
|
||||||
if (!vtime)
|
if (!vtime)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
printf("[RUN]\tchecking for native vsyscall\n");
|
printf("[RUN]\tchecking that vsyscalls are emulated\n");
|
||||||
sethandler(SIGTRAP, sigtrap, 0);
|
sethandler(SIGTRAP, sigtrap, 0);
|
||||||
set_eflags(get_eflags() | X86_EFLAGS_TF);
|
set_eflags(get_eflags() | X86_EFLAGS_TF);
|
||||||
vtime(&tmp);
|
vtime(&tmp);
|
||||||
|
@ -474,11 +474,12 @@ static int test_native_vsyscall(void)
|
||||||
*/
|
*/
|
||||||
is_native = (num_vsyscall_traps > 1);
|
is_native = (num_vsyscall_traps > 1);
|
||||||
|
|
||||||
printf("\tvsyscalls are %s (%d instructions in vsyscall page)\n",
|
printf("[%s]\tvsyscalls are %s (%d instructions in vsyscall page)\n",
|
||||||
|
(is_native ? "FAIL" : "OK"),
|
||||||
(is_native ? "native" : "emulated"),
|
(is_native ? "native" : "emulated"),
|
||||||
(int)num_vsyscall_traps);
|
(int)num_vsyscall_traps);
|
||||||
|
|
||||||
return 0;
|
return is_native;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -498,7 +499,7 @@ int main(int argc, char **argv)
|
||||||
nerrs += test_vsys_r();
|
nerrs += test_vsys_r();
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
nerrs += test_native_vsyscall();
|
nerrs += test_emulation();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return nerrs ? 1 : 0;
|
return nerrs ? 1 : 0;
|
||||||
|
|
Loading…
Reference in New Issue