Author: avg
Date: Thu Jan 26 09:46:34 2017
New Revision: 312794
URL: https://svnweb.freebsd.org/changeset/base/312794

Log:
  MFC r312532: don't abort writing of a core dump after EFAULT

Modified:
  stable/11/sys/kern/imgact_elf.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/kern/imgact_elf.c
==============================================================================
--- stable/11/sys/kern/imgact_elf.c     Thu Jan 26 07:07:09 2017        
(r312793)
+++ stable/11/sys/kern/imgact_elf.c     Thu Jan 26 09:46:34 2017        
(r312794)
@@ -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_writable_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);
 }
 
 /*
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to