diff options
author | cem <cem@FreeBSD.org> | 2015-10-06 18:07:00 +0000 |
---|---|---|
committer | cem <cem@FreeBSD.org> | 2015-10-06 18:07:00 +0000 |
commit | 9c1e214f79cb8f8fb38ba2f8fa010f282ec5be79 (patch) | |
tree | 9844297e32023403c9df2beefdd3462b21290b04 /lib | |
parent | a6f4f28b545e1f0632ba4b20b86a7ab487932373 (diff) | |
download | FreeBSD-src-9c1e214f79cb8f8fb38ba2f8fa010f282ec5be79.zip FreeBSD-src-9c1e214f79cb8f8fb38ba2f8fa010f282ec5be79.tar.gz |
Fix core corruption caused by race in note_procstat_vmmap
This fix is spiritually similar to r287442 and was discovered thanks to
the KASSERT added in that revision.
NT_PROCSTAT_VMMAP output length, when packing kinfo structs, is tied to
the length of filenames corresponding to vnodes in the process' vm map
via vn_fullpath. As vnodes may move during coredump, this is racy.
We do not remove the race, only prevent it from causing coredump
corruption.
- Add a sysctl, kern.coredump_pack_vmmapinfo, to allow users to disable
kinfo packing for PROCSTAT_VMMAP notes. This avoids VMMAP corruption
and truncation, even if names change, at the cost of up to PATH_MAX
bytes per mapped object. The new sysctl is documented in core.5.
- Fix note_procstat_vmmap to self-limit in the second pass. This
addresses corruption, at the cost of sometimes producing a truncated
result.
- Fix PROCSTAT_VMMAP consumers libutil (and libprocstat, via copy-paste)
to grok the new zero padding.
Reported by: pho (https://people.freebsd.org/~pho/stress/log/datamove4-2.txt)
Relnotes: yes
Sponsored by: EMC / Isilon Storage Division
Differential Revision: https://reviews.freebsd.org/D3824
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libprocstat/libprocstat.c | 4 | ||||
-rw-r--r-- | lib/libutil/kinfo_getvmmap.c | 4 |
2 files changed, 8 insertions, 0 deletions
diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 932b5a0..3de64aa 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -1867,6 +1867,8 @@ kinfo_getvmmap_core(struct procstat_core *core, int *cntp) eb = buf + len; while (bp < eb) { kv = (struct kinfo_vmentry *)(uintptr_t)bp; + if (kv->kve_structsize == 0) + break; bp += kv->kve_structsize; cnt++; } @@ -1882,6 +1884,8 @@ kinfo_getvmmap_core(struct procstat_core *core, int *cntp) /* Pass 2: unpack */ while (bp < eb) { kv = (struct kinfo_vmentry *)(uintptr_t)bp; + if (kv->kve_structsize == 0) + break; /* Copy/expand into pre-zeroed buffer */ memcpy(kp, kv, kv->kve_structsize); /* Advance to next packed record */ diff --git a/lib/libutil/kinfo_getvmmap.c b/lib/libutil/kinfo_getvmmap.c index 129aa03..9d9e427 100644 --- a/lib/libutil/kinfo_getvmmap.c +++ b/lib/libutil/kinfo_getvmmap.c @@ -44,6 +44,8 @@ kinfo_getvmmap(pid_t pid, int *cntp) eb = buf + len; while (bp < eb) { kv = (struct kinfo_vmentry *)(uintptr_t)bp; + if (kv->kve_structsize == 0) + break; bp += kv->kve_structsize; cnt++; } @@ -59,6 +61,8 @@ kinfo_getvmmap(pid_t pid, int *cntp) /* Pass 2: unpack */ while (bp < eb) { kv = (struct kinfo_vmentry *)(uintptr_t)bp; + if (kv->kve_structsize == 0) + break; /* Copy/expand into pre-zeroed buffer */ memcpy(kp, kv, kv->kve_structsize); /* Advance to next packed record */ |