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  }