From 85aa27cd9c3cfbf13299c517f11a47a79be3c1c9 Mon Sep 17 00:00:00 2001 From: Paco Cartones <253313177+pacocartones@users.noreply.github.com> Date: Tue, 1 Sep 2026 09:01:04 +0200 Subject: [PATCH] plugin/hosts: don't drop entries after an over-long line (#8496) bufio.Scanner stops at the first line longer than its 64KiB default buffer and reports bufio.ErrTooLong from Err(). parse() never checked Err(), so that line and every entry after it were dropped silently: the hosts file simply looked shorter than it is, with nothing in the log. Raise the scanner's limit to 1MiB (the scanner still grows its buffer lazily, so nothing is preallocated up front) and log an error if the scan does stop early, so the truncation is at least visible. Signed-off-by: Paco Cartones Co-authored-by: Paco Cartones --- plugin/hosts/hostsfile.go | 13 +++++++++++++ plugin/hosts/hostsfile_test.go | 16 ++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/plugin/hosts/hostsfile.go b/plugin/hosts/hostsfile.go index f3ef2cc75..e8f3a9dd7 100644 --- a/plugin/hosts/hostsfile.go +++ b/plugin/hosts/hostsfile.go @@ -164,11 +164,20 @@ func (h *Hostsfile) initInline(inline []string) { h.inline = h.parse(strings.NewReader(strings.Join(inline, "\n"))) } +// maxLineSize is the largest hosts file line we are willing to parse. A line +// can legitimately be long when many names share a single address, so this is +// well above bufio.Scanner's 64KiB default, but still bounded. +const maxLineSize = 1024 * 1024 + // Parse reads the hostsfile and populates the byName and addr maps. func (h *Hostsfile) parse(r io.Reader) *Map { hmap := newMap() scanner := bufio.NewScanner(r) + // The scanner grows its buffer as needed; only raise the limit at which it + // gives up, otherwise a single long line aborts the scan and every entry + // after it is dropped. + scanner.Buffer(nil, maxLineSize) for scanner.Scan() { line := scanner.Bytes() if i := bytes.Index(line, []byte{'#'}); i >= 0 { @@ -220,6 +229,10 @@ func (h *Hostsfile) parse(r io.Reader) *Map { hmap.addr[addr.String()] = append(hmap.addr[addr.String()], name) } } + if err := scanner.Err(); err != nil { + // Entries after the failing line have not been read. + log.Errorf("Failed to parse hosts file %q: %v", h.path, err) + } return hmap } diff --git a/plugin/hosts/hostsfile_test.go b/plugin/hosts/hostsfile_test.go index 4d9595220..6322d9849 100644 --- a/plugin/hosts/hostsfile_test.go +++ b/plugin/hosts/hostsfile_test.go @@ -290,3 +290,19 @@ func TestLookupStaticHostReloadRace(t *testing.T) { wg.Wait() } + +func TestParseLineLongerThanDefaultScanBuffer(t *testing.T) { + // A line longer than bufio.Scanner's default 64KiB buffer must not stop + // the scan: the entries that follow it still have to be parsed. + long := strings.Repeat("a", 70*1024) + h := testHostsfile("127.0.0.1 before.example.org\n" + + "127.0.0.2 " + long + ".example.org\n" + + "127.0.0.3 after.example.org\n") + + if addrs := h.LookupStaticHostV4("before.example.org."); len(addrs) != 1 || addrs[0].String() != "127.0.0.1" { + t.Errorf("LookupStaticHostV4(before.example.org.) = %v, want [127.0.0.1]", addrs) + } + if addrs := h.LookupStaticHostV4("after.example.org."); len(addrs) != 1 || addrs[0].String() != "127.0.0.3" { + t.Errorf("LookupStaticHostV4(after.example.org.) = %v, want [127.0.0.3]", addrs) + } +}