From dcfce847654bd7e2475ad74bedf569b6120701dd Mon Sep 17 00:00:00 2001 From: Richard Marian Thomaiyar Date: Tue, 18 Jun 2019 19:42:30 +0530 Subject: [PATCH 1/1] Update provisioning mode filter logic Updated provisioning mode filtering logic support. Based on the RestrictionMode property, Host (system) interface commands will be filtered as per the allowed list in ProvisionedHostWhitelist once POST complete is achieved. No commands will be allowed in ProvisionedHostDisabled after POST complete and in all other cases filterning logic will not be applied. Tested 1. Verified the filtering logic through EFI shell and made sure filtering logic is applied when RestrictionMode is in ProvisionedHostWhitelist mode 2. Verified no filtering logic is applied in normal modes 3. Made sure BIOS is able to execute commands, which are not in whitelist (Note: New whitelist conf is under review). Change-Id: I7a14e827d70e2d8d6975e600a0fd00e2a790bc22 Signed-off-by: Richard Marian Thomaiyar Signed-off-by: James Feist --- whitelist-filter.cpp | 191 ++++++++++++++++++++++++++++++------------- 1 file changed, 136 insertions(+), 55 deletions(-) diff --git a/whitelist-filter.cpp b/whitelist-filter.cpp index 9f1e7c8..53461b4 100644 --- a/whitelist-filter.cpp +++ b/whitelist-filter.cpp @@ -25,6 +25,7 @@ namespace */ class WhitelistFilter { + public: WhitelistFilter(); ~WhitelistFilter() = default; @@ -35,17 +36,24 @@ class WhitelistFilter private: void postInit(); - void cacheRestrictedMode(); + void cacheRestrictedAndPostCompleteMode(); void handleRestrictedModeChange(sdbusplus::message::message& m); + void handlePostCompleteChange(sdbusplus::message::message& m); ipmi::Cc filterMessage(ipmi::message::Request::ptr request); - bool restrictedMode = true; + sdbusplus::xyz::openbmc_project::Control::Security::server:: + RestrictionMode::Modes restrictionMode = + sdbusplus::xyz::openbmc_project::Control::Security::server:: + RestrictionMode::Modes::ProvisionedHostWhitelist; + bool postCompleted = false; std::shared_ptr bus; - std::unique_ptr objects; std::unique_ptr modeChangeMatch; + std::unique_ptr postCompleteMatch; static constexpr const char restrictionModeIntf[] = "xyz.openbmc_project.Control.Security.RestrictionMode"; + static constexpr const char* systemOsStatusIntf = + "xyz.openbmc_project.State.OperatingSystem.Status"; }; WhitelistFilter::WhitelistFilter() @@ -63,43 +71,83 @@ WhitelistFilter::WhitelistFilter() post_work([this]() { postInit(); }); } -void WhitelistFilter::cacheRestrictedMode() +void WhitelistFilter::cacheRestrictedAndPostCompleteMode() { using namespace sdbusplus::xyz::openbmc_project::Control::Security::server; + std::string restrictionModeSetting; std::string restrictionModeService; + std::string systemOsStatusPath; + std::string systemOsStatusService; try { - restrictionModeSetting = objects->map.at(restrictionModeIntf).at(0); + auto objects = settings::Objects( + *bus, std::vector({restrictionModeIntf})); + auto postCompleteObj = settings::Objects( + *bus, std::vector({systemOsStatusIntf})); + + restrictionModeSetting = objects.map.at(restrictionModeIntf).at(0); restrictionModeService = - objects->service(restrictionModeSetting, restrictionModeIntf); + objects.service(restrictionModeSetting, restrictionModeIntf); + + systemOsStatusPath = postCompleteObj.map.at(systemOsStatusIntf).at(0); + systemOsStatusService = + postCompleteObj.service(systemOsStatusPath, systemOsStatusIntf); } catch (const std::out_of_range& e) { - log( - "Could not look up restriction mode interface from cache"); + log( + "Could not initialize provisioning mode, defaulting to restricted"); + return; + } + catch (const std::exception&) + { + log( + "Could not initialize provisioning mode, defaulting to restricted"); return; } + bus->async_method_call( [this](boost::system::error_code ec, ipmi::Value v) { if (ec) { - log("Error in RestrictionMode Get"); - // Fail-safe to true. - restrictedMode = true; + log("Could not initialize provisioning mode, " + "defaulting to restricted"); return; } auto mode = std::get(v); - auto restrictionMode = - RestrictionMode::convertModesFromString(mode); - restrictedMode = - (restrictionMode == RestrictionMode::Modes::Whitelist); - log((restrictedMode ? "Set restrictedMode = true" - : "Set restrictedMode = false")); + restrictionMode = RestrictionMode::convertModesFromString(mode); + log( + "Read restriction mode", + entry("VALUE=%d", static_cast(restrictionMode))); }, restrictionModeService, restrictionModeSetting, "org.freedesktop.DBus.Properties", "Get", restrictionModeIntf, "RestrictionMode"); + + bus->async_method_call( + [this](boost::system::error_code ec, const ipmi::Value& v) { + if (ec) + { + log("Error in OperatingSystemState Get"); + postCompleted = true; + return; + } + auto value = std::get(v); + if (value == "Standby") + { + postCompleted = true; + } + else + { + postCompleted = false; + } + log("Read POST complete value", + entry("VALUE=%d", postCompleted)); + }, + systemOsStatusService, systemOsStatusPath, + "org.freedesktop.DBus.Properties", "Get", systemOsStatusIntf, + "OperatingSystemState"); } void WhitelistFilter::handleRestrictedModeChange(sdbusplus::message::message& m) @@ -112,61 +160,94 @@ void WhitelistFilter::handleRestrictedModeChange(sdbusplus::message::message& m) { if (property.first == "RestrictionMode") { - RestrictionMode::Modes restrictionMode = - RestrictionMode::convertModesFromString( - std::get(property.second)); - restrictedMode = - (restrictionMode == RestrictionMode::Modes::Whitelist); - log((restrictedMode - ? "Updated restrictedMode = true" - : "Updated restrictedMode = false")); + restrictionMode = RestrictionMode::convertModesFromString( + std::get(property.second)); + log( + "Updated restriction mode", + entry("VALUE=%d", static_cast(restrictionMode))); } } } - -void WhitelistFilter::postInit() +void WhitelistFilter::handlePostCompleteChange(sdbusplus::message::message& m) { - objects = std::make_unique( - *bus, std::vector({restrictionModeIntf})); - if (!objects) + std::string intf; + std::vector> propertyList; + m.read(intf, propertyList); + for (const auto& property : propertyList) { - log( - "Failed to create settings object; defaulting to restricted mode"); - return; + if (property.first == "OperatingSystemState") + { + std::string value = std::get(property.second); + if (value == "Standby") + { + postCompleted = true; + } + else + { + postCompleted = false; + } + log(postCompleted ? "Updated to POST Complete" + : "Updated to !POST Complete"); + } } - +} +void WhitelistFilter::postInit() +{ // Initialize restricted mode - cacheRestrictedMode(); + cacheRestrictedAndPostCompleteMode(); // Wait for changes on Restricted mode - std::string filterStr; - try - { - filterStr = sdbusplus::bus::match::rules::propertiesChanged( - objects->map.at(restrictionModeIntf).at(0), restrictionModeIntf); - } - catch (const std::out_of_range& e) - { - log("Failed to determine restriction mode filter string"); - return; - } + namespace rules = sdbusplus::bus::match::rules; + const std::string filterStrModeChange = + rules::type::signal() + rules::member("PropertiesChanged") + + rules::interface("org.freedesktop.DBus.Properties") + + rules::argN(0, restrictionModeIntf); + + const std::string filterStrPostComplete = + rules::type::signal() + rules::member("PropertiesChanged") + + rules::interface("org.freedesktop.DBus.Properties") + + rules::argN(0, systemOsStatusIntf); + modeChangeMatch = std::make_unique( - *bus, filterStr, [this](sdbusplus::message::message& m) { + *bus, filterStrModeChange, [this](sdbusplus::message::message& m) { handleRestrictedModeChange(m); }); + postCompleteMatch = std::make_unique( + *bus, filterStrPostComplete, [this](sdbusplus::message::message& m) { + handlePostCompleteChange(m); + }); } ipmi::Cc WhitelistFilter::filterMessage(ipmi::message::Request::ptr request) { - if (request->ctx->channel == ipmi::channelSystemIface && restrictedMode) + using namespace sdbusplus::xyz::openbmc_project::Control::Security::server; + + if (request->ctx->channel == ipmi::channelSystemIface && + (restrictionMode != RestrictionMode::Modes::None && + restrictionMode != RestrictionMode::Modes::Provisioning)) { - if (!std::binary_search( - whitelist.cbegin(), whitelist.cend(), - std::make_pair(request->ctx->netFn, request->ctx->cmd))) + if (!postCompleted) + { + // Allow all commands, till POST is not completed + return ipmi::ccSuccess; + } + switch (restrictionMode) { - log("Net function not whitelisted", - entry("NETFN=0x%X", int(request->ctx->netFn)), - entry("CMD=0x%X", int(request->ctx->cmd))); - return ipmi::ccInsufficientPrivilege; + case RestrictionMode::Modes::ProvisionedHostWhitelist: + { + if (!std::binary_search( + whitelist.cbegin(), whitelist.cend(), + std::make_pair(request->ctx->netFn, request->ctx->cmd))) + { + log( + "Net function not whitelisted", + entry("NETFN=0x%X", int(request->ctx->netFn)), + entry("CMD=0x%X", int(request->ctx->cmd))); + return ipmi::ccInsufficientPrivilege; + } + break; + } + default: // for whitelist, blacklist & HostDisabled + return ipmi::ccInsufficientPrivilege; } } return ipmi::ccSuccess; -- 2.17.1