Hi,

We use Perl syscall(2) function to implement sysctl(2) system calls.
This is broken since OpenBSD 7.3.  A sample program looks like this:

#!/usr/bin/perl
use constant SYS_sysctl => 202;
# net.inet6.ip6.soiikey
my @mib = (4, 24, 41, 54);
my $miblen = scalar(@mib);
my $mib = pack("i$miblen", @mib);
$new = pack("H32", "0123456789abcdef0123456789abcdef");
$newlen = length($new);
syscall(SYS_sysctl(), $mib, $miblen, 0, 0, $new, $newlen);

kdump shows two problems:
1. The mib is not printed correctly.
2. The final argument newlen should be 0x10, but is 0x8891aa893c5.

 30762 perl     CALL  (via syscall) 
sysctl(538970683.538976288.538976288.1718165536,0,0,0x8891d2e1de0,0x8891aa893c5)
 30762 perl     RET   sysctl -1 errno 22 Invalid argument

1. The syscall code now contains the KTRC_CODE_SYSCALL flag, but
the kernel checks code == SYS_sysctl.  So the mib is not added to
ktrace output.  Fix is easy by using KTRC_CODE_MASK.

2. Was introdced by this commit in libc.
----------------------------
revision 1.21
date: 2023/01/11 01:55:17;  author: mortimer;  state: Exp;  lines: +24 -13;  
commitid: 72pYktDvmJhq7OyF;
Add retguard to amd64 syscalls.

Since we got rid of padded syscalls we have enough registers to do this.

ok deraadt@ ok kettenis@
----------------------------
It assumes that syscalls only have 6 parameters, which is not true
if syscall(2) adds the syscall number.  Now the final argument
contains retguard values from the stack.

The easies way to fix this without reverting retguard for all
syscalls, is to use revision 1.20 of SYS.h in libc for syscall.S.
Just manually include the old code instead of current SYS.h.

I am aware that syscall(2) should go way, but currently I need it.

ok?

bluhm

Index: sys/kern/kern_ktrace.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/kern_ktrace.c,v
retrieving revision 1.111
diff -u -p -r1.111 kern_ktrace.c
--- sys/kern/kern_ktrace.c      16 Feb 2023 08:50:57 -0000      1.111
+++ sys/kern/kern_ktrace.c      10 May 2023 16:28:39 -0000
@@ -160,7 +160,7 @@ ktrsyscall(struct proc *p, register_t co
        u_int nargs = 0;
        int i;
 
-       if (code == SYS_sysctl) {
+       if ((code & KTRC_CODE_MASK) == SYS_sysctl) {
                /*
                 * The sysctl encoding stores the mib[]
                 * array because it is interesting.
@@ -198,7 +198,7 @@ ktrsysret(struct proc *p, register_t cod
        ktp.ktr_error = error;
        if (error)
                len = 0;
-       else if (code == SYS_lseek)
+       else if ((code & KTRC_CODE_MASK) == SYS_lseek)
                /* the one exception: lseek on ILP32 needs more */
                len = sizeof(long long);
        else
Index: lib/libc/arch/amd64/sys/syscall.S
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/lib/libc/arch/amd64/sys/syscall.S,v
retrieving revision 1.8
diff -u -p -r1.8 syscall.S
--- lib/libc/arch/amd64/sys/syscall.S   7 May 2016 19:05:21 -0000       1.8
+++ lib/libc/arch/amd64/sys/syscall.S   10 May 2023 19:29:17 -0000
@@ -37,6 +37,80 @@
 
 #include <machine/asm.h>
 
-#include "SYS.h"
+#include "DEFS.h"
+#include <sys/syscall.h>
+
+/* offsetof(struct tib, tib_errno) - offsetof(struct tib, __tib_tcb) */
+#define        TCB_OFFSET_ERRNO        32
+
+#define SYSTRAP(x)     movl $(SYS_ ## x),%eax; movq %rcx, %r10; syscall
+
+#define SYSENTRY(x)                                                    \
+       SYSENTRY_HIDDEN(x);                                             \
+       WEAK_ALIAS(x, _thread_sys_##x)
+#define SYSENTRY_HIDDEN(x)                                             \
+       ENTRY(_thread_sys_ ## x)
+
+#define        SYSCALL_END_HIDDEN(x)                                           
\
+       END(_thread_sys_ ## x);                                         \
+       _HIDDEN_FALIAS(x,_thread_sys_##x);                              \
+       END(_HIDDEN(x))
+#define        SYSCALL_END(x)          SYSCALL_END_HIDDEN(x); END(x)
+
+
+#define SET_ERRNO                                                      \
+       movl    %eax,%fs:(TCB_OFFSET_ERRNO);                            \
+       movq    $-1, %rax
+#define HANDLE_ERRNO                                                   \
+       jnc     99f;                                                    \
+       SET_ERRNO;                                                      \
+       99:
+
+#define _SYSCALL_NOERROR(x,y)                                          \
+       SYSENTRY(x);                                                    \
+       SYSTRAP(y)
+#define _SYSCALL_HIDDEN_NOERROR(x,y)                                   \
+       SYSENTRY_HIDDEN(x);                                             \
+       SYSTRAP(y)
+
+#define SYSCALL_NOERROR(x)                                             \
+       _SYSCALL_NOERROR(x,x)
+
+#define SYSCALL_HIDDEN(x)                                              \
+       _SYSCALL_HIDDEN_NOERROR(x,x);                                   \
+       HANDLE_ERRNO
+#define SYSCALL(x)                                                     \
+       _SYSCALL_NOERROR(x,x);                                          \
+       HANDLE_ERRNO
+
+
+/* return, handling errno for failed calls */
+#define _RSYSCALL_RET                                                  \
+       jc      99f;                                                    \
+       ret;                                                            \
+       99: SET_ERRNO;                                                  \
+       ret
+
+#define PSEUDO_NOERROR(x,y)                                            \
+       _SYSCALL_NOERROR(x,y);                                          \
+       ret;                                                            \
+       SYSCALL_END(x)
+
+#define PSEUDO(x,y)                                                    \
+       _SYSCALL_NOERROR(x,y);                                          \
+       _RSYSCALL_RET;                                                  \
+       SYSCALL_END(x)
+#define PSEUDO_HIDDEN(x,y)                                             \
+       _SYSCALL_HIDDEN_NOERROR(x,y);                                   \
+       _RSYSCALL_RET;                                                  \
+       SYSCALL_END_HIDDEN(x)
+
+#define RSYSCALL_NOERROR(x)                                            \
+       PSEUDO_NOERROR(x,x)
+
+#define RSYSCALL(x)                                                    \
+       PSEUDO(x,x)
+#define RSYSCALL_HIDDEN(x)                                             \
+       PSEUDO_HIDDEN(x,x)
 
 RSYSCALL(syscall)

Reply via email to