Skip to content

Commit f52d095

Browse files
rihter007orangecms
authored andcommitted
Fix memory overflow error when parsing PSP/BIOS directory tables with very big value of TotalEntries
Fix errors contents in Find PSP/BIOS directory functions Signed-off-by: Ilya <rihter007@inbox.ru>
1 parent f0c9580 commit f52d095

5 files changed

Lines changed: 63 additions & 17 deletions

File tree

pkg/amd/manifest/bios_directory_table.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ type BIOSDirectoryTableEntry struct {
5555
DestinationAddress uint64
5656
}
5757

58+
const BIOSDirectoryTableEntrySize = 16
59+
5860
// BIOSDirectoryTableHeader represents a BIOS Directory Table Header
5961
// Table 11 from (1)
6062
type BIOSDirectoryTableHeader struct {
@@ -125,7 +127,7 @@ func FindBIOSDirectoryTable(image []byte) (*BIOSDirectoryTable, bytes2.Range, er
125127
break
126128
}
127129

128-
table, bytesRead, err := ParseBIOSDirectoryTable(bytes.NewBuffer(image[idx:]))
130+
table, bytesRead, err := ParseBIOSDirectoryTable(image[idx:])
129131
if err != nil {
130132
shift := uint64(idx + len(cookieBytes))
131133
image = image[shift:]
@@ -134,13 +136,15 @@ func FindBIOSDirectoryTable(image []byte) (*BIOSDirectoryTable, bytes2.Range, er
134136
}
135137
return table, bytes2.Range{Offset: offset + uint64(idx), Length: bytesRead}, err
136138
}
137-
return nil, bytes2.Range{}, fmt.Errorf("EmbeddedFirmwareStructure is not found")
139+
return nil, bytes2.Range{}, fmt.Errorf("BIOSDirectoryTable is not found")
138140
}
139141

140142
// ParseBIOSDirectoryTable converts input bytes into BIOSDirectoryTable
141-
func ParseBIOSDirectoryTable(r io.Reader) (*BIOSDirectoryTable, uint64, error) {
143+
func ParseBIOSDirectoryTable(data []byte) (*BIOSDirectoryTable, uint64, error) {
142144
var table BIOSDirectoryTable
143145
var totalLength uint64
146+
147+
r := bytes.NewBuffer(data)
144148
if err := readAndCountSize(r, binary.LittleEndian, &table.BIOSCookie, &totalLength); err != nil {
145149
return nil, 0, err
146150
}
@@ -151,13 +155,19 @@ func ParseBIOSDirectoryTable(r io.Reader) (*BIOSDirectoryTable, uint64, error) {
151155
if err := readAndCountSize(r, binary.LittleEndian, &table.Checksum, &totalLength); err != nil {
152156
return nil, 0, err
153157
}
158+
154159
if err := readAndCountSize(r, binary.LittleEndian, &table.TotalEntries, &totalLength); err != nil {
155160
return nil, 0, err
156161
}
157162
if err := readAndCountSize(r, binary.LittleEndian, &table.Reserved, &totalLength); err != nil {
158163
return nil, 0, err
159164
}
160165

166+
sizeRequired := uint64(table.TotalEntries) * BIOSDirectoryTableEntrySize
167+
if uint64(r.Len()) < sizeRequired {
168+
return nil, 0, fmt.Errorf("not enough data, required: %d, actual: %d", sizeRequired+totalLength, len(data))
169+
}
170+
161171
table.Entries = make([]BIOSDirectoryTableEntry, 0, table.TotalEntries)
162172
for idx := uint32(0); idx < table.TotalEntries; idx++ {
163173
entry, length, err := ParseBIOSDirectoryTableEntry(r)

pkg/amd/manifest/bios_directory_table_test.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
package manifest
66

77
import (
8-
"bytes"
98
"encoding/binary"
109
"testing"
1110
)
@@ -51,7 +50,7 @@ func TestFindBIOSDirectoryTable(t *testing.T) {
5150
t.Run("bios_table_cookie_found", func(t *testing.T) {
5251
table, r, err := FindBIOSDirectoryTable(append(firmwareChunk, biosDirectoryTableDataChunk...))
5352
if err != nil {
54-
t.Fatalf("Unexecpted error when finding BIOS Directory table")
53+
t.Fatalf("Unexecpted error when finding BIOS Directory table: %v", err)
5554
}
5655
if r.Offset != uint64(len(firmwareChunk)) {
5756
t.Errorf("BIOS Directory Table address is incorrect: %d, expected: %d", r.Offset, uint64(len(firmwareChunk)))
@@ -66,7 +65,7 @@ func TestFindBIOSDirectoryTable(t *testing.T) {
6665
}
6766

6867
func TestBiosDirectoryTableParsing(t *testing.T) {
69-
table, readBytes, err := ParseBIOSDirectoryTable(bytes.NewBuffer(append(biosDirectoryTableDataChunk, 0xff)))
68+
table, readBytes, err := ParseBIOSDirectoryTable(append(biosDirectoryTableDataChunk, 0xff))
7069
if err != nil {
7170
t.Fatalf("Failed to parse BIOS Directory table, err: %v", err)
7271
}
@@ -121,3 +120,19 @@ func TestBiosDirectoryTableParsing(t *testing.T) {
121120
table.Entries[0].DestinationAddress)
122121
}
123122
}
123+
124+
func TestBrokenTotalEntriesBiosDirectoryParsing(t *testing.T) {
125+
biosDirectoryTableData := make([]byte, len(biosDirectoryTableDataChunk))
126+
copy(biosDirectoryTableData, biosDirectoryTableDataChunk)
127+
128+
// 8 is offset of TotalEntries field
129+
biosDirectoryTableData[8] = 0xff
130+
biosDirectoryTableData[9] = 0xff
131+
biosDirectoryTableData[10] = 0xff
132+
biosDirectoryTableData[11] = 0xff
133+
134+
_, _, err := ParseBIOSDirectoryTable(biosDirectoryTableData)
135+
if err == nil {
136+
t.Errorf("expected error when parsing incorrect psp directory table contents")
137+
}
138+
}

pkg/amd/manifest/firmware.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
package manifest
66

77
import (
8-
"bytes"
98
"fmt"
109

1110
bytes2 "github.com/linuxboot/fiano/pkg/bytes"
@@ -72,7 +71,7 @@ func parsePSPFirmware(firmware Firmware) (*PSPFirmware, error) {
7271
var pspDirectoryLevel1Range bytes2.Range
7372
if efs.PSPDirectoryTablePointer != 0 && efs.PSPDirectoryTablePointer < uint32(len(image)) {
7473
var length uint64
75-
pspDirectoryLevel1, length, err = ParsePSPDirectoryTable(bytes.NewBuffer(image[efs.PSPDirectoryTablePointer:]))
74+
pspDirectoryLevel1, length, err = ParsePSPDirectoryTable(image[efs.PSPDirectoryTablePointer:])
7675
if err == nil {
7776
pspDirectoryLevel1Range.Offset = uint64(efs.PSPDirectoryTablePointer)
7877
pspDirectoryLevel1Range.Length = length
@@ -90,7 +89,7 @@ func parsePSPFirmware(firmware Firmware) (*PSPFirmware, error) {
9089
continue
9190
}
9291
if entry.LocationOrValue != 0 && entry.LocationOrValue < uint64(len(image)) {
93-
pspDirectoryLevel2, length, err := ParsePSPDirectoryTable(bytes.NewBuffer(image[entry.LocationOrValue:]))
92+
pspDirectoryLevel2, length, err := ParsePSPDirectoryTable(image[entry.LocationOrValue:])
9493
if err == nil {
9594
result.PSPDirectoryLevel2 = pspDirectoryLevel2
9695
result.PSPDirectoryLevel2Range.Offset = entry.LocationOrValue
@@ -115,7 +114,7 @@ func parsePSPFirmware(firmware Firmware) (*PSPFirmware, error) {
115114
continue
116115
}
117116
var length uint64
118-
biosDirectoryLevel1, length, err = ParseBIOSDirectoryTable(bytes.NewBuffer(image[offset:]))
117+
biosDirectoryLevel1, length, err = ParseBIOSDirectoryTable(image[offset:])
119118
if err != nil {
120119
continue
121120
}
@@ -137,7 +136,7 @@ func parsePSPFirmware(firmware Firmware) (*PSPFirmware, error) {
137136
continue
138137
}
139138
if entry.SourceAddress != 0 && entry.SourceAddress < uint64(len(image)) {
140-
biosDirectoryLevel2, length, err := ParseBIOSDirectoryTable(bytes.NewBuffer(image[entry.SourceAddress:]))
139+
biosDirectoryLevel2, length, err := ParseBIOSDirectoryTable(image[entry.SourceAddress:])
141140
if err == nil {
142141
result.BIOSDirectoryLevel2 = biosDirectoryLevel2
143142
result.BIOSDirectoryLevel2Range.Offset = entry.SourceAddress

pkg/amd/manifest/psp_directory_table.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ type PSPDirectoryTableEntry struct {
4444
LocationOrValue uint64
4545
}
4646

47+
const PSPDirectoryTableEntrySize = 16
48+
4749
// PSPDirectoryTableHeader represents a BIOS Directory Table Header
4850
// Tables 3&4 from (1)
4951
type PSPDirectoryTableHeader struct {
@@ -101,7 +103,7 @@ func FindPSPDirectoryTable(image []byte) (*PSPDirectoryTable, bytes2.Range, erro
101103
break
102104
}
103105

104-
table, length, err := ParsePSPDirectoryTable(bytes.NewBuffer(image[idx:]))
106+
table, length, err := ParsePSPDirectoryTable(image[idx:])
105107
if err != nil {
106108
shift := uint64(idx + len(cookieBytes))
107109
image = image[idx+len(cookieBytes):]
@@ -110,21 +112,21 @@ func FindPSPDirectoryTable(image []byte) (*PSPDirectoryTable, bytes2.Range, erro
110112
}
111113
return table, bytes2.Range{Offset: offset + uint64(idx), Length: length}, err
112114
}
113-
return nil, bytes2.Range{}, fmt.Errorf("EmbeddedFirmwareStructure is not found")
115+
return nil, bytes2.Range{}, fmt.Errorf("PSPDirectoryTable is not found")
114116
}
115117

116118
// ParsePSPDirectoryTable converts input bytes into PSPDirectoryTable
117-
func ParsePSPDirectoryTable(r io.Reader) (*PSPDirectoryTable, uint64, error) {
119+
func ParsePSPDirectoryTable(data []byte) (*PSPDirectoryTable, uint64, error) {
118120
var table PSPDirectoryTable
119121
var totalLength uint64
120122

123+
r := bytes.NewBuffer(data)
121124
if err := readAndCountSize(r, binary.LittleEndian, &table.PSPCookie, &totalLength); err != nil {
122125
return nil, 0, err
123126
}
124127
if table.PSPCookie != PSPDirectoryTableCookie && table.PSPCookie != PSPDirectoryTableLevel2Cookie {
125128
return nil, 0, fmt.Errorf("incorrect cookie: %d", table.PSPCookie)
126129
}
127-
128130
if err := readAndCountSize(r, binary.LittleEndian, &table.Checksum, &totalLength); err != nil {
129131
return nil, 0, err
130132
}
@@ -135,6 +137,11 @@ func ParsePSPDirectoryTable(r io.Reader) (*PSPDirectoryTable, uint64, error) {
135137
return nil, 0, err
136138
}
137139

140+
sizeRequired := uint64(table.TotalEntries) * PSPDirectoryTableEntrySize
141+
if uint64(r.Len()) < sizeRequired {
142+
return nil, 0, fmt.Errorf("not enough data, required: %d, actual: %d", sizeRequired+totalLength, len(data))
143+
}
144+
138145
for idx := uint32(0); idx < table.TotalEntries; idx++ {
139146
entry, length, err := ParsePSPDirectoryTableEntry(r)
140147
if err != nil {

pkg/amd/manifest/psp_directory_table_test.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
package manifest
66

77
import (
8-
"bytes"
98
"encoding/binary"
109
"testing"
1110
)
@@ -64,7 +63,7 @@ func TestFindPSPDirectoryTable(t *testing.T) {
6463
}
6564

6665
func TestPspDirectoryTableParsing(t *testing.T) {
67-
table, length, err := ParsePSPDirectoryTable(bytes.NewBuffer(append(pspDirectoryTableDataChunk, 0xff)))
66+
table, length, err := ParsePSPDirectoryTable(append(pspDirectoryTableDataChunk, 0xff))
6867
if err != nil {
6968
t.Fatalf("Failed to parse PSP Directory table, err: %v", err)
7069
}
@@ -95,3 +94,19 @@ func TestPspDirectoryTableParsing(t *testing.T) {
9594
t.Errorf("Table entry [0] location is incorrect: %d, expected: 0x62400", table.Entries[0].LocationOrValue)
9695
}
9796
}
97+
98+
func TestBrokenTotalEntriesPspDirectoryParsing(t *testing.T) {
99+
pspDirectoryTableData := make([]byte, len(pspDirectoryTableDataChunk))
100+
copy(pspDirectoryTableData, pspDirectoryTableDataChunk)
101+
102+
// 8 is offset of TotalEntries field
103+
pspDirectoryTableData[8] = 0xff
104+
pspDirectoryTableData[9] = 0xff
105+
pspDirectoryTableData[10] = 0xff
106+
pspDirectoryTableData[11] = 0xff
107+
108+
_, _, err := ParsePSPDirectoryTable(pspDirectoryTableData)
109+
if err == nil {
110+
t.Errorf("expected error when parsing incorrect psp directory table contents")
111+
}
112+
}

0 commit comments

Comments
 (0)