diff options
| author | Ian Lance Taylor <iant@golang.org> | 2026-03-23 04:38:52 -0700 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2026-03-25 06:14:20 -0700 |
| commit | e3bda445164c764aa95c7df271dff2170fa1a7ce (patch) | |
| tree | 0a3b39380692cacc59ea0bf3400072af03b846e1 /src/debug/elf/file.go | |
| parent | cbc2d06c9ba8285bb60f1055b44d4d1e742ca734 (diff) | |
| download | go-e3bda445164c764aa95c7df271dff2170fa1a7ce.tar.xz | |
debug/elf: handle program header count overflow
ELF files only have a 16-bit count for program headers.
To handle the very rare case of larger files,
a large program header count is stored as 0xffff
and the first section header info field holds the actual count.
Fixes #78217
Change-Id: I35c7e15025a9677473cb43d09a41f17f75443731
Reviewed-on: https://go-review.googlesource.com/c/go/+/758040
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Diffstat (limited to 'src/debug/elf/file.go')
| -rw-r--r-- | src/debug/elf/file.go | 112 |
1 files changed, 66 insertions, 46 deletions
diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go index cc40b22f39..faba6fa4e9 100644 --- a/src/debug/elf/file.go +++ b/src/debug/elf/file.go @@ -400,6 +400,72 @@ func NewFile(r io.ReaderAt) (*File, error) { return nil, &FormatError{0, "invalid ELF phentsize", phentsize} } + // If the number of sections is greater than or equal to SHN_LORESERVE + // (0xff00), shnum has the value zero and the actual number of section + // header table entries is contained in the sh_size field of the section + // header at index 0. + // + // If the number of segments is greater than or equal to 0xffff, + // phnum has the value 0xffff, and the actual number of segments + // is contained in the sh_info field of the section header at + // index 0. + const pnXnum = 0xffff + if shoff > 0 && (shnum == 0 || phnum == pnXnum) { + var typ, link, info uint32 + var size uint64 + sr.Seek(shoff, io.SeekStart) + switch f.Class { + case ELFCLASS32: + sh := new(Section32) + if err := binary.Read(sr, bo, sh); err != nil { + return nil, err + } + size = uint64(sh.Size) + typ = sh.Type + link = sh.Link + info = sh.Info + case ELFCLASS64: + sh := new(Section64) + if err := binary.Read(sr, bo, sh); err != nil { + return nil, err + } + size = sh.Size + typ = sh.Type + link = sh.Link + info = sh.Info + } + + if SectionType(typ) != SHT_NULL { + return nil, &FormatError{shoff, "invalid type of the initial section", SectionType(typ)} + } + + if shnum == 0 { + if size < uint64(SHN_LORESERVE) { + return nil, &FormatError{shoff, "invalid ELF shnum contained in sh_size", shnum} + } + shnum = int(size) + } + + if phnum == pnXnum { + if info < 0xffff { + return nil, &FormatError{shoff, "invalid ELF phnum contained in sh_info", info} + } + phnum = int(info) + } + + // If the section name string table section index is greater than or + // equal to SHN_LORESERVE (0xff00), this member has the value + // SHN_XINDEX (0xffff) and the actual index of the section name + // string table section is contained in the sh_link field of the + // section header at index 0. + if shstrndx == int(SHN_XINDEX) { + shstrndx = int(link) + if shstrndx < int(SHN_LORESERVE) { + return nil, &FormatError{shoff, "invalid ELF shstrndx contained in sh_link", shstrndx} + } + } + } + // Read program headers f.Progs = make([]*Prog, phnum) phdata, err := saferio.ReadDataAt(sr, uint64(phnum)*uint64(phentsize), phoff) @@ -446,52 +512,6 @@ func NewFile(r io.ReaderAt) (*File, error) { f.Progs[i] = p } - // If the number of sections is greater than or equal to SHN_LORESERVE - // (0xff00), shnum has the value zero and the actual number of section - // header table entries is contained in the sh_size field of the section - // header at index 0. - if shoff > 0 && shnum == 0 { - var typ, link uint32 - sr.Seek(shoff, io.SeekStart) - switch f.Class { - case ELFCLASS32: - sh := new(Section32) - if err := binary.Read(sr, bo, sh); err != nil { - return nil, err - } - shnum = int(sh.Size) - typ = sh.Type - link = sh.Link - case ELFCLASS64: - sh := new(Section64) - if err := binary.Read(sr, bo, sh); err != nil { - return nil, err - } - shnum = int(sh.Size) - typ = sh.Type - link = sh.Link - } - if SectionType(typ) != SHT_NULL { - return nil, &FormatError{shoff, "invalid type of the initial section", SectionType(typ)} - } - - if shnum < int(SHN_LORESERVE) { - return nil, &FormatError{shoff, "invalid ELF shnum contained in sh_size", shnum} - } - - // If the section name string table section index is greater than or - // equal to SHN_LORESERVE (0xff00), this member has the value - // SHN_XINDEX (0xffff) and the actual index of the section name - // string table section is contained in the sh_link field of the - // section header at index 0. - if shstrndx == int(SHN_XINDEX) { - shstrndx = int(link) - if shstrndx < int(SHN_LORESERVE) { - return nil, &FormatError{shoff, "invalid ELF shstrndx contained in sh_link", shstrndx} - } - } - } - if shnum > 0 && shentsize < wantShentsize { return nil, &FormatError{0, "invalid ELF shentsize", shentsize} } |
