diff --git a/pkg/uefi/meregion.go b/pkg/uefi/meregion.go index dae07ef6..9fdb6923 100644 --- a/pkg/uefi/meregion.go +++ b/pkg/uefi/meregion.go @@ -7,7 +7,6 @@ package uefi import ( "bytes" "encoding/binary" - "encoding/hex" "fmt" "github.com/linuxboot/fiano/pkg/log" @@ -16,12 +15,18 @@ import ( // ME Partition parsing, the goal is to spot a padding in the ME Region // after the ME partitions so that this region can be shrunk in the IFD. // -// ME partition informations from http://me.bios.io/ME_blob_format - -// MEFTPSignature is the sequence of bytes that an ME Flash Partition +// Information taken from multiple sources: +// https://web.archive.org/web/20200523203129/https://me.bios.io/ME_blob_format +// https://github.com/platomav/MEAnalyzer/ +// https://fahrplan.events.ccc.de/congress/2017/Fahrplan/system/event_attachments/attachments/000/003/391/original/Intel_ME_myths_and_reality.pdf +// https://github.com/corna/me_cleaner/wiki/How-does-it-work%3F +// https://github.com/mostav02/Remove_IntelME_FPT +// https://io.netgarage.org/me/ + +// MEFPTSignature is the sequence of bytes that an ME Flash Partition // Table is expected to start with ie "$FPT". var ( - MEFTPSignature = []byte{0x24, 0x46, 0x50, 0x54} + MEFPTSignature = []byte{0x24, 0x46, 0x50, 0x54} ) const ( @@ -93,17 +98,17 @@ func (e MEPartitionEntry) Type() string { return fmt.Sprintf("Unknown (%d)", t) } -// FindMEDescriptor searches for an Intel ME FTP signature +// FindMEDescriptor searches for an Intel ME FPT signature func FindMEDescriptor(buf []byte) (int, error) { - if bytes.Equal(buf[16:16+len(MEFTPSignature)], MEFTPSignature) { - // 16 + 4 since the descriptor starts after the signature - return 16 + len(MEFTPSignature), nil - } - if bytes.Equal(buf[:len(MEFTPSignature)], MEFTPSignature) { - // + 4 since the descriptor starts after the signature - return len(MEFTPSignature), nil + // In some images, the signature may occur right at the start, + // in others, it occurs in the second 16 bytes, and + // in some cases, it appears somewhere else in the ME region. + // NOTE: This library excludes the signature from the descriptor. + fptOffset := bytes.Index(buf, MEFPTSignature) + if fptOffset >= 0 { + return fptOffset + len(MEFPTSignature), nil } - return -1, fmt.Errorf("ME Flash Partition Table signature %#02x not found: first 20 bytes are:\n%s", MEFTPSignature, hex.Dump(buf[:20])) + return -1, fmt.Errorf("ME Flash Partition Table signature %#02x not found", MEFPTSignature) } // Buf returns the buffer. diff --git a/pkg/uefi/meregion_test.go b/pkg/uefi/meregion_test.go index 4b4c4115..3b989814 100644 --- a/pkg/uefi/meregion_test.go +++ b/pkg/uefi/meregion_test.go @@ -59,3 +59,35 @@ func TestMEName_UnmarshalText(t *testing.T) { }) } } + +func TestFindFPTSignature(t *testing.T) { + var empty16 = make([]byte, 16) + var empty12 = make([]byte, 12) + var empty = make([]byte, 128) + + var firstRow = append(MEFPTSignature, empty12...) + var secondRow = append(empty16, firstRow...) + var elsewhere = append(empty, firstRow...) + + var tests = []struct { + name string + blob []byte + res int + }{ + {"beginning", firstRow, 4}, + {"2nd row", secondRow, 20}, + {"elsewhere", elsewhere, 132}, + {"nowhere", empty, -1}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + r, e := FindMEDescriptor(test.blob) + if r != test.res { + t.Errorf("got position %d want %d (%q)", r, test.res, e) + } + if test.res == -1 && e == nil { + t.Errorf("expected error") + } + }) + } +}