aboutsummaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2026-06-05 20:21:59 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2026-06-08 20:14:20 +0000
commita2cfe535771ded3ca8526bae405a5b61f71f1f33 (patch)
treee43da13488f0b3ed43927ca9f0ddda51052d46e5 /sys/kern
parent9f378397ee89044a4faec522916b50f0a164d62e (diff)
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_exec.c13
-rw-r--r--sys/kern/kern_exit.c57
-rw-r--r--sys/kern/kern_fork.c3
-rw-r--r--sys/kern/kern_ucoredump.c4
4 files changed, 63 insertions, 14 deletions
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 4066682cbcc5..8ea00543989e 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -341,11 +341,11 @@ post_execve(struct thread *td, int error, struct vmspace *oldvmspace)
}
/*
- * kern_execve() has the astonishing property of not always returning to
- * the caller. If sufficiently bad things happen during the call to
- * do_execve(), it can end up calling exit1(); as a result, callers must
- * avoid doing anything which they might need to undo (e.g., allocating
- * memory).
+ * kern_execve() has the astonishing property of not always returning
+ * to the caller. If sufficiently bad things happen during the call
+ * to do_execve(), it can end up calling exit2(). Callers must avoid
+ * doing anything which they might need to undo (e.g., allocating
+ * memory), unless called from the ptrace(PT_SC_REMOTERQ) handler.
*/
int
kern_execve(struct thread *td, struct image_args *args, struct mac *mac_p,
@@ -1042,8 +1042,7 @@ exec_fail:
if (error && imgp->vmspace_destroyed) {
/* sorry, no more process anymore. exit gracefully */
exec_cleanup(td, oldvmspace);
- exit1(td, 0, SIGABRT);
- /* NOT REACHED */
+ kern_exit(td, 0, SIGABRT);
}
#ifdef KTRACE
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 18ea3a7bd29d..63e46dcf46f7 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -204,9 +204,8 @@ exit_onexit(struct proc *p)
int
sys__exit(struct thread *td, struct _exit_args *uap)
{
-
- exit1(td, uap->rval, 0);
- __unreachable();
+ kern_exit(td, uap->rval, 0);
+ return (0);
}
void
@@ -216,6 +215,48 @@ proc_set_p2_wexit(struct proc *p)
p->p_flag2 |= P2_WEXIT;
}
+static void
+ast_async_exit(struct thread *td, int asts)
+{
+ struct proc *p;
+
+ p = td->td_proc;
+ if ((p->p_flag & P_ASYNC_EXIT) != 0)
+ exit1(td, p->p_xexit, p->p_asig);
+}
+
+/*
+ * The variation on exit1() intended to be used in the syscall
+ * handlers. Unlike exit1(), it might delay the current process exit
+ * to ast. This is needed e.g. when _exit(2) is executed due to the
+ * ptrace(PT_SC_REMOTERQ), which must do more work after the syscall
+ * handler call.
+ */
+void
+kern_exit(struct thread *td, int rval, int signo)
+{
+ struct proc *p;
+
+ KASSERT(rval == 0 || signo == 0,
+ ("kern_exit rv %d sig %d", rval, signo));
+
+ p = td->td_proc;
+ if ((td->td_dbgflags & TDB_SCREMOTEREQ) != 0) {
+ PROC_LOCK(p);
+ p->p_xexit = rval;
+ p->p_asig = signo;
+ p->p_flag |= P_ASYNC_EXIT;
+ ast_sched(td, TDA_ASYNC_EXIT);
+ PROC_UNLOCK(p);
+ return;
+ }
+ if ((p->p_flag & P_ASYNC_EXIT) != 0) {
+ rval = p->p_xexit;
+ signo = p->p_asig;
+ }
+ exit1(td, rval, signo);
+}
+
/*
* Exit: deallocate address space and other resources, change proc state to
* zombie, and unlink proc from allproc and parent's lists. Save exit status
@@ -231,6 +272,7 @@ exit1(struct thread *td, int rval, int signo)
mtx_assert(&Giant, MA_NOTOWNED);
KASSERT(rval == 0 || signo == 0, ("exit1 rv %d sig %d", rval, signo));
+ MPASS((td->td_dbgflags & TDB_SCREMOTEREQ) == 0);
TSPROCEXIT(td->td_proc->p_pid);
p = td->td_proc;
@@ -828,7 +870,7 @@ out:
sbuf_delete(sb);
PROC_LOCK(p);
sigexit(td, sig);
- /* NOTREACHED */
+ return (0);
}
#ifdef COMPAT_43
@@ -1627,3 +1669,10 @@ proc_reparent(struct proc *child, struct proc *parent, bool set_oppid)
if (set_oppid)
child->p_oppid = parent->p_pid;
}
+
+static void
+initexit(void *dummy __unused)
+{
+ ast_register(TDA_ASYNC_EXIT, ASTR_ASTF_REQUIRED, 0, ast_async_exit);
+}
+SYSINIT(exit, SI_SUB_EXEC, SI_ORDER_ANY, initexit, NULL);
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 75f8413e5f36..2fb4d9d4274d 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -66,6 +66,7 @@
#include <sys/signalvar.h>
#include <sys/sx.h>
#include <sys/syscall.h>
+#include <sys/syscallsubr.h>
#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/vmmeter.h>
@@ -1258,7 +1259,7 @@ fork_return(struct thread *td, struct trapframe *frame)
* If the prison was killed mid-fork, die along with it.
*/
if (!prison_isalive(td->td_ucred->cr_prison))
- exit1(td, 0, SIGKILL);
+ kern_exit(td, 0, SIGKILL);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSRET))
diff --git a/sys/kern/kern_ucoredump.c b/sys/kern/kern_ucoredump.c
index d425596b5f24..e08490fbf7b1 100644
--- a/sys/kern/kern_ucoredump.c
+++ b/sys/kern/kern_ucoredump.c
@@ -46,6 +46,7 @@
#include <sys/racct.h>
#include <sys/resourcevar.h>
#include <sys/rmlock.h>
+#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/ucoredump.h>
@@ -197,8 +198,7 @@ sigexit(struct thread *td, int sig)
err != NULL ? err : "");
} else
PROC_UNLOCK(p);
- exit1(td, 0, sig);
- /* NOTREACHED */
+ kern_exit(td, 0, sig);
}