github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/boot/uefi/fv.go (about) 1 // Copyright 2021 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package uefi 6 7 import ( 8 "bytes" 9 "encoding/binary" 10 "fmt" 11 ) 12 13 // These headers are coming from EDK2 14 // MdePkg/Include/Pi/PiFirmwareVolume.h 15 // MdePkg/Include/Pi/PiFirmwareFile.h 16 17 type EFIFirmwareVolumeHeader struct { 18 ZeroVector [16]uint8 19 FileSystemGUID [16]uint8 20 FvLength uint64 21 Signature [4]uint8 22 Attributes uint32 23 HeaderLength uint16 24 Checksum uint16 25 ExtHeaderOffset uint16 26 Reserved uint8 27 Revision uint8 28 } 29 30 type EFIFFSFileHeader struct { 31 Name [16]uint8 32 HeaderChecksum uint8 33 FileChecksum uint8 34 Type uint8 35 Attributes uint8 36 Size [3]uint8 37 State uint8 38 } 39 40 const ( 41 EFIFFSAttribLargeFile uint8 = 0x01 42 EFICommonSectionHeaderSize int = 4 43 EFICommonSectionHeader2Size int = 8 44 EFIFFSFileHeaderSize int = 24 45 EFIFFSFileHeader2Size int = 32 46 ) 47 48 const ( 49 EFISectionTypePE32 uint8 = 0x10 50 EFISectionTypeFVImage uint8 = 0x17 51 ) 52 53 const ( 54 EFIFVFileTypeSecurityCore = 0x03 55 EFIFVFileTypeFirmwareVolumeImage = 0x0b 56 ) 57 58 // UnmarshalBinary unmarshals the FiwmreareVolumeHeader from binary data. 59 func (e *EFIFirmwareVolumeHeader) UnmarshalBinary(data []byte) error { 60 if len(data) < 0x38 { 61 return fmt.Errorf("invalid entry point stucture length %d", len(data)) 62 } 63 if err := binary.Read(bytes.NewReader(data), binary.LittleEndian, e); err != nil { 64 return err 65 } 66 if !bytes.Equal(e.Signature[:], []byte("_FVH")) { 67 return fmt.Errorf("invalid Signature string %q", string(e.Signature[:])) 68 } 69 return nil 70 } 71 72 // UnmarshalBinary unmarshals the EFIFFSFileHeader from binary data. 73 func (e *EFIFFSFileHeader) UnmarshalBinary(data []byte) error { 74 if len(data) < EFIFFSFileHeaderSize { 75 return fmt.Errorf("invalid entry point stucture length %d", len(data)) 76 } 77 if err := binary.Read(bytes.NewReader(data), binary.LittleEndian, e); err != nil { 78 return err 79 } 80 return nil 81 } 82 83 // findSecurityCorePEEntry finds SEC PE entry in Firmware Volume 84 func findSecurityCorePEEntry(data []byte) (offset int, err error) { 85 var fvh EFIFirmwareVolumeHeader 86 var ffs EFIFFSFileHeader 87 if err = fvh.UnmarshalBinary(data); err != nil { 88 return 0, err 89 } 90 offset += int(fvh.HeaderLength) 91 for offset < int(fvh.FvLength) { 92 if err = ffs.UnmarshalBinary(data[offset:]); err != nil { 93 break 94 } 95 fs := int(ffs.Size[0]) + int(ffs.Size[1])<<8 + int(ffs.Size[2])<<16 96 large := ffs.Attributes&EFIFFSAttribLargeFile != 0 97 // file size should not be 0 98 if fs == 0 { 99 return 0, fmt.Errorf("file is corrupt") 100 } 101 switch ffs.Type { 102 case EFIFVFileTypeSecurityCore: 103 peo, err := findSectionInFFS(EFISectionTypePE32, data[offset:offset+fs], large) 104 if err == nil { 105 return offset + peo, nil 106 } 107 case EFIFVFileTypeFirmwareVolumeImage: 108 fvo, err := findSectionInFFS(EFISectionTypeFVImage, data[offset:offset+fs], large) 109 if err == nil { 110 offset2, err := findSecurityCorePEEntry(data[offset+fvo:]) 111 if err == nil { 112 return offset + fvo + offset2, nil 113 } 114 } 115 } 116 117 // next FFS needs to be aligned with 8 bytes. 118 if fs&7 != 0 { 119 fs &= ^7 120 fs += 8 121 } 122 offset += fs 123 } 124 return 0, fmt.Errorf("unable to find SEC ffs in this file") 125 } 126 127 // findSectionInFFS finds given first Given SectionType's entry in FFS 128 func findSectionInFFS(sectionType uint8, data []byte, isLargeFile bool) (cursor int, err error) { 129 fhs := EFIFFSFileHeaderSize 130 shs := EFICommonSectionHeaderSize 131 if isLargeFile { 132 fhs = EFIFFSFileHeader2Size 133 shs = EFICommonSectionHeader2Size 134 } 135 cursor += fhs 136 for cursor < len(data) { 137 if data[cursor+3] == sectionType { 138 return cursor + shs, nil 139 } 140 ss := int(data[cursor]) 141 ss += int(data[cursor+1]) << 8 142 ss += int(data[cursor+2]) << 16 143 if ss == 0 { 144 return 0, fmt.Errorf("unable to parse FFS") 145 } 146 cursor += ss 147 } 148 return cursor, fmt.Errorf("cannot find PE32 entry in FFS") 149 }