[PATCH 1/2] i386: Generate lfence with load/indirect branch/ret [CVE-2020-0551]
Hongtao Liu
crazylht@gmail.com
Thu Mar 26 02:23:03 GMT 2020
On Wed, Mar 25, 2020 at 6:03 PM Jan Beulich <jbeulich@suse.com> wrote:
>
> On 25.03.2020 10:27, Hongtao Liu wrote:
> > On Thu, Mar 12, 2020 at 12:17 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >> On Wed, Mar 11, 2020 at 3:55 AM Jan Beulich <jbeulich@suse.com> wrote:
> >>> On 10.03.2020 17:05, H.J. Lu wrote:
> >>>> + dest = i.operands - 1;
> >>>> +
> >>>> + /* Check fake imm8 operand and 3 source operands. */
> >>>> + if ((i.tm.opcode_modifier.immext
> >>>> + || i.tm.opcode_modifier.vexsources == VEX3SOURCES)
> >>>> + && i.types[dest].bitfield.imm8)
> >>>> + dest--;
> >>>> +
> >>>> + /* add, or, adc, sbb, and, sub, xor, cmp, test, xchg, xadd */
> >>>> + if (!any_vex_p
> >>>> + && (i.tm.base_opcode == 0x0
> >>>> + || i.tm.base_opcode == 0x1
> >>>> + || i.tm.base_opcode == 0x8
> >>>> + || i.tm.base_opcode == 0x9
> >>>> + || i.tm.base_opcode == 0x10
> >>>> + || i.tm.base_opcode == 0x11
> >>>> + || i.tm.base_opcode == 0x18
> >>>> + || i.tm.base_opcode == 0x19
> >>>> + || i.tm.base_opcode == 0x20
> >>>> + || i.tm.base_opcode == 0x21
> >>>> + || i.tm.base_opcode == 0x28
> >>>> + || i.tm.base_opcode == 0x29
> >>>> + || i.tm.base_opcode == 0x30
> >>>> + || i.tm.base_opcode == 0x31
> >>>> + || i.tm.base_opcode == 0x38
> >>>> + || i.tm.base_opcode == 0x39
> >>>> + || (i.tm.base_opcode >= 0x84 && i.tm.base_opcode <= 0x87)
> >>>> + || i.tm.base_opcode == 0xfc0
> >>>> + || i.tm.base_opcode == 0xfc1))
> >>>> + return 1;
> >>>
> >>> Don't quite a few of these fit very well with ...
> >>>
> >>
> >> Changed.
> >>
> >>>> + /* Check for load instruction. */
> >>>> + return (i.types[dest].bitfield.class != ClassNone
> >>>> + || i.types[dest].bitfield.instance == Accum);
> >>>
> >>> ... this generic expression? It would seem to me that only TEST
> >>> and XCHG need special casing, for allowing either operand order.
> >>> Same seems to apply to quite a few of the special cases in the
> >>> big "else" block further up, and even its if() [vldmxcsr] part.
> >>
> >> Hongtao, can you look into it?
> >>
> >
> > Many instruction take mem operand both as input and output, they also
> > need to be handled. But they're not fitting well in generic
> > expressions, because they either only 1 operand, or mem operand is in
> > the dest place.
>
> Well, my earlier reply wasn't quite precise enough, I think. Aiui
> what you're after to exclude are insns only writing their memory
> operand. With the pretty long list of excluded opcodes I wonder
> whether this can be re-arranged to use a common pattern (memory
> operand is destination) and only exclude the few ones which don't
> also read this operand. Then again by using a few & and | the list
> above could be shrunk significantly, and hence may no longer look
> this odd (I notice the committed version has this reduced a little,
> but not quite as much as would be possible).
>
Yes, understand.
> >>>> + if (lfence_before_ret != lfence_before_ret_none
> >>>> + && (i.tm.base_opcode == 0xc2
> >>>> + || i.tm.base_opcode == 0xc3
> >>>> + || i.tm.base_opcode == 0xca
> >>>> + || i.tm.base_opcode == 0xcb))
> >>>> + {
> >>>> + if (last_insn.kind != last_insn_other
> >>>> + && last_insn.seg == now_seg)
> >>>> + {
> >>>> + as_warn_where (last_insn.file, last_insn.line,
> >>>> + _("`%s` skips -mlfence-before-ret on `%s`"),
> >>>> + last_insn.name, i.tm.name);
> >>>> + return;
> >>>> + }
> >>>> + if (lfence_before_ret == lfence_before_ret_or)
> >>>> + {
> >>>> + /* orl: 0x830c2400. */
> >>>> + p = frag_more ((flag_code == CODE_64BIT ? 1 : 0) + 4 + 3);
> >>>> + if (flag_code == CODE_64BIT)
> >>>> + *p++ = 0x48;
> >>>
> >>> Shouldn't this depend on RET's operand size? Likewise wouldn't you
> >>> also need to insert 0x66/0x67 in certain cases?
> >>
> >> Hongtao, can you look into it?
> >
> > I suppose you mean OR's operand size?
>
> Not exactly - I mean RET's operand size ought to affect the one
> chosen for OR.
>
> Jan
> > I wonder whether this shouldn't also enable a safe lfence_before_ret
> > mode (i.e. not the OR one), for RET also being an indirect branch. Of
> > course care would need to be taken to avoid clobbering an already set
> > lfence_before_ret mode.
Also for this part, maybe i'll add some comments to indicate
-mlfence-before-indirect-branch doesn't include ret. Orelse it would
be weird for user when clobber happens, Is it ok for you?
--
BR,
Hongtao
More information about the Binutils
mailing list