NetBSD Problem Report #53316
From martin@duskware.de Sat May 26 11:59:31 2018
Return-Path: <martin@duskware.de>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id EABAB7A21F
for <gnats-bugs@gnats.NetBSD.org>; Sat, 26 May 2018 11:59:31 +0000 (UTC)
From: martin@NetBSD.org
Reply-To: martin@NetBSD.org
To: gnats-bugs@NetBSD.org
Subject: syscalls with more than 6 args may not work
X-Send-Pr-Version: 3.95
>Number: 53316
>Category: port-amd64
>Synopsis: syscalls with more than 6 args may not work
>Confidential: no
>Severity: critical
>Priority: high
>Responsible: port-amd64-maintainer
>State: closed
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sat May 26 12:00:00 +0000 2018
>Closed-Date: Mon May 28 08:00:02 +0000 2018
>Last-Modified: Mon May 28 08:20:01 +0000 2018
>Originator: Martin Husemann
>Release: NetBSD 8.99.18
>Organization:
The NetBSD Foundation, Inc.
>Environment:
System: NetBSD night-owl.duskware.de 8.99.18 NetBSD 8.99.18 (NIGHT-OWL) #600: Sat May 26 09:22:08 CEST 2018 martin@night-owl.duskware.de:/usr/src/sys/arch/amd64/compile/NIGHT-OWL amd64
Architecture: x86_64
Machine: amd64
>Description:
The new test /usr/tests/lib/libc/sys/t_syscall fails on amd64. It tries
to call mmap(2) via __syscall(2) with this code:
p = (const char *)__SYSCALL_TO_UINTPTR_T(__syscall(SYS_mmap,
0, sizeof(secrect_data), PROT_READ, MAP_PRIVATE, fd, 0, 0, 0));
This ends up in the kernel in src/sys/arch/x86/x86/syscall.c here:
119 #ifdef __x86_64__
120 /*
121 * The first 6 syscall args are passed in rdi, rsi, rdx, r10, r8 and r9
122 * (rcx gets copied to r10 in the libc stub because the syscall
123 * instruction overwrites %cx) and are together in the trap frame
124 * with space following for 4 more entries.
125 */
126 if (__predict_false(callp->sy_argsize > 6 * 8)) {
127 error = copyin((register_t *)frame->tf_rsp + 1,
128 &frame->tf_arg6, callp->sy_argsize - 6 * 8);
129 if (error != 0)
130 goto bad;
131 }
In this case, callp->sy_argsize is 72 (bytes), so 9 arguments, 6 of which
come in registers and already are in the trapframe (and thos work fine).
The 3 additional args are copied in from one longword below the current
stack, and verifying with gdb in userland shows the copyin() getting the
right values from the stack.
The syscall stub in libc is plain RSYSCALL. I don't know the amd64 off
hand good enough, maybe this is a variadic function only issue.
The data copied in and the 6 working args match what ktrace prints
about the call.
The test program works fine on various other architectures, including some
64bit ones.
>How-To-Repeat:
cd /tmp
ktrace /usr/tests/lib/libc/sys/t_syscall mmap___syscall
kdump
and watch for this mmap right after a 1k write to the test file:
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0"
2071 1 t_syscall RET write 1024/0x400
2071 1 t_syscall CALL mmap(0,0x400,PROT_READ,0x2<PRIVATE,,,>,3,0,0x7f7f00000000)
2071 1 t_syscall RET mmap 140187597225984/0x7f7ff7ef4000
Note that the last arg is wrong, so the eroneous offset requested in the mmap
leads to a sigbus as we are accessing the resulting map beyound EOF.
>Fix:
n/a
>Release-Note:
>Audit-Trail:
From: Valery Ushakov <uwe@stderr.spb.ru>
To: gnats-bugs@NetBSD.org
Cc: martin@NetBSD.org
Subject: Re: port-amd64/53316: syscalls with more than 6 args may not work
Date: Mon, 28 May 2018 04:34:16 +0300
On Sat, May 26, 2018 at 12:00:00 +0000, martin@NetBSD.org wrote:
> The new test /usr/tests/lib/libc/sys/t_syscall fails on amd64. It tries
> to call mmap(2) via __syscall(2) with this code:
>
> p = (const char *)__SYSCALL_TO_UINTPTR_T(__syscall(SYS_mmap,
> 0, sizeof(secrect_data), PROT_READ, MAP_PRIVATE, fd, 0, 0, 0));
The last but one zero you pass is an int, but the arguments passed on
the stack are passed in 8-byte chunks, so compiler emits movl that
stores zero to the LSW, but the MSW contains garbage. Syscall code in
the kernel will pick that half-garbage value as the 8-byte off_t
argument.
I guess you are passing two zeroes to manually create 64-bit off_t,
but as you can see that doesn't work as expected.
The test should do
... fd, /* pad */ 0, (off_t)0)
I think, which should also DTRT in the 32-bit case.
The code works on sparc64 b/c its ABI defines that stack args are
sign-extended to 8-bytes.
-uwe
State-Changed-From-To: open->closed
State-Changed-By: martin@NetBSD.org
State-Changed-When: Mon, 28 May 2018 08:00:02 +0000
State-Changed-Why:
Fixed (in the test case)
From: Martin Husemann <martin@duskware.de>
To: Valery Ushakov <uwe@stderr.spb.ru>
Cc: gnats-bugs@NetBSD.org, martin@NetBSD.org
Subject: Re: port-amd64/53316: syscalls with more than 6 args may not work
Date: Mon, 28 May 2018 09:56:42 +0200
Duh, of course. Thanks!
Martin
From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/53316 CVS commit: src/tests/lib/libc/sys
Date: Mon, 28 May 2018 07:55:56 +0000
Module Name: src
Committed By: martin
Date: Mon May 28 07:55:56 UTC 2018
Modified Files:
src/tests/lib/libc/sys: t_syscall.c
Log Message:
PR port-amd64/53316: two int don't make a long (when passed to
a C variadic function)
To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/tests/lib/libc/sys/t_syscall.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
>Unformatted:
(Contact us)
$NetBSD: query-full-pr,v 1.43 2018/01/16 07:36:43 maya Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2017
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.