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 }