Re: fcntl64 syscall causes user program stack corruption

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Feb 19, 2018 at 08:31:21PM +0000, James Hogan wrote:
> On Mon, Feb 19, 2018 at 09:06:56PM +0300, Peter Mamonov wrote:
> > Hello,
> > 
> > After upgrading the Linux kernel to the recent version I've found that the 
> > Firefox browser from the Debian 8 (jessie),mipsel stopped working: it causes 
> > Bus Error exception at startup. The problem is reproducible with the QEMU 
> > virtual machine (qemu-system-mips64el). Thorough investigation revealed that 
> > the following syscall in /lib/mipsel-linux-gnu/libpthread-2.19.so causes 
> > Firefox's stack corruption at address 0x7fff5770:
> > 
> > 	0x77fabd28:  li      v0,4220
> > 	0x77fabd2c:  syscall
> > 
> > Relevant registers contents are as follows:
> > 
> > 		  zero       at       v0       v1       a0       a1       a2       a3
> > 	 R0   00000000 300004e0 0000107c 77c2e6b0 00000006 0000000e 7fff574c 7fff5770 
> > 
> > The stack corruption is caused by the following patch:
> > 
> > 	commit 8c6657cb50cb037ff58b3f6a547c6569568f3527
> > 	Author: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
> > 	Date:   Mon Jun 26 23:51:31 2017 -0400
> > 	
> > 	    Switch flock copyin/copyout primitives to copy_{from,to}_user()
> > 	    
> > 	    ... and lose HAVE_ARCH_...; if copy_{to,from}_user() on an
> > 	    architecture sucks badly enough to make it a problem, we have
> > 	    a worse problem.
> > 	    
> > 	    Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
> > 
> > Reverting the change in put_compat_flock() introduced by the patch prevents the 
> > stack corruption:
> > 
> > 	diff --git a/fs/fcntl.c b/fs/fcntl.c
> > 	index 0345a46b8856..c55afd836e5d 100644
> > 	--- a/fs/fcntl.c
> > 	+++ b/fs/fcntl.c
> > 	@@ -550,25 +550,27 @@ static int get_compat_flock64(struct flock *kfl, const struct compat_flock64 __u
> > 	 
> > 	 static int put_compat_flock(const struct flock *kfl, struct compat_flock __user *ufl)
> > 	 {
> > 	-       struct compat_flock fl;
> > 	-
> > 	-       memset(&fl, 0, sizeof(struct compat_flock));
> > 	-       copy_flock_fields(&fl, kfl);
> > 	-       if (copy_to_user(ufl, &fl, sizeof(struct compat_flock)))
> > 	+       if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
> > 	+           __put_user(kfl->l_type, &ufl->l_type) ||
> > 	+           __put_user(kfl->l_whence, &ufl->l_whence) ||
> > 	+           __put_user(kfl->l_start, &ufl->l_start) ||
> > 	+           __put_user(kfl->l_len, &ufl->l_len) ||
> > 	+           __put_user(kfl->l_pid, &ufl->l_pid))
> > 	                return -EFAULT;
> > 	        return 0;
> > 	 }
> > 
> > Actually, the change introduced by the patch is ok. However, it looks like 
> > there is either a mismatch of sizeof(struct compat_flock) between the kernel 
> > and the user space or a mismatch of types used by the kernel and the user 
> > space.  Despite the fact that the user space is built for a different kernel 
> > version (3.16), I believe this syscall should work fine with it, since `struct 
> > compat_flock` did not change since the 3.16.  So, probably, the problem is 
> > caused by some discrepancies which were hidden until "Switch flock 
> > copyin/copyout..." patch.
> > 
> > Please, give your comments.
> 
> Hmm, thanks for reporting this.
> 
> The change this commit makes is to make it write the full compat_flock
> struct out, including the padding at the end, instead of only the
> specific fields, suggesting that MIPS' struct compat_flock on 64-bit
> doesn't match struct flock on 32-bit.
> 
> Here's struct flock from arch/mips/include/uapi/asm/fcntl.h with offset
> annotations for 32-bit:
> 
> struct flock {
> /*0*/	short	l_type;
> /*2*/	short	l_whence;
> /*4*/	__kernel_off_t	l_start;
> /*8*/	__kernel_off_t	l_len;
> /*12*/	long	l_sysid;
> /*16*/	__kernel_pid_t l_pid;
> /*20*/	long	pad[4];
> /*36*/
> };
> 
> and here's struct compat_flock from arch/mips/include/asm/compat.h with
> offset annotations for 64-bit:
> 
> struct compat_flock {
> /*0*/	short		l_type;
> /*2*/	short		l_whence;
> /*4*/	compat_off_t	l_start;
> /*8*/	compat_off_t	l_len;
> /*12*/	s32		l_sysid;
> /*16*/	compat_pid_t	l_pid;
> /*20*/	short		__unused;
> /*24*/	s32		pad[4];
> /*40*/
> };
> 
> Clearly the existence of __unused is outright wrong here.
> 
> Please can you test the following patch to see if it fixes the issue.

Yes, the patch fixes the issue.

And thanks for clarification.

Regards,
Peter

> 
> Thanks again,
> James
> 
> From ebcbbb431aa7cc97330793da8a30c51150963935 Mon Sep 17 00:00:00 2001
> From: James Hogan <jhogan@xxxxxxxxxx>
> Date: Mon, 19 Feb 2018 20:14:34 +0000
> Subject: [PATCH] MIPS: Drop spurious __unused in struct compat_flock
> 
> MIPS' struct compat_flock doesn't match the 32-bit struct flock, as it
> has an extra short __unused before pad[4], which combined with alignment
> increases the size to 40 bytes compared with struct flock's 36 bytes.
> 
> Since commit 8c6657cb50cb ("Switch flock copyin/copyout primitives to
> copy_{from,to}_user()"), put_compat_flock() writes the full compat_flock
> struct to userland, which results in corruption of the userland word
> after the struct flock when running 32-bit userlands on 64-bit kernels.
> 
> This was observed to cause a bus error exception when starting Firefox
> on Debian 8 (Jessie).
> 
> Reported-by: Peter Mamonov <pmamonov@xxxxxxxxx>
> Signed-off-by: James Hogan <jhogan@xxxxxxxxxx>
> Cc: Ralf Baechle <ralf@xxxxxxxxxxxxxx>
> Cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
> Cc: linux-mips@xxxxxxxxxxxxxx
> Cc: <stable@xxxxxxxxxxxxxxx> # 4.13+
> ---
>  arch/mips/include/asm/compat.h | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h
> index 946681db8dc3..9a0fa66b81ac 100644
> --- a/arch/mips/include/asm/compat.h
> +++ b/arch/mips/include/asm/compat.h
> @@ -86,7 +86,6 @@ struct compat_flock {
>  	compat_off_t	l_len;
>  	s32		l_sysid;
>  	compat_pid_t	l_pid;
> -	short		__unused;
>  	s32		pad[4];
>  };
>  
> -- 
> 2.13.6
> 




[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux