4
4
Copyright (c) Microsoft Corporation
5
5
SPDX-License-Identifier: BSD-2-Clause-Patent
6
6
**/
7
- #include < gtest/gtest.h>
7
+ #include < Library/GoogleTestLib.h>
8
+ #include < GoogleTest/Library/MockUefiLib.h>
9
+ #include < GoogleTest/Library/MockUefiRuntimeServicesTableLib.h>
8
10
9
11
extern " C" {
10
12
#include < Uefi.h>
@@ -19,7 +21,8 @@ extern "C" {
19
21
// Definitions
20
22
// /////////////////////////////////////////////////////////////////////////////
21
23
22
- #define PACKET_SIZE (1500 )
24
+ #define PACKET_SIZE (1500 )
25
+ #define REQUEST_OPTION_LENGTH (120 )
23
26
24
27
typedef struct {
25
28
UINT16 OptionCode; // The option code for DHCP6_OPT_SERVER_ID (e.g., 0x03)
@@ -76,6 +79,26 @@ MockConfigure (
76
79
}
77
80
78
81
// Needed by PxeBcSupport
82
+ EFI_STATUS
83
+ PxeBcDns6 (
84
+ IN PXEBC_PRIVATE_DATA *Private,
85
+ IN CHAR16 *HostName,
86
+ OUT EFI_IPv6_ADDRESS *IpAddress
87
+ )
88
+ {
89
+ return EFI_SUCCESS;
90
+ }
91
+
92
+ UINT32
93
+ PxeBcBuildDhcp6Options (
94
+ IN PXEBC_PRIVATE_DATA *Private,
95
+ OUT EFI_DHCP6_PACKET_OPTION **OptList,
96
+ IN UINT8 *Buffer
97
+ )
98
+ {
99
+ return EFI_SUCCESS;
100
+ }
101
+
79
102
EFI_STATUS
80
103
EFIAPI
81
104
QueueDpc (
@@ -159,6 +182,10 @@ TEST_F (PxeBcHandleDhcp6OfferTest, BasicUsageTest) {
159
182
ASSERT_EQ (PxeBcHandleDhcp6Offer (&(PxeBcHandleDhcp6OfferTest::Private)), EFI_DEVICE_ERROR);
160
183
}
161
184
185
+ // /////////////////////////////////////////////////////////////////////////////
186
+ // PxeBcCacheDnsServerAddresses Tests
187
+ // /////////////////////////////////////////////////////////////////////////////
188
+
162
189
class PxeBcCacheDnsServerAddressesTest : public ::testing::Test {
163
190
public:
164
191
PXEBC_PRIVATE_DATA Private = { 0 };
@@ -298,3 +325,250 @@ TEST_F (PxeBcCacheDnsServerAddressesTest, MultipleDnsEntries) {
298
325
FreePool (Private.DnsServer );
299
326
}
300
327
}
328
+
329
+ // /////////////////////////////////////////////////////////////////////////////
330
+ // PxeBcRequestBootServiceTest Test Cases
331
+ // /////////////////////////////////////////////////////////////////////////////
332
+
333
+ class PxeBcRequestBootServiceTest : public ::testing::Test {
334
+ public:
335
+ PXEBC_PRIVATE_DATA Private = { 0 };
336
+ EFI_UDP6_PROTOCOL Udp6Read;
337
+
338
+ protected:
339
+ // Add any setup code if needed
340
+ virtual void
341
+ SetUp (
342
+ )
343
+ {
344
+ Private.Dhcp6Request = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE);
345
+
346
+ // Need to setup the EFI_PXE_BASE_CODE_PROTOCOL
347
+ // The function under test really only needs the following:
348
+ // UdpWrite
349
+ // UdpRead
350
+
351
+ Private.PxeBc .UdpWrite = (EFI_PXE_BASE_CODE_UDP_WRITE)MockUdpWrite;
352
+ Private.PxeBc .UdpRead = (EFI_PXE_BASE_CODE_UDP_READ)MockUdpRead;
353
+
354
+ // Need to setup EFI_UDP6_PROTOCOL
355
+ // The function under test really only needs the following:
356
+ // Configure
357
+
358
+ Udp6Read.Configure = (EFI_UDP6_CONFIGURE)MockConfigure;
359
+ Private.Udp6Read = &Udp6Read;
360
+ }
361
+
362
+ // Add any cleanup code if needed
363
+ virtual void
364
+ TearDown (
365
+ )
366
+ {
367
+ if (Private.Dhcp6Request != NULL ) {
368
+ FreePool (Private.Dhcp6Request );
369
+ }
370
+
371
+ // Clean up any resources or variables
372
+ }
373
+ };
374
+
375
+ TEST_F (PxeBcRequestBootServiceTest, ServerDiscoverBasicUsageTest) {
376
+ PxeBcRequestBootServiceTest::Private.OfferBuffer [0 ].Dhcp6 .OfferType = PxeOfferTypeProxyBinl;
377
+
378
+ DHCP6_OPTION_SERVER_ID Server = { 0 };
379
+
380
+ Server.OptionCode = HTONS (DHCP6_OPT_SERVER_ID);
381
+ Server.OptionLen = HTONS (16 ); // valid length
382
+ UINT8 Index = 0 ;
383
+
384
+ EFI_DHCP6_PACKET *Packet = (EFI_DHCP6_PACKET *)&Private.OfferBuffer [Index].Dhcp6 .Packet .Offer ;
385
+
386
+ UINT8 *Cursor = (UINT8 *)(Packet->Dhcp6 .Option );
387
+
388
+ CopyMem (Cursor, &Server, sizeof (Server));
389
+ Cursor += sizeof (Server);
390
+
391
+ // Update the packet length
392
+ Packet->Length = (UINT16)(Cursor - (UINT8 *)Packet);
393
+ Packet->Size = PACKET_SIZE;
394
+
395
+ ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_SUCCESS);
396
+ }
397
+
398
+ TEST_F (PxeBcRequestBootServiceTest, AttemptDiscoverOverFlowExpectFailure) {
399
+ PxeBcRequestBootServiceTest::Private.OfferBuffer [0 ].Dhcp6 .OfferType = PxeOfferTypeProxyBinl;
400
+
401
+ DHCP6_OPTION_SERVER_ID Server = { 0 };
402
+
403
+ Server.OptionCode = HTONS (DHCP6_OPT_SERVER_ID);
404
+ Server.OptionLen = HTONS (1500 ); // This length would overflow without a check
405
+ UINT8 Index = 0 ;
406
+
407
+ EFI_DHCP6_PACKET *Packet = (EFI_DHCP6_PACKET *)&Private.OfferBuffer [Index].Dhcp6 .Packet .Offer ;
408
+
409
+ UINT8 *Cursor = (UINT8 *)(Packet->Dhcp6 .Option );
410
+
411
+ CopyMem (Cursor, &Server, sizeof (Server));
412
+ Cursor += sizeof (Server);
413
+
414
+ // Update the packet length
415
+ Packet->Length = (UINT16)(Cursor - (UINT8 *)Packet);
416
+ Packet->Size = PACKET_SIZE;
417
+
418
+ // This is going to be stopped by the duid overflow check
419
+ ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_INVALID_PARAMETER);
420
+ }
421
+
422
+ TEST_F (PxeBcRequestBootServiceTest, RequestBasicUsageTest) {
423
+ EFI_DHCP6_PACKET_OPTION RequestOpt = { 0 }; // the data section doesn't really matter
424
+
425
+ RequestOpt.OpCode = HTONS (0x1337 );
426
+ RequestOpt.OpLen = 0 ; // valid length
427
+
428
+ UINT8 Index = 0 ;
429
+
430
+ EFI_DHCP6_PACKET *Packet = (EFI_DHCP6_PACKET *)&Private.Dhcp6Request [Index];
431
+
432
+ UINT8 *Cursor = (UINT8 *)(Packet->Dhcp6 .Option );
433
+
434
+ CopyMem (Cursor, &RequestOpt, sizeof (RequestOpt));
435
+ Cursor += sizeof (RequestOpt);
436
+
437
+ // Update the packet length
438
+ Packet->Length = (UINT16)(Cursor - (UINT8 *)Packet);
439
+ Packet->Size = PACKET_SIZE;
440
+
441
+ ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_SUCCESS);
442
+ }
443
+
444
+ TEST_F (PxeBcRequestBootServiceTest, AttemptRequestOverFlowExpectFailure) {
445
+ EFI_DHCP6_PACKET_OPTION RequestOpt = { 0 }; // the data section doesn't really matter
446
+
447
+ RequestOpt.OpCode = HTONS (0x1337 );
448
+ RequestOpt.OpLen = 1500 ; // this length would overflow without a check
449
+
450
+ UINT8 Index = 0 ;
451
+
452
+ EFI_DHCP6_PACKET *Packet = (EFI_DHCP6_PACKET *)&Private.Dhcp6Request [Index];
453
+
454
+ UINT8 *Cursor = (UINT8 *)(Packet->Dhcp6 .Option );
455
+
456
+ CopyMem (Cursor, &RequestOpt, sizeof (RequestOpt));
457
+ Cursor += sizeof (RequestOpt);
458
+
459
+ // Update the packet length
460
+ Packet->Length = (UINT16)(Cursor - (UINT8 *)Packet);
461
+ Packet->Size = PACKET_SIZE;
462
+
463
+ ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_OUT_OF_RESOURCES);
464
+ }
465
+
466
+ // /////////////////////////////////////////////////////////////////////////////
467
+ // PxeBcDhcp6Discover Test
468
+ // /////////////////////////////////////////////////////////////////////////////
469
+
470
+ class PxeBcDhcp6DiscoverTest : public ::testing::Test {
471
+ public:
472
+ PXEBC_PRIVATE_DATA Private = { 0 };
473
+ EFI_UDP6_PROTOCOL Udp6Read;
474
+
475
+ protected:
476
+ MockUefiRuntimeServicesTableLib RtServicesMock;
477
+
478
+ // Add any setup code if needed
479
+ virtual void
480
+ SetUp (
481
+ )
482
+ {
483
+ Private.Dhcp6Request = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE);
484
+
485
+ // Need to setup the EFI_PXE_BASE_CODE_PROTOCOL
486
+ // The function under test really only needs the following:
487
+ // UdpWrite
488
+ // UdpRead
489
+
490
+ Private.PxeBc .UdpWrite = (EFI_PXE_BASE_CODE_UDP_WRITE)MockUdpWrite;
491
+ Private.PxeBc .UdpRead = (EFI_PXE_BASE_CODE_UDP_READ)MockUdpRead;
492
+
493
+ // Need to setup EFI_UDP6_PROTOCOL
494
+ // The function under test really only needs the following:
495
+ // Configure
496
+
497
+ Udp6Read.Configure = (EFI_UDP6_CONFIGURE)MockConfigure;
498
+ Private.Udp6Read = &Udp6Read;
499
+ }
500
+
501
+ // Add any cleanup code if needed
502
+ virtual void
503
+ TearDown (
504
+ )
505
+ {
506
+ if (Private.Dhcp6Request != NULL ) {
507
+ FreePool (Private.Dhcp6Request );
508
+ }
509
+
510
+ // Clean up any resources or variables
511
+ }
512
+ };
513
+
514
+ // Test Description
515
+ // This will cause an overflow by an untrusted packet during the option parsing
516
+ TEST_F (PxeBcDhcp6DiscoverTest, BasicOverflowTest) {
517
+ EFI_IPv6_ADDRESS DestIp = { 0 };
518
+ EFI_DHCP6_PACKET_OPTION RequestOpt = { 0 }; // the data section doesn't really matter
519
+
520
+ RequestOpt.OpCode = HTONS (0x1337 );
521
+ RequestOpt.OpLen = HTONS (0xFFFF ); // overflow
522
+
523
+ UINT8 *Cursor = (UINT8 *)(Private.Dhcp6Request ->Dhcp6 .Option );
524
+
525
+ CopyMem (Cursor, &RequestOpt, sizeof (RequestOpt));
526
+ Cursor += sizeof (RequestOpt);
527
+
528
+ Private.Dhcp6Request ->Length = (UINT16)(Cursor - (UINT8 *)Private.Dhcp6Request );
529
+
530
+ EXPECT_CALL (RtServicesMock, gRT_GetTime )
531
+ .WillOnce (::testing::Return (0 ));
532
+
533
+ ASSERT_EQ (
534
+ PxeBcDhcp6Discover (
535
+ &(PxeBcDhcp6DiscoverTest::Private),
536
+ 0 ,
537
+ NULL ,
538
+ FALSE ,
539
+ (EFI_IP_ADDRESS *)&DestIp
540
+ ),
541
+ EFI_OUT_OF_RESOURCES
542
+ );
543
+ }
544
+
545
+ // Test Description
546
+ // This will test that we can handle a packet with a valid option length
547
+ TEST_F (PxeBcDhcp6DiscoverTest, BasicUsageTest) {
548
+ EFI_IPv6_ADDRESS DestIp = { 0 };
549
+ EFI_DHCP6_PACKET_OPTION RequestOpt = { 0 }; // the data section doesn't really matter
550
+
551
+ RequestOpt.OpCode = HTONS (0x1337 );
552
+ RequestOpt.OpLen = HTONS (0x30 );
553
+
554
+ UINT8 *Cursor = (UINT8 *)(Private.Dhcp6Request ->Dhcp6 .Option );
555
+
556
+ CopyMem (Cursor, &RequestOpt, sizeof (RequestOpt));
557
+ Cursor += sizeof (RequestOpt);
558
+
559
+ Private.Dhcp6Request ->Length = (UINT16)(Cursor - (UINT8 *)Private.Dhcp6Request );
560
+
561
+ EXPECT_CALL (RtServicesMock, gRT_GetTime )
562
+ .WillOnce (::testing::Return (0 ));
563
+
564
+ ASSERT_EQ (
565
+ PxeBcDhcp6Discover (
566
+ &(PxeBcDhcp6DiscoverTest::Private),
567
+ 0 ,
568
+ NULL ,
569
+ FALSE ,
570
+ (EFI_IP_ADDRESS *)&DestIp
571
+ ),
572
+ EFI_SUCCESS
573
+ );
574
+ }
0 commit comments