mirror of
https://github.com/anchore/syft.git
synced 2026-10-11 21:57:22 +02:00
fix(elf): avoid a panic on a truncated dynamic section (#5321)
Signed-off-by: somaz <genius5711@gmail.com>
This commit is contained in:
@@ -156,32 +156,12 @@ func hasElfDynFlag1(f *elf.File, flag elf.DynFlag1) bool {
|
||||
}
|
||||
|
||||
func hasElfDynTag(f *elf.File, tag elf.DynTag) bool {
|
||||
// source https://github.com/golang/go/blob/9b4b3e5acca2dabe107fa2c3ed963097d78a4562/src/cmd/cgo/internal/testshared/shared_test.go#L280
|
||||
|
||||
ds := f.SectionByType(elf.SHT_DYNAMIC)
|
||||
if ds == nil {
|
||||
return false
|
||||
}
|
||||
d, err := ds.Data()
|
||||
vals, err := f.DynValue(tag)
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Trace("unable to read dynamic section from elf file")
|
||||
return false
|
||||
}
|
||||
|
||||
for len(d) > 0 {
|
||||
var t elf.DynTag
|
||||
switch f.Class {
|
||||
case elf.ELFCLASS32:
|
||||
t = elf.DynTag(f.ByteOrder.Uint32(d[0:4]))
|
||||
d = d[8:]
|
||||
case elf.ELFCLASS64:
|
||||
t = elf.DynTag(f.ByteOrder.Uint64(d[0:8]))
|
||||
d = d[16:]
|
||||
}
|
||||
if t == tag {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return len(vals) > 0
|
||||
}
|
||||
|
||||
func isELFPIE(f *elf.File) bool {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package executable
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@@ -226,3 +228,89 @@ func Test_elfHasExports(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_hasElfDynTag(t *testing.T) {
|
||||
dynEntry := func(class elf.Class, tag elf.DynTag) []byte {
|
||||
if class == elf.ELFCLASS32 {
|
||||
return binary.LittleEndian.AppendUint32(binary.LittleEndian.AppendUint32(nil, uint32(tag)), 0)
|
||||
}
|
||||
return binary.LittleEndian.AppendUint64(binary.LittleEndian.AppendUint64(nil, uint64(tag)), 0)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
class elf.Class
|
||||
dynamic []byte
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "32-bit tag present",
|
||||
class: elf.ELFCLASS32,
|
||||
dynamic: dynEntry(elf.ELFCLASS32, elf.DT_BIND_NOW),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "64-bit tag present",
|
||||
class: elf.ELFCLASS64,
|
||||
dynamic: dynEntry(elf.ELFCLASS64, elf.DT_BIND_NOW),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "64-bit tag absent",
|
||||
class: elf.ELFCLASS64,
|
||||
dynamic: dynEntry(elf.ELFCLASS64, elf.DT_NULL),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "32-bit truncated dynamic section",
|
||||
class: elf.ELFCLASS32,
|
||||
dynamic: dynEntry(elf.ELFCLASS32, elf.DT_BIND_NOW)[:4],
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "64-bit truncated dynamic section",
|
||||
class: elf.ELFCLASS64,
|
||||
dynamic: dynEntry(elf.ELFCLASS64, elf.DT_BIND_NOW)[:12],
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
f, err := elf.NewFile(bytes.NewReader(elfWithDynamicSection(t, tt.class, tt.dynamic)))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.want, hasElfDynTag(f, elf.DT_BIND_NOW))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// elfWithDynamicSection builds a little-endian ELF holding only a null section and a SHT_DYNAMIC section.
|
||||
func elfWithDynamicSection(t *testing.T, class elf.Class, dynamic []byte) []byte {
|
||||
t.Helper()
|
||||
ident := [elf.EI_NIDENT]byte{0x7f, 'E', 'L', 'F', byte(class), byte(elf.ELFDATA2LSB), byte(elf.EV_CURRENT)}
|
||||
var buf bytes.Buffer
|
||||
write := func(v any) {
|
||||
require.NoError(t, binary.Write(&buf, binary.LittleEndian, v))
|
||||
}
|
||||
|
||||
if class == elf.ELFCLASS32 {
|
||||
ehsize, shentsize := binary.Size(elf.Header32{}), binary.Size(elf.Section32{})
|
||||
dataOff := ehsize + 2*shentsize
|
||||
write(elf.Header32{
|
||||
Ident: ident, Type: uint16(elf.ET_DYN), Machine: uint16(elf.EM_386), Version: uint32(elf.EV_CURRENT),
|
||||
Shoff: uint32(ehsize), Ehsize: uint16(ehsize), Shentsize: uint16(shentsize), Shnum: 2,
|
||||
})
|
||||
write(elf.Section32{})
|
||||
write(elf.Section32{Type: uint32(elf.SHT_DYNAMIC), Off: uint32(dataOff), Size: uint32(len(dynamic)), Addralign: 1})
|
||||
} else {
|
||||
ehsize, shentsize := binary.Size(elf.Header64{}), binary.Size(elf.Section64{})
|
||||
dataOff := ehsize + 2*shentsize
|
||||
write(elf.Header64{
|
||||
Ident: ident, Type: uint16(elf.ET_DYN), Machine: uint16(elf.EM_X86_64), Version: uint32(elf.EV_CURRENT),
|
||||
Shoff: uint64(ehsize), Ehsize: uint16(ehsize), Shentsize: uint16(shentsize), Shnum: 2,
|
||||
})
|
||||
write(elf.Section64{})
|
||||
write(elf.Section64{Type: uint32(elf.SHT_DYNAMIC), Off: uint64(dataOff), Size: uint64(len(dynamic)), Addralign: 1})
|
||||
}
|
||||
buf.Write(dynamic)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user