git: 39024a891469 - main - syscalls: fix missing SIGSYS for several ENOSYS errors

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Mon, 02 Oct 2023 22:31:18 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=39024a89146902ca9aba250130b828ad9aced99d

commit 39024a89146902ca9aba250130b828ad9aced99d
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-09-25 16:32:52 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-10-02 22:30:52 +0000

    syscalls: fix missing SIGSYS for several ENOSYS errors
    
    In particular, when the syscall number is too large, or when syscall is
    dynamic.  For that, add nosys_sysent structure to pass fake sysent to
    syscall top code.
    
    Reviewed by:    dchagin, markj
    Discussed with: jhb
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D41976
---
 sys/amd64/amd64/trap.c          |  2 +-
 sys/amd64/ia32/ia32_syscall.c   |  2 +-
 sys/arm/arm/syscall.c           |  2 +-
 sys/arm64/arm64/elf32_machdep.c |  2 +-
 sys/arm64/arm64/trap.c          |  2 +-
 sys/arm64/linux/linux_sysvec.c  |  2 +-
 sys/i386/i386/trap.c            |  2 +-
 sys/i386/linux/linux_sysvec.c   |  2 +-
 sys/kern/kern_sig.c             |  3 ++-
 sys/kern/kern_syscalls.c        | 25 +++++++++++++++++++------
 sys/kern/subr_syscall.c         |  3 ++-
 sys/powerpc/powerpc/trap.c      |  2 +-
 sys/riscv/riscv/trap.c          |  2 +-
 sys/sys/sysent.h                |  3 ++-
 14 files changed, 35 insertions(+), 19 deletions(-)

diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index ef38c0789636..8114105655f8 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -1033,7 +1033,7 @@ cpu_fetch_syscall_args_fallback(struct thread *td, struct syscall_args *sa)
 	}
 
 	if (sa->code >= p->p_sysent->sv_size)
-		sa->callp = &p->p_sysent->sv_table[0];
+		sa->callp = &nosys_sysent;
 	else
 		sa->callp = &p->p_sysent->sv_table[sa->code];
 
diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c
index 3fb905ab9e0a..c61587a93d1f 100644
--- a/sys/amd64/ia32/ia32_syscall.c
+++ b/sys/amd64/ia32/ia32_syscall.c
@@ -183,7 +183,7 @@ ia32_fetch_syscall_args(struct thread *td)
 		params += sizeof(quad_t);
 	}
  	if (sa->code >= p->p_sysent->sv_size)
- 		sa->callp = &p->p_sysent->sv_table[0];
+		sa->callp = &nosys_sysent;
   	else
  		sa->callp = &p->p_sysent->sv_table[sa->code];
 
diff --git a/sys/arm/arm/syscall.c b/sys/arm/arm/syscall.c
index 57644c023646..c440f501e834 100644
--- a/sys/arm/arm/syscall.c
+++ b/sys/arm/arm/syscall.c
@@ -118,7 +118,7 @@ cpu_fetch_syscall_args(struct thread *td)
 	}
 	p = td->td_proc;
 	if (sa->code >= p->p_sysent->sv_size)
-		sa->callp = &p->p_sysent->sv_table[0];
+		sa->callp = &nosys_sysent;
 	else
 		sa->callp = &p->p_sysent->sv_table[sa->code];
 	error = 0;
diff --git a/sys/arm64/arm64/elf32_machdep.c b/sys/arm64/arm64/elf32_machdep.c
index e1fcb533a8cc..9cf1b2e11f8b 100644
--- a/sys/arm64/arm64/elf32_machdep.c
+++ b/sys/arm64/arm64/elf32_machdep.c
@@ -191,7 +191,7 @@ freebsd32_fetch_syscall_args(struct thread *td)
 	}
 
 	if (sa->code >= p->p_sysent->sv_size)
-		sa->callp = &p->p_sysent->sv_table[0];
+		sa->callp = &nosys_sysent;
 	else
 		sa->callp = &p->p_sysent->sv_table[sa->code];
 
diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c
index c3221e9faf9f..2dda8cfc4c20 100644
--- a/sys/arm64/arm64/trap.c
+++ b/sys/arm64/arm64/trap.c
@@ -151,7 +151,7 @@ cpu_fetch_syscall_args(struct thread *td)
 	}
 
 	if (__predict_false(sa->code >= p->p_sysent->sv_size))
-		sa->callp = &p->p_sysent->sv_table[0];
+		sa->callp = &nosys_sysent;
 	else
 		sa->callp = &p->p_sysent->sv_table[sa->code];
 
diff --git a/sys/arm64/linux/linux_sysvec.c b/sys/arm64/linux/linux_sysvec.c
index 5f9252accb5f..19dd5866ba50 100644
--- a/sys/arm64/linux/linux_sysvec.c
+++ b/sys/arm64/linux/linux_sysvec.c
@@ -123,7 +123,7 @@ linux_fetch_syscall_args(struct thread *td)
 	sa->original_code = sa->code;
 	/* LINUXTODO: generic syscall? */
 	if (sa->code >= p->p_sysent->sv_size)
-		sa->callp = &p->p_sysent->sv_table[0];
+		sa->callp = &nosys_sysent;
 	else
 		sa->callp = &p->p_sysent->sv_table[sa->code];
 
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index 172317aead29..d0ee2b30a3ce 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -1113,7 +1113,7 @@ cpu_fetch_syscall_args(struct thread *td)
 	}
 
  	if (sa->code >= p->p_sysent->sv_size)
- 		sa->callp = &p->p_sysent->sv_table[0];
+		sa->callp = &nosys_sysent;
   	else
  		sa->callp = &p->p_sysent->sv_table[sa->code];
 
diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c
index fe3e3f743620..a3d445951cce 100644
--- a/sys/i386/linux/linux_sysvec.c
+++ b/sys/i386/linux/linux_sysvec.c
@@ -522,7 +522,7 @@ linux_fetch_syscall_args(struct thread *td)
 
 	if (sa->code >= p->p_sysent->sv_size)
 		/* nosys */
-		sa->callp = &p->p_sysent->sv_table[p->p_sysent->sv_size - 1];
+		sa->callp = &nosys_sysent;
 	else
 		sa->callp = &p->p_sysent->sv_table[sa->code];
 
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 964ad2398bd9..8d0d2903bac0 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -2686,7 +2686,8 @@ ptrace_syscallreq(struct thread *td, struct proc *p,
 	audited = AUDIT_SYSCALL_ENTER(sc, td) != 0;
 
 	if (!sy_thr_static) {
-		error = syscall_thread_enter(td, se);
+		error = syscall_thread_enter(td, &se);
+		sy_thr_static = (se->sy_thrcnt & SY_THR_STATIC) != 0;
 		if (error != 0) {
 			tsr->ts_ret.sr_error = error;
 			return;
diff --git a/sys/kern/kern_syscalls.c b/sys/kern/kern_syscalls.c
index 78014a36b34b..f923211cb6c8 100644
--- a/sys/kern/kern_syscalls.c
+++ b/sys/kern/kern_syscalls.c
@@ -61,6 +61,17 @@ lkmressys(struct thread *td, struct nosys_args *args)
 	return (nosys(td, args));
 }
 
+struct sysent nosys_sysent = {
+	.sy_call =	(sy_call_t *)nosys,
+	.sy_systrace_args_func = NULL,
+	.sy_narg =	0,
+	.sy_flags =	SYF_CAPENABLED,
+	.sy_auevent =	AUE_NULL,
+	.sy_entry =	0, /* DTRACE_IDNONE */
+	.sy_return =	0,
+	.sy_thrcnt =	SY_THR_STATIC,
+};
+
 static void
 syscall_thread_drain(struct sysent *se)
 {
@@ -78,19 +89,21 @@ syscall_thread_drain(struct sysent *se)
 }
 
 int
-syscall_thread_enter(struct thread *td, struct sysent *se)
+syscall_thread_enter(struct thread *td, struct sysent **se)
 {
 	uint32_t cnt, oldcnt;
 
-	KASSERT((se->sy_thrcnt & SY_THR_STATIC) == 0,
+	KASSERT(((*se)->sy_thrcnt & SY_THR_STATIC) == 0,
 	    ("%s: not a static syscall", __func__));
 
 	do {
-		oldcnt = se->sy_thrcnt;
-		if ((oldcnt & (SY_THR_DRAINING | SY_THR_ABSENT)) != 0)
-			return (ENOSYS);
+		oldcnt = (*se)->sy_thrcnt;
+		if ((oldcnt & (SY_THR_DRAINING | SY_THR_ABSENT)) != 0) {
+			*se = &nosys_sysent;
+			return (0);
+		}
 		cnt = oldcnt + SY_THR_INCR;
-	} while (atomic_cmpset_acq_32(&se->sy_thrcnt, oldcnt, cnt) == 0);
+	} while (atomic_cmpset_acq_32(&(*se)->sy_thrcnt, oldcnt, cnt) == 0);
 	return (0);
 }
 
diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c
index c0262a1b1010..ff13672501b2 100644
--- a/sys/kern/subr_syscall.c
+++ b/sys/kern/subr_syscall.c
@@ -144,7 +144,8 @@ syscallenter(struct thread *td)
 	    AUDIT_SYSCALL_ENTER(sa->code, td) ||
 	    !sy_thr_static)) {
 		if (!sy_thr_static) {
-			error = syscall_thread_enter(td, se);
+			error = syscall_thread_enter(td, &se);
+			sy_thr_static = (se->sy_thrcnt & SY_THR_STATIC) != 0;
 			if (error != 0) {
 				td->td_errno = error;
 				goto retval;
diff --git a/sys/powerpc/powerpc/trap.c b/sys/powerpc/powerpc/trap.c
index 1527e813647d..7f1a267f5cf2 100644
--- a/sys/powerpc/powerpc/trap.c
+++ b/sys/powerpc/powerpc/trap.c
@@ -694,7 +694,7 @@ cpu_fetch_syscall_args(struct thread *td)
 	}
 
 	if (sa->code >= p->p_sysent->sv_size)
-		sa->callp = &p->p_sysent->sv_table[0];
+		sa->callp = &nosys_sysent;
 	else
 		sa->callp = &p->p_sysent->sv_table[sa->code];
 
diff --git a/sys/riscv/riscv/trap.c b/sys/riscv/riscv/trap.c
index b855fcc4163a..ea48b02ba29b 100644
--- a/sys/riscv/riscv/trap.c
+++ b/sys/riscv/riscv/trap.c
@@ -115,7 +115,7 @@ cpu_fetch_syscall_args(struct thread *td)
 	}
 
 	if (__predict_false(sa->code >= p->p_sysent->sv_size))
-		sa->callp = &p->p_sysent->sv_table[0];
+		sa->callp = &nosys_sysent;
 	else
 		sa->callp = &p->p_sysent->sv_table[sa->code];
 
diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h
index 3f52848af982..3ef6b06c5545 100644
--- a/sys/sys/sysent.h
+++ b/sys/sys/sysent.h
@@ -191,6 +191,7 @@ struct sysentvec {
 extern struct sysentvec aout_sysvec;
 extern struct sysent sysent[];
 extern const char *syscallnames[];
+extern struct sysent nosys_sysent;
 
 struct nosys_args {
 	register_t dummy;
@@ -319,7 +320,7 @@ struct nosys_args;
 int	lkmnosys(struct thread *, struct nosys_args *);
 int	lkmressys(struct thread *, struct nosys_args *);
 
-int	syscall_thread_enter(struct thread *td, struct sysent *se);
+int	syscall_thread_enter(struct thread *td, struct sysent **se);
 void	syscall_thread_exit(struct thread *td, struct sysent *se);
 
 int shared_page_alloc(int size, int align);