git: 3ce3b342db7e - main - kern: add some better error messages for coredump() failures

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Sat, 26 Jul 2025 21:31:54 UTC
The branch main has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=3ce3b342db7e5c987e5eee039f7b290a3919ca37

commit 3ce3b342db7e5c987e5eee039f7b290a3919ca37
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2025-07-22 16:49:52 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2025-07-26 21:31:42 +0000

    kern: add some better error messages for coredump() failures
    
    After debugging with a user on discord why their process is not
    generating coredumps, it became clear that we can use better error
    messages -- particularly to distinguish between the different EFAULT
    cases.  For those that are denied by system policies, include some
    more specific pointers to the relevant knob.
    
    Reviewed by:    kib
    Differential Revision:  https://reviews.freebsd.org/D51465
---
 sys/kern/kern_ucoredump.c | 57 ++++++++++++++++++++++++++++-------------------
 1 file changed, 34 insertions(+), 23 deletions(-)

diff --git a/sys/kern/kern_ucoredump.c b/sys/kern/kern_ucoredump.c
index a2412bf06441..d425596b5f24 100644
--- a/sys/kern/kern_ucoredump.c
+++ b/sys/kern/kern_ucoredump.c
@@ -51,7 +51,7 @@
 #include <sys/ucoredump.h>
 #include <sys/wait.h>
 
-static int coredump(struct thread *td);
+static int coredump(struct thread *td, const char **);
 
 int compress_user_cores = 0;
 
@@ -135,7 +135,6 @@ void
 sigexit(struct thread *td, int sig)
 {
 	struct proc *p = td->td_proc;
-	const char *coreinfo;
 	int rv;
 	bool logexit;
 
@@ -158,6 +157,8 @@ sigexit(struct thread *td, int sig)
 	 *     (e.g. via fork()), we won't get a dump at all.
 	 */
 	if (sig_do_core(sig) && thread_single(p, SINGLE_NO_EXIT) == 0) {
+		const char *err = NULL;
+
 		p->p_sig = sig;
 		/*
 		 * Log signals which would cause core dumps
@@ -166,32 +167,34 @@ sigexit(struct thread *td, int sig)
 		 * XXX : Todo, as well as euid, write out ruid too
 		 * Note that coredump() drops proc lock.
 		 */
-		rv = coredump(td);
-		switch (rv) {
-		case 0:
+		rv = coredump(td, &err);
+		if (rv == 0) {
+			MPASS(err == NULL);
 			sig |= WCOREFLAG;
-			coreinfo = " (core dumped)";
-			break;
-		case EFAULT:
-			coreinfo = " (no core dump - bad address)";
-			break;
-		case EINVAL:
-			coreinfo = " (no core dump - invalid argument)";
-			break;
-		case EFBIG:
-			coreinfo = " (no core dump - too large)";
-			break;
-		default:
-			coreinfo = " (no core dump - other error)";
-			break;
+		} else if (err == NULL) {
+			switch (rv) {
+			case EFAULT:
+				err = "bad address";
+				break;
+			case EINVAL:
+				err = "invalild argument";
+				break;
+			case EFBIG:
+				err = "too large";
+				break;
+			default:
+				err = "other error";
+				break;
+			}
 		}
 		if (logexit)
 			log(LOG_INFO,
 			    "pid %d (%s), jid %d, uid %d: exited on "
-			    "signal %d%s\n", p->p_pid, p->p_comm,
+			    "signal %d (%s%s)\n", p->p_pid, p->p_comm,
 			    p->p_ucred->cr_prison->pr_id,
-			    td->td_ucred->cr_uid,
-			    sig &~ WCOREFLAG, coreinfo);
+			    td->td_ucred->cr_uid, sig &~ WCOREFLAG,
+			    err != NULL ? "no core dump - " : "core dumped",
+			    err != NULL ? err : "");
 	} else
 		PROC_UNLOCK(p);
 	exit1(td, 0, sig);
@@ -207,7 +210,7 @@ sigexit(struct thread *td, int sig)
  * ENOSYS; otherwise it returns the error from the process-specific routine.
  */
 static int
-coredump(struct thread *td)
+coredump(struct thread *td, const char **errmsg)
 {
 	struct coredumper *iter, *chosen;
 	struct proc *p = td->td_proc;
@@ -221,6 +224,13 @@ coredump(struct thread *td)
 	if (!do_coredump || (!sugid_coredump && (p->p_flag & P_SUGID) != 0) ||
 	    (p->p_flag2 & P2_NOTRACE) != 0) {
 		PROC_UNLOCK(p);
+
+		if (!do_coredump)
+			*errmsg = "denied by kern.coredump";
+		else if ((p->p_flag2 & P2_NOTRACE) != 0)
+			*errmsg = "process has trace disabled";
+		else
+			*errmsg = "sugid process denied by kern.sugid_coredump";
 		return (EFAULT);
 	}
 
@@ -235,6 +245,7 @@ coredump(struct thread *td)
 	limit = (off_t)lim_cur(td, RLIMIT_CORE);
 	if (limit == 0 || racct_get_available(p, RACCT_CORE) == 0) {
 		PROC_UNLOCK(p);
+		*errmsg = "coredumpsize limit is 0";
 		return (EFBIG);
 	}