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,