All of lore.kernel.org
 help / color / mirror / Atom feed
From: Masami Hiramatsu <mhiramat@kernel.org>
To: Kees Cook <keescook@chromium.org>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>,
	Ricardo Neri <ricardo.neri-calderon@linux.intel.com>,
	akpm@linux-foundation.org, bp@alien8.de, coreteam@netfilter.org,
	syzbot <syzbot+9b64b619f10f19d19a7c@syzkaller.appspotmail.com>,
	davem@davemloft.net, gustavoars@kernel.org, hpa@zytor.com,
	john.stultz@linaro.org, kaber@trash.net,
	kadlec@blackhole.kfki.hu, linux-kernel@vger.kernel.org,
	mingo@redhat.com, netdev@vger.kernel.org,
	netfilter-devel@vger.kernel.org, pablo@netfilter.org,
	syzkaller-bugs@googlegroups.com, tglx@linutronix.de,
	torvalds@linux-foundation.org, wang.yi59@zte.com.cn,
	x86@kernel.org
Subject: Re: UBSAN: array-index-out-of-bounds in arch_uprobe_analyze_insn
Date: Wed, 2 Dec 2020 15:12:49 +0900	[thread overview]
Message-ID: <20201202151249.52e0648ed53689fe64bb6b05@kernel.org> (raw)
In-Reply-To: <202012011616.DFBE3FC5BC@keescook>

Hi Kees,

On Tue, 1 Dec 2020 16:48:55 -0800
Kees Cook <keescook@chromium.org> wrote:

> Hi,
> 
> There appears to be a problem with prefix counting for the instruction
> decoder. It looks like insn_get_prefixes() isn't keeping "nb" and "nbytes"
> in sync correctly:
> 
>         while (inat_is_legacy_prefix(attr)) {
>                 /* Skip if same prefix */
>                 for (i = 0; i < nb; i++)
>                         if (prefixes->bytes[i] == b)
>                                 goto found;
>                 if (nb == 4)
>                         /* Invalid instruction */
>                         break;
>                 prefixes->bytes[nb++] = b;
> 		...
> found:
>                 prefixes->nbytes++;
>                 insn->next_byte++;
>                 lb = b;
>                 b = peek_next(insn_byte_t, insn);
>                 attr = inat_get_opcode_attribute(b);
>         }
> 
> (nbytes is incremented on repeated prefixes, but "nb" isn't)
> 
> However, it looks like nbytes is used as an offset:
> 
> static inline int insn_offset_rex_prefix(struct insn *insn)
> {
>         return insn->prefixes.nbytes;
> }
> static inline int insn_offset_vex_prefix(struct insn *insn)
> {
>         return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes;
> }

Yes, it is designed to do that. nbytes counts how many bytes the prefix is,
and nb is how many bytes of the prefix->bytes consumed.
Since the legacy prefix can be repeated and more than 4 (bytes), we can not
store all of those.

> 
> Which means everything that iterates over prefixes.bytes[] is buggy,
> since they may be trying to read past the end of the array:

Good catch! All following usage are wrong...

> 
> $ git grep -A3 -E '< .*prefixes(\.|->)nbytes'
> boot/compressed/sev-es.c:       for (i = 0; i < insn->prefixes.nbytes; i++) {
> boot/compressed/sev-es.c-               insn_byte_t p =
> insn->prefixes.bytes[i];
> boot/compressed/sev-es.c-
> boot/compressed/sev-es.c-               if (p == 0xf2 || p == 0xf3)
> --
> kernel/uprobes.c:       for (i = 0; i < insn->prefixes.nbytes; i++) {
> kernel/uprobes.c-               insn_attr_t attr;
> kernel/uprobes.c-
> kernel/uprobes.c-               attr = inat_get_opcode_attribute(insn->prefixes.bytes[i]);
> --
> kernel/uprobes.c:       for (i = 0; i < insn->prefixes.nbytes; i++) {
> kernel/uprobes.c-               if (insn->prefixes.bytes[i] == 0x66)
> kernel/uprobes.c-                       return -ENOTSUPP;
> kernel/uprobes.c-       }
> --
> lib/insn-eval.c:        for (i = 0; i < insn->prefixes.nbytes; i++) {
> lib/insn-eval.c-                insn_byte_t p = insn->prefixes.bytes[i];
> lib/insn-eval.c-
> lib/insn-eval.c-                if (p == 0xf2 || p == 0xf3)
> --
> lib/insn-eval.c:        for (i = 0; i < insn->prefixes.nbytes; i++) {
> lib/insn-eval.c-                insn_attr_t attr;
> lib/insn-eval.c-
> lib/insn-eval.c-                attr = inat_get_opcode_attribute(insn->prefixes.bytes[i]);
> 
> I don't see a clear way to fix this.

For the loop, we can check the insn.prefixes.bytes[i] == 0 since
it is initialized by 0 and 0x0 is not a prefix like this.

for (i = 0; insn->prefixes.bytes[i] && i < 4; i++) {
...
}

Thank you,

> 
> -Kees
> 
> On Mon, Sep 21, 2020 at 09:20:07PM -0700, syzbot wrote:
> > syzbot has bisected this issue to:
> > 
> > commit 4b2bd5fec007a4fd3fc82474b9199af25013de4c
> > Author: John Stultz <john.stultz@linaro.org>
> > Date:   Sat Oct 8 00:02:33 2016 +0000
> > 
> >     proc: fix timerslack_ns CAP_SYS_NICE check when adjusting self
> > 
> > bisection log:  https://syzkaller.appspot.com/x/bisect.txt?x=1697348d900000
> > start commit:   325d0eab Merge branch 'akpm' (patches from Andrew)
> > git tree:       upstream
> > final oops:     https://syzkaller.appspot.com/x/report.txt?x=1597348d900000
> > console output: https://syzkaller.appspot.com/x/log.txt?x=1197348d900000
> > kernel config:  https://syzkaller.appspot.com/x/.config?x=b12e84189082991c
> > dashboard link: https://syzkaller.appspot.com/bug?extid=9b64b619f10f19d19a7c
> > syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=1573a8ad900000
> > C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=164ee6c5900000
> > 
> > Reported-by: syzbot+9b64b619f10f19d19a7c@syzkaller.appspotmail.com
> > Fixes: 4b2bd5fec007 ("proc: fix timerslack_ns CAP_SYS_NICE check when adjusting self")
> > 
> > For information about bisection process see: https://goo.gl/tpsmEJ#bisection
> 
> -- 
> Kees Cook


-- 
Masami Hiramatsu <mhiramat@kernel.org>

      reply	other threads:[~2020-12-02  6:13 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-20 23:02 UBSAN: array-index-out-of-bounds in arch_uprobe_analyze_insn syzbot
2020-09-21  0:13 ` syzbot
2020-09-22  4:20 ` syzbot
2020-12-02  0:48   ` Kees Cook
2020-12-02  6:12     ` Masami Hiramatsu [this message]

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=20201202151249.52e0648ed53689fe64bb6b05@kernel.org \
    --to=mhiramat@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=bp@alien8.de \
    --cc=coreteam@netfilter.org \
    --cc=davem@davemloft.net \
    --cc=gustavoars@kernel.org \
    --cc=hpa@zytor.com \
    --cc=john.stultz@linaro.org \
    --cc=kaber@trash.net \
    --cc=kadlec@blackhole.kfki.hu \
    --cc=keescook@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=pablo@netfilter.org \
    --cc=ricardo.neri-calderon@linux.intel.com \
    --cc=srikar@linux.vnet.ibm.com \
    --cc=syzbot+9b64b619f10f19d19a7c@syzkaller.appspotmail.com \
    --cc=syzkaller-bugs@googlegroups.com \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.org \
    --cc=wang.yi59@zte.com.cn \
    --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.