public inbox for linux-msdos@vger.kernel.org
 help / color / mirror / Atom feed
From: Masami Hiramatsu <mhiramat@kernel.org>
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>, Borislav Petkov <bp@suse.de>,
	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 <>
Subject: Re: [v3 PATCH 03/10] x86/mpx, x86/insn: Relocate insn util functions to a new insn-kernel
Date: Thu, 26 Jan 2017 11:23:18 +0900	[thread overview]
Message-ID: <20170126112318.25f828448b42035a4c884c3d@kernel.org> (raw)
In-Reply-To: <20170125202353.101059-4-ricardo.neri-calderon@linux.intel.com>

On Wed, 25 Jan 2017 12:23:46 -0800
Ricardo Neri <ricardo.neri-calderon@linux.intel.com> wrote:

> Other kernel submodules can benefit from using the utility functions
> defined in mpx.c to obtain the addresses and values of operands contained
> in the general purpose registers. An instance of this is the emulation code
> used for instructions protected by the Intel User-Mode Instruction
> Prevention feature.
> 
> Thus, these functions are relocated to a new insn-kernel.c file. The reason
> to not relocate these utilities into insn.c is that the latter solely
> analyses instructions given by a struct insn without any knowledge of the
> kernel context. This new utilities insn-kernel.c aims to be used within the
> context of the kernel. For instance, it can be used to determine memory
> addresses as encoded in the contents of the general purpose registers.

What would you mean the "kernel context" here? Extracting the register offset
or an address by decoding instruction seems not depending on where the
context (pt_regs) in kernel or user...

Of course, this is a kind of "evaluation" of instruction, so it might be
better to split it to other file, but I think insn-eval.c is better.

Thank you,

> 
> These utilities come with a separate header. This is to avoid taking insn.c
> out of sync from the instructions decoders under tools/obj and tools/perf.
> This also avoids adding cumbersome #ifdef's for the #include'd files
> required to decode instructions in a kernel context.
> 
> Functions are simply relocated. There are not functional or indentation
> changes.
> 
> 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/include/asm/insn-kernel.h |  16 ++++
>  arch/x86/lib/Makefile              |   2 +-
>  arch/x86/lib/insn-kernel.c         | 147 +++++++++++++++++++++++++++++++++++++
>  arch/x86/mm/mpx.c                  | 140 +----------------------------------
>  4 files changed, 166 insertions(+), 139 deletions(-)
>  create mode 100644 arch/x86/include/asm/insn-kernel.h
>  create mode 100644 arch/x86/lib/insn-kernel.c
> 
> diff --git a/arch/x86/include/asm/insn-kernel.h b/arch/x86/include/asm/insn-kernel.h
> new file mode 100644
> index 0000000..aef416a
> --- /dev/null
> +++ b/arch/x86/include/asm/insn-kernel.h
> @@ -0,0 +1,16 @@
> +#ifndef _ASM_X86_INSN_KERNEL_H
> +#define _ASM_X86_INSN_KERNEL_H
> +/*
> + * A collection of utility functions for x86 instruction analysis to be
> + * used in a kernel context. Useful when, for instance, making sense
> + * of the registers indicated by operands.
> + */
> +
> +#include <linux/compiler.h>
> +#include <linux/bug.h>
> +#include <linux/err.h>
> +#include <asm/ptrace.h>
> +
> +void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs);
> +
> +#endif /* _ASM_X86_INSN_KERNEL_H */
> diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
> index 34a7413..d33eff1 100644
> --- a/arch/x86/lib/Makefile
> +++ b/arch/x86/lib/Makefile
> @@ -23,7 +23,7 @@ lib-y := delay.o misc.o cmdline.o cpu.o
>  lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
>  lib-y += memcpy_$(BITS).o
>  lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
> -lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o
> +lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o insn-kernel.o
>  lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
>  
>  obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
> diff --git a/arch/x86/lib/insn-kernel.c b/arch/x86/lib/insn-kernel.c
> new file mode 100644
> index 0000000..8072abe
> --- /dev/null
> +++ b/arch/x86/lib/insn-kernel.c
> @@ -0,0 +1,147 @@
> +/*
> + * Utility functions for x86 operand and address decoding
> + *
> + * Copyright (C) Intel Corporation 2016
> + */
> +#include <linux/kernel.h>
> +#include <linux/string.h>
> +#include <asm/inat.h>
> +#include <asm/insn.h>
> +#include <asm/insn-kernel.h>
> +
> +enum reg_type {
> +	REG_TYPE_RM = 0,
> +	REG_TYPE_INDEX,
> +	REG_TYPE_BASE,
> +};
> +
> +static int get_reg_offset(struct insn *insn, struct pt_regs *regs,
> +			  enum reg_type type)
> +{
> +	int regno = 0;
> +
> +	static const int regoff[] = {
> +		offsetof(struct pt_regs, ax),
> +		offsetof(struct pt_regs, cx),
> +		offsetof(struct pt_regs, dx),
> +		offsetof(struct pt_regs, bx),
> +		offsetof(struct pt_regs, sp),
> +		offsetof(struct pt_regs, bp),
> +		offsetof(struct pt_regs, si),
> +		offsetof(struct pt_regs, di),
> +#ifdef CONFIG_X86_64
> +		offsetof(struct pt_regs, r8),
> +		offsetof(struct pt_regs, r9),
> +		offsetof(struct pt_regs, r10),
> +		offsetof(struct pt_regs, r11),
> +		offsetof(struct pt_regs, r12),
> +		offsetof(struct pt_regs, r13),
> +		offsetof(struct pt_regs, r14),
> +		offsetof(struct pt_regs, r15),
> +#endif
> +	};
> +	int nr_registers = ARRAY_SIZE(regoff);
> +	/*
> +	 * Don't possibly decode a 32-bit instructions as
> +	 * reading a 64-bit-only register.
> +	 */
> +	if (IS_ENABLED(CONFIG_X86_64) && !insn->x86_64)
> +		nr_registers -= 8;
> +
> +	switch (type) {
> +	case REG_TYPE_RM:
> +		regno = X86_MODRM_RM(insn->modrm.value);
> +		if (X86_REX_B(insn->rex_prefix.value))
> +			regno += 8;
> +		break;
> +
> +	case REG_TYPE_INDEX:
> +		regno = X86_SIB_INDEX(insn->sib.value);
> +		if (X86_REX_X(insn->rex_prefix.value))
> +			regno += 8;
> +		/*
> +		 * If mod !=3, register R/ESP (regno=4) is not used as index in
> +		 * the address computation. Check is done after looking at REX.X
> +		 * This is because R12 (regno=12) can be used as an index.
> +		 */
> +		if (regno == 4 && X86_MODRM_MOD(insn->modrm.value) != 3)
> +			return -EINVAL;
> +		break;
> +
> +	case REG_TYPE_BASE:
> +		regno = X86_SIB_BASE(insn->sib.value);
> +		/*
> +		 * If R/EBP (regno = 5) is indicated in the base part of the SIB
> +		 * byte, an explicit displacement must be specified. In other
> +		 * words, the mod part of the ModRM byte cannot be zero.
> +		 */
> +		if (regno == 5 && X86_MODRM_MOD(insn->modrm.value) == 0)
> +			return -EINVAL;
> +
> +		if (X86_REX_B(insn->rex_prefix.value))
> +			regno += 8;
> +		break;
> +
> +	default:
> +		pr_err("invalid register type");
> +		BUG();
> +		break;
> +	}
> +
> +	if (regno >= nr_registers) {
> +		WARN_ONCE(1, "decoded an instruction with an invalid register");
> +		return -EINVAL;
> +	}
> +	return regoff[regno];
> +}
> +
> +/*
> + * return the address being referenced be instruction
> + * for rm=3 returning the content of the rm reg
> + * for rm!=3 calculates the address using SIB and Disp
> + */
> +void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
> +{
> +	unsigned long addr, base, indx;
> +	int addr_offset, base_offset, indx_offset;
> +	insn_byte_t sib;
> +
> +	insn_get_modrm(insn);
> +	insn_get_sib(insn);
> +	sib = insn->sib.value;
> +
> +	if (X86_MODRM_MOD(insn->modrm.value) == 3) {
> +		addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM);
> +		if (addr_offset < 0)
> +			goto out_err;
> +		addr = regs_get_register(regs, addr_offset);
> +	} else {
> +		if (insn->sib.nbytes) {
> +			base_offset = get_reg_offset(insn, regs, REG_TYPE_BASE);
> +			if (base_offset < 0)
> +				goto out_err;
> +
> +			indx_offset = get_reg_offset(insn, regs, REG_TYPE_INDEX);
> +			/*
> +			 * A negative offset means that the register cannot be
> +			 * be used as an index.
> +			 */
> +			if (indx_offset < 0)
> +				indx = 0;
> +			else
> +				indx = regs_get_register(regs, indx_offset);
> +
> +			base = regs_get_register(regs, base_offset);
> +			addr = base + indx * (1 << X86_SIB_SCALE(sib));
> +		} else {
> +			addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM);
> +			if (addr_offset < 0)
> +				goto out_err;
> +			addr = regs_get_register(regs, addr_offset);
> +		}
> +		addr += insn->displacement.value;
> +	}
> +	return (void __user *)addr;
> +out_err:
> +	return (void __user *)-1;
> +}
> diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c
> index c59a851..ca6fe13 100644
> --- a/arch/x86/mm/mpx.c
> +++ b/arch/x86/mm/mpx.c
> @@ -11,6 +11,7 @@
>  #include <linux/sched/sysctl.h>
>  
>  #include <asm/insn.h>
> +#include <asm/insn-kernel.h>
>  #include <asm/mman.h>
>  #include <asm/mmu_context.h>
>  #include <asm/mpx.h>
> @@ -59,143 +60,6 @@ static unsigned long mpx_mmap(unsigned long len)
>  	return addr;
>  }
>  
> -enum reg_type {
> -	REG_TYPE_RM = 0,
> -	REG_TYPE_INDEX,
> -	REG_TYPE_BASE,
> -};
> -
> -static int get_reg_offset(struct insn *insn, struct pt_regs *regs,
> -			  enum reg_type type)
> -{
> -	int regno = 0;
> -
> -	static const int regoff[] = {
> -		offsetof(struct pt_regs, ax),
> -		offsetof(struct pt_regs, cx),
> -		offsetof(struct pt_regs, dx),
> -		offsetof(struct pt_regs, bx),
> -		offsetof(struct pt_regs, sp),
> -		offsetof(struct pt_regs, bp),
> -		offsetof(struct pt_regs, si),
> -		offsetof(struct pt_regs, di),
> -#ifdef CONFIG_X86_64
> -		offsetof(struct pt_regs, r8),
> -		offsetof(struct pt_regs, r9),
> -		offsetof(struct pt_regs, r10),
> -		offsetof(struct pt_regs, r11),
> -		offsetof(struct pt_regs, r12),
> -		offsetof(struct pt_regs, r13),
> -		offsetof(struct pt_regs, r14),
> -		offsetof(struct pt_regs, r15),
> -#endif
> -	};
> -	int nr_registers = ARRAY_SIZE(regoff);
> -	/*
> -	 * Don't possibly decode a 32-bit instructions as
> -	 * reading a 64-bit-only register.
> -	 */
> -	if (IS_ENABLED(CONFIG_X86_64) && !insn->x86_64)
> -		nr_registers -= 8;
> -
> -	switch (type) {
> -	case REG_TYPE_RM:
> -		regno = X86_MODRM_RM(insn->modrm.value);
> -		if (X86_REX_B(insn->rex_prefix.value))
> -			regno += 8;
> -		break;
> -
> -	case REG_TYPE_INDEX:
> -		regno = X86_SIB_INDEX(insn->sib.value);
> -		if (X86_REX_X(insn->rex_prefix.value))
> -			regno += 8;
> -		/*
> -		 * If mod !=3, register R/ESP (regno=4) is not used as index in
> -		 * the address computation. Check is done after looking at REX.X
> -		 * This is because R12 (regno=12) can be used as an index.
> -		 */
> -		if (regno == 4 && X86_MODRM_MOD(insn->modrm.value) != 3)
> -			return -EINVAL;
> -		break;
> -
> -	case REG_TYPE_BASE:
> -		regno = X86_SIB_BASE(insn->sib.value);
> -		/*
> -		 * If R/EBP (regno = 5) is indicated in the base part of the SIB
> -		 * byte, an explicit displacement must be specified. In other
> -		 * words, the mod part of the ModRM byte cannot be zero.
> -		 */
> -		if (regno == 5 && X86_MODRM_MOD(insn->modrm.value) == 0)
> -			return -EINVAL;
> -
> -		if (X86_REX_B(insn->rex_prefix.value))
> -			regno += 8;
> -		break;
> -
> -	default:
> -		pr_err("invalid register type");
> -		BUG();
> -		break;
> -	}
> -
> -	if (regno >= nr_registers) {
> -		WARN_ONCE(1, "decoded an instruction with an invalid register");
> -		return -EINVAL;
> -	}
> -	return regoff[regno];
> -}
> -
> -/*
> - * return the address being referenced be instruction
> - * for rm=3 returning the content of the rm reg
> - * for rm!=3 calculates the address using SIB and Disp
> - */
> -static void __user *mpx_get_addr_ref(struct insn *insn, struct pt_regs *regs)
> -{
> -	unsigned long addr, base, indx;
> -	int addr_offset, base_offset, indx_offset;
> -	insn_byte_t sib;
> -
> -	insn_get_modrm(insn);
> -	insn_get_sib(insn);
> -	sib = insn->sib.value;
> -
> -	if (X86_MODRM_MOD(insn->modrm.value) == 3) {
> -		addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM);
> -		if (addr_offset < 0)
> -			goto out_err;
> -		addr = regs_get_register(regs, addr_offset);
> -	} else {
> -		if (insn->sib.nbytes) {
> -			base_offset = get_reg_offset(insn, regs, REG_TYPE_BASE);
> -			if (base_offset < 0)
> -				goto out_err;
> -
> -			indx_offset = get_reg_offset(insn, regs, REG_TYPE_INDEX);
> -			/*
> -			 * A negative offset means that the register cannot be
> -			 * be used as an index.
> -			 */
> -			if (indx_offset < 0)
> -				indx = 0;
> -			else
> -				indx = regs_get_register(regs, indx_offset);
> -
> -			base = regs_get_register(regs, base_offset);
> -			addr = base + indx * (1 << X86_SIB_SCALE(sib));
> -		} else {
> -			addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM);
> -			if (addr_offset < 0)
> -				goto out_err;
> -			addr = regs_get_register(regs, addr_offset);
> -		}
> -		addr += insn->displacement.value;
> -	}
> -	return (void __user *)addr;
> -out_err:
> -	return (void __user *)-1;
> -}
> -
>  static int mpx_insn_decode(struct insn *insn,
>  			   struct pt_regs *regs)
>  {
> @@ -308,7 +172,7 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
>  	info->si_signo = SIGSEGV;
>  	info->si_errno = 0;
>  	info->si_code = SEGV_BNDERR;
> -	info->si_addr = mpx_get_addr_ref(&insn, regs);
> +	info->si_addr = insn_get_addr_ref(&insn, regs);
>  	/*
>  	 * We were not able to extract an address from the instruction,
>  	 * probably because there was something invalid in it.
> -- 
> 2.9.3
> 


-- 
Masami Hiramatsu <mhiramat@kernel.org>

  reply	other threads:[~2017-01-26  2:23 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-25 20:23 [v3 PATCH 00/10] x86: Enable User-Mode Instruction Prevention Ricardo Neri
2017-01-25 20:23 ` [v3 PATCH 01/10] x86/mpx: Do not use SIB index if index points to R/ESP Ricardo Neri
2017-01-25 20:23 ` [v3 PATCH 02/10] x86/mpx: Fail decoding when SIB baseR/EBP is and no displacement is used Ricardo Neri
2017-01-25 20:23 ` [v3 PATCH 03/10] x86/mpx, x86/insn: Relocate insn util functions to a new insn-kernel Ricardo Neri
2017-01-26  2:23   ` Masami Hiramatsu [this message]
2017-01-25 20:23 ` [v3 PATCH 04/10] x86/insn-kernel: Add a function to obtain register offset in ModRM Ricardo Neri
2017-01-26  2:11   ` Masami Hiramatsu
2017-01-26  6:07     ` Ricardo Neri
2017-01-27  7:53       ` Masami Hiramatsu
2017-02-01  1:01         ` Ricardo Neri
2017-01-25 20:23 ` [v3 PATCH 05/10] x86/insn-kernel: Add support to resolve 16-bit addressing encodings Ricardo Neri
2017-01-25 21:58   ` Andy Lutomirski
2017-01-25 22:04     ` H. Peter Anvin
2017-01-26  5:50     ` Ricardo Neri
2017-01-26 17:05       ` Andy Lutomirski
2017-01-27  3:44         ` Ricardo Neri
2017-01-25 20:23 ` [v3 PATCH 06/10] x86/cpufeature: Add User-Mode Instruction Prevention definitions Ricardo Neri
2017-01-25 20:23 ` [v3 PATCH 07/10] x86: Add emulation code for UMIP instructions Ricardo Neri
2017-01-25 20:38   ` H. Peter Anvin
2017-01-26  5:54     ` Ricardo Neri
2017-01-25 20:23 ` [v3 PATCH 08/10] x86/traps: Fixup general protection faults caused by UMIP Ricardo Neri
2017-01-25 20:23 ` [v3 PATCH 09/10] x86: Enable User-Mode Instruction Prevention Ricardo Neri
2017-01-25 20:23 ` [v3 PATCH 10/10] selftests/x86: Add tests for " Ricardo Neri
2017-01-25 20:34 ` [v3 PATCH 00/10] x86: Enable " H. Peter Anvin
2017-01-26  5:51   ` 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=20170126112318.25f828448b42035a4c884c3d@kernel.org \
    --to=mhiramat@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=bp@suse.de \
    --cc=brgerst@gmail.com \
    --cc=cmetcalf@mellanox.com \
    --cc=corbet@lwn.net \
    --cc=dave.hansen@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=jslaby@suse.cz \
    --cc=liang.z.li@intel.com \
    --cc=luto@kernel.org \
    --cc=mingo@redhat.com \
    --cc=mst@redhat.com \
    --cc=paul.gortmaker@windriver.com \
    --cc=pbonzini@redhat.com \
    --cc=peterz@infradead.org \
    --cc=ray.huang@amd.com \
    --cc=ricardo.neri-calderon@linux.intel.com \
    --cc=slaoub@gmail.com \
    --cc=tglx@linutronix.de \
    --cc=vbabka@suse.cz \
    /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