| From 4e9a5ae8df5b3365183150f6df49e49dece80d8c Mon Sep 17 00:00:00 2001 |
| From: Masami Hiramatsu <mhiramat@kernel.org> |
| Date: Thu, 3 Dec 2020 13:50:37 +0900 |
| Subject: x86/uprobes: Do not use prefixes.nbytes when looping over prefixes.bytes |
| |
| From: Masami Hiramatsu <mhiramat@kernel.org> |
| |
| commit 4e9a5ae8df5b3365183150f6df49e49dece80d8c upstream. |
| |
| Since insn.prefixes.nbytes can be bigger than the size of |
| insn.prefixes.bytes[] when a prefix is repeated, the proper check must |
| be |
| |
| insn.prefixes.bytes[i] != 0 and i < 4 |
| |
| instead of using insn.prefixes.nbytes. |
| |
| Introduce a for_each_insn_prefix() macro for this purpose. Debugged by |
| Kees Cook <keescook@chromium.org>. |
| |
| [ bp: Massage commit message, sync with the respective header in tools/ |
| and drop "we". ] |
| |
| Fixes: 2b1444983508 ("uprobes, mm, x86: Add the ability to install and remove uprobes breakpoints") |
| Reported-by: syzbot+9b64b619f10f19d19a7c@syzkaller.appspotmail.com |
| Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org> |
| Signed-off-by: Borislav Petkov <bp@suse.de> |
| Reviewed-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> |
| Cc: stable@vger.kernel.org |
| Link: https://lkml.kernel.org/r/160697103739.3146288.7437620795200799020.stgit@devnote2 |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/include/asm/insn.h | 15 +++++++++++++++ |
| arch/x86/kernel/uprobes.c | 10 ++++++---- |
| tools/arch/x86/include/asm/insn.h | 15 +++++++++++++++ |
| 3 files changed, 36 insertions(+), 4 deletions(-) |
| |
| --- a/arch/x86/include/asm/insn.h |
| +++ b/arch/x86/include/asm/insn.h |
| @@ -195,6 +195,21 @@ static inline int insn_offset_immediate( |
| return insn_offset_displacement(insn) + insn->displacement.nbytes; |
| } |
| |
| +/** |
| + * for_each_insn_prefix() -- Iterate prefixes in the instruction |
| + * @insn: Pointer to struct insn. |
| + * @idx: Index storage. |
| + * @prefix: Prefix byte. |
| + * |
| + * Iterate prefix bytes of given @insn. Each prefix byte is stored in @prefix |
| + * and the index is stored in @idx (note that this @idx is just for a cursor, |
| + * do not change it.) |
| + * Since prefixes.nbytes can be bigger than 4 if some prefixes |
| + * are repeated, it cannot be used for looping over the prefixes. |
| + */ |
| +#define for_each_insn_prefix(insn, idx, prefix) \ |
| + for (idx = 0; idx < ARRAY_SIZE(insn->prefixes.bytes) && (prefix = insn->prefixes.bytes[idx]) != 0; idx++) |
| + |
| #define POP_SS_OPCODE 0x1f |
| #define MOV_SREG_OPCODE 0x8e |
| |
| --- a/arch/x86/kernel/uprobes.c |
| +++ b/arch/x86/kernel/uprobes.c |
| @@ -255,12 +255,13 @@ static volatile u32 good_2byte_insns[256 |
| |
| static bool is_prefix_bad(struct insn *insn) |
| { |
| + insn_byte_t p; |
| int i; |
| |
| - for (i = 0; i < insn->prefixes.nbytes; i++) { |
| + for_each_insn_prefix(insn, i, p) { |
| insn_attr_t attr; |
| |
| - attr = inat_get_opcode_attribute(insn->prefixes.bytes[i]); |
| + attr = inat_get_opcode_attribute(p); |
| switch (attr) { |
| case INAT_MAKE_PREFIX(INAT_PFX_ES): |
| case INAT_MAKE_PREFIX(INAT_PFX_CS): |
| @@ -715,6 +716,7 @@ static const struct uprobe_xol_ops push_ |
| static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn) |
| { |
| u8 opc1 = OPCODE1(insn); |
| + insn_byte_t p; |
| int i; |
| |
| switch (opc1) { |
| @@ -746,8 +748,8 @@ static int branch_setup_xol_ops(struct a |
| * Intel and AMD behavior differ in 64-bit mode: Intel ignores 66 prefix. |
| * No one uses these insns, reject any branch insns with such prefix. |
| */ |
| - for (i = 0; i < insn->prefixes.nbytes; i++) { |
| - if (insn->prefixes.bytes[i] == 0x66) |
| + for_each_insn_prefix(insn, i, p) { |
| + if (p == 0x66) |
| return -ENOTSUPP; |
| } |
| |
| --- a/tools/arch/x86/include/asm/insn.h |
| +++ b/tools/arch/x86/include/asm/insn.h |
| @@ -195,6 +195,21 @@ static inline int insn_offset_immediate( |
| return insn_offset_displacement(insn) + insn->displacement.nbytes; |
| } |
| |
| +/** |
| + * for_each_insn_prefix() -- Iterate prefixes in the instruction |
| + * @insn: Pointer to struct insn. |
| + * @idx: Index storage. |
| + * @prefix: Prefix byte. |
| + * |
| + * Iterate prefix bytes of given @insn. Each prefix byte is stored in @prefix |
| + * and the index is stored in @idx (note that this @idx is just for a cursor, |
| + * do not change it.) |
| + * Since prefixes.nbytes can be bigger than 4 if some prefixes |
| + * are repeated, it cannot be used for looping over the prefixes. |
| + */ |
| +#define for_each_insn_prefix(insn, idx, prefix) \ |
| + for (idx = 0; idx < ARRAY_SIZE(insn->prefixes.bytes) && (prefix = insn->prefixes.bytes[idx]) != 0; idx++) |
| + |
| #define POP_SS_OPCODE 0x1f |
| #define MOV_SREG_OPCODE 0x8e |
| |