From 867e02f0cf5e87c6dd2f9e34b74ca36393d847ee Mon Sep 17 00:00:00 2001 From: rabbitstack Date: Sun, 19 Jul 2026 20:25:14 +0200 Subject: [PATCH] fix(symbolizer): Device driver misattribution EnumDevices() captures driver base/size at startup. If between enumeration and amd the first call stack capture, any driver shifted or reloaded, the base addresses in devs are stale. The address range check:could match the wrong driver if two drivers happen to have overlapping or adjacent ranges in your stale snapshot vs. reality. Mitigation steps: - Validate cache hits against current devs - Remove a stale driver if the new driver lives at the same base but different device path --- pkg/symbolize/driver.go | 64 +++++++++++++++++++++++++++++++++--- pkg/symbolize/driver_test.go | 22 +++++++++++++ 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/pkg/symbolize/driver.go b/pkg/symbolize/driver.go index 5a041b3bf..4eb563301 100644 --- a/pkg/symbolize/driver.go +++ b/pkg/symbolize/driver.go @@ -47,9 +47,31 @@ func (d *driverStore) resolve(addr va.Address) *sys.Driver { // driver already cached? d.mux.RLock() dev, isCached := d.drivers[addr] + var ( + base va.Address + size uint64 + ) + if isCached { + base = va.Address(dev.Base) + size = uint64(dev.Size) + } d.mux.RUnlock() + if isCached { - return dev + if addr >= base && addr < base.Inc(size) { + // entry is still valid + return dev + } + // evict the stale cache entry so that subsequent calls for + // the same address do not keep hitting the validation path + d.mux.Lock() + // recheck under write lock in case if another goroutine may + // have already evicted or refreshed the entry while we were + // upgrading the lock + if current, still := d.drivers[addr]; still && current == dev { + delete(d.drivers, addr) + } + d.mux.Unlock() } d.mux.Lock() @@ -67,15 +89,12 @@ func (d *driverStore) resolve(addr va.Address) *sys.Driver { } func (d *driverStore) addDriver(base va.Address, size uint64, path string) { - d.mux.Lock() - defer d.mux.Unlock() - dev := sys.Driver{ Path: path, Base: base.Uintptr(), Size: uint32(size), } - d.devs = append(d.devs, dev) + d.addDev(dev) } func (d *driverStore) removeDriver(base va.Address, size uint64) { @@ -95,3 +114,38 @@ func (d *driverStore) removeDriver(base va.Address, size uint64) { } } } + +func (d *driverStore) addDev(drv sys.Driver) { + d.mux.Lock() + defer d.mux.Unlock() + + var ( + exists = false + base = va.Address(drv.Base) + size = uint64(drv.Size) + ) + + for i, dev := range d.devs { + switch { + case dev.Base == drv.Base && dev.Path != drv.Path: + // different driver has reloaded at the same base address. + // Evict all cached addresses that still point at the old + // driver so that resolve() cannot return a stale pointer + // for the new occupant. + for addr := range d.drivers { + if addr >= base && addr < base.Inc(size) { + delete(d.drivers, addr) + } + } + d.devs = append(d.devs[:i], d.devs[i+1:]...) + case dev.Base == drv.Base && dev.Path == drv.Path: + // driver exists at identical base address and + // device path. Nothing to do + exists = true + } + } + + if !exists { + d.devs = append(d.devs, drv) + } +} diff --git a/pkg/symbolize/driver_test.go b/pkg/symbolize/driver_test.go index a2b6389ff..c93f36d3f 100644 --- a/pkg/symbolize/driver_test.go +++ b/pkg/symbolize/driver_test.go @@ -256,3 +256,25 @@ func TestAddRemoveRoundTrip(t *testing.T) { t.Error("driver must be gone after round-trip removal") } } + +func TestAddNewDriverSameBase(t *testing.T) { + ds := makeStore(realDrivers()) + + const base va.Address = 0xFFFFF80010000000 + const size uint64 = 0x50000 + + ds.addDriver(base, size, `\Driver\fileinfo.sys`) + if len(ds.devs) != 3 { + t.Error("must be 3 drivers in the store") + } + + ds.addDriver(base, size, `\Driver\FLTMGR.SYS.sys`) + if len(ds.devs) != 3 { + t.Error("must be 3 drivers in the store") + } + + drv := ds.resolve(base) + if drv.Path != `\Driver\FLTMGR.SYS.sys` { + t.Error("unexpected driver resolved") + } +}