git: 09dfe066f00c - main - kernel: copyout extended errors to userspace and add exterrctl(2) to control it
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 31 May 2025 19:52:50 UTC
The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=09dfe066f00c927e88c23265387d432e6d9f0c5e commit 09dfe066f00c927e88c23265387d432e6d9f0c5e Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2025-05-23 05:01:39 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2025-05-31 19:52:41 +0000 kernel: copyout extended errors to userspace and add exterrctl(2) to control it Reviewed by: brooks Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D50483 --- sys/kern/kern_exec.c | 1 + sys/kern/kern_fork.c | 1 + sys/kern/subr_syscall.c | 4 +++ sys/kern/sys_generic.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++- sys/kern/syscalls.master | 8 +++++- sys/sys/exterrvar.h | 13 +++++++++ sys/sys/proc.h | 2 ++ sys/sys/uio.h | 1 + 8 files changed, 101 insertions(+), 2 deletions(-) diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index a943ec339e75..cf067527237e 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -809,6 +809,7 @@ interpret: * it that it now has its own resources back */ p->p_flag |= P_EXEC; + td->td_pflags2 &= ~TDP2_UEXTERR; if ((p->p_flag2 & P2_NOTRACE_EXEC) == 0) p->p_flag2 &= ~P2_NOTRACE; if ((p->p_flag2 & P2_STKGAP_DISABLE_EXEC) == 0) diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 494f06cc0621..2ab9b363f8b5 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -609,6 +609,7 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread * */ p2->p_flag |= p1->p_flag & P_SUGID; td2->td_pflags |= td->td_pflags & (TDP_ALTSTACK | TDP_SIGFASTBLOCK); + td2->td_pflags2 |= td->td_pflags2 & TDP2_UEXTERR; SESS_LOCK(p1->p_session); if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT) p2->p_flag |= P_CONTROLT; diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c index 16fa47c5605a..d5b3b62f0821 100644 --- a/sys/kern/subr_syscall.c +++ b/sys/kern/subr_syscall.c @@ -74,6 +74,8 @@ syscallenter(struct thread *td) td->td_dbgflags |= TDB_SCE; PROC_UNLOCK(p); } + if ((td->td_pflags2 & TDP2_UEXTERR) != 0) + td->td_pflags2 &= ~TDP2_EXTERR; error = (p->p_sysent->sv_fetch_syscall_args)(td); se = sa->callp; #ifdef KTRACE @@ -207,6 +209,8 @@ syscallenter(struct thread *td) PROC_UNLOCK(p); } (p->p_sysent->sv_set_syscall_retval)(td, error); + if (error != 0 && (td->td_pflags2 & TDP2_UEXTERR) != 0) + exterr_copyout(td); } static inline void diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index dd9c28e81388..91bf3e93fa7c 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -34,10 +34,10 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> #include "opt_capsicum.h" #include "opt_ktrace.h" +#define EXTERR_CATEGORY EXTERR_CAT_FILEDESC #include <sys/param.h> #include <sys/systm.h> #include <sys/sysproto.h> @@ -46,6 +46,7 @@ #include <sys/filio.h> #include <sys/fcntl.h> #include <sys/file.h> +#include <sys/exterrvar.h> #include <sys/lock.h> #include <sys/proc.h> #include <sys/signalvar.h> @@ -2200,3 +2201,73 @@ file_kcmp_generic(struct file *fp1, struct file *fp2, struct thread *td) return (3); return (kcmp_cmp((uintptr_t)fp1->f_data, (uintptr_t)fp2->f_data)); } + +void +exterr_copyout(struct thread *td) +{ + struct uexterror ue; + ksiginfo_t ksi; + void *uloc; + size_t sz; + int error; + + MPASS((td->td_pflags2 & TDP2_UEXTERR) != 0); + + uloc = (char *)td->td_exterr_ptr + __offsetof(struct uexterror, + error); + if ((td->td_pflags2 & TDP2_EXTERR) == 0) { + ue.error = 0; + sz = sizeof(ue.error); + } else { + memset(&ue, 0, sizeof(ue)); + ue.error = td->td_kexterr.error; + ue.cat = td->td_kexterr.cat; + ue.src_line = td->td_kexterr.src_line; + ue.p1 = td->td_kexterr.p1; + ue.p2 = td->td_kexterr.p2; + if (td->td_kexterr.msg != NULL) + strlcpy(ue.msg, td->td_kexterr.msg, sizeof(ue.msg)); + sz = sizeof(ue) - __offsetof(struct uexterror, error); + } + error = copyout(&ue.error, uloc, sz); + if (error != 0) { + td->td_pflags2 &= ~TDP2_UEXTERR; + ksiginfo_init_trap(&ksi); + ksi.ksi_signo = SIGSEGV; + ksi.ksi_code = SEGV_ACCERR; + ksi.ksi_addr = uloc; + trapsignal(td, &ksi); + } +} + +int +sys_exterrctl(struct thread *td, struct exterrctl_args *uap) +{ + uint32_t ver; + int error; + + if ((uap->flags & ~(EXTERRCTLF_FORCE)) != 0) + return (EINVAL); + switch (uap->op) { + case EXTERRCTL_ENABLE: + if ((td->td_pflags2 & TDP2_UEXTERR) != 0 && + (uap->flags & EXTERRCTLF_FORCE) == 0) + return (EBUSY); + td->td_pflags2 &= ~TDP2_UEXTERR; + error = copyin(uap->ptr, &ver, sizeof(ver)); + if (error != 0) + return (error); + if (ver != UEXTERROR_VER) + return (EINVAL); + td->td_pflags2 |= TDP2_UEXTERR; + td->td_exterr_ptr = uap->ptr; + return (0); + case EXTERRCTL_DISABLE: + if ((td->td_pflags2 & TDP2_UEXTERR) == 0) + return (EINVAL); + td->td_pflags2 &= ~TDP2_UEXTERR; + return (0); + default: + return (EINVAL); + } +} diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 67396a4cabc5..08b557a7a540 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -3349,5 +3349,11 @@ size_t size ); } - +592 AUE_NULL STD { + int exterrctl( + u_int op, + u_int flags, + _In_reads_bytes_(4) void *ptr + ); + } ; vim: syntax=off diff --git a/sys/sys/exterrvar.h b/sys/sys/exterrvar.h index 6e392ff2c18c..5afcd82b136a 100644 --- a/sys/sys/exterrvar.h +++ b/sys/sys/exterrvar.h @@ -26,6 +26,13 @@ struct uexterror { char msg[128]; }; +#define UEXTERROR_VER 0x10010001 + +#define EXTERRCTL_ENABLE 1 +#define EXTERRCTL_DISABLE 2 + +#define EXTERRCTLF_FORCE 0x00000001 + #ifdef _KERNEL #ifndef EXTERR_CATEGORY @@ -53,6 +60,12 @@ struct uexterror { #define SET_ERROR0(eerror, mmsg) SET_ERROR2(eerror, mmsg, 0, 0) #define SET_ERROR1(eerror, mmsg, pp1) SET_ERROR2(eerror, mmsg, pp1, 0) +#else /* _KERNEL */ + +__BEGIN_DECLS +int exterrctl(u_int op, u_int flags, void *ptr); +__END_DECLS + #endif /* _KERNEL */ #endif diff --git a/sys/sys/proc.h b/sys/sys/proc.h index cab487719c31..b48681420028 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -343,6 +343,7 @@ struct thread { void *td_sigblock_ptr; /* (k) uptr for fast sigblock. */ uint32_t td_sigblock_val; /* (k) fast sigblock value read at td_sigblock_ptr on kern entry */ + void *td_exterr_ptr; #define td_endcopy td_pcb /* @@ -572,6 +573,7 @@ enum { #define TDP2_ACCT 0x00000004 /* Doing accounting */ #define TDP2_SAN_QUIET 0x00000008 /* Disable warnings from K(A|M)SAN */ #define TDP2_EXTERR 0x00000010 /* Kernel reported ext error */ +#define TDP2_UEXTERR 0x00000020 /* User set ext error reporting ptr */ /* * Reasons that the current thread can not be run yet. diff --git a/sys/sys/uio.h b/sys/sys/uio.h index ec4e92d852a6..05c1ed640b63 100644 --- a/sys/sys/uio.h +++ b/sys/sys/uio.h @@ -84,6 +84,7 @@ int copyiniov(const struct iovec *iovp, u_int iovcnt, struct iovec **iov, int copyinuio(const struct iovec *iovp, u_int iovcnt, struct uio **uiop); int copyout_map(struct thread *td, vm_offset_t *addr, size_t sz); int copyout_unmap(struct thread *td, vm_offset_t addr, size_t sz); +void exterr_copyout(struct thread *td); int physcopyin(void *src, vm_paddr_t dst, size_t len); int physcopyout(vm_paddr_t src, void *dst, size_t len); int physcopyin_vlist(struct bus_dma_segment *src, off_t offset,