⬢ DragonFlyBSD Kernel Audit
DF-5833 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -1318,8 +1318,12 @@ __elfN(puthdr)(struct lwp *lp, elf_buf_t target, int sig, enum putmode,
 	noteoff = target->off;
 	if (error == 0)
-		elf_putallnotes(lp, target, sig, mode);
+		error = elf_putallnotes(lp, target, sig, mode);
 	notesz = target->off - noteoff;
+
+	/*
+	 * If the note walk overflowed the DRYRUN-sized reservation the
+	 * LWP set changed mid-dump; the header buffer can no longer be
+	 * filled consistently.  Fail the dump instead of continuing with
+	 * target->off > target->off_max (elf_puttextvp computes vnh_max
+	 * from (off_max - off) and a negative value size_t-underflows to
+	 * an unbounded bound for cb_put_fp's writes).
+	 */
+	if (error)
+		return (error);
@@ -1389,7 +1393,7 @@ __elfN(puthdr)(struct lwp *lp, elf_buf_t target, int sig, enum putmode,
 		phc.phdr = phdr;
 		phc.phdr_max = phdr + numsegs;
 		phc.offset = target->off;
-		each_segment(p, cb_put_phdr, &phc, 1);
+		error = each_segment(p, cb_put_phdr, &phc, 1);
 	}
 	return (error);
 }
@@ -1648,13 +1652,17 @@ elf_puttextvp(struct proc *p, elf_buf_t target)
 	fpc.count = 0;
 	vn_count = target_reserve(target, sizeof(int), &error);
-	if (target->buf != NULL) {
+	/*
+	 * Belt and braces: never compute vnh_max when the reservation
+	 * is already exhausted -- (off_max - off) would size_t-underflow
+	 * and cb_put_fp would write vn_hdr records past the buffer.
+	 */
+	if (target->buf != NULL && target->off <= target->off_max) {
 		fpc.vnh = (struct vn_hdr *)(target->buf + target->off);
 		fpc.vnh_max = fpc.vnh +
 			(target->off_max - target->off) / sizeof(struct vn_hdr);
-		error = each_segment(p, cb_put_fp, &fpc, 0);
+		if (error == 0)
+			error = each_segment(p, cb_put_fp, &fpc, 0);
 		if (vn_count)
 			*vn_count = fpc.count;
 	} else {