vboot_kernel_tests.c revision 2500185a83b453580f187087fffc6376f19f8ff0
1/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 * 5 * Tests for vboot_kernel.c 6 */ 7 8#include <stdint.h> 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12 13#include "cgptlib.h" 14#include "gbb_header.h" 15#include "gpt.h" 16#include "host_common.h" 17#include "load_kernel_fw.h" 18#include "test_common.h" 19#include "vboot_api.h" 20#include "vboot_common.h" 21#include "vboot_kernel.h" 22#include "vboot_nvstorage.h" 23 24#define LOGCALL(fmt, args...) sprintf(call_log + strlen(call_log), fmt, ##args) 25#define TEST_CALLS(expect_log) TEST_STR_EQ(call_log, expect_log, " calls") 26 27/* Mock kernel partition */ 28struct mock_part { 29 uint32_t start; 30 uint32_t size; 31}; 32 33/* Partition list; ends with a 0-size partition. */ 34#define MOCK_PART_COUNT 8 35static struct mock_part mock_parts[MOCK_PART_COUNT]; 36static int mock_part_next; 37 38/* Mock data */ 39static char call_log[4096]; 40static uint8_t kernel_buffer[80000]; 41static int disk_read_to_fail; 42static int disk_write_to_fail; 43static int gpt_init_fail; 44static int key_block_verify_fail; /* 0=ok, 1=sig, 2=hash */ 45static int preamble_verify_fail; 46static int verify_data_fail; 47static RSAPublicKey *mock_data_key; 48static int mock_data_key_allocated; 49 50static uint8_t gbb_data[sizeof(GoogleBinaryBlockHeader) + 2048]; 51static GoogleBinaryBlockHeader *gbb = (GoogleBinaryBlockHeader*)gbb_data; 52static VbExDiskHandle_t handle; 53static VbNvContext vnc; 54static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE]; 55static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data; 56static LoadKernelParams lkp; 57static VbKeyBlockHeader kbh; 58static VbKernelPreambleHeader kph; 59static VbCommonParams cparams; 60 61static void ResetCallLog(void) 62{ 63 *call_log = 0; 64} 65 66/** 67 * Reset mock data (for use before each test) 68 */ 69static void ResetMocks(void) 70{ 71 ResetCallLog(); 72 73 disk_read_to_fail = -1; 74 disk_write_to_fail = -1; 75 76 gpt_init_fail = 0; 77 key_block_verify_fail = 0; 78 preamble_verify_fail = 0; 79 verify_data_fail = 0; 80 81 mock_data_key = (RSAPublicKey *)"TestDataKey"; 82 mock_data_key_allocated = 0; 83 84 memset(gbb, 0, sizeof(*gbb)); 85 gbb->major_version = GBB_MAJOR_VER; 86 gbb->minor_version = GBB_MINOR_VER; 87 gbb->flags = 0; 88 89 memset(&cparams, '\0', sizeof(cparams)); 90 cparams.gbb = gbb; 91 cparams.gbb_data = gbb; 92 cparams.gbb_size = sizeof(gbb_data); 93 94 memset(&vnc, 0, sizeof(vnc)); 95 VbNvSetup(&vnc); 96 VbNvTeardown(&vnc); /* So CRC gets generated */ 97 98 memset(&shared_data, 0, sizeof(shared_data)); 99 VbSharedDataInit(shared, sizeof(shared_data)); 100 shared->kernel_version_tpm = 0x20001; 101 102 memset(&lkp, 0, sizeof(lkp)); 103 lkp.nv_context = &vnc; 104 lkp.shared_data_blob = shared; 105 lkp.gbb_data = gbb; 106 lkp.gbb_size = sizeof(gbb_data); 107 lkp.bytes_per_lba = 512; 108 lkp.ending_lba = 1023; 109 lkp.kernel_buffer = kernel_buffer; 110 lkp.kernel_buffer_size = sizeof(kernel_buffer); 111 112 memset(&kbh, 0, sizeof(kbh)); 113 kbh.data_key.key_version = 2; 114 kbh.key_block_flags = -1; 115 kbh.key_block_size = sizeof(kbh); 116 117 memset(&kph, 0, sizeof(kph)); 118 kph.kernel_version = 1; 119 kph.preamble_size = 4096 - kbh.key_block_size; 120 kph.body_signature.data_size = 70000; 121 kph.bootloader_address = 0xbeadd008; 122 kph.bootloader_size = 0x1234; 123 124 memset(mock_parts, 0, sizeof(mock_parts)); 125 mock_parts[0].start = 100; 126 mock_parts[0].size = 150; /* 75 KB */ 127 mock_part_next = 0; 128} 129 130/* Mocks */ 131 132VbError_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start, 133 uint64_t lba_count, void *buffer) 134{ 135 LOGCALL("VbExDiskRead(h, %d, %d)\n", (int)lba_start, (int)lba_count); 136 137 if ((int)lba_start == disk_read_to_fail) 138 return VBERROR_SIMULATED; 139 140 /* Keep valgrind happy */ 141 Memset(buffer, '\0', lba_count); 142 return VBERROR_SUCCESS; 143} 144 145VbError_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start, 146 uint64_t lba_count, const void *buffer) 147{ 148 LOGCALL("VbExDiskWrite(h, %d, %d)\n", (int)lba_start, (int)lba_count); 149 150 if ((int)lba_start == disk_write_to_fail) 151 return VBERROR_SIMULATED; 152 153 return VBERROR_SUCCESS; 154} 155 156int GptInit(GptData *gpt) 157{ 158 return gpt_init_fail; 159} 160 161int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size) 162{ 163 struct mock_part *p = mock_parts + mock_part_next; 164 165 if (!p->size) 166 return GPT_ERROR_NO_VALID_KERNEL; 167 168 gpt->current_kernel = mock_part_next; 169 *start_sector = p->start; 170 *size = p->size; 171 mock_part_next++; 172 return GPT_SUCCESS; 173} 174 175void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest) 176{ 177 static char fake_guid[] = "FakeGuid"; 178 179 memcpy(dest, fake_guid, sizeof(fake_guid)); 180} 181 182int KeyBlockVerify(const VbKeyBlockHeader *block, uint64_t size, 183 const VbPublicKey *key, int hash_only) { 184 185 if (hash_only && key_block_verify_fail >= 2) 186 return VBERROR_SIMULATED; 187 else if (!hash_only && key_block_verify_fail >= 1) 188 return VBERROR_SIMULATED; 189 190 /* Use this as an opportunity to override the key block */ 191 memcpy((void *)block, &kbh, sizeof(kbh)); 192 return VBERROR_SUCCESS; 193} 194 195RSAPublicKey *PublicKeyToRSA(const VbPublicKey *key) 196{ 197 TEST_EQ(mock_data_key_allocated, 0, " mock data key not allocated"); 198 199 if (mock_data_key) 200 mock_data_key_allocated++; 201 202 return mock_data_key; 203} 204 205void RSAPublicKeyFree(RSAPublicKey* key) 206{ 207 TEST_EQ(mock_data_key_allocated, 1, " mock data key allocated"); 208 TEST_PTR_EQ(key, mock_data_key, " data key ptr"); 209 mock_data_key_allocated--; 210} 211 212int VerifyKernelPreamble(const VbKernelPreambleHeader *preamble, 213 uint64_t size, const RSAPublicKey *key) 214{ 215 if (preamble_verify_fail) 216 return VBERROR_SIMULATED; 217 218 /* Use this as an opportunity to override the preamble */ 219 memcpy((void *)preamble, &kph, sizeof(kph)); 220 return VBERROR_SUCCESS; 221} 222 223int VerifyData(const uint8_t *data, uint64_t size, const VbSignature *sig, 224 const RSAPublicKey *key) 225{ 226 if (verify_data_fail) 227 return VBERROR_SIMULATED; 228 229 return VBERROR_SUCCESS; 230} 231 232 233/** 234 * Test reading/writing GPT 235 */ 236static void ReadWriteGptTest(void) 237{ 238 GptData g; 239 GptHeader *h; 240 241 g.sector_bytes = 512; 242 g.drive_sectors = 1024; 243 244 ResetMocks(); 245 TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead"); 246 TEST_CALLS("VbExDiskRead(h, 1, 1)\n" 247 "VbExDiskRead(h, 2, 32)\n" 248 "VbExDiskRead(h, 991, 32)\n" 249 "VbExDiskRead(h, 1023, 1)\n"); 250 ResetCallLog(); 251 /* 252 * Valgrind complains about access to uninitialized memory here, so 253 * zero the primary header before each test. 254 */ 255 Memset(g.primary_header, '\0', g.sector_bytes); 256 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree"); 257 TEST_CALLS(""); 258 259 /* Data which is changed is written */ 260 ResetMocks(); 261 AllocAndReadGptData(handle, &g); 262 g.modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1; 263 ResetCallLog(); 264 Memset(g.primary_header, '\0', g.sector_bytes); 265 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1"); 266 TEST_CALLS("VbExDiskWrite(h, 1, 1)\n" 267 "VbExDiskWrite(h, 2, 32)\n"); 268 269 /* Data which is changed is written */ 270 ResetMocks(); 271 AllocAndReadGptData(handle, &g); 272 g.modified = -1; 273 ResetCallLog(); 274 Memset(g.primary_header, '\0', g.sector_bytes); 275 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all"); 276 TEST_CALLS("VbExDiskWrite(h, 1, 1)\n" 277 "VbExDiskWrite(h, 2, 32)\n" 278 "VbExDiskWrite(h, 991, 32)\n" 279 "VbExDiskWrite(h, 1023, 1)\n"); 280 281 /* If legacy signature, don't modify GPT header/entries 1 */ 282 ResetMocks(); 283 AllocAndReadGptData(handle, &g); 284 h = (GptHeader *)g.primary_header; 285 memcpy(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE); 286 g.modified = -1; 287 ResetCallLog(); 288 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all"); 289 TEST_CALLS("VbExDiskWrite(h, 991, 32)\n" 290 "VbExDiskWrite(h, 1023, 1)\n"); 291 292 /* Error reading */ 293 ResetMocks(); 294 disk_read_to_fail = 1; 295 TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail"); 296 Memset(g.primary_header, '\0', g.sector_bytes); 297 WriteAndFreeGptData(handle, &g); 298 299 ResetMocks(); 300 disk_read_to_fail = 2; 301 TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail"); 302 Memset(g.primary_header, '\0', g.sector_bytes); 303 WriteAndFreeGptData(handle, &g); 304 305 ResetMocks(); 306 disk_read_to_fail = 991; 307 TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail"); 308 Memset(g.primary_header, '\0', g.sector_bytes); 309 WriteAndFreeGptData(handle, &g); 310 311 ResetMocks(); 312 disk_read_to_fail = 1023; 313 TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail"); 314 Memset(g.primary_header, '\0', g.sector_bytes); 315 WriteAndFreeGptData(handle, &g); 316 317 /* Error writing */ 318 ResetMocks(); 319 disk_write_to_fail = 1; 320 AllocAndReadGptData(handle, &g); 321 g.modified = -1; 322 Memset(g.primary_header, '\0', g.sector_bytes); 323 TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail"); 324 325 ResetMocks(); 326 disk_write_to_fail = 2; 327 AllocAndReadGptData(handle, &g); 328 g.modified = -1; 329 Memset(g.primary_header, '\0', g.sector_bytes); 330 TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail"); 331 332 ResetMocks(); 333 disk_write_to_fail = 991; 334 AllocAndReadGptData(handle, &g); 335 g.modified = -1; 336 Memset(g.primary_header, '\0', g.sector_bytes); 337 TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail"); 338 339 ResetMocks(); 340 disk_write_to_fail = 1023; 341 AllocAndReadGptData(handle, &g); 342 g.modified = -1; 343 Memset(g.primary_header, '\0', g.sector_bytes); 344 TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail"); 345 346} 347 348/** 349 * Trivial invalid calls to LoadKernel() 350 */ 351static void InvalidParamsTest(void) 352{ 353 ResetMocks(); 354 lkp.bytes_per_lba = 0; 355 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_PARAMETER, 356 "Bad lba size"); 357 358 ResetMocks(); 359 lkp.ending_lba = 0; 360 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_PARAMETER, 361 "Bad lba count"); 362 363 ResetMocks(); 364 lkp.bytes_per_lba = 128*1024; 365 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_PARAMETER, 366 "Huge lba size"); 367 368 ResetMocks(); 369 disk_read_to_fail = 1; 370 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_NO_KERNEL_FOUND, 371 "Can't read disk"); 372 373 ResetMocks(); 374 gpt_init_fail = 1; 375 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_NO_KERNEL_FOUND, 376 "Bad GPT"); 377} 378 379static void LoadKernelTest(void) 380{ 381 uint32_t u; 382 383 ResetMocks(); 384 TEST_EQ(LoadKernel(&lkp, &cparams), 0, "First kernel good"); 385 TEST_EQ(lkp.partition_number, 1, " part num"); 386 TEST_EQ(lkp.bootloader_address, 0xbeadd008, " bootloader addr"); 387 TEST_EQ(lkp.bootloader_size, 0x1234, " bootloader size"); 388 TEST_STR_EQ((char *)lkp.partition_guid, "FakeGuid", " guid"); 389 VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &u); 390 TEST_EQ(u, 0, " recovery request"); 391 392 ResetMocks(); 393 mock_parts[1].start = 300; 394 mock_parts[1].size = 150; 395 TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Two good kernels"); 396 TEST_EQ(lkp.partition_number, 1, " part num"); 397 TEST_EQ(mock_part_next, 1, " didn't read second one"); 398 399 /* Fail if no kernels found */ 400 ResetMocks(); 401 mock_parts[0].size = 0; 402 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_NO_KERNEL_FOUND, "No kernels"); 403 VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &u); 404 TEST_EQ(u, VBNV_RECOVERY_RW_NO_OS, " recovery request"); 405 406 /* Skip kernels which are too small */ 407 ResetMocks(); 408 mock_parts[0].size = 10; 409 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, "Too small"); 410 VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &u); 411 TEST_EQ(u, VBNV_RECOVERY_RW_INVALID_OS, " recovery request"); 412 413 ResetMocks(); 414 disk_read_to_fail = 100; 415 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 416 "Fail reading kernel start"); 417 418 ResetMocks(); 419 key_block_verify_fail = 1; 420 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 421 "Fail key block sig"); 422 423 /* In dev mode, fail if hash is bad too */ 424 ResetMocks(); 425 lkp.boot_flags |= BOOT_FLAG_DEVELOPER; 426 key_block_verify_fail = 2; 427 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 428 "Fail key block dev hash"); 429 430 /* But just bad sig is ok */ 431 ResetMocks(); 432 lkp.boot_flags |= BOOT_FLAG_DEVELOPER; 433 key_block_verify_fail = 1; 434 TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Succeed key block dev sig"); 435 436 /* In dev mode and requiring signed kernel, fail if sig is bad */ 437 ResetMocks(); 438 lkp.boot_flags |= BOOT_FLAG_DEVELOPER; 439 VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 1); 440 VbNvTeardown(&vnc); 441 key_block_verify_fail = 1; 442 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 443 "Fail key block dev sig"); 444 445 /* Check key block flag mismatches */ 446 ResetMocks(); 447 kbh.key_block_flags = 448 KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_1; 449 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 450 "Key block dev flag mismatch"); 451 452 ResetMocks(); 453 kbh.key_block_flags = 454 KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_0; 455 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 456 "Key block rec flag mismatch"); 457 458 ResetMocks(); 459 lkp.boot_flags |= BOOT_FLAG_RECOVERY; 460 kbh.key_block_flags = 461 KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_1; 462 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 463 "Key block recdev flag mismatch"); 464 465 ResetMocks(); 466 lkp.boot_flags |= BOOT_FLAG_RECOVERY | BOOT_FLAG_DEVELOPER; 467 kbh.key_block_flags = 468 KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_0; 469 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 470 "Key block rec!dev flag mismatch"); 471 472 ResetMocks(); 473 kbh.data_key.key_version = 1; 474 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 475 "Key block kernel key rollback"); 476 477 ResetMocks(); 478 kbh.data_key.key_version = 0x10000; 479 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 480 "Key block kernel key version too big"); 481 482 ResetMocks(); 483 kbh.data_key.key_version = 3; 484 TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Key block version roll forward"); 485 TEST_EQ(shared->kernel_version_tpm, 0x30001, " shared version"); 486 487 ResetMocks(); 488 kbh.data_key.key_version = 3; 489 mock_parts[1].start = 300; 490 mock_parts[1].size = 150; 491 TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Two kernels roll forward"); 492 TEST_EQ(mock_part_next, 2, " read both"); 493 TEST_EQ(shared->kernel_version_tpm, 0x30001, " shared version"); 494 495 ResetMocks(); 496 kbh.data_key.key_version = 1; 497 lkp.boot_flags |= BOOT_FLAG_DEVELOPER; 498 TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Key version ignored in dev mode"); 499 500 ResetMocks(); 501 kbh.data_key.key_version = 1; 502 lkp.boot_flags |= BOOT_FLAG_RECOVERY; 503 TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Key version ignored in rec mode"); 504 505 ResetMocks(); 506 mock_data_key = NULL; 507 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 508 "Bad data key"); 509 510 ResetMocks(); 511 preamble_verify_fail = 1; 512 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 513 "Bad preamble"); 514 515 ResetMocks(); 516 kph.kernel_version = 0; 517 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 518 "Kernel version rollback"); 519 520 ResetMocks(); 521 kph.kernel_version = 0; 522 lkp.boot_flags |= BOOT_FLAG_DEVELOPER; 523 TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Kernel version ignored in dev mode"); 524 525 ResetMocks(); 526 kph.kernel_version = 0; 527 lkp.boot_flags |= BOOT_FLAG_RECOVERY; 528 TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Kernel version ignored in rec mode"); 529 530 ResetMocks(); 531 kph.preamble_size |= 0x07; 532 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 533 "Kernel body offset"); 534 535 /* Check getting kernel load address from header */ 536 ResetMocks(); 537 kph.body_load_address = (size_t)kernel_buffer; 538 lkp.kernel_buffer = NULL; 539 TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Get load address from preamble"); 540 TEST_PTR_EQ(lkp.kernel_buffer, kernel_buffer, " address"); 541 /* Size is rounded up to nearest sector */ 542 TEST_EQ(lkp.kernel_buffer_size, 70144, " size"); 543 544 ResetMocks(); 545 lkp.kernel_buffer_size = 8192; 546 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 547 "Kernel too big for buffer"); 548 549 ResetMocks(); 550 mock_parts[0].size = 130; 551 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 552 "Kernel too big for partition"); 553 554 ResetMocks(); 555 disk_read_to_fail = 108; 556 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, 557 "Fail reading kernel data"); 558 559 ResetMocks(); 560 verify_data_fail = 1; 561 TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, "Bad data"); 562} 563 564int main(void) 565{ 566 ReadWriteGptTest(); 567 InvalidParamsTest(); 568 LoadKernelTest(); 569 570 if (vboot_api_stub_check_memory()) 571 return 255; 572 573 return gTestSuccess ? 0 : 255; 574} 575