linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
To: Ingo Molnar <mingo@redhat.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	"H. Peter Anvin" <hpa@zytor.com>,
	Andy Lutomirski <luto@kernel.org>, Borislav Petkov <bp@suse.de>
Cc: Peter Zijlstra <peterz@infradead.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	Brian Gerst <brgerst@gmail.com>,
	Chris Metcalf <cmetcalf@mellanox.com>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	Paolo Bonzini <pbonzini@redhat.com>,
	Liang Z Li <liang.z.li@intel.com>,
	Masami Hiramatsu <mhiramat@kernel.org>,
	Huang Rui <ray.huang@amd.com>, Jiri Slaby <jslaby@suse.cz>,
	Jonathan Corbet <corbet@lwn.net>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	Paul Gortmaker <paul.gortmaker@windriver.com>,
	Vlastimil Babka <vbabka@suse.cz>, Chen Yucong <slaoub@gmail.com>,
	Alexandre Julliard <julliard@winehq.org>,
	Stas Sergeev <stsp@list.ru>, Fenghua Yu <fenghua.yu@intel.com>,
	"Ravi V. Shankar" <ravi.v.shankar@intel.com>,
	Shuah Khan <shuah@kernel.org>,
	linux-kernel@vger.kernel.org, x86@kernel.org,
	linux-msdos@vger.kernel.org, wine-devel@winehq.org,
	Ricardo Neri <ricardo.neri-calderon@linux.intel.com>,
	Adam Buchbinder <adam.buchbinder@gmail.com>,
	Colin Ian King <colin.king@canonical.com>,
	Lorenzo Stoakes <lstoakes@gmail.com>,
	Qiaowei Ren <qiaowei.ren@intel.com>,
	Arnaldo Carvalho de Melo <acme@redhat.com>,
	Adrian Hunter <adrian.hunter@intel.com>,
	Kees Cook <keescook@chromium.org>,
	Thomas Garnier <thgarnie@google.com>,
	Dmitry Vyukov <dvyukov@google.com>
Subject: [v6 PATCH 06/21] x86/insn-eval: Add utility functions to get segment selector
Date: Tue,  7 Mar 2017 16:32:39 -0800	[thread overview]
Message-ID: <20170308003254.27833-7-ricardo.neri-calderon@linux.intel.com> (raw)
In-Reply-To: <20170308003254.27833-1-ricardo.neri-calderon@linux.intel.com>

When computing a linear address and segmentation is used, we need to know
the base address of the segment involved in the computation. In most of
the cases, the segment base address will be zero as in USER_DS/USER32_DS.
However, it may be possible that a user space program defines its own
segments via a local descriptor table. In such a case, the segment base
address may not be zero .Thus, the segment base address is needed to
calculate correctly the linear address.

The segment selector to be used when computing a linear address is
determined by either any of segment select override prefixes in the
instruction or inferred from the registers involved in the computation of
the effective address; in that order. Also, there are cases when the
overrides shall be ignored.

For clarity, this process can be split into two steps: resolving the
relevant segment and, once known, read the applicable segment selector.
The method to obtain the segment selector depends on several factors. In
32-bit builds, segment selectors are saved into the pt_regs structure
when switching to kernel mode. The same is also true for virtual-8086
mode. In 64-bit builds, segmentation is mostly ignored, except when
running a program in 32-bit legacy mode. In this case, CS and SS can be
obtained from pt_regs. DS, ES, FS and GS can be read directly from
registers. Lastly, segmentation is possible in 64-bit mode via FS and GS.
In these two cases, base addresses are obtained from the relevant MSRs.

Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Adam Buchbinder <adam.buchbinder@gmail.com>
Cc: Colin Ian King <colin.king@canonical.com>
Cc: Lorenzo Stoakes <lstoakes@gmail.com>
Cc: Qiaowei Ren <qiaowei.ren@intel.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Thomas Garnier <thgarnie@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@suse.de>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Ravi V. Shankar <ravi.v.shankar@intel.com>
Cc: x86@kernel.org
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
 arch/x86/lib/insn-eval.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 195 insertions(+)

diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c
index 78df1c9..8d45df8 100644
--- a/arch/x86/lib/insn-eval.c
+++ b/arch/x86/lib/insn-eval.c
@@ -8,6 +8,7 @@
 #include <asm/inat.h>
 #include <asm/insn.h>
 #include <asm/insn-eval.h>
+#include <asm/vm86.h>
 
 enum reg_type {
 	REG_TYPE_RM = 0,
@@ -15,6 +16,200 @@ enum reg_type {
 	REG_TYPE_BASE,
 };
 
+enum segment {
+	SEG_CS = 0x23,
+	SEG_SS = 0x36,
+	SEG_DS = 0x3e,
+	SEG_ES = 0x26,
+	SEG_FS = 0x64,
+	SEG_GS = 0x65
+};
+
+/**
+ * resolve_seg_selector() - obtain segment selector
+ * @regs:	Set of registers containing the segment selector
+ * @insn:	Instruction structure with selector override prefixes
+ * @regoff:	Operand offset, in pt_regs, of which the selector is needed
+ * @default:	Resolve default segment selector (i.e., ignore overrides)
+ *
+ * The segment selector to which an effective address refers depends on
+ * a) segment selector overrides instruction prefixes or b) the operand
+ * register indicated in the ModRM or SiB byte.
+ *
+ * For case a), the function inspects any prefixes in the insn instruction;
+ * insn can be null to indicate that selector override prefixes shall be
+ * ignored. This is useful when the use of prefixes is forbidden (e.g.,
+ * obtaining the code selector). For case b), the operand register shall be
+ * represented as the offset from the base address of pt_regs. Also, regoff
+ * can be -EINVAL for cases in which registers are not used as operands (e.g.,
+ * when the mod and r/m parts of the ModRM byte are 0 and 5, respectively).
+ *
+ * This function returns the segment selector to utilize as per the conditions
+ * described above. Please note that this functin does not return the value
+ * of the segment selector. The value of the segment selector needs to be
+ * obtained using get_segment_selector and passing the segment selector type
+ * resolved by this function.
+ *
+ * Return: Segment selector to use, among CS, SS, DS, ES, FS or GS.
+ */
+static int resolve_seg_selector(struct insn *insn, int regoff, bool get_default)
+{
+	int i;
+
+	if (!insn)
+		return -EINVAL;
+
+	if (get_default)
+		goto default_seg;
+	/*
+	 * Check first if we have selector overrides. Having more than
+	 * one selector override leads to undefined behavior. We
+	 * only use the first one and return
+	 */
+	for (i = 0; i < insn->prefixes.nbytes; i++) {
+		switch (insn->prefixes.bytes[i]) {
+		case SEG_CS:
+			return SEG_CS;
+		case SEG_SS:
+			return SEG_SS;
+		case SEG_DS:
+			return SEG_DS;
+		case SEG_ES:
+			return SEG_ES;
+		case SEG_FS:
+			return SEG_FS;
+		case SEG_GS:
+			return SEG_GS;
+		default:
+			return -EINVAL;
+		}
+	}
+
+default_seg:
+	/*
+	 * If no overrides, use default selectors as described in the
+	 * Intel documentation: SS for ESP or EBP. DS for all data references,
+	 * except when relative to stack or string destination.
+	 * Also, AX, CX and DX are not valid register operands in 16-bit
+	 * address encodings.
+	 * Callers must interpret the result correctly according to the type
+	 * of instructions (e.g., use ES for string instructions).
+	 * Also, some values of modrm and sib might seem to indicate the use
+	 * of EBP and ESP (e.g., modrm_mod = 0, modrm_rm = 5) but actually
+	 * they refer to cases in which only a displacement used. These cases
+	 * should be indentified by the caller and not with this function.
+	 */
+	switch (regoff) {
+	case offsetof(struct pt_regs, ax):
+		/* fall through */
+	case offsetof(struct pt_regs, cx):
+		/* fall through */
+	case offsetof(struct pt_regs, dx):
+		if (insn && insn->addr_bytes == 2)
+			return -EINVAL;
+	case -EDOM: /* no register involved in address computation */
+	case offsetof(struct pt_regs, bx):
+		/* fall through */
+	case offsetof(struct pt_regs, di):
+		/* fall through */
+	case offsetof(struct pt_regs, si):
+		return SEG_DS;
+	case offsetof(struct pt_regs, bp):
+		/* fall through */
+	case offsetof(struct pt_regs, sp):
+		return SEG_SS;
+	case offsetof(struct pt_regs, ip):
+		return SEG_CS;
+	default:
+		return -EINVAL;
+	}
+}
+
+/**
+ * get_segment_selector() - obtain segment selector
+ * @regs:	Set of registers containing the segment selector
+ * @seg_type:	Type of segment selector to obtain
+ * @regoff:	Operand offset, in pt_regs, of which the selector is needed
+ *
+ * Obtain the segment selector for any of CS, SS, DS, ES, FS, GS. In
+ * CONFIG_X86_32, the segment is obtained from either pt_regs or
+ * kernel_vm86_regs as applicable. In CONFIG_X86_64, CS and SS are obtained
+ * from pt_regs. DS, ES, FS and GS are obtained by reading the ds and es, fs
+ * and gs, respectively.
+ *
+ * Return: Value of the segment selector
+ */
+static unsigned short get_segment_selector(struct pt_regs *regs,
+					   enum segment seg_type)
+{
+#ifdef CONFIG_X86_64
+	unsigned short seg_sel;
+
+	switch (seg_type) {
+	case SEG_CS:
+		return (unsigned short)(regs->cs & 0xffff);
+	case SEG_SS:
+		return (unsigned short)(regs->ss & 0xffff);
+	case SEG_DS:
+		savesegment(ds, seg_sel);
+		return seg_sel;
+	case SEG_ES:
+		savesegment(es, seg_sel);
+		return seg_sel;
+	case SEG_FS:
+		savesegment(fs, seg_sel);
+		return seg_sel;
+	case SEG_GS:
+		savesegment(gs, seg_sel);
+		return seg_sel;
+	default:
+		return -1;
+	}
+#else /* CONFIG_X86_32 */
+	struct kernel_vm86_regs *vm86regs = (struct kernel_vm86_regs *)regs;
+
+	if (v8086_mode(regs)) {
+		switch (seg_type) {
+		case SEG_CS:
+			return (unsigned short)(regs->cs & 0xffff);
+		case SEG_SS:
+			return (unsigned short)(regs->ss & 0xffff);
+		case SEG_DS:
+			return vm86regs->ds;
+		case SEG_ES:
+			return vm86regs->es;
+		case SEG_FS:
+			return vm86regs->fs;
+		case SEG_GS:
+			return vm86regs->gs;
+		default:
+			return -1;
+		}
+	}
+
+	switch (seg_type) {
+	case SEG_CS:
+		return (unsigned short)(regs->cs & 0xffff);
+	case SEG_SS:
+		return (unsigned short)(regs->ss & 0xffff);
+	case SEG_DS:
+		return (unsigned short)(regs->ds & 0xffff);
+	case SEG_ES:
+		return (unsigned short)(regs->es & 0xffff);
+	case SEG_FS:
+		return (unsigned short)(regs->fs & 0xffff);
+	case SEG_GS:
+		/*
+		 * GS may or may not be in regs as per CONFIG_X86_32_LAZY_GS.
+		 * The macro below takes care of both cases.
+		 */
+		return get_user_gs(regs);
+	default:
+		return -1;
+	}
+#endif /* CONFIG_X86_64 */
+}
+
 static int get_reg_offset(struct insn *insn, struct pt_regs *regs,
 			  enum reg_type type)
 {
-- 
2.9.3

  parent reply	other threads:[~2017-03-08  0:56 UTC|newest]

Thread overview: 112+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-03-08  0:32 [v6 PATCH 00/21] x86: Enable User-Mode Instruction Prevention Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 01/21] x86/mpx: Use signed variables to compute effective addresses Ricardo Neri
2017-04-11 21:56   ` Borislav Petkov
2017-04-26  1:40     ` Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 02/21] x86/mpx: Do not use SIB index if index points to R/ESP Ricardo Neri
2017-04-11 11:31   ` Borislav Petkov
2017-04-26  1:39     ` Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 03/21] x86/mpx: Do not use R/EBP as base in the SIB byte with Mod = 0 Ricardo Neri
2017-04-11 22:08   ` Borislav Petkov
2017-04-26  2:04     ` Ricardo Neri
2017-04-26  8:05       ` Borislav Petkov
2017-04-27 22:49         ` Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 04/21] x86/mpx, x86/insn: Relocate insn util functions to a new insn-kernel Ricardo Neri
2017-04-12 10:03   ` Borislav Petkov
2017-04-26  2:05     ` Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 05/21] x86/insn-eval: Add utility functions to get register offsets Ricardo Neri
2017-04-12 16:28   ` Borislav Petkov
2017-04-26 18:13     ` Ricardo Neri
2017-04-28 10:40       ` Borislav Petkov
2017-03-08  0:32 ` Ricardo Neri [this message]
2017-04-18  9:42   ` [v6 PATCH 06/21] x86/insn-eval: Add utility functions to get segment selector Borislav Petkov
2017-04-26 20:44     ` Ricardo Neri
2017-04-26 20:47       ` Ricardo Neri
2017-04-30 17:15       ` Borislav Petkov
2017-05-05 18:31         ` Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 07/21] x86/insn-eval: Add utility function to get segment descriptor Ricardo Neri
2017-04-19 10:26   ` Borislav Petkov
2017-04-26 21:51     ` Ricardo Neri
2017-05-04 11:02       ` Borislav Petkov
2017-05-12  2:13         ` Ricardo Neri
2017-05-15 17:27           ` Borislav Petkov
2017-03-08  0:32 ` [v6 PATCH 08/21] x86/insn-eval: Add utility function to get segment descriptor base address Ricardo Neri
2017-04-20  8:25   ` Borislav Petkov
2017-04-26 22:37     ` Ricardo Neri
2017-05-05 17:19       ` Borislav Petkov
2017-05-12  2:09         ` Ricardo Neri
2017-04-26 22:52     ` Ricardo Neri
2017-05-05 17:28       ` Borislav Petkov
2017-05-12  2:06         ` Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 09/21] x86/insn-eval: Add functions to get default operand and address sizes Ricardo Neri
2017-04-20 13:06   ` Borislav Petkov
2017-04-27  1:07     ` Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 10/21] x86/insn-eval: Do not use R/EBP as base if mod in ModRM is zero Ricardo Neri
2017-04-21 10:52   ` Borislav Petkov
2017-04-27  1:29     ` Ricardo Neri
2017-05-07 17:20       ` Borislav Petkov
2017-05-12  1:57         ` Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 11/21] insn/eval: Incorporate segment base in address computation Ricardo Neri
2017-04-21 14:55   ` Borislav Petkov
2017-04-27  1:31     ` Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 12/21] x86/insn: Support both signed 32-bit and 64-bit effective addresses Ricardo Neri
2017-04-25 13:51   ` Borislav Petkov
2017-04-27  3:33     ` Ricardo Neri
2017-05-08 11:42       ` Borislav Petkov
2017-05-12  1:55         ` Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 13/21] x86/insn-eval: Add support to resolve 16-bit addressing encodings Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 14/21] x86/insn-eval: Add wrapper function for 16-bit and 32-bit address encodings Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 15/21] x86/mm: Relocate page fault error codes to traps.h Ricardo Neri
2017-03-08 16:08   ` Andy Lutomirski
2017-03-08  0:32 ` [v6 PATCH 16/21] x86/cpufeature: Add User-Mode Instruction Prevention definitions Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 17/21] x86: Add emulation code for UMIP instructions Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 18/21] x86/umip: Force a page fault when unable to copy emulated result to user Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 19/21] x86/traps: Fixup general protection faults caused by UMIP Ricardo Neri
2017-03-08 15:54   ` Andy Lutomirski
2017-03-08  0:32 ` [v6 PATCH 20/21] x86: Enable User-Mode Instruction Prevention Ricardo Neri
2017-03-08  0:32 ` [v6 PATCH 21/21] selftests/x86: Add tests for " Ricardo Neri
2017-03-08 15:56   ` Andy Lutomirski
2017-03-10 23:38     ` Ricardo Neri
2017-03-08 14:08 ` [v6 PATCH 00/21] x86: Enable " Stas Sergeev
2017-03-08 16:06   ` Andy Lutomirski
2017-03-08 16:29     ` Stas Sergeev
2017-03-08 16:46       ` Andy Lutomirski
2017-03-08 16:53         ` Stas Sergeev
2017-03-09  1:11           ` Ricardo Neri
2017-03-09 22:05             ` Stas Sergeev
2017-03-10  2:41             ` Andy Lutomirski
2017-03-10 10:30               ` Stas Sergeev
2017-03-10 21:04                 ` Andy Lutomirski
2017-03-10 21:37                   ` Stas Sergeev
2017-03-09  1:15         ` Ricardo Neri
2017-03-09 22:10           ` Stas Sergeev
2017-03-10  2:39             ` Andy Lutomirski
2017-03-10 11:33               ` Stas Sergeev
2017-03-10 14:17                 ` Andy Lutomirski
2017-03-11  1:22                   ` Ricardo Neri
2017-03-10 23:59                 ` Ricardo Neri
2017-03-13 21:25                   ` Stas Sergeev
2017-03-27 23:46                     ` Ricardo Neri
2017-03-28  9:38                       ` Stas Sergeev
2017-03-29  4:38                         ` Ricardo Neri
2017-03-29 20:55                           ` Stas Sergeev
2017-03-30  5:14                             ` Ricardo Neri
2017-03-30 10:10                               ` Stas Sergeev
2017-03-31  1:33                                 ` Ricardo Neri
2017-03-31 14:11                                   ` Alexandre Julliard
2017-03-31 21:26                                     ` Stas Sergeev
2017-04-01  2:18                                       ` Andy Lutomirski
2017-04-04  2:02                                     ` Ricardo Neri
2017-04-04  6:08                                       ` Alexandre Julliard
2017-04-01 13:08                               ` Stas Sergeev
2017-04-01 17:49                                 ` H. Peter Anvin
2017-04-02 15:52                                   ` Andy Lutomirski
2017-04-04  9:59                                   ` Stas Sergeev
2017-04-04  2:05                                 ` Ricardo Neri
2017-04-04  8:03                                   ` Stas Sergeev
2017-03-10 23:58               ` Ricardo Neri
2017-03-09  0:46   ` Ricardo Neri
2017-03-09 22:01     ` Stas Sergeev
2017-03-10 23:47       ` Ricardo Neri
2017-03-10 23:58         ` Stas Sergeev
2017-03-11  0:13           ` Ricardo Neri
2017-03-08 16:07 ` Andy Lutomirski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170308003254.27833-7-ricardo.neri-calderon@linux.intel.com \
    --to=ricardo.neri-calderon@linux.intel.com \
    --cc=acme@redhat.com \
    --cc=adam.buchbinder@gmail.com \
    --cc=adrian.hunter@intel.com \
    --cc=akpm@linux-foundation.org \
    --cc=bp@suse.de \
    --cc=brgerst@gmail.com \
    --cc=cmetcalf@mellanox.com \
    --cc=colin.king@canonical.com \
    --cc=corbet@lwn.net \
    --cc=dave.hansen@linux.intel.com \
    --cc=dvyukov@google.com \
    --cc=fenghua.yu@intel.com \
    --cc=hpa@zytor.com \
    --cc=jslaby@suse.cz \
    --cc=julliard@winehq.org \
    --cc=keescook@chromium.org \
    --cc=liang.z.li@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-msdos@vger.kernel.org \
    --cc=lstoakes@gmail.com \
    --cc=luto@kernel.org \
    --cc=mhiramat@kernel.org \
    --cc=mingo@redhat.com \
    --cc=mst@redhat.com \
    --cc=paul.gortmaker@windriver.com \
    --cc=pbonzini@redhat.com \
    --cc=peterz@infradead.org \
    --cc=qiaowei.ren@intel.com \
    --cc=ravi.v.shankar@intel.com \
    --cc=ray.huang@amd.com \
    --cc=shuah@kernel.org \
    --cc=slaoub@gmail.com \
    --cc=stsp@list.ru \
    --cc=tglx@linutronix.de \
    --cc=thgarnie@google.com \
    --cc=vbabka@suse.cz \
    --cc=wine-devel@winehq.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).