Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F111645737
D3548.id8428.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D3548.id8428.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D3548: Detect badly behaved coredump note helpers
Attached
Detach File
Event Timeline
Log In to Comment