[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1510541769-21064-5-git-send-email-ricardo.neri-calderon@linux.intel.com>
Date: Sun, 12 Nov 2017 18:56:09 -0800
From: Ricardo Neri <ricardo.neri-calderon@...ux.intel.com>
To: Ingo Molnar <mingo@...nel.org>,
Thomas Gleixner <tglx@...utronix.de>,
"H. Peter Anvin" <hpa@...or.com>
Cc: Borislav Petkov <bp@...e.de>, Andy Lutomirski <luto@...nel.org>,
Tony Luck <tony.luck@...el.com>,
Paolo Bonzini <pbonzini@...hat.com>,
"Ravi V. Shankar" <ravi.v.shankar@...el.com>, x86@...nel.org,
ricardo.neri@...el.com, linux-kernel@...r.kernel.org,
Ricardo Neri <ricardo.neri-calderon@...ux.intel.com>
Subject: [PATCH 4/4] x86/umip: Warn if UMIP-protected instructions are used
Issue a rate-limited warning whenever any of the instructions that UMIP
protects (i.e., sgdt, sidt, sldt, str and smsw) are used by user space
programs.
This is useful because, with UMIP enabled, the few programs that use such
instructions will start receiving a SIGSEGV signal. In the specific cases
for which emulation is provided (instructions sgdt, sidt and smsw in
protected and virtual-8086 modes), a warning is also helpful to encourage
updates in such programs to avoid the use of such instructions.
Cc: Andy Lutomirski <luto@...nel.org>
Cc: H. Peter Anvin <hpa@...or.com>
Cc: Borislav Petkov <bp@...e.de>
Cc: Tony Luck <tony.luck@...el.com>
Cc: Paolo Bonzini <pbonzini@...hat.com>
Cc: Ravi V. Shankar <ravi.v.shankar@...el.com>
Cc: x86@...nel.org
Suggested-by: Linus Torvalds <torvalds@...ux-foundation.org>
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@...ux.intel.com>
---
arch/x86/kernel/umip.c | 65 +++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 59 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kernel/umip.c b/arch/x86/kernel/umip.c
index 6a6fede..39e1992 100644
--- a/arch/x86/kernel/umip.c
+++ b/arch/x86/kernel/umip.c
@@ -82,6 +82,54 @@
#define UMIP_INST_SLDT 3 /* 0F 00 /0 */
#define UMIP_INST_STR 4 /* 0F 00 /1 */
+const char * const umip_insns[5] = {
+ [UMIP_INST_SGDT] = "sgdt",
+ [UMIP_INST_SIDT] = "sidt",
+ [UMIP_INST_SMSW] = "smsw",
+ [UMIP_INST_SLDT] = "sldt",
+ [UMIP_INST_STR] = "str",
+};
+
+/*
+ * If you change these strings, ensure that buffers using them are sufficiently
+ * large.
+ */
+static const char umip_warn_use[] = "cannot be used by applications.";
+static const char umip_warn_emu[] = "For now, expensive software emulation returns result.";
+
+/**
+ * umip_warn() - Print a rate-limited warning
+ * @regs: Register set with the context in which the warning is printed
+ * @msg: Pointer to a string with the warning message
+ * @error: Error code to print along with the warning
+ *
+ * Print the message contained in @msg along with the task name, ID number and
+ * instruction and stack pointers of the associated process. Optionally, an
+ * error code is printed if @error is not zero. These warning messages are
+ * limited to a burst of 5 messages every two minutes.
+ *
+ * Returns:
+ *
+ * None.
+ */
+static void umip_pr_warn(struct pt_regs *regs, char *msg, long error)
+{
+ struct task_struct *tsk = current;
+ char err_str[8 + BITS_PER_LONG / 4] = "";
+
+ /* Bursts of 5 messages every two minutes */
+ static DEFINE_RATELIMIT_STATE(ratelimit, 2 * 60 * HZ, 5);
+
+ if (!__ratelimit(&ratelimit))
+ return;
+
+ if (error)
+ snprintf(err_str, sizeof(err_str), " error:%lx", error);
+
+ pr_warn("%s[%d] %s ip:%lx sp:%lx%s\n", tsk->comm, task_pid_nr(tsk), msg,
+ regs->ip, regs->sp, err_str);
+}
+
/**
* identify_insn() - Identify a UMIP-protected instruction
* @insn: Instruction structure with opcode and ModRM byte.
@@ -236,10 +284,7 @@ static void force_sig_info_umip_fault(void __user *addr, struct pt_regs *regs)
if (!(show_unhandled_signals && unhandled_signal(tsk, SIGSEGV)))
return;
- pr_err_ratelimited("%s[%d] umip emulation segfault ip:%lx sp:%lx error:%x in %lx\n",
- tsk->comm, task_pid_nr(tsk), regs->ip,
- regs->sp, X86_PF_USER | X86_PF_WRITE,
- regs->ip);
+ umip_pr_warn(regs, "segfault at", X86_PF_USER | X86_PF_WRITE);
}
/**
@@ -264,10 +309,10 @@ static void force_sig_info_umip_fault(void __user *addr, struct pt_regs *regs)
bool fixup_umip_exception(struct pt_regs *regs)
{
int not_copied, nr_copied, reg_offset, dummy_data_size, umip_inst;
+ unsigned char buf[MAX_INSN_SIZE], warn[128];
unsigned long seg_base = 0, *reg_addr;
/* 10 bytes is the maximum size of the result of UMIP instructions */
unsigned char dummy_data[10] = { 0 };
- unsigned char buf[MAX_INSN_SIZE];
void __user *uaddr;
struct insn insn;
char seg_defs;
@@ -326,10 +371,18 @@ bool fixup_umip_exception(struct pt_regs *regs)
if (umip_inst < 0)
return false;
+ snprintf(warn, sizeof(warn), "%s %s", umip_insns[umip_inst],
+ umip_warn_use);
+
/* Do not emulate sldt, str or user long mode processes. */
if (umip_inst == UMIP_INST_STR || umip_inst == UMIP_INST_SLDT ||
- user_64bit_mode(regs))
+ user_64bit_mode(regs)) {
+ umip_pr_warn(regs, warn, 0);
return false;
+ }
+
+ snprintf(warn, sizeof(warn), "%s %s", warn, umip_warn_emu);
+ umip_pr_warn(regs, warn, 0);
if (emulate_umip_insn(&insn, umip_inst, dummy_data, &dummy_data_size))
return false;
--
2.7.4
Powered by blists - more mailing lists