LKML Archive on lore.kernel.org
 help / color / 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
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 index

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-19 10:08 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

LKML Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/lkml/0 lkml/git/0.git
	git clone --mirror https://lore.kernel.org/lkml/1 lkml/git/1.git
	git clone --mirror https://lore.kernel.org/lkml/2 lkml/git/2.git
	git clone --mirror https://lore.kernel.org/lkml/3 lkml/git/3.git
	git clone --mirror https://lore.kernel.org/lkml/4 lkml/git/4.git
	git clone --mirror https://lore.kernel.org/lkml/5 lkml/git/5.git
	git clone --mirror https://lore.kernel.org/lkml/6 lkml/git/6.git
	git clone --mirror https://lore.kernel.org/lkml/7 lkml/git/7.git
	git clone --mirror https://lore.kernel.org/lkml/8 lkml/git/8.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 lkml lkml/ https://lore.kernel.org/lkml \
		linux-kernel@vger.kernel.org
	public-inbox-index lkml

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-kernel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git