collector/zfs: Prevent `procfs` integer underflow (#2961)
* collector/zfs: Prevent `procfs` integer underflow Prevent integer underflow when parsing the `procfs` file as it used a `ParseUint` to parse signed values. Fixes: #2766 --------- Signed-off-by: Pranshu Srivastava <rexagod@gmail.com>
This commit is contained in:
parent
fdaa8fc00d
commit
ff20a6ac48
|
@ -3776,6 +3776,9 @@ node_zfs_arc_l2_writes_lock_retry 0
|
|||
# HELP node_zfs_arc_l2_writes_sent kstat.zfs.misc.arcstats.l2_writes_sent
|
||||
# TYPE node_zfs_arc_l2_writes_sent untyped
|
||||
node_zfs_arc_l2_writes_sent 0
|
||||
# HELP node_zfs_arc_memory_available_bytes kstat.zfs.misc.arcstats.memory_available_bytes
|
||||
# TYPE node_zfs_arc_memory_available_bytes untyped
|
||||
node_zfs_arc_memory_available_bytes -9.223372036854776e+17
|
||||
# HELP node_zfs_arc_memory_direct_count kstat.zfs.misc.arcstats.memory_direct_count
|
||||
# TYPE node_zfs_arc_memory_direct_count untyped
|
||||
node_zfs_arc_memory_direct_count 542
|
||||
|
|
|
@ -3798,6 +3798,9 @@ node_zfs_arc_l2_writes_lock_retry 0
|
|||
# HELP node_zfs_arc_l2_writes_sent kstat.zfs.misc.arcstats.l2_writes_sent
|
||||
# TYPE node_zfs_arc_l2_writes_sent untyped
|
||||
node_zfs_arc_l2_writes_sent 0
|
||||
# HELP node_zfs_arc_memory_available_bytes kstat.zfs.misc.arcstats.memory_available_bytes
|
||||
# TYPE node_zfs_arc_memory_available_bytes untyped
|
||||
node_zfs_arc_memory_available_bytes -9.223372036854776e+17
|
||||
# HELP node_zfs_arc_memory_direct_count kstat.zfs.misc.arcstats.memory_direct_count
|
||||
# TYPE node_zfs_arc_memory_direct_count untyped
|
||||
node_zfs_arc_memory_direct_count 542
|
||||
|
|
|
@ -1,93 +1,94 @@
|
|||
6 1 0x01 91 4368 5266997922 97951858082072
|
||||
name type data
|
||||
hits 4 8772612
|
||||
misses 4 604635
|
||||
anon_evictable_data 4 0
|
||||
anon_evictable_metadata 4 0
|
||||
anon_size 4 1917440
|
||||
arc_loaned_bytes 4 0
|
||||
arc_meta_limit 4 6275982336
|
||||
arc_meta_max 4 449286096
|
||||
arc_meta_min 4 16777216
|
||||
arc_meta_used 4 308103632
|
||||
arc_need_free 4 0
|
||||
arc_no_grow 4 0
|
||||
arc_prune 4 0
|
||||
arc_sys_free 4 261496832
|
||||
arc_tempreserve 4 0
|
||||
c 4 1643208777
|
||||
c_max 4 8367976448
|
||||
c_min 4 33554432
|
||||
data_size 4 1295836160
|
||||
deleted 4 60403
|
||||
demand_data_hits 4 7221032
|
||||
demand_data_misses 4 73300
|
||||
demand_metadata_hits 4 1464353
|
||||
demand_metadata_misses 4 498170
|
||||
prefetch_data_hits 4 3615
|
||||
prefetch_data_misses 4 17094
|
||||
prefetch_metadata_hits 4 83612
|
||||
prefetch_metadata_misses 4 16071
|
||||
mru_hits 4 855535
|
||||
mru_ghost_hits 4 21100
|
||||
mfu_hits 4 7829854
|
||||
mfu_ghost_hits 4 821
|
||||
deleted 4 60403
|
||||
mutex_miss 4 2
|
||||
evict_skip 4 2265729
|
||||
evict_not_enough 4 680
|
||||
duplicate_buffers 4 0
|
||||
duplicate_buffers_size 4 0
|
||||
duplicate_reads 4 0
|
||||
evict_l2_cached 4 0
|
||||
evict_l2_eligible 4 8992514560
|
||||
evict_l2_ineligible 4 992552448
|
||||
evict_l2_skip 4 0
|
||||
evict_not_enough 4 680
|
||||
evict_skip 4 2265729
|
||||
hash_chain_max 4 3
|
||||
hash_chains 4 412
|
||||
hash_collisions 4 50564
|
||||
hash_elements 4 42359
|
||||
hash_elements_max 4 88245
|
||||
hash_collisions 4 50564
|
||||
hash_chains 4 412
|
||||
hash_chain_max 4 3
|
||||
p 4 516395305
|
||||
c 4 1643208777
|
||||
c_min 4 33554432
|
||||
c_max 4 8367976448
|
||||
size 4 1603939792
|
||||
hdr_size 4 16361080
|
||||
data_size 4 1295836160
|
||||
metadata_size 4 175298560
|
||||
other_size 4 116443992
|
||||
anon_size 4 1917440
|
||||
anon_evictable_data 4 0
|
||||
anon_evictable_metadata 4 0
|
||||
mru_size 4 402593792
|
||||
mru_evictable_data 4 278091264
|
||||
mru_evictable_metadata 4 18606592
|
||||
mru_ghost_size 4 999728128
|
||||
mru_ghost_evictable_data 4 883765248
|
||||
mru_ghost_evictable_metadata 4 115962880
|
||||
mfu_size 4 1066623488
|
||||
mfu_evictable_data 4 1017613824
|
||||
mfu_evictable_metadata 4 9163776
|
||||
mfu_ghost_size 4 104936448
|
||||
mfu_ghost_evictable_data 4 96731136
|
||||
mfu_ghost_evictable_metadata 4 8205312
|
||||
l2_hits 4 0
|
||||
l2_misses 4 0
|
||||
hits 4 8772612
|
||||
l2_abort_lowmem 4 0
|
||||
l2_asize 4 0
|
||||
l2_cdata_free_on_write 4 0
|
||||
l2_cksum_bad 4 0
|
||||
l2_compress_failures 4 0
|
||||
l2_compress_successes 4 0
|
||||
l2_compress_zeros 4 0
|
||||
l2_evict_l1cached 4 0
|
||||
l2_evict_lock_retry 4 0
|
||||
l2_evict_reading 4 0
|
||||
l2_feeds 4 0
|
||||
l2_rw_clash 4 0
|
||||
l2_free_on_write 4 0
|
||||
l2_hdr_size 4 0
|
||||
l2_hits 4 0
|
||||
l2_io_error 4 0
|
||||
l2_misses 4 0
|
||||
l2_read_bytes 4 0
|
||||
l2_rw_clash 4 0
|
||||
l2_size 4 0
|
||||
l2_write_bytes 4 0
|
||||
l2_writes_sent 4 0
|
||||
l2_writes_done 4 0
|
||||
l2_writes_error 4 0
|
||||
l2_writes_lock_retry 4 0
|
||||
l2_evict_lock_retry 4 0
|
||||
l2_evict_reading 4 0
|
||||
l2_evict_l1cached 4 0
|
||||
l2_free_on_write 4 0
|
||||
l2_cdata_free_on_write 4 0
|
||||
l2_abort_lowmem 4 0
|
||||
l2_cksum_bad 4 0
|
||||
l2_io_error 4 0
|
||||
l2_size 4 0
|
||||
l2_asize 4 0
|
||||
l2_hdr_size 4 0
|
||||
l2_compress_successes 4 0
|
||||
l2_compress_zeros 4 0
|
||||
l2_compress_failures 4 0
|
||||
memory_throttle_count 4 0
|
||||
duplicate_buffers 4 0
|
||||
duplicate_buffers_size 4 0
|
||||
duplicate_reads 4 0
|
||||
l2_writes_sent 4 0
|
||||
memory_available_bytes 3 -922337203685477580
|
||||
memory_direct_count 4 542
|
||||
memory_indirect_count 4 3006
|
||||
arc_no_grow 4 0
|
||||
arc_tempreserve 4 0
|
||||
arc_loaned_bytes 4 0
|
||||
arc_prune 4 0
|
||||
arc_meta_used 4 308103632
|
||||
arc_meta_limit 4 6275982336
|
||||
arc_meta_max 4 449286096
|
||||
arc_meta_min 4 16777216
|
||||
arc_need_free 4 0
|
||||
arc_sys_free 4 261496832
|
||||
memory_throttle_count 4 0
|
||||
metadata_size 4 175298560
|
||||
mfu_evictable_data 4 1017613824
|
||||
mfu_evictable_metadata 4 9163776
|
||||
mfu_ghost_evictable_data 4 96731136
|
||||
mfu_ghost_evictable_metadata 4 8205312
|
||||
mfu_ghost_hits 4 821
|
||||
mfu_ghost_size 4 104936448
|
||||
mfu_hits 4 7829854
|
||||
mfu_size 4 1066623488
|
||||
misses 4 604635
|
||||
mru_evictable_data 4 278091264
|
||||
mru_evictable_metadata 4 18606592
|
||||
mru_ghost_evictable_data 4 883765248
|
||||
mru_ghost_evictable_metadata 4 115962880
|
||||
mru_ghost_hits 4 21100
|
||||
mru_ghost_size 4 999728128
|
||||
mru_hits 4 855535
|
||||
mru_size 4 402593792
|
||||
mutex_miss 4 2
|
||||
other_size 4 116443992
|
||||
p 4 516395305
|
||||
prefetch_data_hits 4 3615
|
||||
prefetch_data_misses 4 17094
|
||||
prefetch_metadata_hits 4 83612
|
||||
prefetch_metadata_misses 4 16071
|
||||
size 4 1603939792
|
||||
|
|
|
@ -95,7 +95,7 @@ func (s zfsSysctl) metricName() string {
|
|||
return strings.Replace(parts[len(parts)-1], "-", "_", -1)
|
||||
}
|
||||
|
||||
func (c *zfsCollector) constSysctlMetric(subsystem string, sysctl zfsSysctl, value uint64) prometheus.Metric {
|
||||
func (c *zfsCollector) constSysctlMetric(subsystem string, sysctl zfsSysctl, value float64) prometheus.Metric {
|
||||
metricName := sysctl.metricName()
|
||||
|
||||
return prometheus.MustNewConstMetric(
|
||||
|
@ -106,7 +106,7 @@ func (c *zfsCollector) constSysctlMetric(subsystem string, sysctl zfsSysctl, val
|
|||
nil,
|
||||
),
|
||||
prometheus.UntypedValue,
|
||||
float64(value),
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -63,8 +63,15 @@ func (c *zfsCollector) updateZfsStats(subsystem string, ch chan<- prometheus.Met
|
|||
}
|
||||
defer file.Close()
|
||||
|
||||
return c.parseProcfsFile(file, c.linuxPathMap[subsystem], func(s zfsSysctl, v uint64) {
|
||||
ch <- c.constSysctlMetric(subsystem, s, v)
|
||||
return c.parseProcfsFile(file, c.linuxPathMap[subsystem], func(s zfsSysctl, v interface{}) {
|
||||
var valueAsFloat64 float64
|
||||
switch value := v.(type) {
|
||||
case int64:
|
||||
valueAsFloat64 = float64(value)
|
||||
case uint64:
|
||||
valueAsFloat64 = float64(value)
|
||||
}
|
||||
ch <- c.constSysctlMetric(subsystem, s, valueAsFloat64)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -144,7 +151,7 @@ func (c *zfsCollector) updatePoolStats(ch chan<- prometheus.Metric) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *zfsCollector) parseProcfsFile(reader io.Reader, fmtExt string, handler func(zfsSysctl, uint64)) error {
|
||||
func (c *zfsCollector) parseProcfsFile(reader io.Reader, fmtExt string, handler func(zfsSysctl, interface{})) error {
|
||||
scanner := bufio.NewScanner(reader)
|
||||
|
||||
parseLine := false
|
||||
|
@ -163,11 +170,18 @@ func (c *zfsCollector) parseProcfsFile(reader io.Reader, fmtExt string, handler
|
|||
|
||||
// kstat data type (column 2) should be KSTAT_DATA_UINT64, otherwise ignore
|
||||
// TODO: when other KSTAT_DATA_* types arrive, much of this will need to be restructured
|
||||
if parts[1] == kstatDataUint64 || parts[1] == kstatDataInt64 {
|
||||
key := fmt.Sprintf("kstat.zfs.misc.%s.%s", fmtExt, parts[0])
|
||||
key := fmt.Sprintf("kstat.zfs.misc.%s.%s", fmtExt, parts[0])
|
||||
switch parts[1] {
|
||||
case kstatDataUint64:
|
||||
value, err := strconv.ParseUint(parts[2], 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse expected integer value for %q", key)
|
||||
return fmt.Errorf("could not parse expected unsigned integer value for %q: %w", key, err)
|
||||
}
|
||||
handler(zfsSysctl(key), value)
|
||||
case kstatDataInt64:
|
||||
value, err := strconv.ParseInt(parts[2], 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse expected signed integer value for %q: %w", key, err)
|
||||
}
|
||||
handler(zfsSysctl(key), value)
|
||||
}
|
||||
|
|
|
@ -35,24 +35,25 @@ func TestArcstatsParsing(t *testing.T) {
|
|||
}
|
||||
|
||||
handlerCalled := false
|
||||
err = c.parseProcfsFile(arcstatsFile, "arcstats", func(s zfsSysctl, v uint64) {
|
||||
err = c.parseProcfsFile(arcstatsFile, "arcstats", func(s zfsSysctl, v interface{}) {
|
||||
|
||||
if s != zfsSysctl("kstat.zfs.misc.arcstats.hits") {
|
||||
if s == zfsSysctl("kstat.zfs.misc.arcstats.hits") {
|
||||
if v.(uint64) != uint64(8772612) {
|
||||
t.Fatalf("Incorrect value parsed from procfs data")
|
||||
}
|
||||
} else if s == zfsSysctl("kstat.zfs.misc.arcstats.memory_available_bytes") {
|
||||
if v.(int64) != int64(-922337203685477580) {
|
||||
t.Fatalf("Incorrect value parsed from procfs data")
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
handlerCalled = true
|
||||
|
||||
if v != uint64(8772612) {
|
||||
t.Fatalf("Incorrect value parsed from procfs data")
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !handlerCalled {
|
||||
t.Fatal("Arcstats parsing handler was not called for some expected sysctls")
|
||||
}
|
||||
|
@ -71,7 +72,7 @@ func TestZfetchstatsParsing(t *testing.T) {
|
|||
}
|
||||
|
||||
handlerCalled := false
|
||||
err = c.parseProcfsFile(zfetchstatsFile, "zfetchstats", func(s zfsSysctl, v uint64) {
|
||||
err = c.parseProcfsFile(zfetchstatsFile, "zfetchstats", func(s zfsSysctl, v interface{}) {
|
||||
|
||||
if s != zfsSysctl("kstat.zfs.misc.zfetchstats.hits") {
|
||||
return
|
||||
|
@ -79,7 +80,7 @@ func TestZfetchstatsParsing(t *testing.T) {
|
|||
|
||||
handlerCalled = true
|
||||
|
||||
if v != uint64(7067992) {
|
||||
if v.(uint64) != uint64(7067992) {
|
||||
t.Fatalf("Incorrect value parsed from procfs data")
|
||||
}
|
||||
|
||||
|
@ -107,7 +108,7 @@ func TestZilParsing(t *testing.T) {
|
|||
}
|
||||
|
||||
handlerCalled := false
|
||||
err = c.parseProcfsFile(zilFile, "zil", func(s zfsSysctl, v uint64) {
|
||||
err = c.parseProcfsFile(zilFile, "zil", func(s zfsSysctl, v interface{}) {
|
||||
|
||||
if s != zfsSysctl("kstat.zfs.misc.zil.zil_commit_count") {
|
||||
return
|
||||
|
@ -115,7 +116,7 @@ func TestZilParsing(t *testing.T) {
|
|||
|
||||
handlerCalled = true
|
||||
|
||||
if v != uint64(10) {
|
||||
if v.(uint64) != uint64(10) {
|
||||
t.Fatalf("Incorrect value parsed from procfs data")
|
||||
}
|
||||
|
||||
|
@ -143,7 +144,7 @@ func TestVdevCacheStatsParsing(t *testing.T) {
|
|||
}
|
||||
|
||||
handlerCalled := false
|
||||
err = c.parseProcfsFile(vdevCacheStatsFile, "vdev_cache_stats", func(s zfsSysctl, v uint64) {
|
||||
err = c.parseProcfsFile(vdevCacheStatsFile, "vdev_cache_stats", func(s zfsSysctl, v interface{}) {
|
||||
|
||||
if s != zfsSysctl("kstat.zfs.misc.vdev_cache_stats.delegations") {
|
||||
return
|
||||
|
@ -151,7 +152,7 @@ func TestVdevCacheStatsParsing(t *testing.T) {
|
|||
|
||||
handlerCalled = true
|
||||
|
||||
if v != uint64(40) {
|
||||
if v.(uint64) != uint64(40) {
|
||||
t.Fatalf("Incorrect value parsed from procfs data")
|
||||
}
|
||||
|
||||
|
@ -179,7 +180,7 @@ func TestXuioStatsParsing(t *testing.T) {
|
|||
}
|
||||
|
||||
handlerCalled := false
|
||||
err = c.parseProcfsFile(xuioStatsFile, "xuio_stats", func(s zfsSysctl, v uint64) {
|
||||
err = c.parseProcfsFile(xuioStatsFile, "xuio_stats", func(s zfsSysctl, v interface{}) {
|
||||
|
||||
if s != zfsSysctl("kstat.zfs.misc.xuio_stats.onloan_read_buf") {
|
||||
return
|
||||
|
@ -187,7 +188,7 @@ func TestXuioStatsParsing(t *testing.T) {
|
|||
|
||||
handlerCalled = true
|
||||
|
||||
if v != uint64(32) {
|
||||
if v.(uint64) != uint64(32) {
|
||||
t.Fatalf("Incorrect value parsed from procfs data")
|
||||
}
|
||||
|
||||
|
@ -215,7 +216,7 @@ func TestFmParsing(t *testing.T) {
|
|||
}
|
||||
|
||||
handlerCalled := false
|
||||
err = c.parseProcfsFile(fmFile, "fm", func(s zfsSysctl, v uint64) {
|
||||
err = c.parseProcfsFile(fmFile, "fm", func(s zfsSysctl, v interface{}) {
|
||||
|
||||
if s != zfsSysctl("kstat.zfs.misc.fm.erpt-dropped") {
|
||||
return
|
||||
|
@ -223,7 +224,7 @@ func TestFmParsing(t *testing.T) {
|
|||
|
||||
handlerCalled = true
|
||||
|
||||
if v != uint64(18) {
|
||||
if v.(uint64) != uint64(18) {
|
||||
t.Fatalf("Incorrect value parsed from procfs data")
|
||||
}
|
||||
|
||||
|
@ -251,7 +252,7 @@ func TestDmuTxParsing(t *testing.T) {
|
|||
}
|
||||
|
||||
handlerCalled := false
|
||||
err = c.parseProcfsFile(dmuTxFile, "dmu_tx", func(s zfsSysctl, v uint64) {
|
||||
err = c.parseProcfsFile(dmuTxFile, "dmu_tx", func(s zfsSysctl, v interface{}) {
|
||||
|
||||
if s != zfsSysctl("kstat.zfs.misc.dmu_tx.dmu_tx_assigned") {
|
||||
return
|
||||
|
@ -259,7 +260,7 @@ func TestDmuTxParsing(t *testing.T) {
|
|||
|
||||
handlerCalled = true
|
||||
|
||||
if v != uint64(3532844) {
|
||||
if v.(uint64) != uint64(3532844) {
|
||||
t.Fatalf("Incorrect value parsed from procfs data")
|
||||
}
|
||||
|
||||
|
@ -367,7 +368,7 @@ func TestAbdstatsParsing(t *testing.T) {
|
|||
}
|
||||
|
||||
handlerCalled := false
|
||||
err = c.parseProcfsFile(abdstatsFile, "abdstats", func(s zfsSysctl, v uint64) {
|
||||
err = c.parseProcfsFile(abdstatsFile, "abdstats", func(s zfsSysctl, v interface{}) {
|
||||
|
||||
if s != zfsSysctl("kstat.zfs.misc.abdstats.linear_data_size") {
|
||||
return
|
||||
|
@ -375,7 +376,7 @@ func TestAbdstatsParsing(t *testing.T) {
|
|||
|
||||
handlerCalled = true
|
||||
|
||||
if v != uint64(223232) {
|
||||
if v.(uint64) != uint64(223232) {
|
||||
t.Fatalf("Incorrect value parsed from procfs abdstats data")
|
||||
}
|
||||
|
||||
|
@ -403,7 +404,7 @@ func TestDbufstatsParsing(t *testing.T) {
|
|||
}
|
||||
|
||||
handlerCalled := false
|
||||
err = c.parseProcfsFile(dbufstatsFile, "dbufstats", func(s zfsSysctl, v uint64) {
|
||||
err = c.parseProcfsFile(dbufstatsFile, "dbufstats", func(s zfsSysctl, v interface{}) {
|
||||
|
||||
if s != zfsSysctl("kstat.zfs.misc.dbufstats.hash_hits") {
|
||||
return
|
||||
|
@ -411,7 +412,7 @@ func TestDbufstatsParsing(t *testing.T) {
|
|||
|
||||
handlerCalled = true
|
||||
|
||||
if v != uint64(108807) {
|
||||
if v.(uint64) != uint64(108807) {
|
||||
t.Fatalf("Incorrect value parsed from procfs dbufstats data")
|
||||
}
|
||||
|
||||
|
@ -439,7 +440,7 @@ func TestDnodestatsParsing(t *testing.T) {
|
|||
}
|
||||
|
||||
handlerCalled := false
|
||||
err = c.parseProcfsFile(dnodestatsFile, "dnodestats", func(s zfsSysctl, v uint64) {
|
||||
err = c.parseProcfsFile(dnodestatsFile, "dnodestats", func(s zfsSysctl, v interface{}) {
|
||||
|
||||
if s != zfsSysctl("kstat.zfs.misc.dnodestats.dnode_hold_alloc_hits") {
|
||||
return
|
||||
|
@ -447,7 +448,7 @@ func TestDnodestatsParsing(t *testing.T) {
|
|||
|
||||
handlerCalled = true
|
||||
|
||||
if v != uint64(37617) {
|
||||
if v.(uint64) != uint64(37617) {
|
||||
t.Fatalf("Incorrect value parsed from procfs dnodestats data")
|
||||
}
|
||||
|
||||
|
@ -475,7 +476,7 @@ func TestVdevMirrorstatsParsing(t *testing.T) {
|
|||
}
|
||||
|
||||
handlerCalled := false
|
||||
err = c.parseProcfsFile(vdevMirrorStatsFile, "vdev_mirror_stats", func(s zfsSysctl, v uint64) {
|
||||
err = c.parseProcfsFile(vdevMirrorStatsFile, "vdev_mirror_stats", func(s zfsSysctl, v interface{}) {
|
||||
|
||||
if s != zfsSysctl("kstat.zfs.misc.vdev_mirror_stats.preferred_not_found") {
|
||||
return
|
||||
|
@ -483,7 +484,7 @@ func TestVdevMirrorstatsParsing(t *testing.T) {
|
|||
|
||||
handlerCalled = true
|
||||
|
||||
if v != uint64(94) {
|
||||
if v.(uint64) != uint64(94) {
|
||||
t.Fatalf("Incorrect value parsed from procfs vdev_mirror_stats data")
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue