aboutsummaryrefslogtreecommitdiff
path: root/src/debug/elf/file.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2026-03-23 04:38:52 -0700
committerGopher Robot <gobot@golang.org>2026-03-25 06:14:20 -0700
commite3bda445164c764aa95c7df271dff2170fa1a7ce (patch)
tree0a3b39380692cacc59ea0bf3400072af03b846e1 /src/debug/elf/file.go
parentcbc2d06c9ba8285bb60f1055b44d4d1e742ca734 (diff)
downloadgo-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.go112
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}
}