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
This commit is contained in:
Konstantin Belousov 2023-09-25 19:32:52 +03:00
parent 6b3bb233cd
commit 39024a8914
14 changed files with 35 additions and 19 deletions

View file

@ -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];

View file

@ -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];

View file

@ -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;

View file

@ -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];

View file

@ -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];

View file

@ -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];

View file

@ -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];

View file

@ -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];

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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];

View file

@ -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];

View file

@ -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);