| Patrick Venture | fa06a5f | 2019-07-01 09:22:38 -0700 | [diff] [blame] | 1 | /* The goal of these tests is to verify that once a host-client has started the | 
|  | 2 | * process with one blob bundle, they cannot pivot to upload data to another. | 
|  | 3 | * | 
|  | 4 | * This prevent someone from starting to upload a BMC firmware, and then midway | 
|  | 5 | * through start uploading a BIOS image. | 
|  | 6 | */ | 
|  | 7 | #include "firmware_handler.hpp" | 
|  | 8 | #include "flags.hpp" | 
|  | 9 | #include "image_mock.hpp" | 
|  | 10 | #include "status.hpp" | 
|  | 11 | #include "triggerable_mock.hpp" | 
|  | 12 | #include "util.hpp" | 
|  | 13 |  | 
|  | 14 | #include <memory> | 
|  | 15 | #include <string> | 
|  | 16 | #include <unordered_map> | 
|  | 17 | #include <vector> | 
|  | 18 |  | 
|  | 19 | #include <gtest/gtest.h> | 
|  | 20 |  | 
|  | 21 | namespace ipmi_flash | 
|  | 22 | { | 
|  | 23 | namespace | 
|  | 24 | { | 
|  | 25 |  | 
|  | 26 | using ::testing::Return; | 
|  | 27 |  | 
|  | 28 | class IpmiOnlyTwoFirmwaresTest : public ::testing::Test | 
|  | 29 | { | 
|  | 30 | protected: | 
|  | 31 | void SetUp() override | 
|  | 32 | { | 
|  | 33 | blobs = { | 
|  | 34 | {hashBlobId, &hashImageMock}, | 
|  | 35 | {staticLayoutBlobId, &staticImageMock}, | 
| Patrick Venture | 7c2a00e | 2019-07-01 17:33:03 -0700 | [diff] [blame^] | 36 | {biosBlobId, &biosImageMock}, | 
| Patrick Venture | fa06a5f | 2019-07-01 09:22:38 -0700 | [diff] [blame] | 37 | }; | 
|  | 38 |  | 
|  | 39 | std::unique_ptr<TriggerableActionInterface> bmcPrepareMock = | 
|  | 40 | std::make_unique<TriggerMock>(); | 
|  | 41 | bmcPrepareMockPtr = | 
|  | 42 | reinterpret_cast<TriggerMock*>(bmcPrepareMock.get()); | 
|  | 43 |  | 
|  | 44 | std::unique_ptr<TriggerableActionInterface> bmcVerifyMock = | 
|  | 45 | std::make_unique<TriggerMock>(); | 
|  | 46 | bmcVerifyMockPtr = reinterpret_cast<TriggerMock*>(bmcVerifyMock.get()); | 
|  | 47 |  | 
|  | 48 | std::unique_ptr<TriggerableActionInterface> bmcUpdateMock = | 
|  | 49 | std::make_unique<TriggerMock>(); | 
|  | 50 | bmcUpdateMockPtr = reinterpret_cast<TriggerMock*>(bmcUpdateMock.get()); | 
|  | 51 |  | 
|  | 52 | std::unique_ptr<TriggerableActionInterface> biosPrepareMock = | 
|  | 53 | std::make_unique<TriggerMock>(); | 
|  | 54 | biosPrepareMockPtr = | 
|  | 55 | reinterpret_cast<TriggerMock*>(biosPrepareMock.get()); | 
|  | 56 |  | 
|  | 57 | std::unique_ptr<TriggerableActionInterface> biosVerifyMock = | 
|  | 58 | std::make_unique<TriggerMock>(); | 
|  | 59 | biosVerifyMockPtr = | 
|  | 60 | reinterpret_cast<TriggerMock*>(biosVerifyMock.get()); | 
|  | 61 |  | 
|  | 62 | std::unique_ptr<TriggerableActionInterface> biosUpdateMock = | 
|  | 63 | std::make_unique<TriggerMock>(); | 
|  | 64 | biosUpdateMockPtr = | 
|  | 65 | reinterpret_cast<TriggerMock*>(biosUpdateMock.get()); | 
|  | 66 |  | 
|  | 67 | ActionMap packs; | 
|  | 68 |  | 
|  | 69 | std::unique_ptr<ActionPack> bmcPack = std::make_unique<ActionPack>(); | 
|  | 70 | bmcPack->preparation = std::move(bmcPrepareMock); | 
|  | 71 | bmcPack->verification = std::move(bmcVerifyMock); | 
|  | 72 | bmcPack->update = std::move(bmcUpdateMock); | 
|  | 73 |  | 
|  | 74 | std::unique_ptr<ActionPack> biosPack = std::make_unique<ActionPack>(); | 
|  | 75 | biosPack->preparation = std::move(biosPrepareMock); | 
|  | 76 | biosPack->verification = std::move(biosVerifyMock); | 
|  | 77 | biosPack->update = std::move(biosUpdateMock); | 
|  | 78 |  | 
|  | 79 | packs[staticLayoutBlobId] = std::move(bmcPack); | 
| Patrick Venture | 7c2a00e | 2019-07-01 17:33:03 -0700 | [diff] [blame^] | 80 | packs[biosBlobId] = std::move(biosPack); | 
| Patrick Venture | fa06a5f | 2019-07-01 09:22:38 -0700 | [diff] [blame] | 81 |  | 
|  | 82 | handler = FirmwareBlobHandler::CreateFirmwareBlobHandler( | 
|  | 83 | blobs, data, std::move(packs)); | 
|  | 84 | } | 
|  | 85 |  | 
|  | 86 | void expectedState(FirmwareBlobHandler::UpdateState state) | 
|  | 87 | { | 
|  | 88 | auto realHandler = dynamic_cast<FirmwareBlobHandler*>(handler.get()); | 
|  | 89 | EXPECT_EQ(state, realHandler->getCurrentState()); | 
|  | 90 | } | 
|  | 91 |  | 
|  | 92 | ImageHandlerMock hashImageMock, staticImageMock, biosImageMock; | 
|  | 93 |  | 
|  | 94 | std::vector<HandlerPack> blobs; | 
|  | 95 | std::vector<DataHandlerPack> data = { | 
|  | 96 | {FirmwareFlags::UpdateFlags::ipmi, nullptr}}; | 
|  | 97 |  | 
|  | 98 | std::unique_ptr<blobs::GenericBlobInterface> handler; | 
|  | 99 |  | 
|  | 100 | TriggerMock *bmcPrepareMockPtr, *bmcVerifyMockPtr, *bmcUpdateMockPtr; | 
|  | 101 | TriggerMock *biosPrepareMockPtr, *biosVerifyMockPtr, *biosUpdateMockPtr; | 
|  | 102 |  | 
|  | 103 | std::uint16_t session = 1; | 
|  | 104 | std::uint16_t flags = | 
|  | 105 | blobs::OpenFlags::write | FirmwareFlags::UpdateFlags::ipmi; | 
| Patrick Venture | fa06a5f | 2019-07-01 09:22:38 -0700 | [diff] [blame] | 106 | }; | 
|  | 107 |  | 
|  | 108 | TEST_F(IpmiOnlyTwoFirmwaresTest, OpeningBiosAfterBlobFails) | 
|  | 109 | { | 
|  | 110 | /* You can only have one file open at a time, and the first firmware file | 
|  | 111 | * you open locks it down | 
|  | 112 | */ | 
|  | 113 | EXPECT_CALL(staticImageMock, open(staticLayoutBlobId)) | 
|  | 114 | .WillOnce(Return(true)); | 
|  | 115 | EXPECT_CALL(*bmcPrepareMockPtr, trigger()).WillOnce(Return(true)); | 
|  | 116 |  | 
|  | 117 | EXPECT_TRUE(handler->open(session, flags, staticLayoutBlobId)); | 
|  | 118 | expectedState(FirmwareBlobHandler::UpdateState::uploadInProgress); | 
|  | 119 |  | 
|  | 120 | EXPECT_CALL(staticImageMock, close()).WillOnce(Return()); | 
|  | 121 | handler->close(session); | 
|  | 122 |  | 
|  | 123 | expectedState(FirmwareBlobHandler::UpdateState::verificationPending); | 
|  | 124 |  | 
| Patrick Venture | 7c2a00e | 2019-07-01 17:33:03 -0700 | [diff] [blame^] | 125 | EXPECT_CALL(biosImageMock, open(biosBlobId)).Times(0); | 
|  | 126 | EXPECT_FALSE(handler->open(session, flags, biosBlobId)); | 
| Patrick Venture | fa06a5f | 2019-07-01 09:22:38 -0700 | [diff] [blame] | 127 | } | 
|  | 128 |  | 
|  | 129 | TEST_F(IpmiOnlyTwoFirmwaresTest, OpeningHashBeforeBiosSucceeds) | 
|  | 130 | { | 
|  | 131 | /* Opening the hash blob does nothing special in this regard. */ | 
|  | 132 | EXPECT_CALL(hashImageMock, open(hashBlobId)).WillOnce(Return(true)); | 
|  | 133 | EXPECT_TRUE(handler->open(session, flags, hashBlobId)); | 
|  | 134 |  | 
|  | 135 | expectedState(FirmwareBlobHandler::UpdateState::uploadInProgress); | 
|  | 136 |  | 
|  | 137 | EXPECT_CALL(hashImageMock, close()).WillOnce(Return()); | 
|  | 138 | handler->close(session); | 
|  | 139 |  | 
|  | 140 | expectedState(FirmwareBlobHandler::UpdateState::verificationPending); | 
|  | 141 | ASSERT_FALSE(handler->canHandleBlob(verifyBlobId)); | 
|  | 142 |  | 
| Patrick Venture | 7c2a00e | 2019-07-01 17:33:03 -0700 | [diff] [blame^] | 143 | EXPECT_CALL(biosImageMock, open(biosBlobId)).WillOnce(Return(true)); | 
|  | 144 | EXPECT_TRUE(handler->open(session, flags, biosBlobId)); | 
| Patrick Venture | fa06a5f | 2019-07-01 09:22:38 -0700 | [diff] [blame] | 145 |  | 
|  | 146 | expectedState(FirmwareBlobHandler::UpdateState::uploadInProgress); | 
|  | 147 |  | 
|  | 148 | EXPECT_CALL(biosImageMock, close()).WillOnce(Return()); | 
|  | 149 | handler->close(session); | 
|  | 150 | } | 
|  | 151 |  | 
|  | 152 | } // namespace | 
|  | 153 | } // namespace ipmi_flash |