lkml.org 
[lkml]   [2017]   [Nov]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[RESEND PATCH v2 4/4] x86/umip: Warn if UMIP-protected instructions are used
Date
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.

An existing rate-limited pr_err() is converted to use the new function
umip_pr_warn() in order to have it printing at the same rate and log
level.

Cc: Andy Lutomirski <luto@kernel.org>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Ravi V. Shankar <ravi.v.shankar@intel.com>
Cc: x86@kernel.org
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.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 2e09b5b..50f4b11 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_pr_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
\
 
 \ /
  Last update: 2017-11-14 07:32    [W:0.160 / U:0.560 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site