All of lore.kernel.org
 help / color / mirror / Atom feed
From: Al Viro <viro@zeniv.linux.org.uk>
To: Alexander Potapenko <glider@google.com>
Cc: Kees Cook <keescook@chromium.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	Alexey Dobriyan <adobriyan@gmail.com>,
	LKML <linux-kernel@vger.kernel.org>,
	sunhaoyl@outlook.com
Subject: Re: [PATCH] fs/binfmt_elf.c: allocate initialized memory in fill_thread_core_info()
Date: Wed, 13 May 2020 04:33:49 +0100	[thread overview]
Message-ID: <20200513033349.GR23230@ZenIV.linux.org.uk> (raw)
In-Reply-To: <CAG_fn=Xopqwu8qpdH2xDHmGSy1utp7uyPn7s6btm0hdaV7JVRg@mail.gmail.com>

On Tue, May 12, 2020 at 10:20:21AM +0200, Alexander Potapenko wrote:
> On Tue, May 12, 2020 at 5:44 AM Al Viro <viro@zeniv.linux.org.uk> wrote:
> >
> > On Tue, May 12, 2020 at 02:09:01AM +0100, Al Viro wrote:
> > > On Tue, Apr 21, 2020 at 10:14:25AM +0200, Alexander Potapenko wrote:
> > > > > Not lately and I would also like to hear the details; which regset it is?
> > > > > Should be reasonably easy to find - just memset() the damn thing to something
> > > > > recognizable, do whatever triggers that KMSAN report and look at that
> > > > > resulting coredump.
> > > >
> > > > The bug is easily triggerable by the following program:
> > > >
> > > > ================================================
> > > > int main() {
> > > >   volatile char *c = 0;
> > > >   (void)*c;
> > > >   return 0;
> > > > }
> > > > ================================================
> > > >
> > > > in my QEMU after I do `ulimit -c 10000`.
> > >
> > > .config, please - I hadn't been able to reproduce that on mine.
> > > Coredump obviously does happen, but not a trace of the poison
> > > is there - with your memset(data, 0xae, size) added, that is.
> >
> > Actually, more interesting question would be your /proc/cpuinfo...
> 
> See both attached.
> I was also able to reproduce the bug on my desktop using the attached
> dump.sh script.

xsaves is the critical part here.  FWIW, the breakage first appeared in

commit 91c3dba7dbc199191272f4a9863f86ea3bfd679f
Author: Yu-cheng Yu <yu-cheng.yu@intel.com>
Date:   Fri Jun 17 13:07:17 2016 -0700

    x86/fpu/xstate: Fix PTRACE frames for XSAVES
    
    XSAVES uses compacted format and is a kernel instruction. The kernel
    should use standard-format, non-supervisor state data for PTRACE.

The b0rken part is
+       for (i = 0; i < XFEATURE_MAX; i++) {
+               /*
+                * Copy only in-use xstates:
+                */
+               if ((header.xfeatures >> i) & 1) {
+                       void *src = __raw_xsave_addr(xsave, 1 << i);
+
+                       offset = xstate_offsets[i];
+                       size = xstate_sizes[i];
+
+                       ret = xstate_copyout(offset, size, kbuf, ubuf, src, 0, count);
+
+                       if (ret)
+                               return ret;
+
+                       if (offset + size >= count)
+                               break;
+               }
+
+       }

The skipped parts are left uninitialized.  I'm not sure what's the best
way to deal with that.  Sure, we can zero the buffer passed to ->get().
However, most of the instances (and I'd looked through quite a few)
do _not_ leave uninitialized chunks.  So I would rather have
xstateregs_get() zero the gaps explicitly.  I'll try to put together
a sane fix when I get some sleep.

FWIW, what I'm going to do is
	* make all callers of copy_regset_to_user() pass 0 as pos
(there are very few exceptions - one on arm64, three on sparc32
and five on sparc64; I hadn't dealt with arm64 one yet, but all
cases on sparc are handled)
	* switch copy_regset_to_user() to doing all copyout at
once - allocate a buffer, pass it to ->get(), then copy_to_user()
the entire thing, same as coredump does
	* introduce
struct membuf {
	void *p;
	size_t left;
};
static inline int membuf_zero(struct membuf *s, size_t size)
static inline void membuf_align(struct membuf *s, int n)
static inline int membuf_write(struct membuf *s, const void *v, size_t size)
and membuf_store(s, v) (basically, write the value of v to the damn thing,
with sizeof(v) for size).
	* introduce
typedef int user_regset_get2_fn(struct task_struct *target,
				const struct user_regset *regset,
				struct membuf to);
and
	user_regset_get2_fn             *get2;
in user_regset, replacing ->get().  Instances would be using the
membuf_...() primitives for actual copying.
	* convert the instances.  I've done that for several architectures,
and it's _much_ cleaner than the current mess with ->get().
	* get rid of user_regset_copyout() et.al. once there's no
callers left.

This bug clearly needs to be fixed in a way that would be easy
to backport, so it has go in front of that queue.  I'll try to
come up with a clean fix and post it (hopefully tomorrow)...

  reply	other threads:[~2020-05-13  3:33 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-19 10:08 [PATCH] fs/binfmt_elf.c: allocate initialized memory in fill_thread_core_info() glider
2020-04-19 10:10 ` Alexander Potapenko
2020-04-20 22:33 ` Andrew Morton
2020-04-20 22:41   ` Kees Cook
2020-04-21  3:42     ` Al Viro
2020-04-21  8:14       ` Alexander Potapenko
2020-05-12  1:09         ` Al Viro
2020-05-12  3:44           ` Al Viro
2020-05-12  8:20             ` Alexander Potapenko
2020-05-13  3:33               ` Al Viro [this message]
2020-05-24 23:45                 ` Al Viro
2020-05-26 22:38                   ` Al Viro
2020-05-27 12:08                     ` Alexander Potapenko
2020-05-27 19:04                     ` Borislav Petkov
2020-05-27 19:53                       ` Al Viro
2020-05-27 20:09                         ` Borislav Petkov
2020-04-21 12:54       ` Alexander Potapenko
2020-04-21 15:09         ` Jann Horn
2020-04-21 16:04           ` Yu-cheng Yu
2020-04-21 16:16             ` Jann Horn
2020-04-21 16:26               ` Yu-cheng Yu
2020-04-21 20:20               ` Kees Cook
2020-04-21  8:06     ` Alexander Potapenko
2020-05-27 21:55     ` Kees Cook
2020-04-21  8:00   ` Alexander Potapenko

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=20200513033349.GR23230@ZenIV.linux.org.uk \
    --to=viro@zeniv.linux.org.uk \
    --cc=adobriyan@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=glider@google.com \
    --cc=keescook@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=sunhaoyl@outlook.com \
    /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.