lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 13 Nov 2017 22:29:45 -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: [RESEND PATCH v2 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.

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@...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 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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ