mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-10-17 10:09:05 +02:00
pdh: fix heap corruption from undersized counter array buffer (#2513)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
71b4ba80ed
commit
3c65af9c47
+21
-14
@@ -300,7 +300,10 @@ func (c *Collector) collectWorkerRaw() {
|
||||
bytesNeeded uint32
|
||||
)
|
||||
|
||||
buf := make([]byte, 1)
|
||||
// buf starts empty so that the first call only queries the required size with a nil buffer.
|
||||
// PdhGetRawCounterArrayW writes 8 bytes into a non-nil buffer, even if lpdwBufferSize is smaller,
|
||||
// which corrupts the neighboring heap memory of a tiny allocation.
|
||||
var buf []byte
|
||||
|
||||
for data := range c.collectCh {
|
||||
err = (func() error {
|
||||
@@ -337,12 +340,13 @@ func (c *Collector) collectWorkerRaw() {
|
||||
nameCache := map[string]string{}
|
||||
|
||||
for _, counter := range c.counters {
|
||||
instances:
|
||||
for _, instance := range counter.Instances {
|
||||
// Get the info with the current buffer size
|
||||
bytesNeeded = uint32(cap(buf))
|
||||
bytesNeeded = uint32(len(buf))
|
||||
|
||||
for {
|
||||
ret := GetRawCounterArray(instance, &bytesNeeded, &itemCount, &buf[0])
|
||||
ret := GetRawCounterArray(instance, &bytesNeeded, &itemCount, unsafe.SliceData(buf))
|
||||
|
||||
if ret == ErrorSuccess {
|
||||
break
|
||||
@@ -350,20 +354,20 @@ func (c *Collector) collectWorkerRaw() {
|
||||
|
||||
if err := NewPdhError(ret); ret != MoreData {
|
||||
if isKnownCounterDataError(err) {
|
||||
break
|
||||
continue instances
|
||||
}
|
||||
|
||||
return fmt.Errorf("GetRawCounterArray: %w", err)
|
||||
}
|
||||
|
||||
if bytesNeeded <= uint32(cap(buf)) {
|
||||
return fmt.Errorf("GetRawCounterArray reports buffer too small (%d), but buffer is large enough (%d): %w", uint32(cap(buf)), bytesNeeded, NewPdhError(ret))
|
||||
if bytesNeeded <= uint32(len(buf)) {
|
||||
return fmt.Errorf("GetRawCounterArray reports buffer too small (%d), but buffer is large enough (%d): %w", uint32(len(buf)), bytesNeeded, NewPdhError(ret))
|
||||
}
|
||||
|
||||
buf = make([]byte, bytesNeeded)
|
||||
}
|
||||
|
||||
items = unsafe.Slice((*RawCounterItem)(unsafe.Pointer(&buf[0])), itemCount)
|
||||
items = unsafe.Slice((*RawCounterItem)(unsafe.Pointer(unsafe.SliceData(buf))), itemCount)
|
||||
|
||||
for _, item := range items {
|
||||
if item.RawValue.CStatus != CstatusValidData && item.RawValue.CStatus != CstatusNewData {
|
||||
@@ -459,7 +463,9 @@ func (c *Collector) collectWorkerFormatted() {
|
||||
bytesNeeded uint32
|
||||
)
|
||||
|
||||
buf := make([]byte, 1)
|
||||
// buf starts empty so that the first call only queries the required size with a nil buffer.
|
||||
// See collectWorkerRaw.
|
||||
var buf []byte
|
||||
|
||||
for data := range c.collectCh {
|
||||
err = (func() error {
|
||||
@@ -496,12 +502,13 @@ func (c *Collector) collectWorkerFormatted() {
|
||||
nameCache := map[string]string{}
|
||||
|
||||
for _, counter := range c.counters {
|
||||
instances:
|
||||
for _, instance := range counter.Instances {
|
||||
// Get the info with the current buffer size
|
||||
bytesNeeded = uint32(cap(buf))
|
||||
bytesNeeded = uint32(len(buf))
|
||||
|
||||
for {
|
||||
ret := GetFormattedCounterArrayDouble(instance, &bytesNeeded, &itemCount, &buf[0])
|
||||
ret := GetFormattedCounterArrayDouble(instance, &bytesNeeded, &itemCount, unsafe.SliceData(buf))
|
||||
|
||||
if ret == ErrorSuccess {
|
||||
break
|
||||
@@ -509,20 +516,20 @@ func (c *Collector) collectWorkerFormatted() {
|
||||
|
||||
if err := NewPdhError(ret); ret != MoreData {
|
||||
if isKnownCounterDataError(err) {
|
||||
break
|
||||
continue instances
|
||||
}
|
||||
|
||||
return fmt.Errorf("GetFormattedCounterArrayDouble: %w", err)
|
||||
}
|
||||
|
||||
if bytesNeeded <= uint32(cap(buf)) {
|
||||
return fmt.Errorf("GetFormattedCounterArrayDouble reports buffer too small (%d), but buffer is large enough (%d): %w", uint32(cap(buf)), bytesNeeded, NewPdhError(ret))
|
||||
if bytesNeeded <= uint32(len(buf)) {
|
||||
return fmt.Errorf("GetFormattedCounterArrayDouble reports buffer too small (%d), but buffer is large enough (%d): %w", uint32(len(buf)), bytesNeeded, NewPdhError(ret))
|
||||
}
|
||||
|
||||
buf = make([]byte, bytesNeeded)
|
||||
}
|
||||
|
||||
items = unsafe.Slice((*FmtCounterValueItemDouble)(unsafe.Pointer(&buf[0])), itemCount)
|
||||
items = unsafe.Slice((*FmtCounterValueItemDouble)(unsafe.Pointer(unsafe.SliceData(buf))), itemCount)
|
||||
|
||||
for _, item := range items {
|
||||
if item.FmtValue.CStatus != CstatusValidData && item.FmtValue.CStatus != CstatusNewData {
|
||||
|
||||
Reference in New Issue
Block a user