18b7c156eSVernon Mauery #include <ipmi-allowlist.hpp> 28b7c156eSVernon Mauery #include <ipmid/api.hpp> 38b7c156eSVernon Mauery #include <ipmid/utils.hpp> 48b7c156eSVernon Mauery #include <phosphor-logging/elog-errors.hpp> 58b7c156eSVernon Mauery #include <phosphor-logging/log.hpp> 68b7c156eSVernon Mauery #include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp> 78b7c156eSVernon Mauery 88b7c156eSVernon Mauery #include <algorithm> 98b7c156eSVernon Mauery #include <array> 108b7c156eSVernon Mauery 118b7c156eSVernon Mauery using namespace phosphor::logging; 128b7c156eSVernon Mauery using namespace sdbusplus::xyz::openbmc_project::Common::Error; 138b7c156eSVernon Mauery using namespace sdbusplus::xyz::openbmc_project::Control::Security::server; 148b7c156eSVernon Mauery 158b7c156eSVernon Mauery namespace ipmi 168b7c156eSVernon Mauery { 178b7c156eSVernon Mauery 188b7c156eSVernon Mauery // put the filter provider in an unnamed namespace 198b7c156eSVernon Mauery namespace 208b7c156eSVernon Mauery { 218b7c156eSVernon Mauery 228b7c156eSVernon Mauery /** @class AllowlistFilter 238b7c156eSVernon Mauery * 248b7c156eSVernon Mauery * Class that implements an IPMI message filter based 258b7c156eSVernon Mauery * on incoming interface and a restriction mode setting 268b7c156eSVernon Mauery */ 278b7c156eSVernon Mauery class AllowlistFilter 288b7c156eSVernon Mauery { 298b7c156eSVernon Mauery 308b7c156eSVernon Mauery public: 318b7c156eSVernon Mauery AllowlistFilter(); 328b7c156eSVernon Mauery ~AllowlistFilter() = default; 338b7c156eSVernon Mauery AllowlistFilter(AllowlistFilter const&) = delete; 348b7c156eSVernon Mauery AllowlistFilter(AllowlistFilter&&) = delete; 358b7c156eSVernon Mauery AllowlistFilter& operator=(AllowlistFilter const&) = delete; 368b7c156eSVernon Mauery AllowlistFilter& operator=(AllowlistFilter&&) = delete; 378b7c156eSVernon Mauery 388b7c156eSVernon Mauery private: 398b7c156eSVernon Mauery void postInit(); 408b7c156eSVernon Mauery void cacheRestrictedAndPostCompleteMode(); 418b7c156eSVernon Mauery void handleRestrictedModeChange(sdbusplus::message_t& m); 428b7c156eSVernon Mauery void handlePostCompleteChange(sdbusplus::message_t& m); 438b7c156eSVernon Mauery void updatePostComplete(const std::string& value); 448b7c156eSVernon Mauery void updateRestrictionMode(const std::string& value); 458b7c156eSVernon Mauery ipmi::Cc filterMessage(ipmi::message::Request::ptr request); 468b7c156eSVernon Mauery void handleCoreBiosDoneChange(sdbusplus::message_t& m); 478b7c156eSVernon Mauery void cacheCoreBiosDone(); 488b7c156eSVernon Mauery 498b7c156eSVernon Mauery // the BMC KCS Policy Control Modes document uses different names 508b7c156eSVernon Mauery // than the RestrictionModes D-Bus interface; use aliases 518b7c156eSVernon Mauery static constexpr RestrictionMode::Modes restrictionModeAllowAll = 528b7c156eSVernon Mauery RestrictionMode::Modes::Provisioning; 538b7c156eSVernon Mauery static constexpr RestrictionMode::Modes restrictionModeRestricted = 548b7c156eSVernon Mauery RestrictionMode::Modes::ProvisionedHostWhitelist; 558b7c156eSVernon Mauery static constexpr RestrictionMode::Modes restrictionModeDenyAll = 568b7c156eSVernon Mauery RestrictionMode::Modes::ProvisionedHostDisabled; 578b7c156eSVernon Mauery 588b7c156eSVernon Mauery RestrictionMode::Modes restrictionMode = restrictionModeRestricted; 598b7c156eSVernon Mauery bool postCompleted = true; 608b7c156eSVernon Mauery bool coreBIOSDone = true; 618b7c156eSVernon Mauery int channelSMM = -1; 628b7c156eSVernon Mauery std::shared_ptr<sdbusplus::asio::connection> bus; 638b7c156eSVernon Mauery std::unique_ptr<sdbusplus::bus::match_t> modeChangeMatch; 648b7c156eSVernon Mauery std::unique_ptr<sdbusplus::bus::match_t> modeIntfAddedMatch; 658b7c156eSVernon Mauery std::unique_ptr<sdbusplus::bus::match_t> postCompleteMatch; 668b7c156eSVernon Mauery std::unique_ptr<sdbusplus::bus::match_t> postCompleteIntfAddedMatch; 678b7c156eSVernon Mauery std::unique_ptr<sdbusplus::bus::match_t> platStateChangeMatch; 688b7c156eSVernon Mauery std::unique_ptr<sdbusplus::bus::match_t> platStateIntfAddedMatch; 698b7c156eSVernon Mauery 708b7c156eSVernon Mauery static constexpr const char restrictionModeIntf[] = 718b7c156eSVernon Mauery "xyz.openbmc_project.Control.Security.RestrictionMode"; 728b7c156eSVernon Mauery static constexpr const char* systemOsStatusIntf = 738b7c156eSVernon Mauery "xyz.openbmc_project.State.OperatingSystem.Status"; 748b7c156eSVernon Mauery static constexpr const char* hostMiscIntf = 758b7c156eSVernon Mauery "xyz.openbmc_project.State.Host.Misc"; 768b7c156eSVernon Mauery static constexpr const char* restrictionModePath = 778b7c156eSVernon Mauery "/xyz/openbmc_project/control/security/restriction_mode"; 788b7c156eSVernon Mauery static constexpr const char* systemOsStatusPath = 798b7c156eSVernon Mauery "/xyz/openbmc_project/state/os"; 808b7c156eSVernon Mauery }; 818b7c156eSVernon Mauery 828b7c156eSVernon Mauery static inline uint8_t getSMMChannel() 838b7c156eSVernon Mauery { 848b7c156eSVernon Mauery ipmi::ChannelInfo chInfo; 858b7c156eSVernon Mauery 868b7c156eSVernon Mauery for (int channel = 0; channel < ipmi::maxIpmiChannels; channel++) 878b7c156eSVernon Mauery { 888b7c156eSVernon Mauery if (ipmi::getChannelInfo(channel, chInfo) != ipmi::ccSuccess) 898b7c156eSVernon Mauery { 908b7c156eSVernon Mauery continue; 918b7c156eSVernon Mauery } 928b7c156eSVernon Mauery 938b7c156eSVernon Mauery if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) == 948b7c156eSVernon Mauery ipmi::EChannelMediumType::systemInterface && 958b7c156eSVernon Mauery channel != ipmi::channelSystemIface) 968b7c156eSVernon Mauery { 978b7c156eSVernon Mauery log<level::INFO>("SMM channel number", 988b7c156eSVernon Mauery entry("CHANNEL=%d", channel)); 998b7c156eSVernon Mauery return channel; 1008b7c156eSVernon Mauery } 1018b7c156eSVernon Mauery } 1028b7c156eSVernon Mauery log<level::ERR>("Unable to find SMM Channel Info"); 1038b7c156eSVernon Mauery return -1; 1048b7c156eSVernon Mauery } 1058b7c156eSVernon Mauery 1068b7c156eSVernon Mauery AllowlistFilter::AllowlistFilter() 1078b7c156eSVernon Mauery { 1088b7c156eSVernon Mauery bus = getSdBus(); 1098b7c156eSVernon Mauery 1108b7c156eSVernon Mauery log<level::INFO>("Loading Allowlist filter"); 1118b7c156eSVernon Mauery 1128b7c156eSVernon Mauery ipmi::registerFilter(ipmi::prioOpenBmcBase, 1138b7c156eSVernon Mauery [this](ipmi::message::Request::ptr request) { 1148b7c156eSVernon Mauery return filterMessage(request); 1158b7c156eSVernon Mauery }); 1168b7c156eSVernon Mauery 1178b7c156eSVernon Mauery channelSMM = getSMMChannel(); 1188b7c156eSVernon Mauery // wait until io->run is going to fetch RestrictionMode 1198b7c156eSVernon Mauery post_work([this]() { postInit(); }); 1208b7c156eSVernon Mauery } 1218b7c156eSVernon Mauery 1228b7c156eSVernon Mauery void AllowlistFilter::cacheRestrictedAndPostCompleteMode() 1238b7c156eSVernon Mauery { 1248b7c156eSVernon Mauery try 1258b7c156eSVernon Mauery { 1268b7c156eSVernon Mauery auto service = 1278b7c156eSVernon Mauery ipmi::getService(*bus, restrictionModeIntf, restrictionModePath); 1288b7c156eSVernon Mauery ipmi::Value v = 1298b7c156eSVernon Mauery ipmi::getDbusProperty(*bus, service, restrictionModePath, 1308b7c156eSVernon Mauery restrictionModeIntf, "RestrictionMode"); 1318b7c156eSVernon Mauery auto& mode = std::get<std::string>(v); 1328b7c156eSVernon Mauery restrictionMode = RestrictionMode::convertModesFromString(mode); 1338b7c156eSVernon Mauery log<level::INFO>("Read restriction mode", 1348b7c156eSVernon Mauery entry("VALUE=%d", static_cast<int>(restrictionMode))); 1358b7c156eSVernon Mauery } 1368b7c156eSVernon Mauery catch (const std::exception&) 1378b7c156eSVernon Mauery { 1388b7c156eSVernon Mauery log<level::ERR>("Could not initialize provisioning mode, " 1398b7c156eSVernon Mauery "defaulting to restricted", 1408b7c156eSVernon Mauery entry("VALUE=%d", static_cast<int>(restrictionMode))); 1418b7c156eSVernon Mauery } 1428b7c156eSVernon Mauery 1438b7c156eSVernon Mauery try 1448b7c156eSVernon Mauery { 1458b7c156eSVernon Mauery auto service = 1468b7c156eSVernon Mauery ipmi::getService(*bus, systemOsStatusIntf, systemOsStatusPath); 1478b7c156eSVernon Mauery ipmi::Value v = 1488b7c156eSVernon Mauery ipmi::getDbusProperty(*bus, service, systemOsStatusPath, 1498b7c156eSVernon Mauery systemOsStatusIntf, "OperatingSystemState"); 1508b7c156eSVernon Mauery auto& value = std::get<std::string>(v); 1518b7c156eSVernon Mauery updatePostComplete(value); 1528b7c156eSVernon Mauery log<level::INFO>("Read POST complete value", 1538b7c156eSVernon Mauery entry("VALUE=%d", postCompleted)); 1548b7c156eSVernon Mauery } 1558b7c156eSVernon Mauery catch (const std::exception&) 1568b7c156eSVernon Mauery { 1578b7c156eSVernon Mauery log<level::ERR>("Error in OperatingSystemState Get"); 1588b7c156eSVernon Mauery postCompleted = true; 1598b7c156eSVernon Mauery } 1608b7c156eSVernon Mauery } 1618b7c156eSVernon Mauery 1628b7c156eSVernon Mauery void AllowlistFilter::updateRestrictionMode(const std::string& value) 1638b7c156eSVernon Mauery { 1648b7c156eSVernon Mauery restrictionMode = RestrictionMode::convertModesFromString(value); 1658b7c156eSVernon Mauery log<level::INFO>("Updated restriction mode", 1668b7c156eSVernon Mauery entry("VALUE=%d", static_cast<int>(restrictionMode))); 1678b7c156eSVernon Mauery } 1688b7c156eSVernon Mauery 1698b7c156eSVernon Mauery void AllowlistFilter::handleRestrictedModeChange(sdbusplus::message_t& m) 1708b7c156eSVernon Mauery { 1718b7c156eSVernon Mauery std::string signal = m.get_member(); 1728b7c156eSVernon Mauery if (signal == "PropertiesChanged") 1738b7c156eSVernon Mauery { 1748b7c156eSVernon Mauery std::string intf; 1758b7c156eSVernon Mauery std::vector<std::pair<std::string, ipmi::Value>> propertyList; 1768b7c156eSVernon Mauery m.read(intf, propertyList); 1778b7c156eSVernon Mauery for (const auto& property : propertyList) 1788b7c156eSVernon Mauery { 1798b7c156eSVernon Mauery if (property.first == "RestrictionMode") 1808b7c156eSVernon Mauery { 1818b7c156eSVernon Mauery updateRestrictionMode(std::get<std::string>(property.second)); 1828b7c156eSVernon Mauery } 1838b7c156eSVernon Mauery } 1848b7c156eSVernon Mauery } 1858b7c156eSVernon Mauery else if (signal == "InterfacesAdded") 1868b7c156eSVernon Mauery { 1878b7c156eSVernon Mauery sdbusplus::message::object_path path; 1888b7c156eSVernon Mauery DbusInterfaceMap restModeObj; 1898b7c156eSVernon Mauery m.read(path, restModeObj); 1908b7c156eSVernon Mauery auto intfItr = restModeObj.find(restrictionModeIntf); 1918b7c156eSVernon Mauery if (intfItr == restModeObj.end()) 1928b7c156eSVernon Mauery { 1938b7c156eSVernon Mauery return; 1948b7c156eSVernon Mauery } 1958b7c156eSVernon Mauery PropertyMap& propertyList = intfItr->second; 1968b7c156eSVernon Mauery auto itr = propertyList.find("RestrictionMode"); 1978b7c156eSVernon Mauery if (itr == propertyList.end()) 1988b7c156eSVernon Mauery { 1998b7c156eSVernon Mauery return; 2008b7c156eSVernon Mauery } 2018b7c156eSVernon Mauery updateRestrictionMode(std::get<std::string>(itr->second)); 2028b7c156eSVernon Mauery } 2038b7c156eSVernon Mauery } 2048b7c156eSVernon Mauery 2058b7c156eSVernon Mauery void AllowlistFilter::updatePostComplete(const std::string& value) 2068b7c156eSVernon Mauery { 2078b7c156eSVernon Mauery // The short string "Standby" is deprecated in favor of the full enum string 2088b7c156eSVernon Mauery // Support for the short string will be removed in the future. 2098b7c156eSVernon Mauery postCompleted = (value == "Standby") || 2108b7c156eSVernon Mauery (value == "xyz.openbmc_project.State.OperatingSystem." 2118b7c156eSVernon Mauery "Status.OSStatus.Standby"); 2128b7c156eSVernon Mauery log<level::INFO>(postCompleted ? "Updated to POST Complete" 2138b7c156eSVernon Mauery : "Updated to !POST Complete"); 2148b7c156eSVernon Mauery } 2158b7c156eSVernon Mauery 2168b7c156eSVernon Mauery void AllowlistFilter::handlePostCompleteChange(sdbusplus::message_t& m) 2178b7c156eSVernon Mauery { 2188b7c156eSVernon Mauery std::string signal = m.get_member(); 2198b7c156eSVernon Mauery if (signal == "PropertiesChanged") 2208b7c156eSVernon Mauery { 2218b7c156eSVernon Mauery std::string intf; 2228b7c156eSVernon Mauery std::vector<std::pair<std::string, ipmi::Value>> propertyList; 2238b7c156eSVernon Mauery m.read(intf, propertyList); 2248b7c156eSVernon Mauery for (const auto& property : propertyList) 2258b7c156eSVernon Mauery { 2268b7c156eSVernon Mauery if (property.first == "OperatingSystemState") 2278b7c156eSVernon Mauery { 2288b7c156eSVernon Mauery updatePostComplete(std::get<std::string>(property.second)); 2298b7c156eSVernon Mauery } 2308b7c156eSVernon Mauery } 2318b7c156eSVernon Mauery } 2328b7c156eSVernon Mauery else if (signal == "InterfacesAdded") 2338b7c156eSVernon Mauery { 2348b7c156eSVernon Mauery sdbusplus::message::object_path path; 2358b7c156eSVernon Mauery DbusInterfaceMap postCompleteObj; 2368b7c156eSVernon Mauery m.read(path, postCompleteObj); 2378b7c156eSVernon Mauery auto intfItr = postCompleteObj.find(systemOsStatusIntf); 2388b7c156eSVernon Mauery if (intfItr == postCompleteObj.end()) 2398b7c156eSVernon Mauery { 2408b7c156eSVernon Mauery return; 2418b7c156eSVernon Mauery } 2428b7c156eSVernon Mauery PropertyMap& propertyList = intfItr->second; 2438b7c156eSVernon Mauery auto itr = propertyList.find("OperatingSystemState"); 2448b7c156eSVernon Mauery if (itr == propertyList.end()) 2458b7c156eSVernon Mauery { 2468b7c156eSVernon Mauery return; 2478b7c156eSVernon Mauery } 2488b7c156eSVernon Mauery updatePostComplete(std::get<std::string>(itr->second)); 2498b7c156eSVernon Mauery } 2508b7c156eSVernon Mauery } 2518b7c156eSVernon Mauery 2528b7c156eSVernon Mauery void AllowlistFilter::cacheCoreBiosDone() 2538b7c156eSVernon Mauery { 2548b7c156eSVernon Mauery std::string coreBiosDonePath; 2558b7c156eSVernon Mauery std::string coreBiosDoneService; 2568b7c156eSVernon Mauery try 2578b7c156eSVernon Mauery { 2588b7c156eSVernon Mauery ipmi::DbusObjectInfo coreBiosDoneObj = 2598b7c156eSVernon Mauery ipmi::getDbusObject(*bus, hostMiscIntf); 2608b7c156eSVernon Mauery 2618b7c156eSVernon Mauery coreBiosDonePath = coreBiosDoneObj.first; 2628b7c156eSVernon Mauery coreBiosDoneService = coreBiosDoneObj.second; 2638b7c156eSVernon Mauery } 2648b7c156eSVernon Mauery catch (const std::exception&) 2658b7c156eSVernon Mauery { 2668b7c156eSVernon Mauery log<level::ERR>("Could not initialize CoreBiosDone, " 2678b7c156eSVernon Mauery "coreBIOSDone asserted as default"); 2688b7c156eSVernon Mauery return; 2698b7c156eSVernon Mauery } 2708b7c156eSVernon Mauery 2718b7c156eSVernon Mauery bus->async_method_call( 2728b7c156eSVernon Mauery [this](boost::system::error_code ec, const ipmi::Value& v) { 2738b7c156eSVernon Mauery if (ec) 2748b7c156eSVernon Mauery { 2758b7c156eSVernon Mauery log<level::ERR>( 2768b7c156eSVernon Mauery "async call failed, coreBIOSDone asserted as default"); 2778b7c156eSVernon Mauery return; 2788b7c156eSVernon Mauery } 2798b7c156eSVernon Mauery coreBIOSDone = std::get<bool>(v); 2808b7c156eSVernon Mauery log<level::INFO>("Read CoreBiosDone", 2818b7c156eSVernon Mauery entry("VALUE=%d", static_cast<int>(coreBIOSDone))); 2828b7c156eSVernon Mauery }, 2838b7c156eSVernon Mauery coreBiosDoneService, coreBiosDonePath, 2848b7c156eSVernon Mauery "org.freedesktop.DBus.Properties", "Get", hostMiscIntf, "CoreBiosDone"); 2858b7c156eSVernon Mauery } 2868b7c156eSVernon Mauery 2878b7c156eSVernon Mauery void AllowlistFilter::handleCoreBiosDoneChange(sdbusplus::message_t& msg) 2888b7c156eSVernon Mauery { 2898b7c156eSVernon Mauery std::string signal = msg.get_member(); 2908b7c156eSVernon Mauery if (signal == "PropertiesChanged") 2918b7c156eSVernon Mauery { 2928b7c156eSVernon Mauery std::string intf; 2938b7c156eSVernon Mauery std::vector<std::pair<std::string, ipmi::Value>> propertyList; 2948b7c156eSVernon Mauery msg.read(intf, propertyList); 2958b7c156eSVernon Mauery auto it = 2968b7c156eSVernon Mauery std::find_if(propertyList.begin(), propertyList.end(), 2978b7c156eSVernon Mauery [](const std::pair<std::string, ipmi::Value>& prop) { 2988b7c156eSVernon Mauery return prop.first == "CoreBiosDone"; 2998b7c156eSVernon Mauery }); 3008b7c156eSVernon Mauery 3018b7c156eSVernon Mauery if (it != propertyList.end()) 3028b7c156eSVernon Mauery { 3038b7c156eSVernon Mauery coreBIOSDone = std::get<bool>(it->second); 3048b7c156eSVernon Mauery log<level::INFO>(coreBIOSDone ? "coreBIOSDone asserted" 3058b7c156eSVernon Mauery : "coreBIOSDone not asserted"); 3068b7c156eSVernon Mauery } 3078b7c156eSVernon Mauery } 3088b7c156eSVernon Mauery else if (signal == "InterfacesAdded") 3098b7c156eSVernon Mauery { 3108b7c156eSVernon Mauery sdbusplus::message::object_path path; 3118b7c156eSVernon Mauery DbusInterfaceMap eSpiresetObj; 3128b7c156eSVernon Mauery msg.read(path, eSpiresetObj); 3138b7c156eSVernon Mauery auto intfItr = eSpiresetObj.find(hostMiscIntf); 3148b7c156eSVernon Mauery if (intfItr == eSpiresetObj.end()) 3158b7c156eSVernon Mauery { 3168b7c156eSVernon Mauery return; 3178b7c156eSVernon Mauery } 3188b7c156eSVernon Mauery PropertyMap& propertyList = intfItr->second; 3198b7c156eSVernon Mauery auto itr = propertyList.find("CoreBiosDone"); 3208b7c156eSVernon Mauery if (itr == propertyList.end()) 3218b7c156eSVernon Mauery { 3228b7c156eSVernon Mauery return; 3238b7c156eSVernon Mauery } 3248b7c156eSVernon Mauery coreBIOSDone = std::get<bool>(itr->second); 3258b7c156eSVernon Mauery log<level::INFO>(coreBIOSDone ? "coreBIOSDone asserted" 3268b7c156eSVernon Mauery : "coreBIOSDone not asserted"); 3278b7c156eSVernon Mauery } 3288b7c156eSVernon Mauery } 3298b7c156eSVernon Mauery 3308b7c156eSVernon Mauery void AllowlistFilter::postInit() 3318b7c156eSVernon Mauery { 3328b7c156eSVernon Mauery // Wait for changes on Restricted mode 3338b7c156eSVernon Mauery namespace rules = sdbusplus::bus::match::rules; 3348b7c156eSVernon Mauery const std::string filterStrModeChange = 3358b7c156eSVernon Mauery rules::type::signal() + rules::member("PropertiesChanged") + 3368b7c156eSVernon Mauery rules::interface("org.freedesktop.DBus.Properties") + 3378b7c156eSVernon Mauery rules::argN(0, restrictionModeIntf); 3388b7c156eSVernon Mauery 3398b7c156eSVernon Mauery const std::string filterStrModeIntfAdd = 3408b7c156eSVernon Mauery rules::interfacesAdded() + 3418b7c156eSVernon Mauery rules::argNpath( 3428b7c156eSVernon Mauery 0, "/xyz/openbmc_project/control/security/restriction_mode"); 3438b7c156eSVernon Mauery 3448b7c156eSVernon Mauery const std::string filterStrPostComplete = 3458b7c156eSVernon Mauery rules::type::signal() + rules::member("PropertiesChanged") + 3468b7c156eSVernon Mauery rules::interface("org.freedesktop.DBus.Properties") + 3478b7c156eSVernon Mauery rules::argN(0, systemOsStatusIntf); 3488b7c156eSVernon Mauery 3498b7c156eSVernon Mauery const std::string filterStrPostIntfAdd = 3508b7c156eSVernon Mauery rules::interfacesAdded() + 3518b7c156eSVernon Mauery rules::argNpath(0, "/xyz/openbmc_project/state/os"); 3528b7c156eSVernon Mauery 3538b7c156eSVernon Mauery const std::string filterStrPlatStateChange = 3548b7c156eSVernon Mauery rules::type::signal() + rules::member("PropertiesChanged") + 3558b7c156eSVernon Mauery rules::interface("org.freedesktop.DBus.Properties") + 3568b7c156eSVernon Mauery rules::argN(0, hostMiscIntf); 3578b7c156eSVernon Mauery 3588b7c156eSVernon Mauery const std::string filterStrPlatStateIntfAdd = 3598b7c156eSVernon Mauery rules::interfacesAdded() + 3608b7c156eSVernon Mauery rules::argNpath(0, "/xyz/openbmc_project/misc/platform_state"); 3618b7c156eSVernon Mauery 3628b7c156eSVernon Mauery modeChangeMatch = std::make_unique<sdbusplus::bus::match_t>( 3638b7c156eSVernon Mauery *bus, filterStrModeChange, 3648b7c156eSVernon Mauery [this](sdbusplus::message_t& m) { handleRestrictedModeChange(m); }); 3658b7c156eSVernon Mauery modeIntfAddedMatch = std::make_unique<sdbusplus::bus::match_t>( 3668b7c156eSVernon Mauery *bus, filterStrModeIntfAdd, 3678b7c156eSVernon Mauery [this](sdbusplus::message_t& m) { handleRestrictedModeChange(m); }); 3688b7c156eSVernon Mauery 3698b7c156eSVernon Mauery postCompleteMatch = std::make_unique<sdbusplus::bus::match_t>( 3708b7c156eSVernon Mauery *bus, filterStrPostComplete, 3718b7c156eSVernon Mauery [this](sdbusplus::message_t& m) { handlePostCompleteChange(m); }); 3728b7c156eSVernon Mauery 3738b7c156eSVernon Mauery postCompleteIntfAddedMatch = std::make_unique<sdbusplus::bus::match_t>( 3748b7c156eSVernon Mauery *bus, filterStrPostIntfAdd, 3758b7c156eSVernon Mauery [this](sdbusplus::message_t& m) { handlePostCompleteChange(m); }); 3768b7c156eSVernon Mauery 3778b7c156eSVernon Mauery platStateChangeMatch = std::make_unique<sdbusplus::bus::match_t>( 3788b7c156eSVernon Mauery *bus, filterStrPlatStateChange, 3798b7c156eSVernon Mauery [this](sdbusplus::message_t& m) { handleCoreBiosDoneChange(m); }); 3808b7c156eSVernon Mauery 3818b7c156eSVernon Mauery platStateIntfAddedMatch = std::make_unique<sdbusplus::bus::match_t>( 3828b7c156eSVernon Mauery *bus, filterStrPlatStateIntfAdd, 3838b7c156eSVernon Mauery [this](sdbusplus::message_t& m) { handleCoreBiosDoneChange(m); }); 3848b7c156eSVernon Mauery 3858b7c156eSVernon Mauery // Initialize restricted mode 3868b7c156eSVernon Mauery cacheRestrictedAndPostCompleteMode(); 3878b7c156eSVernon Mauery // Initialize CoreBiosDone 3888b7c156eSVernon Mauery cacheCoreBiosDone(); 3898b7c156eSVernon Mauery } 3908b7c156eSVernon Mauery 3918b7c156eSVernon Mauery ipmi::Cc AllowlistFilter::filterMessage(ipmi::message::Request::ptr request) 3928b7c156eSVernon Mauery { 3938b7c156eSVernon Mauery auto channelMask = static_cast<unsigned short>(1 << request->ctx->channel); 3948b7c156eSVernon Mauery bool Allowlisted = std::binary_search( 3958b7c156eSVernon Mauery allowlist.cbegin(), allowlist.cend(), 3968b7c156eSVernon Mauery std::make_tuple(request->ctx->netFn, request->ctx->cmd, channelMask), 3978b7c156eSVernon Mauery [](const netfncmd_tuple& first, const netfncmd_tuple& value) { 3988b7c156eSVernon Mauery return (std::get<2>(first) & std::get<2>(value)) 3998b7c156eSVernon Mauery ? first < std::make_tuple(std::get<0>(value), 4008b7c156eSVernon Mauery std::get<1>(value), 4018b7c156eSVernon Mauery std::get<2>(first)) 4028b7c156eSVernon Mauery : first < value; 4038b7c156eSVernon Mauery }); 4048b7c156eSVernon Mauery 4058b7c156eSVernon Mauery // no special handling for non-system-interface channels 4068b7c156eSVernon Mauery if (!(request->ctx->channel == ipmi::channelSystemIface || 4078b7c156eSVernon Mauery request->ctx->channel == channelSMM)) 4088b7c156eSVernon Mauery { 4098b7c156eSVernon Mauery if (!Allowlisted) 4108b7c156eSVernon Mauery { 4118b7c156eSVernon Mauery log<level::INFO>("Channel/NetFn/Cmd not Allowlisted", 4128b7c156eSVernon Mauery entry("CHANNEL=0x%X", request->ctx->channel), 4138b7c156eSVernon Mauery entry("NETFN=0x%X", int(request->ctx->netFn)), 4148b7c156eSVernon Mauery entry("CMD=0x%X", int(request->ctx->cmd))); 4158b7c156eSVernon Mauery return ipmi::ccInsufficientPrivilege; 4168b7c156eSVernon Mauery } 4178b7c156eSVernon Mauery return ipmi::ccSuccess; 4188b7c156eSVernon Mauery } 4198b7c156eSVernon Mauery 4208b7c156eSVernon Mauery // for system interface, filtering is done as follows: 4218b7c156eSVernon Mauery // Allow All: preboot ? ccSuccess : ccSuccess 4228b7c156eSVernon Mauery // Restricted: preboot ? ccSuccess : 4238b7c156eSVernon Mauery // ( Allowlist ? ccSuccess : ccInsufficientPrivilege ) 4248b7c156eSVernon Mauery // Deny All: preboot ? ccSuccess : ccInsufficientPrivilege 4258b7c156eSVernon Mauery 4268b7c156eSVernon Mauery if (!(postCompleted || coreBIOSDone)) 4278b7c156eSVernon Mauery { 4288b7c156eSVernon Mauery // Allow all commands, till POST or CoreBiosDone is completed 4298b7c156eSVernon Mauery return ipmi::ccSuccess; 4308b7c156eSVernon Mauery } 4318b7c156eSVernon Mauery 4328b7c156eSVernon Mauery switch (restrictionMode) 4338b7c156eSVernon Mauery { 4348b7c156eSVernon Mauery case RestrictionMode::Modes::None: 4358b7c156eSVernon Mauery case restrictionModeAllowAll: 4368b7c156eSVernon Mauery { 4378b7c156eSVernon Mauery // Allow All 4388b7c156eSVernon Mauery return ipmi::ccSuccess; 4398b7c156eSVernon Mauery break; 4408b7c156eSVernon Mauery } 4418b7c156eSVernon Mauery case restrictionModeRestricted: 4428b7c156eSVernon Mauery { 4438b7c156eSVernon Mauery // Restricted - follow Allowlist 4448b7c156eSVernon Mauery break; 4458b7c156eSVernon Mauery } 4468b7c156eSVernon Mauery case restrictionModeDenyAll: 4478b7c156eSVernon Mauery { 4488b7c156eSVernon Mauery // Deny All 4498b7c156eSVernon Mauery Allowlisted = false; 4508b7c156eSVernon Mauery break; 4518b7c156eSVernon Mauery } 452*80d4d5f9SMatt Simmering default: // for Allowlist and Blocklist 4538b7c156eSVernon Mauery return ipmi::ccInsufficientPrivilege; 4548b7c156eSVernon Mauery } 4558b7c156eSVernon Mauery 4568b7c156eSVernon Mauery if (!Allowlisted) 4578b7c156eSVernon Mauery { 4588b7c156eSVernon Mauery log<level::INFO>("Channel/NetFn/Cmd not allowlisted", 4598b7c156eSVernon Mauery entry("CHANNEL=0x%X", request->ctx->channel), 4608b7c156eSVernon Mauery entry("NETFN=0x%X", int(request->ctx->netFn)), 4618b7c156eSVernon Mauery entry("CMD=0x%X", int(request->ctx->cmd))); 4628b7c156eSVernon Mauery return ipmi::ccInsufficientPrivilege; 4638b7c156eSVernon Mauery } 4648b7c156eSVernon Mauery return ipmi::ccSuccess; 4658b7c156eSVernon Mauery } // namespace 4668b7c156eSVernon Mauery 4678b7c156eSVernon Mauery // instantiate the AllowlistFilter when this shared object is loaded 4688b7c156eSVernon Mauery AllowlistFilter allowlistFilter; 4698b7c156eSVernon Mauery 4708b7c156eSVernon Mauery } // namespace 4718b7c156eSVernon Mauery 4728b7c156eSVernon Mauery } // namespace ipmi 473