DF-5833 / fix.diff
--- 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 { |