diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -1595,7 +1595,7 @@ } 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 @@ /* 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 @@ tmpbuf = malloc(CORE_BUF_SIZE, M_TEMP, M_WAITOK | M_ZERO); } + if (cdw->init_fn != NULL) { + error = (*cdw->init_fn)(cdw, ¶ms, compm); + 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 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1998,14 +1998,48 @@ 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 @@ void *tmpbuf) { vm_map_t map; - struct mount *mp; size_t resid, runlen; int error; bool success; @@ -2068,14 +2101,7 @@ } } 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 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -2665,6 +2666,8 @@ 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 @@ 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 @@ 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 @@ 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 --- a/sys/sys/exec.h +++ b/sys/sys/exec.h @@ -37,6 +37,8 @@ #ifndef _SYS_EXEC_H_ #define _SYS_EXEC_H_ +#include + /* * 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 @@ }; /* 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 *, int); +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 --- 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 @@ 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 --- a/sys/sys/sysent.h +++ b/sys/sys/sysent.h @@ -90,6 +90,7 @@ #define SY_THR_STATIC_KLD SY_THR_STATIC #endif +struct coredump_writer; struct image_params; struct proc; struct __sigset; @@ -108,7 +109,8 @@ 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;