NetBSD-Bugs archive

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

port-amd64/53316: syscalls with more than 6 args may not work



>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:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat May 26 12:00:00 +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@localhost:/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



Home | Main Index | Thread Index | Old Index