Index: lib/libprocstat/libprocstat.c =================================================================== --- lib/libprocstat/libprocstat.c +++ lib/libprocstat/libprocstat.c @@ -767,6 +767,8 @@ eb = buf + len; while (bp < eb) { kf = (struct kinfo_file *)(uintptr_t)bp; + if (kf->kf_structsize == 0) + break; bp += kf->kf_structsize; cnt++; } @@ -782,6 +784,8 @@ /* Pass 2: unpack */ while (bp < eb) { kf = (struct kinfo_file *)(uintptr_t)bp; + if (kf->kf_structsize == 0) + break; /* Copy/expand into pre-zeroed buffer */ memcpy(kp, kf, kf->kf_structsize); /* Advance to next packed record */ Index: lib/libutil/kinfo_getfile.c =================================================================== --- lib/libutil/kinfo_getfile.c +++ lib/libutil/kinfo_getfile.c @@ -44,6 +44,8 @@ eb = buf + len; while (bp < eb) { kf = (struct kinfo_file *)(uintptr_t)bp; + if (kf->kf_structsize == 0) + break; bp += kf->kf_structsize; cnt++; } @@ -59,6 +61,8 @@ /* Pass 2: unpack */ while (bp < eb) { kf = (struct kinfo_file *)(uintptr_t)bp; + if (kf->kf_structsize == 0) + break; /* Copy/expand into pre-zeroed buffer */ memcpy(kp, kf, kf->kf_structsize); /* Advance to next packed record */ Index: sys/kern/imgact_elf.c =================================================================== --- sys/kern/imgact_elf.c +++ sys/kern/imgact_elf.c @@ -1677,7 +1677,8 @@ __elfN(putnote)(struct note_info *ninfo, struct sbuf *sb) { Elf_Note note; - ssize_t old_len; + ssize_t old_len, sect_len; + size_t new_len, descsz, i; if (ninfo->type == -1) { ninfo->outfunc(ninfo->outarg, sb, &ninfo->outsize); @@ -1696,7 +1697,36 @@ return; sbuf_start_section(sb, &old_len); ninfo->outfunc(ninfo->outarg, sb, &ninfo->outsize); - sbuf_end_section(sb, old_len, ELF_NOTE_ROUNDSIZE, 0); + sect_len = sbuf_end_section(sb, old_len, ELF_NOTE_ROUNDSIZE, 0); + if (sect_len < 0) + return; + + new_len = (size_t)sect_len; + descsz = roundup(note.n_descsz, ELF_NOTE_ROUNDSIZE); + if (new_len < descsz) { + /* + * It is expected that individual note emitters will correctly + * predict their expected output size and fill up to that size + * themselves, padding in a format-specific way if needed. + * However, in case they don't, just do it here with zeros. + */ + for (i = 0; i < descsz - new_len; i++) + sbuf_putc(sb, 0); + } else if (new_len > descsz) { + /* + * putnote can't always truncate sb. We may have drained some + * of it already. So, just warn the user they may have a corrupt + * core. + * + * This should NEVER happen. It is intended as a weak + * assertion. + */ + printf("%s: Note type %u changed as we read it (%zu > %zu). " + "Since it is longer than expected, this coredump's notes " + "are likely corrupt. THIS IS A BUG in the note_procstat " + "routine for type %u.\n", __func__, (unsigned)note.n_type, + new_len, descsz, (unsigned)note.n_type); + } } /* @@ -1879,10 +1909,12 @@ note_procstat_files(void *arg, struct sbuf *sb, size_t *sizep) { struct proc *p; - size_t size; + size_t size, sect_sz, i; + ssize_t start_len, sect_len; int structsize; p = (struct proc *)arg; + structsize = sizeof(struct kinfo_file); if (sb == NULL) { size = 0; sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN); @@ -1894,10 +1926,24 @@ sbuf_delete(sb); *sizep = size; } else { - structsize = sizeof(struct kinfo_file); + sbuf_start_section(sb, &start_len); + sbuf_bcat(sb, &structsize, sizeof(structsize)); PROC_LOCK(p); - kern_proc_filedesc_out(p, sb, -1); + kern_proc_filedesc_out(p, sb, *sizep - sizeof(structsize)); + + sect_len = sbuf_end_section(sb, start_len, 0, 0); + if (sect_len < 0) + return; + sect_sz = sect_len; + + KASSERT(sect_sz <= *sizep, + ("kern_proc_filedesc_out did not respect maxlen; " + "requested %zu, got %zu", *sizep - sizeof(structsize), + sect_sz - sizeof(structsize))); + + for (i = 0; i < *sizep - sect_sz && sb->s_error == 0; i++) + sbuf_putc(sb, 0); } } Index: sys/kern/kern_descrip.c =================================================================== --- sys/kern/kern_descrip.c +++ sys/kern/kern_descrip.c @@ -3271,13 +3271,21 @@ return (kflags); } -/* Trim unused data from kf_path by truncating the structure size. */ +static volatile int pack_kinfo_enabled = 1; +SYSCTL_INT(_kern_proc, OID_AUTO, procstat_pack_kinfo, CTLFLAG_RW, + __DEVOLATILE(int *, &pack_kinfo_enabled), 0, + "If disabled, do not pack file paths in procstat -f kinfo"); + static void -pack_kinfo(struct kinfo_file *kif) +kinfo_compute_size(struct kinfo_file *kif) { - kif->kf_structsize = offsetof(struct kinfo_file, kf_path) + - strlen(kif->kf_path) + 1; + /* Trim unused data from kf_path by truncating the structure size. */ + if (pack_kinfo_enabled) + kif->kf_structsize = offsetof(struct kinfo_file, kf_path) + + strlen(kif->kf_path) + 1; + else + kif->kf_structsize = sizeof(*kif); kif->kf_structsize = roundup(kif->kf_structsize, sizeof(uint64_t)); } @@ -3307,7 +3315,7 @@ error = fo_fill_kinfo(fp, kif, fdp); if (error == 0) kif->kf_status |= KF_ATTR_VALID; - pack_kinfo(kif); + kinfo_compute_size(kif); } static void @@ -3327,7 +3335,7 @@ kif->kf_fd = fd; kif->kf_ref_count = -1; kif->kf_offset = -1; - pack_kinfo(kif); + kinfo_compute_size(kif); vrele(vp); } Index: sys/kern/vfs_vnops.c =================================================================== --- sys/kern/vfs_vnops.c +++ sys/kern/vfs_vnops.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -2379,6 +2380,24 @@ return (error); } +static inline void +vn_fill_junk(struct kinfo_file *kif) +{ + size_t len, olen; + + /* + * Simulate vn_fullpath returning changing values for a given + * vp during e.g. coredump. + */ + len = (arc4random() % (sizeof(kif->kf_path) - 2)) + 1; + olen = strlen(kif->kf_path); + if (len < olen) + strcpy(&kif->kf_path[len - 1], "$"); + else + for (; olen < len; olen++) + strcpy(&kif->kf_path[olen], "A"); +} + int vn_fill_kinfo_vnode(struct vnode *vp, struct kinfo_file *kif) { @@ -2396,6 +2415,10 @@ if (freepath != NULL) free(freepath, M_TEMP); + KFAIL_POINT_CODE(DEBUG_FP, fill_kinfo_vnode__random_path, + vn_fill_junk(kif); + ); + /* * Retrieve vnode attributes. */