From owner-svn-src-all@freebsd.org Fri Jan 20 13:39:09 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 41568CB83B7; Fri, 20 Jan 2017 13:39:09 +0000 (UTC) (envelope-from avg@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 0948715F7; Fri, 20 Jan 2017 13:39:08 +0000 (UTC) (envelope-from avg@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v0KDd8wb048767; Fri, 20 Jan 2017 13:39:08 GMT (envelope-from avg@FreeBSD.org) Received: (from avg@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v0KDd87p048766; Fri, 20 Jan 2017 13:39:08 GMT (envelope-from avg@FreeBSD.org) Message-Id: <201701201339.v0KDd87p048766@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: avg set sender to avg@FreeBSD.org using -f From: Andriy Gapon Date: Fri, 20 Jan 2017 13:39:08 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r312532 - head/sys/kern X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 20 Jan 2017 13:39:09 -0000 Author: avg Date: Fri Jan 20 13:39:07 2017 New Revision: 312532 URL: https://svnweb.freebsd.org/changeset/base/312532 Log: don't abort writing of a core dump after EFAULT It's possible to get EFAULT when writing a segment backed by a file if the segment extends beyond the file. The core dump could still be useful if we skip the rest of the segment and proceed to other segements. The skipped segment (or a portion of it) will be zero-filled. While there, use 'const' to signify that core_write() only reads the buffer and use __DECONST before calling vn_rdwr_inchunks() because it can be used for both reading and writing. Before the change: kernel: Failed to write core file for process mmap_trunc_core (error 14) kernel: pid 77718 (mmap_trunc_core), uid 1001: exited on signal 6 After the change: kernel: Failed to fully fault in a core file segment at VA 0x800645000 with size 0x4000 to be written at offset 0x29000 for process mmap_trunc_core kernel: pid 4901 (mmap_trunc_core), uid 1001: exited on signal 6 (core dumped) Reviewed by: julian, kib Obtained from: Panzura (older version of the change) MFC after: 5 days Sponsored by: Panzura Differential Revision: https://reviews.freebsd.org/D9233 Modified: head/sys/kern/imgact_elf.c Modified: head/sys/kern/imgact_elf.c ============================================================================== --- head/sys/kern/imgact_elf.c Fri Jan 20 13:21:27 2017 (r312531) +++ head/sys/kern/imgact_elf.c Fri Jan 20 13:39:07 2017 (r312532) @@ -1160,7 +1160,7 @@ struct coredump_params { static void cb_put_phdr(vm_map_entry_t, void *); static void cb_size_segment(vm_map_entry_t, void *); -static int core_write(struct coredump_params *, void *, size_t, off_t, +static int core_write(struct coredump_params *, const void *, size_t, off_t, enum uio_seg); static void each_dumpable_segment(struct thread *, segment_callback, void *); static int __elfN(corehdr)(struct coredump_params *, int, void *, size_t, @@ -1202,7 +1202,14 @@ compress_chunk(struct coredump_params *p while (len > 0) { chunk_len = MIN(len, CORE_BUF_SIZE); - copyin(base, buf, chunk_len); + + /* + * We can get EFAULT error here. + * In that case zero out the current chunk of the segment. + */ + error = copyin(base, buf, chunk_len); + if (error != 0) + bzero(buf, chunk_len); error = gzio_write(p->gzs, buf, chunk_len); if (error != 0) break; @@ -1222,12 +1229,12 @@ core_gz_write(void *base, size_t len, of #endif /* GZIO */ static int -core_write(struct coredump_params *p, void *base, size_t len, off_t offset, - enum uio_seg seg) +core_write(struct coredump_params *p, const void *base, size_t len, + off_t offset, enum uio_seg seg) { - return (vn_rdwr_inchunks(UIO_WRITE, p->vp, base, len, offset, - seg, IO_UNIT | IO_DIRECT | IO_RANGELOCKED, + return (vn_rdwr_inchunks(UIO_WRITE, p->vp, __DECONST(void *, base), + len, offset, seg, IO_UNIT | IO_DIRECT | IO_RANGELOCKED, p->active_cred, p->file_cred, NULL, p->td)); } @@ -1235,12 +1242,32 @@ static int core_output(void *base, size_t len, off_t offset, struct coredump_params *p, void *tmpbuf) { + int error; #ifdef GZIO if (p->gzs != NULL) return (compress_chunk(p, base, tmpbuf, len)); #endif - return (core_write(p, base, len, offset, UIO_USERSPACE)); + /* + * EFAULT is a non-fatal error that we can get, for example, + * if the segment is backed by a file but extends beyond its + * end. + */ + error = core_write(p, base, len, offset, UIO_USERSPACE); + if (error == EFAULT) { + log(LOG_WARNING, "Failed to fully fault in a core file segment " + "at VA %p with size 0x%zx to be written at offset 0x%jx " + "for process %s\n", base, len, offset, curproc->p_comm); + + /* + * Write a "real" zero byte at the end of the target region + * in the case this is the last segment. + * The intermediate space will be implicitly zero-filled. + */ + error = core_write(p, zero_region, 1, offset + len - 1, + UIO_SYSSPACE); + } + return (error); } /*