-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
debug/elf: don't check section size #33121
Comments
Thank you for this report @gregory-m! Kindly paging @tklauser @heschik @aclements. |
I'm not really sure how hard debug/elf should work to handle invalid input files. |
I have same question as @ianlancetaylor, because I have 2 more panics in different places. |
Fuzzing the ELF loader isn't very succesful since it keeps crashing in debug/elf. Most of the time the culprit is a call to elf.Section.Data(). This method allocates a buffer with a size taken from the ELF, which can lead to outlandishly large allocations. It's not clear how to validate elf.Section.Size since the code that creates the section doesn't know the total length of the ELF. Instead, add a wrapper that catches panics due to ELF parsing, and turns them into errors. This isn't a fool proof solution since the runtime can still kill the process due to an OOM, but hopefully we will still crash less overall. See golang/go#33121
Fuzzing the ELF loader isn't very succesful since it keeps crashing in debug/elf. Most of the time the culprit is a call to elf.Section.Data(). This method allocates a buffer with a size taken from the ELF, which can lead to outlandishly large allocations. It's not clear how to validate elf.Section.Size since the code that creates the section doesn't know the total length of the ELF. Instead, add a wrapper that catches panics due to ELF parsing, and turns them into errors. This isn't a fool proof solution since the runtime can still kill the process due to an OOM, but hopefully we will still crash less overall. See golang/go#33121
Fuzzing the ELF loader isn't very succesful since it keeps crashing in debug/elf. Most of the time the culprit is a call to elf.Section.Data(). This method allocates a buffer with a size taken from the ELF, which can lead to outlandishly large allocations. It's not clear how to validate elf.Section.Size since the code that creates the section doesn't know the total length of the ELF. Instead, add a wrapper that catches panics due to ELF parsing, and turns them into errors. This isn't a fool proof solution since the runtime can still kill the process due to an OOM, but hopefully we will still crash less overall. See golang/go#33121
Fuzzing the ELF loader isn't very succesful since it keeps crashing in debug/elf. Most of the time the culprit is a call to elf.Section.Data(). This method allocates a buffer with a size taken from the ELF, which can lead to outlandishly large allocations. It's not clear how to validate elf.Section.Size since the code that creates the section doesn't know the total length of the ELF. Instead, add a wrapper that catches panics due to ELF parsing, and turns them into errors. This isn't a fool proof solution since the runtime can still kill the process due to an OOM, but hopefully we will still crash less overall. See golang/go#33121
Here is at least one reason why NewFile() should not crash because of invalidated input. We have a service that extracts BuildIDs from ELF files provided from different sources (distro packages or arbitrary upload from user). We already saw some crashes of the service (luckily, it automatically recovers =)). Now I ran into this again while experimenting with the Go fuzzer. Go built from commit 7e72d38.
The input file is In line 470 ( This crash prevents the fuzzer from going on and finding more/other issues. |
The issue reported on the first comment has been fixed on tip. Now it returns an error As for the issue reported by @rockdaboot, maybe we can fix it like this: diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go
index 708980bc1c..f4592f2cf2 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -467,8 +467,12 @@ func NewFile(r io.ReaderAt) (*File, error) {
}
// Read section headers
- f.Sections = make([]*Section, shnum)
- names := make([]uint32, shnum)
+ safeShnum := 0xfffff
+ if safeShnum > shnum {
+ safeShnum = shnum
+ }
+ f.Sections = make([]*Section, 0, safeShnum)
+ names := make([]uint32, 0, safeShnum)
for i := 0; i < shnum; i++ {
off := shoff + int64(i)*int64(shentsize)
sr.Seek(off, seekStart)
@@ -479,7 +483,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
return nil, err
}
- names[i] = sh.Name
+ names = append(names, sh.Name)
s.SectionHeader = SectionHeader{
Type: SectionType(sh.Type),
Flags: SectionFlag(sh.Flags),
@@ -496,7 +500,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
return nil, err
}
- names[i] = sh.Name
+ names = append(names, sh.Name)
s.SectionHeader = SectionHeader{
Type: SectionType(sh.Type),
Flags: SectionFlag(sh.Flags),
@@ -544,7 +548,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
}
}
- f.Sections[i] = s
+ f.Sections = append(f.Sections, s)
}
if len(f.Sections) == 0 { @ianlancetaylor I will send a CL if you're okay with this solution. |
@ZekeLu Thanks, your suggestion looks much better than the hack that I applied here to continue with fuzzing 😄 : diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go
index 708980bc1c..2b1aaa3938 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -466,6 +466,13 @@ func NewFile(r io.ReaderAt) (*File, error) {
return nil, &FormatError{0, "invalid ELF shentsize", shentsize}
}
+ // Plausibility check to avoid an unbounded memory allocation.
+ var test [1]byte
+ sr.Seek(int64(shnum) * 40, seekStart)
+ if err := binary.Read(sr, f.ByteOrder, test); err != nil {
+ return nil, err
+ }
+
// Read section headers
f.Sections = make([]*Section, shnum)
names := make([]uint32, shnum) |
We've more or less decided that debug/elf should do at least minimal work to avoid panicking on invalid files. See #47653 and several recent commits to the debug/elf package. @ZekeLu Since ELF files can have enormous numbers of sections, we should probably use |
Ah, I totally forgot that we already have |
Change https://go.dev/cl/445076 mentions this issue: |
This avoids allocating an overly large slice for corrupt input. No test case because the problem can only happen for invalid data. Let the fuzzer find cases like this. Updates #33121. Change-Id: Ie2d947a3865d3499034286f2d08d3e3204015f3e GitHub-Last-Rev: 6c62fc3 GitHub-Pull-Request: #56405 Reviewed-on: https://go-review.googlesource.com/c/go/+/445076 Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]>
The listed issues have been fixed.
@gregory-m Can you confirm whether the 2 more panics can still be reproduced on go tip? @gopherbot Please add label WaitingForInfo. |
With CL445076 I can't reproduce it. |
This avoids allocating an overly large slice for corrupt input. No test case because the problem can only happen for invalid data. Let the fuzzer find cases like this. Updates golang#33121. Change-Id: Ie2d947a3865d3499034286f2d08d3e3204015f3e GitHub-Last-Rev: 6c62fc3 GitHub-Pull-Request: golang#56405 Reviewed-on: https://go-review.googlesource.com/c/go/+/445076 Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]>
We should be running the local dev setup on 1.20 due to golang/go#33121 Signed-off-by: crozzy <[email protected]>
We should be running the local dev setup on 1.20 due to golang/go#33121 Signed-off-by: crozzy <[email protected]>
We should be running the local dev setup on 1.20 due to golang/go#33121 Signed-off-by: crozzy <[email protected]>
Some of the go detection logic was prone to this bug: golang/go#33121 in the go debug library, as 1.20 includes the fix we deem it required to avoid panics originating in claircore. Signed-off-by: crozzy <[email protected]>
Some of the go detection logic was prone to this bug: golang/go#33121 in the go debug library, as 1.20 includes the fix we deem it required to avoid panics originating in claircore. Signed-off-by: crozzy <[email protected]>
Some of the go detection logic was prone to this bug: golang/go#33121 in the go debug library, as 1.20 includes the fix we deem it required to avoid panics originating in claircore. Signed-off-by: crozzy <[email protected]>
What version of Go are you using (
go version
)?go1.12.7
also reproducible on tip
Does this issue reproduce with the latest release?
yes
What did you do?
https://play.golang.org/p/_5bUxWBh14g
What did you expect to see?
no panic
What did you see instead?
Fund with https://github.com/dvyukov/go-fuzz
The text was updated successfully, but these errors were encountered: