Page MenuHomeFreeBSD

D3548.id8428.diff
No OneTemporary

D3548.id8428.diff

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);
+ }
}
/*
@@ -1875,29 +1905,56 @@
CTASSERT(sizeof(struct kinfo_file) == KINFO_FILE_SIZE);
#endif
+static volatile int pack_fileinfo_enabled = 1;
+SYSCTL_INT(_kern, OID_AUTO, coredump_pack_fileinfo, CTLFLAG_RW,
+ __DEVOLATILE(int *, &pack_fileinfo_enabled), 0,
+ "Enable file path packing in 'procstat -f' coredump notes");
+
static void
note_procstat_files(void *arg, struct sbuf *sb, size_t *sizep)
{
struct proc *p;
- size_t size;
- int structsize;
+ size_t size, sect_sz, i;
+ ssize_t start_len, sect_len;
+ int structsize, filedesc_flags;
+
+ if (pack_fileinfo_enabled)
+ filedesc_flags = FILEDESC_OUT_PACK_KINFO;
+ else
+ filedesc_flags = 0;
p = (struct proc *)arg;
+ structsize = sizeof(struct kinfo_file);
if (sb == NULL) {
size = 0;
sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN);
sbuf_set_drain(sb, sbuf_drain_count, &size);
sbuf_bcat(sb, &structsize, sizeof(structsize));
PROC_LOCK(p);
- kern_proc_filedesc_out(p, sb, -1);
+ kern_proc_filedesc_out(p, sb, -1, filedesc_flags);
sbuf_finish(sb);
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),
+ filedesc_flags);
+
+ 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
@@ -3283,7 +3283,7 @@
static void
export_file_to_kinfo(struct file *fp, int fd, cap_rights_t *rightsp,
- struct kinfo_file *kif, struct filedesc *fdp)
+ struct kinfo_file *kif, struct filedesc *fdp, int flags)
{
int error;
@@ -3307,12 +3307,15 @@
error = fo_fill_kinfo(fp, kif, fdp);
if (error == 0)
kif->kf_status |= KF_ATTR_VALID;
- pack_kinfo(kif);
+ if ((flags & FILEDESC_OUT_PACK_KINFO) != 0)
+ pack_kinfo(kif);
+ else
+ kif->kf_structsize = roundup2(sizeof(*kif), sizeof(uint64_t));
}
static void
export_vnode_to_kinfo(struct vnode *vp, int fd, int fflags,
- struct kinfo_file *kif)
+ struct kinfo_file *kif, int flags)
{
int error;
@@ -3327,7 +3330,10 @@
kif->kf_fd = fd;
kif->kf_ref_count = -1;
kif->kf_offset = -1;
- pack_kinfo(kif);
+ if ((flags & FILEDESC_OUT_PACK_KINFO) != 0)
+ pack_kinfo(kif);
+ else
+ kif->kf_structsize = roundup2(sizeof(*kif), sizeof(uint64_t));
vrele(vp);
}
@@ -3336,6 +3342,7 @@
struct sbuf *sb;
ssize_t remainder;
struct kinfo_file kif;
+ int flags;
};
static int
@@ -3363,7 +3370,8 @@
if (efbuf->remainder == 0)
return (0);
- export_file_to_kinfo(fp, fd, rightsp, &efbuf->kif, efbuf->fdp);
+ export_file_to_kinfo(fp, fd, rightsp, &efbuf->kif, efbuf->fdp,
+ efbuf->flags);
FILEDESC_SUNLOCK(efbuf->fdp);
error = export_kinfo_to_sb(efbuf);
FILEDESC_SLOCK(efbuf->fdp);
@@ -3380,7 +3388,7 @@
return (0);
if (efbuf->fdp != NULL)
FILEDESC_SUNLOCK(efbuf->fdp);
- export_vnode_to_kinfo(vp, fd, fflags, &efbuf->kif);
+ export_vnode_to_kinfo(vp, fd, fflags, &efbuf->kif, efbuf->flags);
error = export_kinfo_to_sb(efbuf);
if (efbuf->fdp != NULL)
FILEDESC_SLOCK(efbuf->fdp);
@@ -3393,7 +3401,8 @@
* Takes a locked proc as argument, and returns with the proc unlocked.
*/
int
-kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen)
+kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen,
+ int flags)
{
struct file *fp;
struct filedesc *fdp;
@@ -3425,6 +3434,7 @@
efbuf->fdp = NULL;
efbuf->sb = sb;
efbuf->remainder = maxlen;
+ efbuf->flags = flags;
if (tracevp != NULL)
export_vnode_to_sb(tracevp, KF_FD_TYPE_TRACE, FREAD | FWRITE,
efbuf);
@@ -3501,7 +3511,7 @@
return (error);
}
maxlen = req->oldptr != NULL ? req->oldlen : -1;
- error = kern_proc_filedesc_out(p, &sb, maxlen);
+ error = kern_proc_filedesc_out(p, &sb, maxlen, FILEDESC_OUT_PACK_KINFO);
error2 = sbuf_finish(&sb);
sbuf_delete(&sb);
return (error != 0 ? error : error2);
@@ -3541,7 +3551,7 @@
vref(vp);
FILEDESC_SUNLOCK(fdp);
- export_vnode_to_kinfo(vp, type, 0, kif);
+ export_vnode_to_kinfo(vp, type, 0, kif, FILEDESC_OUT_PACK_KINFO);
kinfo_to_okinfo(kif, okif);
error = SYSCTL_OUT(req, okif, sizeof(*okif));
FILEDESC_SLOCK(fdp);
@@ -3584,7 +3594,7 @@
for (i = 0; fdp->fd_refcnt > 0 && i <= fdp->fd_lastfile; i++) {
if ((fp = fdp->fd_ofiles[i].fde_file) == NULL)
continue;
- export_file_to_kinfo(fp, i, NULL, kif, fdp);
+ export_file_to_kinfo(fp, i, NULL, kif, fdp, FILEDESC_OUT_PACK_KINFO);
FILEDESC_SUNLOCK(fdp);
kinfo_to_okinfo(kif, okif);
error = SYSCTL_OUT(req, okif, sizeof(*okif));
Index: sys/kern/vfs_vnops.c
===================================================================
--- sys/kern/vfs_vnops.c
+++ sys/kern/vfs_vnops.c
@@ -46,6 +46,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/disk.h>
+#include <sys/fail.h>
#include <sys/fcntl.h>
#include <sys/file.h>
#include <sys/kdb.h>
@@ -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.
*/
Index: sys/sys/user.h
===================================================================
--- sys/sys/user.h
+++ sys/sys/user.h
@@ -550,7 +550,9 @@
* to be locked on enter. On return the process is unlocked.
*/
-int kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen);
+#define FILEDESC_OUT_PACK_KINFO 0x00000001U
+int kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen,
+ int flags);
int kern_proc_cwd_out(struct proc *p, struct sbuf *sb, ssize_t maxlen);
int kern_proc_out(struct proc *p, struct sbuf *sb, int flags);
int kern_proc_vmmap_out(struct proc *p, struct sbuf *sb);

File Metadata

Mime Type
text/plain
Expires
Fri, Mar 7, 11:15 AM (19 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17030913
Default Alt Text
D3548.id8428.diff (9 KB)

Event Timeline