Re: [uaccess] 780464aed0: WARNING:at_arch/x86/include/asm/uaccess.h:#strnlen_user/0x

From: Jann Horn
Date: Mon Mar 04 2019 - 10:58:35 EST


On Mon, Mar 4, 2019 at 4:16 PM Masami Hiramatsu <mhiramat@xxxxxxxxxx> wrote:
>
> Hello,
>
> On Mon, 4 Mar 2019 18:06:10 +0900
> Masami Hiramatsu <mhiramat@xxxxxxxxxx> wrote:
>
> > On Sun, 3 Mar 2019 18:37:59 -0800
> > Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> wrote:
> >
> > > On Sun, Mar 3, 2019 at 5:14 PM Masami Hiramatsu <mhiramat@xxxxxxxxxx> wrote:
> > > >
> > > > I think it comes from WARN_ON_ONCE(!segment_eq(get_fs(), USER_DS)) in
> > > > user_access_ok(). The call trace shows that strndup_user might be called
> > > > from kernel daemon context.
> > >
> > > Ahh, yes.
> > >
> > > We've had this before. We've gotten rid of the actual "use system
> > > calls", but we still have some of the init sequence in particular just
> > > calling the wrappers instead.
> >
> > Are those safe if we are in init sequence?
> >
> > >
> > > And yes, ksys_mount() takes __user pointers.
> > >
> > > It would be a lot better to use "do_mount()", which is the interface
> > > that takes actual "char *" pointers.
> >
> > Unfortunately, it still takes a __user pointer.
> >
> > long do_mount(const char *dev_name, const char __user *dir_name,
> > const char *type_page, unsigned long flags, void *data_page)
> >
> > So what we need is
> >
> > long do_mount(const char *dev_name, struct path *dir_path,
> > const char *type_page, unsigned long flags, void *data_page)
> >
> > or introduce kern_do_mount()?
>
> Would this work?
>
> ( BTW, what is this code for? It seems totally insane termination.
> at least this should be done in copy_mount_options().
> if (data_page)
> ((char *)data_page)[PAGE_SIZE - 1] = 0;
> )
>
> =======
> devtmpfs: Avoid passing kernel memory to __user parameter
>
> From: Masami Hiramatsu <mhiramat@xxxxxxxxxx>
>
> Since ksys_mount(), ksys_chdir() and ksys_chroot() takes
> __user parameters, devtmpfsd must not pass the kernel memory
> to them. On some arch, it is not possible to pass th kernel
> memory to them, since the memory address spaces can be
> different.

strncpy_from_user() also uses user_access_begin(), and that thing's
used from all the VFS syscalls via getname(). And those are used all
over the place in init/ - for example:
init/do_mounts.c uses ksys_open() and ksys_chroot()
init/do_mounts_initrd.c uses ksys_open(), ksys_chdir(), ksys_mount(),
ksys_mkdir() and ksys_unlink()
init/do_mounts_md.c uses ksys_open()
and so on.
(identify_ramdisk_image() even uses ksys_lseek() and ksys_read()
instead of just using kernel_read()...)