All of lore.kernel.org
 help / color / mirror / Atom feed
From: Borislav Petkov <bp@suse.de>
To: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	"H. Peter Anvin" <hpa@zytor.com>,
	Andy Lutomirski <luto@kernel.org>,
	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>,
	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>,
	"Ravi V. Shankar" <ravi.v.shankar@intel.com>,
	Shuah Khan <shuah@kernel.org>,
	linux-kernel@vger.kernel.org, x86@kernel.org,
	ricardo.neri@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: Re: [PATCH v8 12/28] x86/insn-eval: Add utility functions to get segment selector
Date: Tue, 26 Sep 2017 12:43:53 +0200	[thread overview]
Message-ID: <20170926104353.vmpxybv3v5immc56@pd.tnic> (raw)
In-Reply-To: <20170819002809.111312-13-ricardo.neri-calderon@linux.intel.com>

Hi,

On Fri, Aug 18, 2017 at 05:27:53PM -0700, Ricardo Neri wrote:
> 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.

...

>  arch/x86/include/asm/inat.h |  10 ++
>  arch/x86/lib/insn-eval.c    | 278 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 288 insertions(+)

so I did a bunch of simplifications on top, see if you agree:

* we should always test for if (!insn) first because otherwise we can't talk
about a segment at all.

* the nomenclature should be clear: if we return INAT_SEG_REG_* those are own
defined indices and not registers or prefixes or whatever else, so everywhere we
state that we're returning an *index*.

* and then shorten local variables' names as reading "reg" every
other line doesn't make it clearer :)

* also some comments formatting for better readability.

* and prefixing register names with "r" in the comments means then all
register widths, not only 32-bit. Dunno, is "(E)" SDM nomenclature for
the different register widths?

---
diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c
index 86f58ce6c302..720529573d72 100644
--- a/arch/x86/lib/insn-eval.c
+++ b/arch/x86/lib/insn-eval.c
@@ -44,50 +44,45 @@ static bool is_string_insn(struct insn *insn)
 }
 
 /**
- * get_overridden_seg_reg() - obtain segment register to use from prefixes
- * @insn:	Instruction structure with segment override prefixes
- * @regs:	Structure with register values as seen when entering kernel mode
+ * get_seg_reg_idx() - obtain segment register index to use from prefixes
+ * @insn:	Instruction with segment override prefixes
+ * @regs:	Register values as seen when entering kernel mode
  * @regoff:	Operand offset, in pt_regs, used to deterimine segment register
  *
- * The segment register to which an effective address refers depends on
- * a) whether running in long mode (in such a case semgment override prefixes
- * are ignored. b) Whether segment override prefixes must be ignored for certain
- * registers: always use CS when the register is (R|E)IP; always use ES when
- * operand register is (E)DI with a string instruction as defined in the Intel
- * documentation. c) If segment overrides prefixes are found in the instruction
- * prefixes. d) Use the default segment register associated with the operand
- * register.
+ * The segment register to which an effective address refers, depends on:
+ *
+ * a) whether running in long mode (in such a case segment override prefixes
+ * are ignored).
+ *
+ * b) Whether segment override prefixes must be ignored for certain
+ * registers: always use CS when the register is rIP; always use ES when
+ * operand register is rDI with a string instruction as defined in the Intel
+ * documentation.
  *
- * This function returns the overridden segment register to use, if any, as per
- * the conditions described above. Please note that this function
+ * c) If segment overrides prefixes are found in the instruction prefixes.
+ *
+ * d) Use the default segment register associated with the operand register.
+ *
+ * This function returns the segment register override to use, if any,
+ * as per the conditions described above. Please note that this function
  * does not return the value in the segment register (i.e., the segment
- * selector). The segment selector needs to be obtained using
- * get_segment_selector() and passing the segment register resolved by
+ * selector) but our defined index. The segment selector needs to be obtained
+ * using get_segment_selector() and passing the segment register resolved by
  * this function.
  *
- * Return: A constant identifying the segment register to use, among CS, SS, DS,
+ * Returns:
+ *
+ * A constant identifying the segment register to use, among CS, SS, DS,
  * ES, FS, or GS. INAT_SEG_REG_IGNORE is returned if running in long mode.
  * INAT_SEG_REG_DEFAULT is returned if no segment override prefixes were found
- * and the default segment register shall be used. -EINVAL in case of error.
+ * and the default segment register shall be used.
+ *
+ * -EINVAL in case of error.
  */
-static int get_overridden_seg_reg(struct insn *insn, struct pt_regs *regs,
-				  int regoff)
+static int get_seg_reg_idx(struct insn *insn, struct pt_regs *regs, int regoff)
 {
-	int i;
-	int sel_overrides = 0;
-	int seg_register = INAT_SEG_REG_DEFAULT;
-
-	/*
-	 * Segment override prefixes should not be used for (E)IP. Check this
-	 * case first as we might not have (and not needed at all) a
-	 * valid insn structure to evaluate segment override prefixes.
-	 */
-	if (regoff == offsetof(struct pt_regs, ip)) {
-		if (user_64bit_mode(regs))
-			return INAT_SEG_REG_IGNORE;
-		else
-			return INAT_SEG_REG_DEFAULT;
-	}
+	int idx = INAT_SEG_REG_DEFAULT;
+	int sel_overrides = 0, i;
 
 	if (!insn)
 		return -EINVAL;
@@ -101,27 +96,27 @@ static int get_overridden_seg_reg(struct insn *insn, struct pt_regs *regs,
 		attr = inat_get_opcode_attribute(insn->prefixes.bytes[i]);
 		switch (attr) {
 		case INAT_MAKE_PREFIX(INAT_PFX_CS):
-			seg_register = INAT_SEG_REG_CS;
+			idx = INAT_SEG_REG_CS;
 			sel_overrides++;
 			break;
 		case INAT_MAKE_PREFIX(INAT_PFX_SS):
-			seg_register = INAT_SEG_REG_SS;
+			idx = INAT_SEG_REG_SS;
 			sel_overrides++;
 			break;
 		case INAT_MAKE_PREFIX(INAT_PFX_DS):
-			seg_register = INAT_SEG_REG_DS;
+			idx = INAT_SEG_REG_DS;
 			sel_overrides++;
 			break;
 		case INAT_MAKE_PREFIX(INAT_PFX_ES):
-			seg_register = INAT_SEG_REG_ES;
+			idx = INAT_SEG_REG_ES;
 			sel_overrides++;
 			break;
 		case INAT_MAKE_PREFIX(INAT_PFX_FS):
-			seg_register = INAT_SEG_REG_FS;
+			idx = INAT_SEG_REG_FS;
 			sel_overrides++;
 			break;
 		case INAT_MAKE_PREFIX(INAT_PFX_GS):
-			seg_register = INAT_SEG_REG_GS;
+			idx = INAT_SEG_REG_GS;
 			sel_overrides++;
 			break;
 		/* No default action needed. */
@@ -133,26 +128,26 @@ static int get_overridden_seg_reg(struct insn *insn, struct pt_regs *regs,
 	 * overrides for FS and GS.
 	 */
 	if (user_64bit_mode(regs)) {
-		if (seg_register != INAT_SEG_REG_FS &&
-		    seg_register != INAT_SEG_REG_GS)
+		if (idx != INAT_SEG_REG_FS &&
+		    idx != INAT_SEG_REG_GS)
 			return INAT_SEG_REG_IGNORE;
 	/* More than one segment override prefix leads to undefined behavior. */
 	} else if (sel_overrides > 1) {
 		return -EINVAL;
 	/*
 	 * Segment override prefixes are always ignored for string instructions
-	 * that involve the use the (E)DI register.
+	 * that use the (E)DI register.
 	 */
 	} else if ((regoff == offsetof(struct pt_regs, di)) &&
 		   is_string_insn(insn)) {
 		return INAT_SEG_REG_DEFAULT;
 	}
 
-	return seg_register;
+	return idx;
 }
 
 /**
- * resolve_seg_register() - obtain segment register
+ * resolve_seg_reg() - obtain segment register index
  * @insn:	Instruction structure with segment override prefixes
  * @regs:	Structure with register values as seen when entering kernel mode
  * @regoff:	Operand offset, in pt_regs, used to deterimine segment register
@@ -169,36 +164,38 @@ static int get_overridden_seg_reg(struct insn *insn, struct pt_regs *regs,
  *
  * Return: A constant identifying the segment register to use, among CS, SS, DS,
  * ES, FS, or GS. INAT_SEG_REG_IGNORE is returned if running in long mode.
+ *
  * -EINVAL in case of error.
  */
-static int resolve_seg_register(struct insn *insn, struct pt_regs *regs,
-				int regoff)
+static int resolve_seg_reg(struct insn *insn, struct pt_regs *regs, int regoff)
 {
-	int seg_reg;
+	int idx;
 
-	seg_reg = get_overridden_seg_reg(insn, regs, regoff);
+	if (!insn)
+		return -EINVAL;
 
-	if (seg_reg < 0)
-		return seg_reg;
+	idx = get_seg_reg_idx(insn, regs, regoff);
+	if (idx < 0)
+		return idx;
 
-	if (seg_reg == INAT_SEG_REG_IGNORE)
-		return seg_reg;
+	if (idx == INAT_SEG_REG_IGNORE)
+		return idx;
 
-	if (seg_reg != INAT_SEG_REG_DEFAULT)
-		return seg_reg;
+	if (idx != INAT_SEG_REG_DEFAULT)
+		return idx;
 
 	/*
 	 * If we are here, we use the default segment register as described
 	 * in the Intel documentation:
-	 *  + DS for all references involving (E)AX, (E)CX, (E)DX, (E)BX, and
-	 * (E)SI.
-	 *  + If used in a string instruction, ES for (E)DI. Otherwise, DS.
+	 *
+	 *  + DS for all references involving r[ABCD]X, and rSI.
+	 *  + If used in a string instruction, ES for rDI. Otherwise, DS.
 	 *  + AX, CX and DX are not valid register operands in 16-bit address
 	 *    encodings but are valid for 32-bit and 64-bit encodings.
 	 *  + -EDOM is reserved to identify for cases in which no register
 	 *    is used (i.e., displacement-only addressing). Use DS.
-	 *  + SS for (E)SP or (E)BP.
-	 *  + CS for (E)IP.
+	 *  + SS for rSP or rBP.
+	 *  + CS for rIP.
 	 */
 
 	switch (regoff) {
@@ -206,24 +203,26 @@ static int resolve_seg_register(struct insn *insn, struct pt_regs *regs,
 	case offsetof(struct pt_regs, cx):
 	case offsetof(struct pt_regs, dx):
 		/* Need insn to verify address size. */
-		if (!insn || insn->addr_bytes == 2)
+		if (insn->addr_bytes == 2)
 			return -EINVAL;
+
 	case -EDOM:
 	case offsetof(struct pt_regs, bx):
 	case offsetof(struct pt_regs, si):
 		return INAT_SEG_REG_DS;
+
 	case offsetof(struct pt_regs, di):
-		/* Need insn to see if insn is string instruction. */
-		if (!insn)
-			return -EINVAL;
 		if (is_string_insn(insn))
 			return INAT_SEG_REG_ES;
 		return INAT_SEG_REG_DS;
+
 	case offsetof(struct pt_regs, bp):
 	case offsetof(struct pt_regs, sp):
 		return INAT_SEG_REG_SS;
+
 	case offsetof(struct pt_regs, ip):
 		return INAT_SEG_REG_CS;
+
 	default:
 		return -EINVAL;
 	}
@@ -232,17 +231,20 @@ static int resolve_seg_register(struct insn *insn, struct pt_regs *regs,
 /**
  * get_segment_selector() - obtain segment selector
  * @regs:	Structure with register values as seen when entering kernel mode
- * @seg_reg:	Segment register to use
+ * @seg_reg:	Segment register index to use
  *
- * Obtain the segment selector from any of the CS, SS, DS, ES, FS, GS segment
- * registers. 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
+ * Obtain the segment selector from any of the CS, SS, DS, ES, FS, GS
+ * segment registers. In CONFIG_X86_32, the segment is obtained from either
+ * pt_regs or kernel_vm86_regs as applicable. On 64-bit, CS and SS are obtained
  * from pt_regs. DS, ES, FS and GS are obtained by reading the actual CPU
- * registers. This done for only for completeness as in CONFIG_X86_64 segment
- * registers are ignored.
+ * registers. This done only for completeness as in long mode segment registers
+ * are ignored.
+ *
+ * Returns:
+ *
+ * Value of the segment selector, including null when running in long mode.
  *
- * Return: Value of the segment selector, including null when running in
- * long mode. -1 on error.
+ * -EINVAL on error.
  */
 static short get_segment_selector(struct pt_regs *regs, int seg_reg)
 {

-- 
Regards/Gruss,
    Boris.

SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
-- 

  reply	other threads:[~2017-09-26 10:44 UTC|newest]

Thread overview: 67+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-19  0:27 [PATCH v8 00/28] x86: Enable User-Mode Instruction Prevention Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 01/28] x86/mm: Relocate page fault error codes to traps.h Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 02/28] x86/boot: Relocate definition of the initial state of CR0 Ricardo Neri
2017-08-19  0:27   ` Ricardo Neri
2017-08-19  0:27   ` Ricardo Neri
2017-08-25 17:41   ` Borislav Petkov
2017-08-25 17:41     ` Borislav Petkov
2017-08-25 17:41     ` Borislav Petkov
2017-08-31  4:04     ` Ricardo Neri
2017-08-31  4:04       ` Ricardo Neri
2017-08-31  4:04       ` Ricardo Neri
2017-08-31  9:51       ` Borislav Petkov
2017-08-31  9:51         ` Borislav Petkov
2017-08-31  9:51         ` Borislav Petkov
2017-09-02 17:35         ` Ricardo Neri
2017-09-02 17:35           ` Ricardo Neri
2017-09-02 17:35           ` Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 03/28] ptrace,x86: Make user_64bit_mode() available to 32-bit builds Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 04/28] uprobes/x86: Use existing definitions for segment override prefixes Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 05/28] x86/mpx: Use signed variables to compute effective addresses Ricardo Neri
2017-08-29 16:09   ` Borislav Petkov
2017-08-31  4:19     ` Ricardo Neri
2017-08-31  9:52       ` Borislav Petkov
2017-08-19  0:27 ` [PATCH v8 06/28] x86/mpx: Do not use SIB.index if its value is 100b and ModRM.mod is not 11b Ricardo Neri
2017-08-31 19:38   ` Borislav Petkov
2017-09-02 17:19     ` Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 07/28] x86/mpx: Do not use SIB.base if its value is 101b and ModRM.mod = 0 Ricardo Neri
2017-09-06 15:44   ` Borislav Petkov
2017-08-19  0:27 ` [PATCH v8 08/28] x86/mpx, x86/insn: Relocate insn util functions to a new insn-eval file Ricardo Neri
2017-09-06 15:54   ` Borislav Petkov
2017-09-06 19:27     ` Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 09/28] x86/insn-eval: Do not BUG on invalid register type Ricardo Neri
2017-09-07 17:54   ` Borislav Petkov
2017-09-07 20:27     ` Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 10/28] x86/insn-eval: Add a utility function to get register offsets Ricardo Neri
2017-09-08 13:35   ` Borislav Petkov
2017-09-14 18:30     ` Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 11/28] x86/insn-eval: Add utility function to identify string instructions Ricardo Neri
2017-09-08 13:57   ` Borislav Petkov
2017-09-14 18:30     ` Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 12/28] x86/insn-eval: Add utility functions to get segment selector Ricardo Neri
2017-09-26 10:43   ` Borislav Petkov [this message]
2017-09-27  4:21     ` Ricardo Neri
2017-09-27 11:47       ` Borislav Petkov
2017-09-27 22:32         ` Ricardo Neri
2017-09-28  9:36           ` Borislav Petkov
2017-09-29  6:06             ` Ricardo Neri
2017-09-29 11:56               ` Borislav Petkov
2017-10-04 16:47                 ` Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 13/28] x86/insn-eval: Add utility function to get segment descriptor Ricardo Neri
2017-09-26 18:05   ` Borislav Petkov
2017-09-27 17:39     ` Neri, Ricardo
2017-08-19  0:27 ` [PATCH v8 14/28] x86/insn-eval: Add utility functions to get segment descriptor base address and limit Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 15/28] x86/insn-eval: Add function to get default params of code segment Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 16/28] x86/insn-eval: Indicate a 32-bit displacement if ModRM.mod is 0 and ModRM.rm is 101b Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 17/28] x86/insn-eval: Incorporate segment base in linear address computation Ricardo Neri
2017-08-19  0:27 ` [PATCH v8 18/28] x86/insn-eval: Add support to resolve 32-bit address encodings Ricardo Neri
2017-08-19  0:28 ` [PATCH v8 19/28] x86/insn-eval: Add wrapper function for 32 and 64-bit addresses Ricardo Neri
2017-08-19  0:28 ` [PATCH v8 20/28] x86/insn-eval: Handle 32-bit address encodings in virtual-8086 mode Ricardo Neri
2017-08-19  0:28 ` [PATCH v8 21/28] x86/insn-eval: Add support to resolve 16-bit addressing encodings Ricardo Neri
2017-08-19  0:28 ` [PATCH v8 22/28] x86/cpufeature: Add User-Mode Instruction Prevention definitions Ricardo Neri
2017-08-19  0:28 ` [PATCH v8 23/28] x86: Add emulation code for UMIP instructions Ricardo Neri
2017-08-19  0:28 ` [PATCH v8 24/28] x86/umip: Force a page fault when unable to copy emulated result to user Ricardo Neri
2017-08-19  0:28 ` [PATCH v8 25/28] x86: Enable User-Mode Instruction Prevention Ricardo Neri
2017-08-19  0:28 ` [PATCH v8 26/28] x86/traps: Fixup general protection faults caused by UMIP Ricardo Neri
2017-08-19  0:28 ` [PATCH v8 27/28] selftests/x86: Add tests for User-Mode Instruction Prevention Ricardo Neri
2017-08-19  0:28 ` [PATCH v8 28/28] selftests/x86: Add tests for instruction str and sldt Ricardo Neri

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=20170926104353.vmpxybv3v5immc56@pd.tnic \
    --to=bp@suse.de \
    --cc=acme@redhat.com \
    --cc=adam.buchbinder@gmail.com \
    --cc=adrian.hunter@intel.com \
    --cc=akpm@linux-foundation.org \
    --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=hpa@zytor.com \
    --cc=jslaby@suse.cz \
    --cc=keescook@chromium.org \
    --cc=linux-kernel@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=ricardo.neri-calderon@linux.intel.com \
    --cc=ricardo.neri@intel.com \
    --cc=shuah@kernel.org \
    --cc=slaoub@gmail.com \
    --cc=tglx@linutronix.de \
    --cc=thgarnie@google.com \
    --cc=vbabka@suse.cz \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.