Date: Tue, 30 Jun 2026 17:21:55 +0000 From: Mark Johnston <markj@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Cc: Konstantin Belousov <kib@FreeBSD.org> Subject: git: 46f7b5a64048 - releng/15.1 - execve_block(): a mechanism for mutual exclusion with execve() on the process Message-ID: <6a43fb33.45e1a.6097eb@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch releng/15.1 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=46f7b5a64048b17d87badc989788cc041ec9f5a3 commit 46f7b5a64048b17d87badc989788cc041ec9f5a3 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2026-05-26 17:36:20 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2026-06-29 19:16:40 +0000 execve_block(): a mechanism for mutual exclusion with execve() on the process (cherry picked from commit e1a84b7708c2514769625c2af6c5034694013b6a) (cherry picked from commit a80e40ce9ee0a0641927730a193ff1f5641e71b6) execve_block_pass(9): a helper to wait for the execblock to pass (cherry picked from commit 450fe67d19eb2ea8e27109214ff21064fdcf808c) (cherry picked from commit cbd58477285888b1b7ff21bdd0bc039f7ffad4ef) proc: Allow to make proc_rwmem() operate on a consistent address space (cherry picked from commit e1b0d051bbf7e4e730470cbd6622f71a639834c3) (cherry picked from commit be6e5131066753dc23f8e9f223acc023b7618b63) kern_proc.c: ensure stability of the vmspace we read the strings from (cherry picked from commit a22c044cce41864a32af6b8281a3c416a2664d7f) (cherry picked from commit 3748c2e257046056b969a5d47231695798198f4d) kern_proc.c: ensure stability of the vmspace for sysctl kern.proc.vmmap (cherry picked from commit 5fe6e08d2db56b530f0df2903ef24cfabab7b8ea) (cherry picked from commit 20ed389b365030b868298d7ab4e8a01270c06c9f) kern_proc.c: ensure stability of the vmspace for sysctl kern.proc.vm_layout (cherry picked from commit 31fa677e4af00b795bf671847b4dc72960c90f14) (cherry picked from commit eb03358c407d6f3c073320bdc26a5e4ceb923ca1) kern_proc.c: make kern.proc.osrel atomic (cherry picked from commit 80626f34ee985671bb8c60ee986b89587b7a1511) (cherry picked from commit 5e633db3f8e126578c097c9649ba3be552664c6a) kern_proc.c: disallow execve around sysctl kern.proc.kstacks (cherry picked from commit 8b5abd9027b8b1f6290c756730ee3adebed007f4) (cherry picked from commit 60d8df61846fc1f5f7e2a400d2b0237c9f1a6be8) kern_proc.c: disallow execve around sysctl kern.proc.rlimit (cherry picked from commit 5a91fa5a7656c99e527fe7e6f6bf6bd9e85ab589) (cherry picked from commit 24d8b3364405e5c32618c6930d4fdd8bc543a08f) kern_event: block the target process from execing for sysctl kern.proc.kqueue (cherry picked from commit 79b384bd8fdff4869ce4799edb0342ff5c25b6fa) (cherry picked from commit d172933cf69fb4dc58e07261653481a33cdf1da0) kern_resource.c: disallow execve around sysctl kern.proc.rlimitusage (cherry picked from commit 836749817036b90b60af0584fa21f2d9dbd60ff7) (cherry picked from commit 035f66ff2924808f534df9065388aabf66e77266) kern_procctl(PROC_WX_MAPPINGS_PERMIT): ensure stability of the target vmspace (cherry picked from commit 6a572920f251ac8ac6a80a55d4d039736ea7dd65) (cherry picked from commit d80a7fd6e6df65b4d85e6977557c3fbe8d9ff02e) linux_prlimit(): block execve for the target (cherry picked from commit e41c28e67fac9cd22a85b160c5c9d0477ed03600) (cherry picked from commit e9002239571fb1502505ff85061934ef0ebd2e1e) pfs_readdir(): block the target process from execing (cherry picked from commit 4c0a0909f928baac982b7de4bfa5b5ca7de5291a) (cherry picked from commit 1744ce4b052d4aea94c1c3b87fefabd0952e6082) pseudofs: ensure that the target process vmspace is stable for VOP_READ/WRITE (cherry picked from commit a4993bac41350e85bc9affb862d2974a1a09bb5e) (cherry picked from commit 277f612073d0b086604448814867cadaacad4ca8) procfs, linprocfs: ensure target process vmspace stability (cherry picked from commit 5db31f1b47b586a5091eb41fc957236f28b78dba) (cherry picked from commit 78981848b85fdd826eb830dfdd6d92c14b0f8bb3) sys_set*id(9): wait for the execblocks to pass (cherry picked from commit d0384f50dad25d3358d76f7556969ea1d515ba68) (cherry picked from commit e0492444761b638ff072222d39ba5d6088a63370) kern_exec.c: explicitly include sys/limits.h for UINT_MAX (cherry picked from commit f5fce0bcc370a9700249e64901eabf2e0be4ecb0) (cherry picked from commit 42d8b0bf7a5a074c7035585a06dd44aed1b2cbdd) Approved by: so Security: FreeBSD-SA-26:39.execve Security: CVE-2026-49415 --- sys/compat/linprocfs/linprocfs.c | 16 +--- sys/compat/linux/linux_misc.c | 15 +++ sys/fs/cuse/cuse.c | 4 +- sys/fs/procfs/procfs_map.c | 17 ++-- sys/fs/procfs/procfs_mem.c | 6 +- sys/fs/pseudofs/pseudofs_vnops.c | 69 ++++++++++---- sys/kern/kern_event.c | 22 ++++- sys/kern/kern_exec.c | 83 ++++++++++++++++- sys/kern/kern_exit.c | 1 + sys/kern/kern_fork.c | 1 + sys/kern/kern_proc.c | 191 +++++++++++++++++++++++---------------- sys/kern/kern_procctl.c | 21 +++-- sys/kern/kern_prot.c | 20 +++- sys/kern/kern_resource.c | 27 ++++-- sys/kern/sys_process.c | 131 ++++++++++++++++++++++----- sys/sys/imgact.h | 4 + sys/sys/proc.h | 3 +- sys/sys/ptrace.h | 15 ++- 18 files changed, 470 insertions(+), 176 deletions(-) diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c index 7ac48786c77b..df3434848a81 100644 --- a/sys/compat/linprocfs/linprocfs.c +++ b/sys/compat/linprocfs/linprocfs.c @@ -1315,19 +1315,13 @@ linprocfs_doprocmaps(PFS_FILL_ARGS) struct vattr vat; bool private; - PROC_LOCK(p); - error = p_candebug(td, p); - PROC_UNLOCK(p); - if (error) - return (error); - if (uio->uio_rw != UIO_READ) return (EOPNOTSUPP); - error = 0; - vm = vmspace_acquire_ref(p); - if (vm == NULL) - return (ESRCH); + error = proc_vmspace_ref(td, p, PRVM_BLOCK_EXEC | PRVM_CHECK_DEBUG, + &vm); + if (error != 0) + return (error); if (SV_CURPROC_FLAG(SV_LP64)) l_map_str = l64_map_str; @@ -1425,7 +1419,7 @@ linprocfs_doprocmaps(PFS_FILL_ARGS) } } vm_map_unlock_read(map); - vmspace_free(vm); + proc_vmspace_unref(td, p, PRVM_CHECK_DEBUG | PRVM_BLOCK_EXEC, vm); return (error); } diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 937b010c8435..d35429e17f12 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -2010,6 +2010,7 @@ linux_prlimit64(struct thread *td, struct linux_prlimit64_args *args) u_int which; int flags; int error; + bool exec_blocked; if (args->new == NULL && args->old != NULL) { if (linux_get_dummy_limit(td, args->resource, &rlim)) { @@ -2037,6 +2038,7 @@ linux_prlimit64(struct thread *td, struct linux_prlimit64_args *args) return (error); } + exec_blocked = false; flags = PGET_HOLD | PGET_NOTWEXIT; if (args->new != NULL) flags |= PGET_CANDEBUG; @@ -2049,6 +2051,14 @@ linux_prlimit64(struct thread *td, struct linux_prlimit64_args *args) error = pget(args->pid, flags, &p); if (error != 0) return (error); + exec_blocked = true; + PROC_LOCK(p); + execve_block_wait(td, p); + error = args->new != NULL ? p_candebug(td, p) : + p_cansee(td, p); + PROC_UNLOCK(p); + if (error != 0) + goto out; } if (args->old != NULL) { PROC_LOCK(p); @@ -2071,6 +2081,11 @@ linux_prlimit64(struct thread *td, struct linux_prlimit64_args *args) error = kern_proc_setrlimit(td, p, which, &nrlim); out: + if (exec_blocked) { + PROC_LOCK(p); + execve_unblock(td, p); + PROC_UNLOCK(p); + } PRELE(p); return (error); } diff --git a/sys/fs/cuse/cuse.c b/sys/fs/cuse/cuse.c index b914b2d5017c..8f67c4b5572b 100644 --- a/sys/fs/cuse/cuse.c +++ b/sys/fs/cuse/cuse.c @@ -916,7 +916,7 @@ cuse_proc2proc_copy(struct proc *proc_s, vm_offset_t data_s, }; PHOLD(proc_s); - error = proc_rwmem(proc_s, &uio); + error = proc_rwmem(proc_s, &uio, 0); PRELE(proc_s); } else if (proc_cur == proc_s) { @@ -935,7 +935,7 @@ cuse_proc2proc_copy(struct proc *proc_s, vm_offset_t data_s, }; PHOLD(proc_d); - error = proc_rwmem(proc_d, &uio); + error = proc_rwmem(proc_d, &uio, 0); PRELE(proc_d); } else { error = EINVAL; diff --git a/sys/fs/procfs/procfs_map.c b/sys/fs/procfs/procfs_map.c index d4913a7b0f1d..1ed785f1ad90 100644 --- a/sys/fs/procfs/procfs_map.c +++ b/sys/fs/procfs/procfs_map.c @@ -40,6 +40,7 @@ #include <sys/malloc.h> #include <sys/mount.h> #include <sys/proc.h> +#include <sys/ptrace.h> #include <sys/resourcevar.h> #include <sys/rwlock.h> #include <sys/sbuf.h> @@ -93,15 +94,14 @@ procfs_doprocmap(PFS_FILL_ARGS) bool wrap32; #endif - PROC_LOCK(p); - error = p_candebug(td, p); - PROC_UNLOCK(p); - if (error) - return (error); - if (uio->uio_rw != UIO_READ) return (EOPNOTSUPP); + error = proc_vmspace_ref(td, p, PRVM_BLOCK_EXEC | PRVM_CHECK_DEBUG, + &vm); + if (error != 0) + return (error); + #ifdef COMPAT_FREEBSD32 wrap32 = false; if (SV_CURPROC_FLAG(SV_ILP32)) { @@ -111,9 +111,6 @@ procfs_doprocmap(PFS_FILL_ARGS) } #endif - vm = vmspace_acquire_ref(p); - if (vm == NULL) - return (ESRCH); map = &vm->vm_map; vm_map_lock_read(map); VM_MAP_ENTRY_FOREACH(entry, map) { @@ -238,6 +235,6 @@ procfs_doprocmap(PFS_FILL_ARGS) } } vm_map_unlock_read(map); - vmspace_free(vm); + proc_vmspace_unref(td, p, PRVM_BLOCK_EXEC | PRVM_CHECK_DEBUG, vm); return (error); } diff --git a/sys/fs/procfs/procfs_mem.c b/sys/fs/procfs/procfs_mem.c index 0020b8f8a8d8..eb692c32923b 100644 --- a/sys/fs/procfs/procfs_mem.c +++ b/sys/fs/procfs/procfs_mem.c @@ -60,11 +60,7 @@ procfs_doprocmem(PFS_FILL_ARGS) if (uio->uio_resid == 0) return (0); - PROC_LOCK(p); - error = p_candebug(td, p); - PROC_UNLOCK(p); - if (error == 0) - error = proc_rwmem(p, uio); + error = proc_rwmem(p, uio, PRVM_CHECK_DEBUG | PRVM_BLOCK_EXEC); return (error); } diff --git a/sys/fs/pseudofs/pseudofs_vnops.c b/sys/fs/pseudofs/pseudofs_vnops.c index 8cd092118d0e..059e8fd0e8b2 100644 --- a/sys/fs/pseudofs/pseudofs_vnops.c +++ b/sys/fs/pseudofs/pseudofs_vnops.c @@ -37,6 +37,7 @@ #include <sys/ctype.h> #include <sys/dirent.h> #include <sys/fcntl.h> +#include <sys/imgact.h> #include <sys/limits.h> #include <sys/lock.h> #include <sys/malloc.h> @@ -132,6 +133,7 @@ static int pfs_lookup_proc(pid_t pid, struct proc **p) { struct proc *proc; + struct thread *td; proc = pfind(pid); if (proc == NULL) @@ -141,8 +143,10 @@ pfs_lookup_proc(pid_t pid, struct proc **p) return (0); } _PHOLD(proc); - PROC_UNLOCK(proc); + td = curthread; + execve_block_wait(td, proc); *p = proc; + PROC_UNLOCK(proc); return (1); } @@ -672,6 +676,7 @@ pfs_read(struct vop_read_args *va) struct pfs_node *pn = pvd->pvd_pn; struct uio *uio = va->a_uio; struct proc *proc; + struct thread *td; struct sbuf *sb = NULL; int error, locked; off_t buflen, buflim; @@ -690,21 +695,30 @@ pfs_read(struct vop_read_args *va) if (pn->pn_fill == NULL) PFS_RETURN (EIO); + td = curthread; + /* * This is necessary because either process' privileges may * have changed since the open() call. */ - if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) + if (!pfs_visible(td, pn, pvd->pvd_pid, &proc)) PFS_RETURN (EIO); - if (proc != NULL) { - _PHOLD(proc); - PROC_UNLOCK(proc); - } vhold(vn); locked = VOP_ISLOCKED(vn); VOP_UNLOCK(vn); + if (proc != NULL) { + _PHOLD(proc); + execve_block_wait(td, proc); + if (!pfs_visible_proc(td, pn, proc)) { + PROC_UNLOCK(proc); + error = EIO; + goto ret; + } + PROC_UNLOCK(proc); + } + if (pn->pn_flags & PFS_RAWRD) { PFS_TRACE(("%zd resid", uio->uio_resid)); error = pn_fill(curthread, proc, pn, NULL, uio); @@ -774,8 +788,12 @@ pfs_read(struct vop_read_args *va) ret: vn_lock(vn, locked | LK_RETRY); vdrop(vn); - if (proc != NULL) - PRELE(proc); + if (proc != NULL) { + PROC_LOCK(proc); + execve_unblock(td, proc); + _PRELE(proc); + PROC_UNLOCK(proc); + } PFS_RETURN (error); } @@ -846,6 +864,7 @@ pfs_readdir(struct vop_readdir_args *va) struct pfs_node *pd = pvd->pvd_pn; pid_t pid = pvd->pvd_pid; struct proc *p, *proc; + struct thread *td; struct pfs_node *pn; struct uio *uio; struct pfsentry *pfsent, *pfsent2; @@ -891,11 +910,13 @@ pfs_readdir(struct vop_readdir_args *va) KASSERT(pid == NO_PID || proc != NULL, ("%s(): no process for pid %lu", __func__, (unsigned long)pid)); + td = curthread; if (pid != NO_PID) { PROC_LOCK(proc); /* check if the directory is visible to the caller */ if (!pfs_visible_proc(curthread, pd, proc)) { + execve_unblock(td, proc); _PRELE(proc); PROC_UNLOCK(proc); pfs_unlock(pd); @@ -955,6 +976,7 @@ pfs_readdir(struct vop_readdir_args *va) resid -= PFS_DELEN; } if (proc != NULL) { + execve_unblock(td, proc); _PRELE(proc); PROC_UNLOCK(proc); } @@ -1079,6 +1101,7 @@ pfs_write(struct vop_write_args *va) struct pfs_node *pn = pvd->pvd_pn; struct uio *uio = va->a_uio; struct proc *proc; + struct thread *td; struct sbuf sb; int error; @@ -1098,36 +1121,44 @@ pfs_write(struct vop_write_args *va) if (uio->uio_resid > PFS_MAXBUFSIZ) PFS_RETURN (EIO); + td = curthread; + /* * This is necessary because either process' privileges may * have changed since the open() call. */ - if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) + if (!pfs_visible(td, pn, pvd->pvd_pid, &proc)) PFS_RETURN (EIO); if (proc != NULL) { _PHOLD(proc); + execve_block_wait(td, proc); + if (!pfs_visible_proc(td, pn, proc)) { + PROC_UNLOCK(proc); + error = EIO; + goto out; + } PROC_UNLOCK(proc); } if (pn->pn_flags & PFS_RAWWR) { error = pn_fill(curthread, proc, pn, NULL, uio); - if (proc != NULL) - PRELE(proc); - PFS_RETURN (error); + goto out; } sbuf_uionew(&sb, uio, &error); - if (error) { - if (proc != NULL) - PRELE(proc); - PFS_RETURN (error); - } + if (error != 0) + goto out; error = pn_fill(curthread, proc, pn, &sb, uio); sbuf_delete(&sb); - if (proc != NULL) - PRELE(proc); +out: + if (proc != NULL) { + PROC_LOCK(proc); + execve_unblock(td, proc); + _PRELE(proc); + PROC_UNLOCK(proc); + } PFS_RETURN (error); } diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 8c7a0949f024..01bd22fbefd1 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -49,6 +49,7 @@ #include <sys/filedesc.h> #include <sys/filio.h> #include <sys/fcntl.h> +#include <sys/imgact.h> #include <sys/jail.h> #include <sys/jaildesc.h> #include <sys/kthread.h> @@ -3381,10 +3382,6 @@ sysctl_kern_proc_kqueue(SYSCTL_HANDLER_ARGS) if ((u_int)arg2 > 2 || (u_int)arg2 == 0) return (EINVAL); - error = pget((pid_t)name[0], PGET_HOLD | PGET_CANDEBUG, &p); - if (error != 0) - return (error); - td = curthread; #ifdef COMPAT_FREEBSD32 compat32 = SV_CURPROC_FLAG(SV_ILP32); @@ -3392,6 +3389,17 @@ sysctl_kern_proc_kqueue(SYSCTL_HANDLER_ARGS) compat32 = false; #endif + error = pget((pid_t)name[0], PGET_NOTWEXIT, &p); + if (error != 0) + return (error); + + _PHOLD(p); + execve_block_wait(td, p); + error = p_candebug(td, p); + if (error != 0) + goto out1; + PROC_UNLOCK(p); + s = sbuf_new_for_sysctl(&sm, NULL, 0, req); if (s == NULL) { error = ENOMEM; @@ -3412,7 +3420,11 @@ sysctl_kern_proc_kqueue(SYSCTL_HANDLER_ARGS) sbuf_delete(s); out: - PRELE(p); + PROC_LOCK(p); +out1: + execve_unblock(td, p); + _PRELE(p); + PROC_UNLOCK(p); return (error); } diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 0a9ae0aabb3e..c75354a4ffa6 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -26,7 +26,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> #include "opt_capsicum.h" #include "opt_hwpmc_hooks.h" #include "opt_hwt_hooks.h" @@ -46,6 +45,7 @@ #include <sys/imgact.h> #include <sys/imgact_elf.h> #include <sys/kernel.h> +#include <sys/limits.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mman.h> @@ -385,6 +385,77 @@ execve_nosetid(struct image_params *imgp) } } +/* + * Returns true if the execblock was obtained, in this case the + * process lock is kept. Returns false if the execblock was not + * obtained, but the function slept and the lock was dropped. + */ +bool +execve_block(struct thread *td, struct proc *p) +{ + PROC_LOCK_ASSERT(p, MA_OWNED); + MPASS(td == curthread); + MPASS(p != td->td_proc || (p->p_flag & P_INEXEC) == 0); + + if (p != td->td_proc && (p->p_flag & P_INEXEC) != 0) { + p->p_flag |= P_INEXEC_WAIT; + msleep(&p->p_execblock, &p->p_mtx, PDROP, "inexec", 0); + return (false); + } + MPASS(p->p_execblock < UINT_MAX); + p->p_execblock++; + return (true); +} + +/* + * Might drop the process lock internally, callers must re-check the + * invariants afterward. + */ +void +execve_block_wait(struct thread *td, struct proc *p) +{ + bool first; + + PROC_ASSERT_HELD(p); + PROC_LOCK_ASSERT(p, MA_OWNED); + + for (first = true;; first = false) { + if (!first) + PROC_LOCK(p); + if (execve_block(td, p)) + return; + } +} + +void +execve_unblock(struct thread *td, struct proc *p) +{ + PROC_LOCK_ASSERT(p, MA_OWNED); + MPASS(td == curthread); + + MPASS(p->p_execblock > 0); + p->p_execblock--; + if (p->p_execblock == 0 && (p->p_flag & P_INEXEC_WAIT) != 0) { + p->p_flag &= ~P_INEXEC_WAIT; + wakeup(&p->p_execblock); + } +} + +void +execve_block_pass(struct thread *td) +{ + struct proc *p; + + MPASS(td == curthread); + p = td->td_proc; + PROC_LOCK_ASSERT(p, MA_OWNED); + + while (p->p_execblock != 0) { + p->p_flag |= P_INEXEC_WAIT; + msleep(&p->p_execblock, &p->p_mtx, 0, "exeblk", 0); + } +} + /* * In-kernel implementation of execve(). All arguments are assumed to be * userspace pointers from the passed thread. @@ -440,6 +511,7 @@ do_execve(struct thread *td, struct image_args *args, struct mac *mac_p, PROC_LOCK(p); KASSERT((p->p_flag & P_INEXEC) == 0, ("%s(): process already has P_INEXEC flag", __func__)); + execve_block_pass(td); p->p_flag |= P_INEXEC; PROC_UNLOCK(p); @@ -909,7 +981,10 @@ interpret: * as we're now a bona fide freshly-execed process. */ KNOTE_LOCKED(p->p_klist, NOTE_EXEC); - p->p_flag &= ~P_INEXEC; + MPASS(p->p_execblock == 0); + if ((p->p_flag & P_INEXEC_WAIT) != 0) + wakeup(&p->p_execblock); + p->p_flag &= ~(P_INEXEC | P_INEXEC_WAIT); /* clear "fork but no exec" flag, as we _are_ execing */ p->p_acflag &= ~AFORK; @@ -1005,7 +1080,9 @@ exec_fail_dealloc: exec_fail: /* we're done here, clear P_INEXEC */ PROC_LOCK(p); - p->p_flag &= ~P_INEXEC; + if ((p->p_flag & P_INEXEC_WAIT) != 0) + wakeup(&p->p_execblock); + p->p_flag &= ~(P_INEXEC | P_INEXEC_WAIT); PROC_UNLOCK(p); SDT_PROBE1(proc, , , exec__failure, error); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 18ea3a7bd29d..667545bd6ac7 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -323,6 +323,7 @@ exit1(struct thread *td, int rval, int signo) while (p->p_lock > 0) msleep(&p->p_lock, &p->p_mtx, PWAIT, "exithold", 0); + MPASS(p->p_execblock == 0); PROC_UNLOCK(p); /* Drain the limit callout while we don't have the proc locked */ callout_drain(&p->p_limco); diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index a453af959bb1..07385752c02d 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -430,6 +430,7 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread * bzero(&p2->p_startzero, __rangeof(struct proc, p_startzero, p_endzero)); + p2->p_execblock = 0; /* Tell the prison that we exist. */ prison_proc_hold(p2->p_ucred->cr_prison); diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 758f54c540ab..3f0bb5a915f4 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -43,6 +43,7 @@ #include <sys/eventhandler.h> #include <sys/exec.h> #include <sys/fcntl.h> +#include <sys/imgact.h> #include <sys/ipc.h> #include <sys/jail.h> #include <sys/kernel.h> @@ -1838,8 +1839,8 @@ pargs_drop(struct pargs *pa) } static int -proc_read_string(struct thread *td, struct proc *p, const char *sptr, char *buf, - size_t len) +proc_read_string(struct thread *td, struct vmspace *vm, const char *sptr, + char *buf, size_t len) { ssize_t n; @@ -1848,7 +1849,7 @@ proc_read_string(struct thread *td, struct proc *p, const char *sptr, char *buf, * and is aligned at the end of the page, and the following page is not * mapped. */ - n = proc_readmem(td, p, (vm_offset_t)sptr, buf, len); + n = vmspace_iop(td, vm, (vm_offset_t)sptr, buf, len, UIO_READ); if (n <= 0) return (ENOMEM); return (0); @@ -1864,8 +1865,8 @@ enum proc_vector_type { #ifdef COMPAT_FREEBSD32 static int -get_proc_vector32(struct thread *td, struct proc *p, char ***proc_vectorp, - size_t *vsizep, enum proc_vector_type type) +get_proc_vector32(struct thread *td, struct proc *p, struct vmspace *vm, + char ***proc_vectorp, size_t *vsizep, enum proc_vector_type type) { struct freebsd32_ps_strings pss; Elf32_Auxinfo aux; @@ -1876,8 +1877,8 @@ get_proc_vector32(struct thread *td, struct proc *p, char ***proc_vectorp, int i, error; error = 0; - if (proc_readmem(td, p, PROC_PS_STRINGS(p), &pss, sizeof(pss)) != - sizeof(pss)) + if (vmspace_iop(td, vm, PROC_PS_STRINGS(p), &pss, sizeof(pss), + UIO_READ) != sizeof(pss)) return (ENOMEM); switch (type) { case PROC_ARG: @@ -1900,8 +1901,8 @@ get_proc_vector32(struct thread *td, struct proc *p, char ***proc_vectorp, if (vptr % 4 != 0) return (ENOEXEC); for (ptr = vptr, i = 0; i < PROC_AUXV_MAX; i++) { - if (proc_readmem(td, p, ptr, &aux, sizeof(aux)) != - sizeof(aux)) + if (vmspace_iop(td, vm, ptr, &aux, sizeof(aux), + UIO_READ) != sizeof(aux)) return (ENOMEM); if (aux.a_type == AT_NULL) break; @@ -1917,7 +1918,7 @@ get_proc_vector32(struct thread *td, struct proc *p, char ***proc_vectorp, return (EINVAL); } proc_vector32 = malloc(size, M_TEMP, M_WAITOK); - if (proc_readmem(td, p, vptr, proc_vector32, size) != size) { + if (vmspace_iop(td, vm, vptr, proc_vector32, size, UIO_READ) != size) { error = ENOMEM; goto done; } @@ -1938,8 +1939,8 @@ done: #endif static int -get_proc_vector(struct thread *td, struct proc *p, char ***proc_vectorp, - size_t *vsizep, enum proc_vector_type type) +get_proc_vector(struct thread *td, struct proc *p, struct vmspace *vm, + char ***proc_vectorp, size_t *vsizep, enum proc_vector_type type) { struct ps_strings pss; Elf_Auxinfo aux; @@ -1949,11 +1950,13 @@ get_proc_vector(struct thread *td, struct proc *p, char ***proc_vectorp, int i; #ifdef COMPAT_FREEBSD32 - if (SV_PROC_FLAG(p, SV_ILP32) != 0) - return (get_proc_vector32(td, p, proc_vectorp, vsizep, type)); + if (SV_PROC_FLAG(p, SV_ILP32) != 0) { + return (get_proc_vector32(td, p, vm, proc_vectorp, + vsizep, type)); + } #endif - if (proc_readmem(td, p, PROC_PS_STRINGS(p), &pss, sizeof(pss)) != - sizeof(pss)) + if (vmspace_iop(td, vm, PROC_PS_STRINGS(p), &pss, sizeof(pss), + UIO_READ) != sizeof(pss)) return (ENOMEM); switch (type) { case PROC_ARG: @@ -1991,8 +1994,8 @@ get_proc_vector(struct thread *td, struct proc *p, char ***proc_vectorp, * to the allocated proc_vector. */ for (ptr = vptr, i = 0; i < PROC_AUXV_MAX; i++) { - if (proc_readmem(td, p, ptr, &aux, sizeof(aux)) != - sizeof(aux)) + if (vmspace_iop(td, vm, ptr, &aux, sizeof(aux), + UIO_READ) != sizeof(aux)) return (ENOMEM); if (aux.a_type == AT_NULL) break; @@ -2014,7 +2017,7 @@ get_proc_vector(struct thread *td, struct proc *p, char ***proc_vectorp, return (EINVAL); /* In case we are built without INVARIANTS. */ } proc_vector = malloc(size, M_TEMP, M_WAITOK); - if (proc_readmem(td, p, vptr, proc_vector, size) != size) { + if (vmspace_iop(td, vm, vptr, proc_vector, size, UIO_READ) != size) { free(proc_vector, M_TEMP); return (ENOMEM); } @@ -2030,6 +2033,7 @@ static int get_ps_strings(struct thread *td, struct proc *p, struct sbuf *sb, enum proc_vector_type type) { + struct vmspace *vm; size_t done, len, nchr, vsize; int error, i; char **proc_vector, *sptr; @@ -2042,9 +2046,14 @@ get_ps_strings(struct thread *td, struct proc *p, struct sbuf *sb, */ nchr = 2 * (PATH_MAX + ARG_MAX); - error = get_proc_vector(td, p, &proc_vector, &vsize, type); + error = proc_vmspace_ref(td, p, PRVM_BLOCK_EXEC | + PRVM_CHECK_VISIBILITY, &vm); if (error != 0) return (error); + + error = get_proc_vector(td, p, vm, &proc_vector, &vsize, type); + if (error != 0) + goto out; for (done = 0, i = 0; i < (int)vsize && done < nchr; i++) { /* * The program may have scribbled into its argv array, e.g. to @@ -2054,7 +2063,7 @@ get_ps_strings(struct thread *td, struct proc *p, struct sbuf *sb, if (proc_vector[i] == NULL) break; for (sptr = proc_vector[i]; ; sptr += GET_PS_STRINGS_CHUNK_SZ) { - error = proc_read_string(td, p, sptr, pss_string, + error = proc_read_string(td, vm, sptr, pss_string, sizeof(pss_string)); if (error != 0) goto done; @@ -2071,6 +2080,8 @@ get_ps_strings(struct thread *td, struct proc *p, struct sbuf *sb, } done: free(proc_vector, M_TEMP); +out: + proc_vmspace_unref(td, p, PRVM_BLOCK_EXEC | PRVM_CHECK_VISIBILITY, vm); return (error); } @@ -2091,11 +2102,17 @@ proc_getenvv(struct thread *td, struct proc *p, struct sbuf *sb) int proc_getauxv(struct thread *td, struct proc *p, struct sbuf *sb) { + struct vmspace *vm; size_t vsize, size; char **auxv; int error; - error = get_proc_vector(td, p, &auxv, &vsize, PROC_AUX); + error = proc_vmspace_ref(td, p, PRVM_BLOCK_EXEC | PRVM_CHECK_DEBUG, + &vm); + if (error != 0) + return (error); + error = get_proc_vector(td, p, vm, &auxv, &vsize, PROC_AUX); + proc_vmspace_unref(td, p, PRVM_BLOCK_EXEC | PRVM_CHECK_DEBUG, vm); if (error == 0) { #ifdef COMPAT_FREEBSD32 if (SV_PROC_FLAG(p, SV_ILP32) != 0) @@ -2408,6 +2425,7 @@ sysctl_kern_proc_ovmmap(SYSCTL_HANDLER_ARGS) int error, *name; struct vnode *vp; struct proc *p; + struct thread *td; vm_map_t map; struct vmspace *vm; @@ -2416,11 +2434,12 @@ sysctl_kern_proc_ovmmap(SYSCTL_HANDLER_ARGS) return (EINVAL); name = (int *)arg1; + td = curthread; error = pget((pid_t)name[0], PGET_WANTREAD, &p); if (error != 0) return (error); - vm = vmspace_acquire_ref(p); - if (vm == NULL) { + error = proc_vmspace_ref(td, p, PRVM_CHECK_DEBUG, &vm); + if (error != 0) { PRELE(p); return (ESRCH); } @@ -2532,7 +2551,7 @@ sysctl_kern_proc_ovmmap(SYSCTL_HANDLER_ARGS) } } vm_map_unlock_read(map); - vmspace_free(vm); + proc_vmspace_unref(td, p, PRVM_CHECK_DEBUG, vm); PRELE(p); free(kve, M_TEMP); return (error); @@ -2627,6 +2646,7 @@ kern_proc_vmmap_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, int flags) struct ucred *cred; struct vnode *vp; struct vmspace *vm; + struct thread *td; vm_offset_t addr; unsigned int last_timestamp; int error; @@ -2638,10 +2658,11 @@ kern_proc_vmmap_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, int flags) _PHOLD(p); PROC_UNLOCK(p); - vm = vmspace_acquire_ref(p); - if (vm == NULL) { + td = curthread; + error = proc_vmspace_ref(td, p, PRVM_CHECK_DEBUG, &vm); + if (error != 0) { PRELE(p); - return (ESRCH); + return (error); } kve = malloc(sizeof(*kve), M_TEMP, M_WAITOK | M_ZERO); @@ -2745,7 +2766,7 @@ kern_proc_vmmap_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, int flags) if (vp != NULL) { vn_fullpath(vp, &fullpath, &freepath); kve->kve_vn_type = vntype_to_kinfo(vp->v_type); - cred = curthread->td_ucred; + cred = td->td_ucred; vn_lock(vp, LK_SHARED | LK_RETRY); if (VOP_GETATTR(vp, &va, cred) == 0) { kve->kve_vn_fileid = va.va_fileid; @@ -2801,7 +2822,7 @@ kern_proc_vmmap_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, int flags) } } vm_map_unlock_read(map); - vmspace_free(vm); + proc_vmspace_unref(td, p, PRVM_CHECK_DEBUG, vm); PRELE(p); free(kve, M_TEMP); return (error); @@ -2840,7 +2861,7 @@ sysctl_kern_proc_kstack(SYSCTL_HANDLER_ARGS) struct kinfo_kstack *kkstp; int error, i, *name, numthreads; lwpid_t *lwpidarray; - struct thread *td; + struct thread *td, *ctd; struct stack *st; struct sbuf sb; struct proc *p; @@ -2851,7 +2872,8 @@ sysctl_kern_proc_kstack(SYSCTL_HANDLER_ARGS) return (EINVAL); name = (int *)arg1; - error = pget((pid_t)name[0], PGET_NOTINEXEC | PGET_WANTREAD, &p); + ctd = curthread; + error = pget((pid_t)name[0], PGET_WANTREAD, &p); if (error != 0) return (error); @@ -2860,6 +2882,14 @@ sysctl_kern_proc_kstack(SYSCTL_HANDLER_ARGS) lwpidarray = NULL; PROC_LOCK(p); + execve_block_wait(ctd, p); + error = p_candebug(ctd, p); + if (error != 0) { + execve_unblock(ctd, p); + _PRELE(p); + PROC_UNLOCK(p); + return (error); + } do { if (lwpidarray != NULL) { free(lwpidarray, M_TEMP); @@ -2872,15 +2902,6 @@ sysctl_kern_proc_kstack(SYSCTL_HANDLER_ARGS) PROC_LOCK(p); } while (numthreads < p->p_numthreads); - /* *** 716 LINES SKIPPED ***home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a43fb33.45e1a.6097eb>
