The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=8eb37cd06b345e7187e4b65484a1194ed7e300f8
commit 8eb37cd06b345e7187e4b65484a1194ed7e300f8 Author: Kyle Evans <kev...@freebsd.org> AuthorDate: 2025-07-15 20:14:55 +0000 Commit: Kyle Evans <kev...@freebsd.org> CommitDate: 2025-07-26 21:31:41 +0000 kern: factor out the 'writing' bits of user process coredumping Instead of assuming we have a vnode to dump to, pull out the bits that describe how to write acoredump into a struct coredump_writer; the ctx in that is expected to be opaque, but used by write/extend functions. This should not be a functional change- we change two callers to use the classic vnode write/extend interface. This opens us up to other possible targets for coredumps, such as a shmfd. Reviewed by: markj (earlier version), kib Differential Revision: https://reviews.freebsd.org/D51337 --- sys/kern/imgact_elf.c | 11 ++++++++--- sys/kern/kern_exec.c | 50 ++++++++++++++++++++++++++++++++++++++------------ sys/kern/kern_sig.c | 23 +++++++++++++++++++++-- sys/sys/exec.h | 32 ++++++++++++++++++++++++++++++-- sys/sys/imgact_elf.h | 3 ++- sys/sys/sysent.h | 4 +++- 6 files changed, 102 insertions(+), 21 deletions(-) diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index b7ffbe68b483..a7d3e22e6279 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -1595,7 +1595,7 @@ core_compressed_write(void *base, size_t len, off_t offset, void *arg) } int -__elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags) +__elfN(coredump)(struct thread *td, struct coredump_writer *cdw, off_t limit, int flags) { struct ucred *cred = td->td_ucred; int compm, error = 0; @@ -1625,9 +1625,8 @@ __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags) /* Set up core dump parameters. */ params.offset = 0; params.active_cred = cred; - params.file_cred = NOCRED; params.td = td; - params.vp = vp; + params.cdw = cdw; params.comp = NULL; #ifdef RACCT @@ -1662,6 +1661,12 @@ __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags) tmpbuf = malloc(CORE_BUF_SIZE, M_TEMP, M_WAITOK | M_ZERO); } + if (cdw->init_fn != NULL) { + error = (*cdw->init_fn)(cdw, ¶ms); + if (error != 0) + goto done; + } + /* * Allocate memory for building the header, fill it up, * and write it out following the notes. diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 03268365891e..a0a22ee8539b 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1998,14 +1998,48 @@ compress_chunk(struct coredump_params *cp, char *base, char *buf, size_t len) return (error); } +int +core_vn_write(const struct coredump_writer *cdw, const void *base, size_t len, + off_t offset, enum uio_seg seg, struct ucred *cred, size_t *resid, + struct thread *td) +{ + struct coredump_vnode_ctx *ctx = cdw->ctx; + + return (vn_rdwr_inchunks(UIO_WRITE, ctx->vp, __DECONST(void *, base), + len, offset, seg, IO_UNIT | IO_DIRECT | IO_RANGELOCKED, + cred, ctx->fcred, resid, td)); +} + int core_write(struct coredump_params *cp, const void *base, size_t len, off_t offset, enum uio_seg seg, size_t *resid) { + return ((*cp->cdw->write_fn)(cp->cdw, base, len, offset, seg, + cp->active_cred, resid, cp->td)); +} - return (vn_rdwr_inchunks(UIO_WRITE, cp->vp, __DECONST(void *, base), - len, offset, seg, IO_UNIT | IO_DIRECT | IO_RANGELOCKED, - cp->active_cred, cp->file_cred, resid, cp->td)); +int +core_vn_extend(const struct coredump_writer *cdw, off_t newsz, + struct ucred *cred) +{ + struct coredump_vnode_ctx *ctx = cdw->ctx; + struct mount *mp; + int error; + + error = vn_start_write(ctx->vp, &mp, V_WAIT); + if (error != 0) + return (error); + vn_lock(ctx->vp, LK_EXCLUSIVE | LK_RETRY); + error = vn_truncate_locked(ctx->vp, newsz, false, cred); + VOP_UNLOCK(ctx->vp); + vn_finished_write(mp); + return (error); +} + +static int +core_extend(struct coredump_params *cp, off_t newsz) +{ + return ((*cp->cdw->extend_fn)(cp->cdw, newsz, cp->td->td_ucred)); } int @@ -2013,7 +2047,6 @@ core_output(char *base, size_t len, off_t offset, struct coredump_params *cp, void *tmpbuf) { vm_map_t map; - struct mount *mp; size_t resid, runlen; int error; bool success; @@ -2068,14 +2101,7 @@ core_output(char *base, size_t len, off_t offset, struct coredump_params *cp, } } if (!success) { - error = vn_start_write(cp->vp, &mp, V_WAIT); - if (error != 0) - break; - vn_lock(cp->vp, LK_EXCLUSIVE | LK_RETRY); - error = vn_truncate_locked(cp->vp, offset + runlen, - false, cp->td->td_ucred); - VOP_UNLOCK(cp->vp); - vn_finished_write(mp); + error = core_extend(cp, offset + runlen); if (error != 0) break; } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 5d51aa675cb7..e96f72d56e18 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -49,6 +49,7 @@ #include <sys/condvar.h> #include <sys/devctl.h> #include <sys/event.h> +#include <sys/exec.h> #include <sys/fcntl.h> #include <sys/imgact.h> #include <sys/jail.h> @@ -2665,6 +2666,8 @@ static void ptrace_coredumpreq(struct thread *td, struct proc *p, struct thr_coredump_req *tcq) { + struct coredump_vnode_ctx wctx; + struct coredump_writer cdw; void *rl_cookie; if (p->p_sysent->sv_coredump == NULL) { @@ -2672,8 +2675,15 @@ ptrace_coredumpreq(struct thread *td, struct proc *p, return; } + wctx.vp = tcq->tc_vp; + wctx.fcred = NOCRED; + + cdw.ctx = &wctx; + cdw.write_fn = core_vn_write; + cdw.extend_fn = core_vn_extend; + rl_cookie = vn_rangelock_wlock(tcq->tc_vp, 0, OFF_MAX); - tcq->tc_error = p->p_sysent->sv_coredump(td, tcq->tc_vp, + tcq->tc_error = p->p_sysent->sv_coredump(td, &cdw, tcq->tc_limit, tcq->tc_flags); vn_rangelock_unlock(tcq->tc_vp, rl_cookie); } @@ -4135,6 +4145,8 @@ coredump(struct thread *td) struct proc *p = td->td_proc; struct ucred *cred = td->td_ucred; struct vnode *vp; + struct coredump_vnode_ctx wctx; + struct coredump_writer cdw; struct flock lf; struct vattr vattr; size_t fullpathsize; @@ -4212,8 +4224,15 @@ coredump(struct thread *td) p->p_acflag |= ACORE; PROC_UNLOCK(p); + wctx.vp = vp; + wctx.fcred = NOCRED; + + cdw.ctx = &wctx; + cdw.write_fn = core_vn_write; + cdw.extend_fn = core_vn_extend; + if (p->p_sysent->sv_coredump != NULL) { - error = p->p_sysent->sv_coredump(td, vp, limit, 0); + error = p->p_sysent->sv_coredump(td, &cdw, limit, 0); } else { error = ENOSYS; } diff --git a/sys/sys/exec.h b/sys/sys/exec.h index 4bf114a7c698..fed93949dae5 100644 --- a/sys/sys/exec.h +++ b/sys/sys/exec.h @@ -37,6 +37,8 @@ #ifndef _SYS_EXEC_H_ #define _SYS_EXEC_H_ +#include <sys/_uio.h> + /* * Before ps_args existed, the following structure, found at the top of * the user stack of each user process, was used by ps(1) to locate @@ -58,12 +60,38 @@ struct ps_strings { }; /* Coredump output parameters. */ +struct coredump_params; +struct coredump_writer; +struct thread; +struct ucred; + +typedef int coredump_init_fn(const struct coredump_writer *, + const struct coredump_params *); +typedef int coredump_write_fn(const struct coredump_writer *, const void *, size_t, + off_t, enum uio_seg, struct ucred *, size_t *, struct thread *); +typedef int coredump_extend_fn(const struct coredump_writer *, off_t, + struct ucred *); + +struct coredump_vnode_ctx { + struct vnode *vp; + struct ucred *fcred; +}; + +coredump_write_fn core_vn_write; +coredump_extend_fn core_vn_extend; + +struct coredump_writer { + void *ctx; + coredump_init_fn *init_fn; + coredump_write_fn *write_fn; + coredump_extend_fn *extend_fn; +}; + struct coredump_params { off_t offset; struct ucred *active_cred; - struct ucred *file_cred; struct thread *td; - struct vnode *vp; + const struct coredump_writer *cdw; struct compressor *comp; }; diff --git a/sys/sys/imgact_elf.h b/sys/sys/imgact_elf.h index c9444e5aec41..2845a9dbc1e2 100644 --- a/sys/sys/imgact_elf.h +++ b/sys/sys/imgact_elf.h @@ -45,6 +45,7 @@ {(pos)->a_type = (id); (pos)->a_un.a_ptr = (ptr); (pos)++;} #endif +struct coredump_writer; struct image_params; struct thread; struct vnode; @@ -114,7 +115,7 @@ bool __elfN(brand_inuse)(Elf_Brandinfo *entry); int __elfN(insert_brand_entry)(Elf_Brandinfo *entry); int __elfN(remove_brand_entry)(Elf_Brandinfo *entry); int __elfN(freebsd_fixup)(uintptr_t *, struct image_params *); -int __elfN(coredump)(struct thread *, struct vnode *, off_t, int); +int __elfN(coredump)(struct thread *, struct coredump_writer *, off_t, int); size_t __elfN(populate_note)(int, void *, void *, size_t, void **); int __elfN(freebsd_copyout_auxargs)(struct image_params *, uintptr_t); void __elfN(puthdr)(struct thread *, void *, size_t, int, size_t, int); diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h index 4ddfc8516053..1714fa5a7416 100644 --- a/sys/sys/sysent.h +++ b/sys/sys/sysent.h @@ -90,6 +90,7 @@ struct sysent { /* system call table */ #define SY_THR_STATIC_KLD SY_THR_STATIC #endif +struct coredump_writer; struct image_params; struct proc; struct __sigset; @@ -108,7 +109,8 @@ struct sysentvec { int *sv_szsigcode; /* size of sigtramp code */ int sv_sigcodeoff; char *sv_name; /* name of binary type */ - int (*sv_coredump)(struct thread *, struct vnode *, off_t, int); + int (*sv_coredump)(struct thread *, struct coredump_writer *, + off_t, int); /* function to dump core, or NULL */ int sv_elf_core_osabi; const char *sv_elf_core_abi_vendor;