summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/exec_elf.c5
-rw-r--r--sys/kern/kern_sig.c63
-rw-r--r--sys/sys/core.h3
-rw-r--r--sys/uvm/uvm_unix.c35
4 files changed, 76 insertions, 30 deletions
diff --git a/sys/kern/exec_elf.c b/sys/kern/exec_elf.c
index 1550478c8a7..0322e7c2b47 100644
--- a/sys/kern/exec_elf.c
+++ b/sys/kern/exec_elf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec_elf.c,v 1.89 2012/09/17 17:11:49 matthew Exp $ */
+/* $OpenBSD: exec_elf.c,v 1.90 2013/01/15 01:34:27 deraadt Exp $ */
/*
* Copyright (c) 1996 Per Fogelstrom
@@ -1072,6 +1072,9 @@ ELFNAMEEND(coredump)(struct proc *p, void *cookie)
if (error)
goto out;
+ coredump_unmap(cookie, (vaddr_t)psections[i].p_vaddr,
+ (vaddr_t)psections[i].p_vaddr + psections[i].p_filesz);
+
#ifdef DIAGNOSTIC
offset += psections[i].p_filesz;
#endif
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 4cf0c268468..0820b9c0501 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sig.c,v 1.145 2012/12/02 07:03:32 guenther Exp $ */
+/* $OpenBSD: kern_sig.c,v 1.146 2013/01/15 01:34:27 deraadt Exp $ */
/* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */
/*
@@ -1410,7 +1410,7 @@ coredump(struct proc *p)
struct nameidata nd;
struct vattr vattr;
struct coredump_iostate io;
- int error, error1, len;
+ int error, len;
char name[sizeof("/var/crash/") + MAXCOMLEN + sizeof(".core")];
char *dir = "";
@@ -1474,14 +1474,18 @@ coredump(struct proc *p)
io.io_vp = vp;
io.io_cred = cred;
io.io_offset = 0;
+ VOP_UNLOCK(vp, 0, p);
+ vref(vp);
+ error = vn_close(vp, FWRITE, cred, p);
+ if (error) {
+ vrele(vp);
+ return (error);
+ }
error = (*p->p_emul->e_coredump)(p, &io);
out:
- VOP_UNLOCK(vp, 0, p);
- error1 = vn_close(vp, FWRITE, cred, p);
crfree(cred);
- if (error == 0)
- error = error1;
+ vrele(vp);
return (error);
#endif
}
@@ -1520,7 +1524,7 @@ coredump_trad(struct proc *p, void *cookie)
return (error);
error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&core,
(int)core.c_hdrsize, (off_t)0,
- UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, NULL, p);
+ UIO_SYSSPACE, IO_UNIT, cred, NULL, p);
return (error);
#endif
}
@@ -1530,22 +1534,45 @@ int
coredump_write(void *cookie, enum uio_seg segflg, const void *data, size_t len)
{
struct coredump_iostate *io = cookie;
- int error;
+ off_t coffset = 0;
+ size_t csize;
+ int chunk, error;
+
+ csize = len;
+ do {
+ /* Rest of the loop sleeps with lock held, so... */
+ yield();
+
+ chunk = MIN(csize, MAXPHYS);
+ error = vn_rdwr(UIO_WRITE, io->io_vp,
+ (caddr_t)data + coffset, chunk,
+ io->io_offset + coffset, segflg,
+ IO_UNIT, io->io_cred, NULL, io->io_proc);
+ if (error) {
+ printf("pid %d (%s): %s write of %lu@%p"
+ " at %lld failed: %d\n",
+ io->io_proc->p_pid, io->io_proc->p_comm,
+ segflg == UIO_USERSPACE ? "user" : "system",
+ len, data, (long long) io->io_offset, error);
+ return (error);
+ }
- error = vn_rdwr(UIO_WRITE, io->io_vp, (void *)data, len,
- io->io_offset, segflg,
- IO_NODELOCKED|IO_UNIT, io->io_cred, NULL, io->io_proc);
- if (error) {
- printf("pid %d (%s): %s write of %lu@%p at %lld failed: %d\n",
- io->io_proc->p_pid, io->io_proc->p_comm,
- segflg == UIO_USERSPACE ? "user" : "system",
- len, data, (long long) io->io_offset, error);
- return (error);
- }
+ coffset += chunk;
+ csize -= chunk;
+ } while (csize > 0);
io->io_offset += len;
return (0);
}
+
+void
+coredump_unmap(void *cookie, vaddr_t start, vaddr_t end)
+{
+ struct coredump_iostate *io = cookie;
+
+ uvm_unmap(&io->io_proc->p_vmspace->vm_map, start, end);
+}
+
#endif /* !SMALL_KERNEL */
/*
diff --git a/sys/sys/core.h b/sys/sys/core.h
index 941b63b32b0..464fa5843df 100644
--- a/sys/sys/core.h
+++ b/sys/sys/core.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: core.h,v 1.4 2009/03/05 19:52:24 kettenis Exp $ */
+/* $OpenBSD: core.h,v 1.5 2013/01/15 01:34:27 deraadt Exp $ */
/* $NetBSD: core.h,v 1.4 1994/10/29 08:20:14 cgd Exp $ */
/*
@@ -91,4 +91,5 @@ struct coreseg {
int coredump_trad(struct proc *, void *);
int coredump_write(void *, enum uio_seg, const void *, size_t);
+void coredump_unmap(void *, vaddr_t, vaddr_t);
#endif
diff --git a/sys/uvm/uvm_unix.c b/sys/uvm/uvm_unix.c
index f4d4490b853..a94bf92cbf0 100644
--- a/sys/uvm/uvm_unix.c
+++ b/sys/uvm/uvm_unix.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_unix.c,v 1.43 2012/03/09 13:01:29 ariane Exp $ */
+/* $OpenBSD: uvm_unix.c,v 1.44 2013/01/15 01:34:27 deraadt Exp $ */
/* $NetBSD: uvm_unix.c,v 1.18 2000/09/13 15:00:25 thorpej Exp $ */
/*
@@ -162,8 +162,8 @@ uvm_coredump(struct proc *p, struct vnode *vp, struct ucred *cred,
vm_map_entry_t entry;
vaddr_t start, end, top;
struct coreseg cseg;
- off_t offset;
- int flag, error = 0;
+ off_t offset, coffset;
+ int csize, chunk, flag, error = 0;
offset = chdr->c_hdrsize + chdr->c_seghdrsize + chdr->c_cpusize;
@@ -233,14 +233,29 @@ uvm_coredump(struct proc *p, struct vnode *vp, struct ucred *cred,
break;
offset += chdr->c_seghdrsize;
- error = vn_rdwr(UIO_WRITE, vp,
- (caddr_t)(u_long)cseg.c_addr, (int)cseg.c_size,
- offset, UIO_USERSPACE,
- IO_NODELOCKED|IO_UNIT, cred, NULL, p);
- if (error)
- break;
-
+
+ coffset = 0;
+ csize = (int)cseg.c_size;
+ do {
+ /* Rest of the loop sleeps with lock held, so... */
+ yield();
+
+ chunk = MIN(csize, MAXPHYS);
+ error = vn_rdwr(UIO_WRITE, vp,
+ (caddr_t)(u_long)cseg.c_addr + coffset,
+ chunk, offset + coffset, UIO_USERSPACE,
+ IO_UNIT, cred, NULL, p);
+ if (error)
+ return (error);
+
+ coffset += chunk;
+ csize -= chunk;
+ } while (csize > 0);
offset += cseg.c_size;
+
+ /* Discard the memory */
+ uvm_unmap(map, cseg.c_addr, cseg.c_addr + cseg.c_size);
+
chdr->c_nseg++;
}