github.com/linuxboot/fiano@v1.2.0/pkg/visitors/extract_test.go (about) 1 // Copyright 2018 the LinuxBoot 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 visitors 6 7 import ( 8 "os" 9 "testing" 10 11 "github.com/linuxboot/fiano/pkg/log" 12 "github.com/linuxboot/fiano/pkg/uefi" 13 ) 14 15 var ( 16 // FV examples 17 sampleFV []byte // Sample FV from OVMF 18 ) 19 20 func init() { 21 var err error 22 sampleFV, err = os.ReadFile("../../integration/roms/ovmfSECFV.fv") 23 if err != nil { 24 log.Fatalf("%v", err) 25 } 26 } 27 28 var ( 29 // File headers 30 // Hardcoded checksums for testing :( 31 // I don't know how to do it better without rewriting or calling code under test. 32 emptyPadHeader = append(uefi.FFGUID[:], 33 []byte{8, uefi.EmptyBodyChecksum, byte(uefi.FVFileTypePad), 0, uefi.FileHeaderMinLength, 0x00, 0x00, 0xF8}...) // Empty pad file header with no data 34 goodFreeFormHeader = append(uefi.FFGUID[:], 35 []byte{202, uefi.EmptyBodyChecksum, byte(uefi.FVFileTypeFreeForm), 0, uefi.FileHeaderMinLength, 0x00, 0x00, 0xF8}...) // Empty freeform file header with no data 36 nvarStoreHeader = append(uefi.NVAR[:], 37 []byte{182, uefi.EmptyBodyChecksum, byte(uefi.FVFileTypeRaw), 0, uefi.FileHeaderMinLength, 0x00, 0x00, 0xF8}...) // Empty NVAR file header with no data 38 ) 39 40 var ( 41 // File examples 42 emptyPadFile = emptyPadHeader // Empty pad file with no data 43 badFreeFormFile []byte // File with bad checksum. Should construct fine, but not validate 44 goodFreeFormFile []byte // Good file 45 nvarStoreFile []byte // File containing an NVarStore 46 ) 47 48 func init() { 49 goodFreeFormFile = append(goodFreeFormHeader, linuxSec...) 50 goodFreeFormFile = append(goodFreeFormFile, smallSec...) 51 goodFreeFormFile = append(goodFreeFormFile, []byte{0, 0}...) // Alignment 52 goodFreeFormFile = append(goodFreeFormFile, tinySec...) 53 goodFreeFormFile[20] = byte(uefi.FileHeaderMinLength + len(tinySec) + 2 + len(linuxSec) + len(smallSec)) 54 55 badFreeFormFile = make([]byte, len(goodFreeFormFile)) 56 copy(badFreeFormFile, goodFreeFormFile) 57 badFreeFormFile[16] = 0 // Zero out checksum 58 59 nvarStoreFile = append(nvarStoreHeader, nvarEntryHeader...) 60 nvarStoreFile = append(nvarStoreFile, byte(0)) 61 nvarStoreFile = append(nvarStoreFile, []byte("Test")...) 62 nvarStoreFile = append(nvarStoreFile, byte(0)) 63 nvarStoreFile = append(nvarStoreFile, uefi.FFGUID[:]...) 64 nvarStoreFile[20] = byte(uefi.FileHeaderMinLength + len(nvarEntryHeader) + 6 + len(uefi.FFGUID)) 65 66 } 67 68 var ( 69 // NVAR examples 70 nvarEntryHeader = []byte{0x4E, 0x56, 0x41, 0x52, 16, 0, 0xFF, 0xFF, 0xFF, byte(uefi.NVarEntryValid | uefi.NVarEntryASCIIName)} 71 ) 72 73 var ( 74 // Section examples 75 tinySec = []byte{4, 0, 0, byte(uefi.SectionTypeRaw)} // Section header with no data 76 smallSec = append([]byte{22, 0, 0, byte(uefi.SectionTypeRaw)}, make([]byte, 18)...) // 20 byte Section 77 linuxSec = []byte{0x10, 0x00, 0x00, 0x15, 0x4c, 0x00, 0x69, 0x00, 78 0x6e, 0x00, 0x75, 0x00, 0x78, 0x00, 0x00, 0x00} // Linux UI section 79 ) 80 81 func TestExtractAssembleFile(t *testing.T) { 82 var tests = []struct { 83 name string 84 origBuf []byte 85 newBuf []byte 86 }{ 87 {"emptyPadFile", emptyPadFile, emptyPadFile}, 88 {"badFreeFormFile", badFreeFormFile, goodFreeFormFile}, 89 {"goodFreeFormFile", goodFreeFormFile, goodFreeFormFile}, 90 {"nvarStoreFile", nvarStoreFile, nvarStoreFile}, 91 } 92 // Set erasepolarity to FF 93 uefi.Attributes.ErasePolarity = 0xFF 94 for _, test := range tests { 95 t.Run(test.name, func(t *testing.T) { 96 tmpDir, err := os.MkdirTemp("", "section-test") 97 98 if err != nil { 99 t.Fatalf("could not create temp dir: %v", err) 100 } 101 defer os.RemoveAll(tmpDir) 102 103 f, err := uefi.NewFile(test.origBuf) 104 if err != nil { 105 t.Fatalf("Unable to parse file object %v, got %v", test.origBuf, err.Error()) 106 } 107 var fIndex uint64 108 if err = f.Apply(&Extract{BasePath: tmpDir, DirPath: ".", Index: &fIndex}); err != nil { 109 t.Fatalf("Unable to extract file %v, got %v", test.origBuf, err.Error()) 110 } 111 if err = f.Apply(&ParseDir{BasePath: tmpDir}); err != nil { 112 t.Fatalf("Unable to parse files %v, got %v", test.origBuf, err.Error()) 113 } 114 if err = f.Apply(&Assemble{}); err != nil { 115 t.Fatalf("Unable to reassemble file %v, got %v", test.origBuf, err.Error()) 116 } 117 nb := f.Buf() 118 if len(test.newBuf) != len(nb) { 119 t.Fatalf("Binary sizes differ!\n Expected: %v\n Assembled: %v\n", len(test.newBuf), len(nb)) 120 } 121 for i := range test.newBuf { 122 if test.newBuf[i] != nb[i] { 123 t.Fatalf("Binaries differ at %v!\n Expected: %v\n Assembled: %v\n", i, test.newBuf[i], nb[i]) 124 } 125 } 126 }) 127 } 128 } 129 130 func TestExtractAssembleFV(t *testing.T) { 131 var tests = []struct { 132 name string 133 origBuf []byte 134 newBuf []byte 135 }{ 136 {"sampleFV", sampleFV, sampleFV}, 137 } 138 // Set erasepolarity to FF 139 uefi.Attributes.ErasePolarity = 0xFF 140 for _, test := range tests { 141 t.Run(test.name, func(t *testing.T) { 142 tmpDir, err := os.MkdirTemp("", "section-test") 143 144 if err != nil { 145 t.Fatalf("could not create temp dir: %v", err) 146 } 147 defer os.RemoveAll(tmpDir) 148 149 fv, err := uefi.NewFirmwareVolume(test.origBuf, 0, false) 150 if err != nil { 151 t.Fatalf("Unable to parse file object %v, got %v", test.origBuf, err.Error()) 152 } 153 var fIndex uint64 154 if err = fv.Apply(&Extract{BasePath: tmpDir, DirPath: ".", Index: &fIndex}); err != nil { 155 t.Fatalf("Unable to extract file %v, got %v", test.origBuf, err.Error()) 156 } 157 if err = fv.Apply(&ParseDir{BasePath: tmpDir}); err != nil { 158 t.Fatalf("Unable to parse files %v, got %v", test.origBuf, err.Error()) 159 } 160 if err = fv.Apply(&Assemble{}); err != nil { 161 t.Fatalf("Unable to reassemble file %v, got %v", test.origBuf, err.Error()) 162 } 163 nb := fv.Buf() 164 if len(test.newBuf) != len(nb) { 165 t.Fatalf("Binary sizes differ!\n Expected: %v\n Assembled: %v\n", len(test.newBuf), len(nb)) 166 } 167 for i := range test.newBuf { 168 if test.newBuf[i] != nb[i] { 169 t.Fatalf("Binaries differ at %v!\n Expected: %v\n Assembled: %v\n", i, test.newBuf[i], nb[i]) 170 } 171 } 172 }) 173 } 174 } 175 176 func TestExtractAssembleSection(t *testing.T) { 177 var tests = []struct { 178 name string 179 buf []byte 180 fileOrder int 181 }{ 182 {"tinySec", tinySec, 0}, 183 {"tinySec", tinySec, 1}, 184 {"smallSec", smallSec, 0}, 185 {"smallSec", smallSec, 1}, 186 {"linuxSec", linuxSec, 0}, 187 {"linuxSec", linuxSec, 1}, 188 } 189 for _, test := range tests { 190 t.Run(test.name, func(t *testing.T) { 191 tmpDir, err := os.MkdirTemp("", "section-test") 192 193 if err != nil { 194 t.Fatalf("could not create temp dir: %v", err) 195 } 196 defer os.RemoveAll(tmpDir) 197 198 s, err := uefi.NewSection(test.buf, test.fileOrder) 199 if err != nil { 200 t.Fatalf("Unable to parse section object %v, got %v", test.buf, err.Error()) 201 } 202 var fIndex uint64 203 if err = s.Apply(&Extract{BasePath: tmpDir, DirPath: ".", Index: &fIndex}); err != nil { 204 t.Fatalf("Unable to extract section %v, got %v", test.buf, err.Error()) 205 } 206 if err = s.Apply(&ParseDir{BasePath: tmpDir}); err != nil { 207 t.Fatalf("Unable to parse files %v, got %v", test.buf, err.Error()) 208 } 209 if err = s.Apply(&Assemble{}); err != nil { 210 t.Fatalf("Unable to reassemble file %v, got %v", test.buf, err.Error()) 211 } 212 nb := s.Buf() 213 if len(test.buf) != len(nb) { 214 t.Fatalf("Binary sizes differ!\n Expected: %v\n Assembled: %v\n", len(test.buf), len(nb)) 215 } 216 for i := range test.buf { 217 if test.buf[i] != nb[i] { 218 t.Fatalf("Binaries differ at %v!\n Expected: %v\n Assembled: %v\n", i, test.buf[i], nb[i]) 219 } 220 } 221 }) 222 } 223 }