Visitar URL original
fix(go.d/isc_dhcpd): guard against out-of-range slice when parsing leases by Saadanjum0 · Pull Request #24122 · netdata/netdata · GitHub
Skip to content

fix(go.d/isc_dhcpd): guard against out-of-range slice when parsing leases - #24122

Open
Saadanjum0 wants to merge 1 commit into
netdata:masterfrom
Saadanjum0:fix/isc-dhcpd-leases-parse-panic
Open

Saadanjum0 wants to merge 1 commit into
netdata:masterfrom
Saadanjum0:fix/isc-dhcpd-leases-parse-panic

Conversation

@Saadanjum0

@Saadanjum0 Saadanjum0 commented Oct 2, 2026 •

Copy link
Copy Markdown

Problem

parseDHCPdLeasesFile() in src/go/plugin/go.d/collector/isc_dhcpd/parse.go
matches lines by a loose prefix (lease, iaaddr, binding state) and then
slices a fixed number of bytes off each end to recover the value, assuming
the line is always long enough:

case !l.isAddrValid() && bytes.HasPrefix(bs, []byte("lease")):
    s := string(bs)
    if addr, err := netip.ParseAddr(s[6 : len(s)-2]); err == nil && addr.IsValid() {
        l.addr = addr
    }

dhcpd.leases is rewritten/appended by the dhcpd daemon, so the file can be
truncated mid-write at EOF (daemon killed, disk full, process crash). A
truncated line can still satisfy the prefix check while being too short for
the slice — e.g. a line cut short to lease 1 or iaaddr 2. The slice then
panics:

panic: runtime error: slice bounds out of range [6:5]

This does not crash the collector. go.d's job runtime
(src/go/plugin/framework/jobruntime/job_v1.go) already recovers panics in
both Job.collect() and Job.autoDetection(). What actually happens instead:

  • During collection: the panic is recovered every cycle, logged as
    PANIC: ..., and the entire leases file yields zero metrics for that
    cycle — including any otherwise well-formed leases in the same file.
  • During Check()/autodetection: the panic disables autodetection
    (disableAutoDetection()), so the job never starts at all.

So the practical impact is silent data loss on an already-running job, or a
job that silently never starts — not a crash. Still worth fixing: a
truncated/malformed leases file otherwise leaves the collector permanently
blind to all leases until the file is fixed or the agent is restarted.

Fix

Added cutAffixes(), a single bounds-checked helper shared by the three
call sites (lease address, iaaddr address, binding state), that skips the
line when it is too short to hold the expected value instead of panicking.

Testing

Added parse_test.go with malformed-line cases simulating a leases file
truncated mid-write (e.g. lease 1, iaaddr 2, a cut-off binding state
line) that reproduce the panic on the old code and pass after the fix, plus
a well-formed case. Ran the full existing isc_dhcpd package test suite
locally (temporarily lifting the darwin build exclusion to run on macOS) —
all pass with no behavior change for well-formed leases files.


Summary by cubic

Fixes the isc_dhcpd leases parser panicking when dhcpd.leases contains lines truncated mid-write (daemon killed, disk full, crash). Previously the framework-recovered panic hid the issue but made the job report zero metrics for the whole file or prevented it from starting; now malformed lines are skipped and well-formed leases still parse.

Bug Fixes

  • Adds a bounds-checked cutAffixes() helper shared by the three slice call sites to skip too-short lines instead of panicking.
  • Adds tests for truncated lease, iaaddr, and binding state lines plus a well-formed case.

Written for commit 52724c7. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of truncated DHCP lease entries to prevent parsing failures and ensure malformed lines are skipped safely.
    • Valid lease addresses and binding states continue to be parsed correctly.

…ases

parseDHCPdLeasesFile() matched lines by a loose prefix ("lease", "iaaddr",
"binding state") and then sliced a fixed number of bytes off each end to
recover the value, assuming the line was always long enough. dhcpd.leases
is rewritten/appended by the dhcpd daemon, so the file can be truncated
mid-write at EOF (daemon killed, disk full, process crash). A truncated
line can still satisfy the prefix check while being too short for the
slice, e.g. a line cut short to "lease 1" or "iaaddr 2", and the slice
then panics with "slice bounds out of range".

This does not crash the collector: go.d's job runtime
(src/go/plugin/framework/jobruntime/job_v1.go) already recovers panics in
both Job.collect() and Job.autoDetection(). What actually happens instead:
during collection the panic is recovered every cycle, logged as "PANIC",
and the whole leases file yields zero metrics for that cycle, including
otherwise well-formed leases; during Check()/autodetection the panic
disables autodetection, so the job never starts.

Add cutAffixes(), a single bounds-checked helper shared by all three call
sites, and skip the line instead of panicking when it is too short to
hold the expected value.
@Saadanjum0
Saadanjum0 requested a review from ilyam8 as a code owner October 2, 2026 12:49
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@github-actions github-actions Bot added area/collectors Everything related to data collection collectors/go.d area/go labels Oct 2, 2026
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can show, collapse, or hide each part of a finding: code, evidence, and all

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Prevent panics on truncated ISC DHCP lease lines

🐞 Bug fix 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Guard lease address and binding-state parsing against truncated lines that previously caused
 panics.
• Skip undersized lines so malformed input does not prevent the collector from processing leases.
• Add malformed-line regressions and verify a well-formed lease still parses.
Diagram

graph TD
  F["Leases file"] --> P["Line parser"] --> G{"Length sufficient?"} -- "Yes" --> V["Parse field"] --> E["Lease entries"] --> C["Collector metrics"]
  G -- "No" --> S["Skip line"]
Loading
High-Level Assessment

The shared bounds check addresses the panic at all three affected slices without changing parsing behavior for well-formed lines. A stricter grammar parser would be a broader change than this targeted fix requires.

Files changed (2) +82 / -5

Bug fix (1) +21 / -5
parse.goBounds-check three lease-field extractions +21/-5

Bounds-check three lease-field extractions

• Adds a shared helper that rejects lines too short for the expected prefix and suffix. Lease addresses, IPv6 iaaddr addresses, and binding states now skip undersized values instead of slicing out of range.

src/go/plugin/go.d/collector/isc_dhcpd/parse.go

Tests (1) +61 / -0
parse_test.goCover truncated lease lines and valid parsing +61/-0

Cover truncated lease lines and valid parsing

• Adds regression cases for truncated lease, iaaddr, and binding-state lines that assert parsing does not panic and produces no leases. A well-formed lease case verifies address and binding-state extraction.

src/go/plugin/go.d/collector/isc_dhcpd/parse_test.go

@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

🧰 Additional context used
📚 Code guidelines (2)
src/go/AGENTS.md — auto-discovered
AGENTS.md — auto-discovered

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 35598e39-bb7c-4418-bacc-5a107a0ed079

📥 Commits

Reviewing files that changed from the base of the PR and between 85d8388 and 52724c7.

📒 Files selected for processing (2)
  • src/go/plugin/go.d/collector/isc_dhcpd/parse.go
  • src/go/plugin/go.d/collector/isc_dhcpd/parse_test.go

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

DHCP lease parsing now checks line lengths before extracting addresses and binding states. Tests cover four truncated lease-line forms and a well-formed lease.

Changes

DHCP lease parsing

Layer / File(s) Summary
Guarded lease value extraction
src/go/plugin/go.d/collector/isc_dhcpd/parse.go, src/go/plugin/go.d/collector/isc_dhcpd/parse_test.go
cutAffixes checks whether a line is long enough before extracting address or binding-state values. Tests cover four truncated line forms and verify address and binding-state parsing for a well-formed lease.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~8 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 52724

No actionable merge-blocking risk remains for this change after normal checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: preventing out-of-range slice errors while parsing ISC DHCP leases.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.
Architecture diagram
sequenceDiagram
    participant Daemon as dhcpd daemon
    participant FS as dhcpd.leases file
    participant Parser as parseDHCPdLeasesFile()
    participant Helper as cutAffixes()
    participant Job as go.d Job Runtime
    participant Metrics as Metrics Pipeline

    Note over Daemon,FS: Runtime data source
    Daemon->>FS: Writes/appends lease records (may truncate mid-write on crash)

    Note over Parser,Metrics: Collection cycle
    Job->>Parser: collect() - read leases file
    
    loop Each line in file
        Parser->>Parser: Match prefix (lease / iaaddr / binding state)
        alt Matched lease address line
            Parser->>Helper: cutAffixes(s, 6, 2)
            Helper-->>Parser: value or not-ok (too short)
            alt Value ok
                Parser->>Parser: netip.ParseAddr() + validate
            else Line too short (truncated)
                Note over Parser: Skip line, no panic
            end
        else Matched iaaddr line
            Parser->>Helper: cutAffixes(s, 7, 2)
            Helper-->>Parser: value or not-ok
            alt Value ok
                Parser->>Parser: netip.ParseAddr() + validate
            else Line too short
                Note over Parser: Skip line, no panic
            end
        else Matched binding state line
            Parser->>Helper: cutAffixes(s, 14, 1)
            Helper-->>Parser: value or not-ok
            alt Value ok
                Parser->>Parser: Store binding state
            else Line too short
                Note over Parser: Skip line, no panic
            end
        end
    end

    Parser-->>Job: lease entries (well-formed only)
    Job->>Metrics: Send collected lease data

    Note over Parser,Metrics: Unhappy path - before fix
    Parser->>Parser: Out-of-range slice panic on truncated line
    Job->>Job: Recover panic (framework)
    Job->>Metrics: Zero metrics for entire file that cycle

    Note over Parser,Metrics: Now: malformed lines skipped, valid leases still parsed
Loading

Re-trigger cubic

@sonarqubecloud

sonarqubecloud Bot commented Oct 2, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/collectors Everything related to data collection area/go collectors/go.d

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants