Add SecureBoot monitoring
TESTED=gpaste/5349581642268672
Google-Bug-Id: 438259309
Signed-off-by: Christian Kungler <ckungler@google.com>
Change-Id: I24dee723f201b09b13217ab050f2dbd2c6b7fdc8
diff --git a/ec_util.cpp b/ec_util.cpp
index 416dace..60c38de 100644
--- a/ec_util.cpp
+++ b/ec_util.cpp
@@ -189,6 +189,22 @@
return stdplus::raw::copyFrom<ec_response_key_rotation_status>(response_body);
}
+secure_boot_enforcement_state EcUtilImpl::getSecureBootEnforcementState()
+ const {
+ const uint16_t kGetSecureBootEnforcementState =
+ EC_CMD_BOARD_SPECIFIC_BASE +
+ EC_PRV_CMD_HOTH_GET_SECURE_BOOT_ENFORCEMENT;
+
+ if (!isHostCommandSupported(kGetSecureBootEnforcementState)) {
+ throw CommandNotSupportedException(kGetSecureBootEnforcementState);
+ }
+
+ std::vector<uint8_t> response_body =
+ sendCommand(kGetSecureBootEnforcementState,
+ /*request_ptr=*/nullptr, /*request_size=*/0);
+ return stdplus::raw::copyFrom<secure_boot_enforcement_state>(response_body);
+}
+
} // namespace internal
} // namespace hoth
diff --git a/ec_util.hpp b/ec_util.hpp
index 5b8f25d..fb8e9c0 100644
--- a/ec_util.hpp
+++ b/ec_util.hpp
@@ -91,6 +91,8 @@
ec_response_key_rotation_status getHothKeyRotationStatus() const override;
+ secure_boot_enforcement_state getSecureBootEnforcementState() const override;
+
private:
[[nodiscard]] std::vector<uint8_t> sendCommand(uint16_t command,
uint8_t* request_ptr,
diff --git a/ec_util_interface.hpp b/ec_util_interface.hpp
index cb12818..b33beb2 100644
--- a/ec_util_interface.hpp
+++ b/ec_util_interface.hpp
@@ -52,6 +52,10 @@
// Get Hoth KeyRotation metrics
virtual ec_response_key_rotation_status getHothKeyRotationStatus() const = 0;
+
+ // Get Hoth Secure Boot Enforcement status
+ virtual secure_boot_enforcement_state getSecureBootEnforcementState()
+ const = 0;
};
} // namespace internal
diff --git a/google3/host_commands.h b/google3/host_commands.h
index 4c0cbc2..d327c8b 100644
--- a/google3/host_commands.h
+++ b/google3/host_commands.h
@@ -691,4 +691,16 @@
// of cr51 hash
} __attribute__((packed, aligned(4)));
+
+// The return value for EC_PRV_CMD_HOTH_GET_SECURE_BOOT_ENFORCEMENT. This
+// struct reflects the current state of secure boot enforcement.
+struct secure_boot_enforcement_state {
+ uint8_t enabled; // 0 = disable(d), 1 = enable(d)
+ uint8_t reserved0[3]; // Reserved. Write zeroes.
+} __attribute__((packed));
+
+// EC_PRV_CMD_HOTH_GET_SECURE_BOOT_ENFORCEMENT queries the current secure boot
+// enforcement state.
+#define EC_PRV_CMD_HOTH_GET_SECURE_BOOT_ENFORCEMENT 0x001D
+
#endif /* __PRIVATE_CR51_INCLUDE_CR51_HOST_COMMANDS_H */
diff --git a/hoth_state.cpp b/hoth_state.cpp
index ff6b3ef..3cc178f 100644
--- a/hoth_state.cpp
+++ b/hoth_state.cpp
@@ -183,6 +183,20 @@
stdplus::print(stderr, "Fetching Hoth key rotation had an exception: {}\n",
e.what());
}
+
+ try {
+ secure_boot_enforcement_state secure_boot_state =
+ ecUtil->getSecureBootEnforcementState();
+ HothStateObject::secureBootEnforced(secure_boot_state.enabled != 0);
+ } catch (const internal::CommandNotSupportedException &e) {
+ // Do not log if unsupported
+ HothStateObject::secureBootEnforced(false);
+ } catch (const std::exception &e) {
+ HothStateObject::secureBootEnforced(false);
+ stdplus::print(
+ stderr, "Fetching Hoth secure boot enforcement had an exception: {}\n",
+ e.what());
+ }
}
void HothState::timerUpdateMetrics() {
diff --git a/test/ec_util_mock.hpp b/test/ec_util_mock.hpp
index a756057..23dc1c5 100644
--- a/test/ec_util_mock.hpp
+++ b/test/ec_util_mock.hpp
@@ -34,6 +34,8 @@
MOCK_CONST_METHOD0(getHothKeyRotationStatus,
ec_response_key_rotation_status());
MOCK_CONST_METHOD1(isHostCommandSupported, bool(uint16_t));
+ MOCK_CONST_METHOD0(getSecureBootEnforcementState,
+ secure_boot_enforcement_state());
};
} // namespace internal
diff --git a/test/ec_util_unittest.cpp b/test/ec_util_unittest.cpp
index 575b785..db0d6dd 100644
--- a/test/ec_util_unittest.cpp
+++ b/test/ec_util_unittest.cpp
@@ -218,6 +218,70 @@
EXPECT_THROW(ecUtil.getHothKeyRotationStatus(), CommandNotSupportedException);
}
+class EcUtilSecureBootEnforcementTest : public EcUtilTest {};
+
+TEST_F(EcUtilSecureBootEnforcementTest, commandNotSupported) {
+ std::vector<uint8_t> rsp(goodResponseStr.begin(), goodResponseStr.end());
+ rsp.push_back(0);
+ EXPECT_CALL(hostCmd,
+ sendCommand(EC_CMD_BOARD_SPECIFIC_BASE +
+ EC_PRV_CMD_HOTH_IS_HOST_COMMAND_SUPPORTED,
+ _, _, _))
+ .WillOnce(Return(rsp));
+ EXPECT_THROW(ecUtil.getSecureBootEnforcementState(),
+ CommandNotSupportedException);
+}
+
+TEST_F(EcUtilSecureBootEnforcementTest, sendCommandReturnsBadResultFails) {
+ std::vector<uint8_t> rsp_supported(goodResponseStr.begin(),
+ goodResponseStr.end());
+ rsp_supported.push_back(1);
+ EXPECT_CALL(hostCmd,
+ sendCommand(EC_CMD_BOARD_SPECIFIC_BASE +
+ EC_PRV_CMD_HOTH_IS_HOST_COMMAND_SUPPORTED,
+ _, _, _))
+ .WillOnce(Return(rsp_supported));
+
+ std::vector<uint8_t> rsp(goodResponseStr.begin(), goodResponseStr.end());
+ // Change the RspHeader.result to something other than EC_RES_SUCCESS
+ rsp[2] = internal::EC_RES_ERROR;
+
+ EXPECT_CALL(
+ hostCmd,
+ sendCommand(
+ EC_CMD_BOARD_SPECIFIC_BASE + EC_PRV_CMD_HOTH_GET_SECURE_BOOT_ENFORCEMENT,
+ ecUtil.kVersionZero, nullptr, 0))
+ .WillOnce(Return(rsp));
+
+ EXPECT_THROW(ecUtil.getSecureBootEnforcementState(), CommandRunException);
+}
+
+TEST_F(EcUtilSecureBootEnforcementTest, sendCommandReturnsGoodResponseSuccess) {
+ std::vector<uint8_t> rsp_supported(goodResponseStr.begin(),
+ goodResponseStr.end());
+ rsp_supported.push_back(1);
+ EXPECT_CALL(hostCmd,
+ sendCommand(EC_CMD_BOARD_SPECIFIC_BASE +
+ EC_PRV_CMD_HOTH_IS_HOST_COMMAND_SUPPORTED,
+ _, _, _))
+ .WillOnce(Return(rsp_supported));
+
+ std::vector<uint8_t> rsp(goodResponseStr.begin(), goodResponseStr.end());
+ secure_boot_enforcement_state expected = {.enabled = 1, .reserved0 = {}};
+ const uint8_t* body_ptr = reinterpret_cast<const uint8_t*>(&expected);
+ rsp.insert(rsp.end(), body_ptr, body_ptr + sizeof(expected));
+
+ EXPECT_CALL(
+ hostCmd,
+ sendCommand(
+ EC_CMD_BOARD_SPECIFIC_BASE + EC_PRV_CMD_HOTH_GET_SECURE_BOOT_ENFORCEMENT,
+ ecUtil.kVersionZero, nullptr, 0))
+ .WillOnce(Return(rsp));
+
+ secure_boot_enforcement_state actual = ecUtil.getSecureBootEnforcementState();
+ EXPECT_EQ(actual.enabled, expected.enabled);
+}
+
} // namespace
} // namespace internal
} // namespace hoth
diff --git a/test/hoth_state_unittest.cpp b/test/hoth_state_unittest.cpp
index a0c09a4..efc8589 100644
--- a/test/hoth_state_unittest.cpp
+++ b/test/hoth_state_unittest.cpp
@@ -175,6 +175,35 @@
EXPECT_EQ(hoth_state->keyRotationValidationHashData(), 0x46464646);
}
+TEST_F(HothStateTest, SecureBootEnforced) {
+ secure_boot_enforcement_state response = {};
+ response.enabled = 1;
+ EXPECT_CALL(ecUtil, getSecureBootEnforcementState())
+ .WillOnce(Return(response));
+ EXPECT_NO_THROW(hoth_state->updateMetrics());
+ EXPECT_TRUE(hoth_state->secureBootEnforced());
+
+ response.enabled = 0;
+ EXPECT_CALL(ecUtil, getSecureBootEnforcementState())
+ .WillOnce(Return(response));
+ EXPECT_NO_THROW(hoth_state->updateMetrics());
+ EXPECT_FALSE(hoth_state->secureBootEnforced());
+}
+
+TEST_F(HothStateTest, SecureBootEnforcedUnsupported) {
+ EXPECT_CALL(ecUtil, getSecureBootEnforcementState())
+ .WillOnce(testing::Throw(internal::CommandNotSupportedException(0)));
+ EXPECT_NO_THROW(hoth_state->updateMetrics());
+ EXPECT_FALSE(hoth_state->secureBootEnforced());
+}
+
+TEST_F(HothStateTest, SecureBootEnforcedException) {
+ EXPECT_CALL(ecUtil, getSecureBootEnforcementState())
+ .WillOnce(testing::Throw(std::runtime_error("test")));
+ EXPECT_NO_THROW(hoth_state->updateMetrics());
+ EXPECT_FALSE(hoth_state->secureBootEnforced());
+}
+
ec_response_statistics getMockStatistics() {
ec_response_statistics ret = {
.valid_words = 22,
diff --git a/yaml/xyz/openbmc_project/Control/Hoth/State.interface.yaml b/yaml/xyz/openbmc_project/Control/Hoth/State.interface.yaml
index 1ca65c7..6830c46 100644
--- a/yaml/xyz/openbmc_project/Control/Hoth/State.interface.yaml
+++ b/yaml/xyz/openbmc_project/Control/Hoth/State.interface.yaml
@@ -252,3 +252,13 @@
If validation method is hash, first 32 bits of cr51 hash.
errors:
- self.Error.ExpectedInfoNotFound
+
+ - name: SecureBootEnforced
+ type: boolean
+ default: false
+ flags:
+ - readonly
+ description: >
+ Whether secure boot is enforced.
+ errors:
+ - self.Error.ExpectedInfoNotFound