github.com/linuxboot/fiano@v1.2.0/pkg/uefi/nvram_test.go (about)

     1  // Copyright 2019 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 uefi
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/hex"
    10  	"testing"
    11  
    12  	"github.com/linuxboot/fiano/pkg/guid"
    13  )
    14  
    15  func TestNVarAttribute_IsValid(t *testing.T) {
    16  	var tests = []struct {
    17  		name string
    18  		attr NVarAttribute
    19  		res  bool
    20  	}{
    21  		{"zero", NVarAttribute(0), false},
    22  		{"validOnly", NVarEntryValid, true},
    23  		{"NotValid", NVarEntryValid ^ 0xff, false},
    24  		{"ff", NVarAttribute(0xff), true},
    25  	}
    26  	for _, test := range tests {
    27  		t.Run(test.name, func(t *testing.T) {
    28  			if res := test.attr.IsValid(); res != test.res {
    29  				t.Errorf("IsValid wrong result!, input was %#x, wanted %v, got %v", test.attr, test.res, res)
    30  			}
    31  		})
    32  	}
    33  }
    34  
    35  var (
    36  	// Small buffs to reuse
    37  	emptyNVarBuf       = []byte{}
    38  	erasedSmallNVarBuf = []byte{0xFF, 0xFF, 0xFF, 0xFF}
    39  	zeroed16NVarBuf    = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
    40  	erased16NVarBuf    = []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
    41  	signatureNVarBuf   = []byte{0x4E, 0x56, 0x41, 0x52}
    42  	noNextNVarBuf      = []byte{0xFF, 0xFF, 0xFF}
    43  )
    44  var (
    45  	// Header & NVar Tests
    46  	headerOnlyEmptyNVar      = append(append(append(signatureNVarBuf[:], []byte{10, 0}...), noNextNVarBuf...), byte(NVarEntryValid|NVarEntryDataOnly))
    47  	badIncompleteNVar        = append(append(append(signatureNVarBuf[:], []byte{11, 0}...), noNextNVarBuf...), byte(NVarEntryValid|NVarEntryDataOnly))
    48  	invalidNVar              = append(append(append(signatureNVarBuf[:], []byte{10, 0}...), noNextNVarBuf...), byte(0))
    49  	badMissingGUIDNVar       = append(append(append(signatureNVarBuf[:], []byte{10, 0}...), noNextNVarBuf...), byte(NVarEntryValid|NVarEntryASCIIName))
    50  	badMissingNameEndNVAR    = append(append(append(signatureNVarBuf[:], []byte{15, 0}...), noNextNVarBuf...), []byte{byte(NVarEntryValid | NVarEntryASCIIName), 0, byte('T'), byte('e'), byte('s'), byte('t')}...)
    51  	stored0GUIDASCIINameNVar = append(append(append(signatureNVarBuf[:], []byte{16, 0}...), noNextNVarBuf...), []byte{byte(NVarEntryValid | NVarEntryASCIIName), 0, byte('T'), byte('e'), byte('s'), byte('t'), 0}...)
    52  	stored1GUIDASCIINameNVar = append(append(append(signatureNVarBuf[:], []byte{16, 0}...), noNextNVarBuf...), []byte{byte(NVarEntryValid | NVarEntryASCIIName), 1, byte('T'), byte('e'), byte('s'), byte('t'), 0}...)
    53  )
    54  var (
    55  	testNVarStore = append(append(headerOnlyEmptyNVar, stored0GUIDASCIINameNVar...), erased16NVarBuf...)
    56  )
    57  
    58  func TestNVar_parseHeader(t *testing.T) {
    59  	var tests = []struct {
    60  		name string
    61  		buf  []byte
    62  		msg  string
    63  	}{
    64  		{"emptyNVarBuf", emptyNVarBuf, "EOF"},
    65  		{"erasedSmallNVarBuf", erasedSmallNVarBuf, "unexpected EOF"},
    66  		{"erased16NVarBuf", erased16NVarBuf, "NVAR Signature not found"},
    67  		{"badIncompleteNVar", badIncompleteNVar, "NVAR Size bigger than remaining size"},
    68  		{"goodEmptyNVar", headerOnlyEmptyNVar, ""},
    69  	}
    70  	for _, test := range tests {
    71  		t.Run(test.name, func(t *testing.T) {
    72  			var v NVar
    73  			err := v.parseHeader(test.buf)
    74  			if err == nil && test.msg != "" {
    75  				t.Errorf("Error was not returned, expected %v", test.msg)
    76  			} else if err != nil && err.Error() != test.msg {
    77  				t.Errorf("Mismatched Error returned, expected \n%v\n got \n%v\n", test.msg, err.Error())
    78  			} else if err == nil && v.DataOffset != 10 {
    79  				t.Errorf("Invalid DataOffset, expected 10 got %v", v.DataOffset)
    80  			}
    81  		})
    82  	}
    83  }
    84  
    85  const NoNVarEntry NVarEntryType = 0xFF
    86  
    87  func TestNewNVar_noStore(t *testing.T) {
    88  	var tests = []struct {
    89  		name       string
    90  		buf        []byte
    91  		msg        string
    92  		t          NVarEntryType
    93  		DataOffset int64
    94  	}{
    95  		{"emptyNVarBuf", emptyNVarBuf, "", NoNVarEntry, 0},
    96  		{"erasedSmallNVarBuf", erasedSmallNVarBuf, "", NoNVarEntry, 0},
    97  		{"erased16NVarBuf", erased16NVarBuf, "", NoNVarEntry, 0},
    98  		{"badIncompleteNVar", badIncompleteNVar, "NVAR Size bigger than remaining size", InvalidNVarEntry, 10},
    99  		{"goodEmptyNVar", headerOnlyEmptyNVar, "", InvalidLinkNVarEntry, 10},
   100  		{"invalidNVar", invalidNVar, "", InvalidNVarEntry, 10},
   101  	}
   102  	for _, test := range tests {
   103  		t.Run(test.name, func(t *testing.T) {
   104  			var s NVarStore
   105  			Attributes.ErasePolarity = 0xFF
   106  			v, err := newNVar(test.buf, 0, &s)
   107  			if err == nil && test.msg != "" {
   108  				t.Errorf("Error was not returned, expected %v", test.msg)
   109  			} else if err != nil && err.Error() != test.msg {
   110  				t.Errorf("Mismatched Error returned, expected \n%v\n got \n%v\n", test.msg, err.Error())
   111  			} else if err != nil {
   112  				// expected error
   113  				return
   114  			}
   115  			if test.t == NoNVarEntry {
   116  				if v != nil {
   117  					t.Errorf("No NVar expected got \n%v\n", v)
   118  
   119  				}
   120  				return
   121  			} else if v == nil {
   122  				t.Error("No NVar returned")
   123  				return
   124  
   125  			}
   126  
   127  			if v.Type != test.t {
   128  				t.Errorf("Invalid Type, expected %v got %v", test.t, v.Type)
   129  			}
   130  			if v.DataOffset != test.DataOffset {
   131  				t.Errorf("Invalid DataOffset, expected %v got %v", test.DataOffset, v.DataOffset)
   132  			}
   133  		})
   134  	}
   135  }
   136  
   137  func TestNewNVar_ErasePolarity(t *testing.T) {
   138  	var tests = []struct {
   139  		name string
   140  		ep   byte
   141  		msg  string
   142  	}{
   143  		{"ErasePolarity", 0xF0, "erase polarity not 0x00 or 0xFF, got 0xf0"},
   144  		{"ErasePolarity", 0x00, ""},
   145  		{"ErasePolarity", 0xFF, ""},
   146  	}
   147  	for _, test := range tests {
   148  		t.Run(test.name, func(t *testing.T) {
   149  			var s NVarStore
   150  			Attributes.ErasePolarity = test.ep
   151  			v, err := newNVar(headerOnlyEmptyNVar, 0, &s)
   152  			if err == nil && test.msg != "" {
   153  				t.Errorf("Error was not returned, expected %v", test.msg)
   154  			} else if err != nil && err.Error() != test.msg {
   155  				t.Errorf("Mismatched Error returned, expected \n%v\n got \n%v\n", test.msg, err.Error())
   156  			} else if err == nil && v == nil {
   157  				t.Error("No NVar returned")
   158  			}
   159  		})
   160  	}
   161  }
   162  
   163  func TestNewNVar_Store(t *testing.T) {
   164  	var tests = []struct {
   165  		name       string
   166  		offset     uint64
   167  		buf        []byte
   168  		msg        string
   169  		t          NVarEntryType
   170  		DataOffset int64
   171  		GUID       *guid.GUID
   172  		Name       string
   173  	}{
   174  		{"goodEmptyNVar", 123, headerOnlyEmptyNVar, "", DataNVarEntry, 10, guid.MustParse("2df19db9-a1b4-4b02-b4bb-5ddb4866e13f"), "Stored"},
   175  		{"badMissingGUIDNVar", 0, badMissingGUIDNVar, "EOF", FullNVarEntry, 16, nil, ""},
   176  		{"badMissingNameEndNVAR", 0, badMissingNameEndNVAR, "EOF", FullNVarEntry, 15, nil, ""},
   177  		{"stored0GUIDASCIINameNVar", 0, stored0GUIDASCIINameNVar, "", FullNVarEntry, 16, FFGUID, "Test"},
   178  		{"stored1GUIDASCIINameNVar", 0, stored1GUIDASCIINameNVar, "", FullNVarEntry, 16, ZeroGUID, "Test"},
   179  	}
   180  	for _, test := range tests {
   181  		t.Run(test.name, func(t *testing.T) {
   182  			storedVar := NVar{GUID: *guid.MustParse("2df19db9-a1b4-4b02-b4bb-5ddb4866e13f"), Name: "Stored", Type: LinkNVarEntry, NextOffset: 123}
   183  			invalidVar := NVar{Type: InvalidNVarEntry}
   184  			s := NVarStore{buf: erased16NVarBuf}
   185  			s.Entries = append(s.Entries, &invalidVar, &storedVar)
   186  			Attributes.ErasePolarity = 0xFF
   187  			v, err := newNVar(test.buf, test.offset, &s)
   188  			if err == nil && test.msg != "" {
   189  				t.Errorf("Error was not returned, expected %v", test.msg)
   190  			} else if err != nil && err.Error() != test.msg {
   191  				t.Errorf("Mismatched Error returned, expected \n%v\n got \n%v\n", test.msg, err.Error())
   192  			} else if err != nil {
   193  				// expected error
   194  				return
   195  			}
   196  			if test.t == NoNVarEntry {
   197  				if v != nil {
   198  					t.Errorf("No NVar expected got \n%v\n", v)
   199  
   200  				}
   201  				return
   202  			} else if v == nil {
   203  				t.Error("No NVar returned")
   204  				return
   205  
   206  			}
   207  
   208  			if v.Type != test.t {
   209  				t.Errorf("Invalid Type, expected %v got %v", test.t, v.Type)
   210  			}
   211  			if v.DataOffset != test.DataOffset {
   212  				t.Errorf("Invalid DataOffset, expected %v got %v", test.DataOffset, v.DataOffset)
   213  			}
   214  			if test.GUID != nil && v.GUID != *test.GUID {
   215  				t.Errorf("Invalid GUID, expected %v got %v", *test.GUID, v.GUID)
   216  			}
   217  			if v.Name != test.Name {
   218  				t.Errorf("Invalid Name, expected %v got %v", test.Name, v.Name)
   219  			}
   220  		})
   221  	}
   222  }
   223  
   224  func TestNVar_parseContent(t *testing.T) {
   225  	var tests = []struct {
   226  		name string
   227  		buf  []byte
   228  		msg  string
   229  	}{
   230  		{"emptyNVarBuf", emptyNVarBuf, "EOF"},
   231  		{"tooSmallNVarBuf", noNextNVarBuf, "unexpected EOF"},
   232  		{"erasedSmallNVarBuf", erasedSmallNVarBuf, "NVAR Signature not found"},
   233  		{"badIncompleteNVar", badIncompleteNVar, "error parsing NVAR store in var StoreInVar: error parsing NVAR entry at offset 0x0: NVAR Size bigger than remaining size"},
   234  		{"goodEmptyNVar", headerOnlyEmptyNVar, ""},
   235  	}
   236  	for _, test := range tests {
   237  		t.Run(test.name, func(t *testing.T) {
   238  			v := NVar{Name: "StoreInVar"}
   239  			Attributes.ErasePolarity = 0xFF
   240  			err := v.parseContent(test.buf)
   241  			if err == nil && test.msg != "" {
   242  				t.Errorf("Error was not returned, expected %v", test.msg)
   243  			} else if err != nil && err.Error() != test.msg {
   244  				t.Errorf("Mismatched Error returned, expected \n%v\n got \n%v\n", test.msg, err.Error())
   245  			} else if err == nil && v.NVarStore == nil {
   246  				t.Errorf("No NVarStore parsed, got nil")
   247  			}
   248  		})
   249  	}
   250  }
   251  
   252  func TestNVar_NewNVarStore(t *testing.T) {
   253  	var tests = []struct {
   254  		name  string
   255  		buf   []byte
   256  		msg   string
   257  		count int
   258  	}{
   259  		{"emptyNVarBuf", emptyNVarBuf, "", 0},
   260  		{"tooSmallNVarBuf", noNextNVarBuf, "", 0},
   261  		{"erasedSmallNVarBuf", erasedSmallNVarBuf, "", 0},
   262  		{"erased16NVarBuf", erased16NVarBuf, "", 0},
   263  		{"badIncompleteNVar", badIncompleteNVar, "error parsing NVAR entry at offset 0x0: NVAR Size bigger than remaining size", 0},
   264  		{"goodEmptyNVar", headerOnlyEmptyNVar, "", 1},
   265  		{"testNVarStore", testNVarStore, "", 2},
   266  	}
   267  	for _, test := range tests {
   268  		t.Run(test.name, func(t *testing.T) {
   269  			Attributes.ErasePolarity = 0xFF
   270  			s, err := NewNVarStore(test.buf)
   271  			if err == nil && test.msg != "" {
   272  				t.Errorf("Error was not returned, expected %v", test.msg)
   273  			} else if err != nil && err.Error() != test.msg {
   274  				t.Errorf("Mismatched Error returned, expected \n%v\n got \n%v\n", test.msg, err.Error())
   275  			} else if err == nil && len(s.Entries) != test.count {
   276  				t.Errorf("Wrong number of NVar found, expected %v got %v", test.count, len(s.Entries))
   277  			}
   278  		})
   279  	}
   280  }
   281  
   282  func TestNVar_Assemble(t *testing.T) {
   283  	var stored1GUIDIndex = uint8(1)
   284  	var tests = []struct {
   285  		name      string
   286  		nvar      NVar
   287  		buf       []byte
   288  		checkOnly bool
   289  		msg       string
   290  	}{
   291  		{"Invalid", NVar{}, []byte{}, true, "unable to construct Invalid NVAR"},
   292  		{"badLinkUpdate", NVar{Type: LinkNVarEntry, NextOffset: 1}, []byte{}, false, "unable to update data in link, use compact first"},
   293  		{"badHeaderSize", NVar{Type: DataNVarEntry, Header: NVarHeader{Attributes: NVarEntryValid | NVarEntryDataOnly}}, headerOnlyEmptyNVar, true, "NVAR header size mismatch, expected 0 got 10"},
   294  		{"badSize", NVar{Type: DataNVarEntry, Header: NVarHeader{Attributes: NVarEntryValid | NVarEntryDataOnly}, DataOffset: 10}, headerOnlyEmptyNVar, true, "NVAR size mismatch, expected 0 got 10"},
   295  		{"goodEmpty", NVar{Type: DataNVarEntry, Header: NVarHeader{Size: 10, Attributes: NVarEntryValid | NVarEntryDataOnly}, DataOffset: 10}, headerOnlyEmptyNVar, true, ""},
   296  		{"goodEmptyUpdate", NVar{Type: DataNVarEntry, Header: NVarHeader{Size: 10, Attributes: NVarEntryValid | NVarEntryDataOnly}, DataOffset: 10}, headerOnlyEmptyNVar, false, ""},
   297  		{"badMissingName", NVar{Type: DataNVarEntry, Header: NVarHeader{Size: 16, Attributes: NVarEntryValid | NVarEntryASCIIName}, DataOffset: 16, GUIDIndex: &stored1GUIDIndex}, stored1GUIDASCIINameNVar, true, "NVAR header size mismatch, expected 16 got 12"},
   298  		{"good1GUIDASCIINameNVar", NVar{Type: DataNVarEntry, Header: NVarHeader{Size: 16, Attributes: NVarEntryValid | NVarEntryASCIIName}, Name: "Test", DataOffset: 16, GUIDIndex: &stored1GUIDIndex}, stored1GUIDASCIINameNVar, true, ""},
   299  	}
   300  	for _, test := range tests {
   301  		t.Run(test.name, func(t *testing.T) {
   302  			v := test.nvar
   303  			err := v.Assemble(test.buf[v.DataOffset:], test.checkOnly)
   304  			if err == nil && test.msg != "" {
   305  				t.Errorf("Error was not returned, expected %v", test.msg)
   306  			} else if err != nil && err.Error() != test.msg {
   307  				t.Errorf("Mismatched Error returned, expected \n%v\n got \n%v\n", test.msg, err.Error())
   308  			} else if err != nil {
   309  				// expected error
   310  				return
   311  			}
   312  			if !bytes.Equal(test.buf, v.Buf()) {
   313  				t.Errorf("Bad assembled variable content, expected \n%v\n got \n%v\n", hex.Dump(test.buf), hex.Dump(v.Buf()))
   314  			}
   315  
   316  		})
   317  	}
   318  }
   319  
   320  func TestNVarStore_GetGUIDStoreBuf(t *testing.T) {
   321  	var tests = []struct {
   322  		name      string
   323  		GUIDStore []guid.GUID
   324  		buf       []byte
   325  		msg       string
   326  	}{
   327  		{"empty", []guid.GUID{}, []byte{}, ""},
   328  		{"1GUID", []guid.GUID{*FFGUID}, erased16NVarBuf, ""},
   329  		{"2GUID", []guid.GUID{*FFGUID, *ZeroGUID}, append(zeroed16NVarBuf, erased16NVarBuf...), ""},
   330  	}
   331  	for _, test := range tests {
   332  		t.Run(test.name, func(t *testing.T) {
   333  			var s NVarStore
   334  			s.GUIDStore = test.GUIDStore
   335  			buf, err := s.GetGUIDStoreBuf()
   336  			if err == nil && test.msg != "" {
   337  				t.Errorf("Error was not returned, expected %v", test.msg)
   338  			} else if err != nil && err.Error() != test.msg {
   339  				t.Errorf("Mismatched Error returned, expected \n%v\n got \n%v\n", test.msg, err.Error())
   340  			} else if err != nil {
   341  				// expected error
   342  				return
   343  			}
   344  			if !bytes.Equal(test.buf, buf) {
   345  				t.Errorf("Bad assembled GUID store content, expected \n%v\n got \n%v\n", hex.Dump(test.buf), hex.Dump(buf))
   346  			}
   347  
   348  		})
   349  	}
   350  }