From b1e329a6e5763cd40933f446bce759b585169e2d Mon Sep 17 00:00:00 2001 From: Brad Bishop Date: Wed, 2 Aug 2017 01:23:12 -0400 Subject: Add phosphor-msl-verify phosphor-msl-verify is a oneshot application for basic minimum ship level (MSL) verification. https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/xyz/openbmc_project/Control/README.msl.md Change-Id: Ifa036bb0a45255af7c7773bd910e83c64842d868 Signed-off-by: Brad Bishop --- mslverify/.gitignore | 1 + mslverify/Makefile.am | 15 ++++ mslverify/README.md | 10 +++ mslverify/util.hpp | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++ mslverify/verify.cpp | 114 +++++++++++++++++++++++++ 5 files changed, 365 insertions(+) create mode 100644 mslverify/.gitignore create mode 100644 mslverify/Makefile.am create mode 100644 mslverify/README.md create mode 100644 mslverify/util.hpp create mode 100644 mslverify/verify.cpp (limited to 'mslverify') diff --git a/mslverify/.gitignore b/mslverify/.gitignore new file mode 100644 index 0000000..0bd39bd --- /dev/null +++ b/mslverify/.gitignore @@ -0,0 +1 @@ +phosphor-msl-verify diff --git a/mslverify/Makefile.am b/mslverify/Makefile.am new file mode 100644 index 0000000..4d79c0a --- /dev/null +++ b/mslverify/Makefile.am @@ -0,0 +1,15 @@ +AM_DEFAULT_SOURCE_EXT = .cpp +AM_CPPFLAGS = -iquote ${top_srcdir} + +sbin_PROGRAMS = phosphor-msl-verify + +phosphor_msl_verify_SOURCES = \ + verify.cpp +phosphor_msl_verify_LDADD = \ + $(SDBUSPLUS_LIBS) \ + $(PHOSPHOR_DBUS_INTERFACES_LIBS) \ + $(PHOSPHOR_LOGGING_LIBS) +phosphor_msl_verify_CXXFLAGS = \ + $(SDBUSPLUS_CFLAGS) \ + $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) \ + $(PHOSPHOR_LOGGING_CFLAGS) diff --git a/mslverify/README.md b/mslverify/README.md new file mode 100644 index 0000000..612561e --- /dev/null +++ b/mslverify/README.md @@ -0,0 +1,10 @@ +phosphor-msl-verify + +phosphor-msl-verify is a "oneshot" application for basic minimum ship level +[(MSL)](https://github.com/openbmc/phosphor-dbus-interfaces/xyz/openbmc_project/control/README.msl) +verification. + +The application first determines if MSL validation is disabled and if not, +searches the D-Bus object namespace for any MeetsMSL interfaces and exits with +non-zero status if any inventory items implementing the interface are found +that do not meet the MSL. diff --git a/mslverify/util.hpp b/mslverify/util.hpp new file mode 100644 index 0000000..2c26fc2 --- /dev/null +++ b/mslverify/util.hpp @@ -0,0 +1,225 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace util +{ +namespace detail +{ +namespace errors = sdbusplus::xyz::openbmc_project::Common::Error; +} // namespace detail + +/** @brief Alias for PropertiesChanged signal callbacks. */ +template +using Properties = std::map>; + +namespace sdbusplus +{ + +/** @brief Get the bus connection. */ +static auto& getBus() __attribute__((pure)); +static auto& getBus() +{ + static auto bus = ::sdbusplus::bus::new_default(); + return bus; +} + +/** @brief Invoke a method. */ +template +static auto callMethod( + ::sdbusplus::bus::bus& bus, + const std::string& busName, + const std::string& path, + const std::string& interface, + const std::string& method, + Args&& ... args) +{ + auto reqMsg = bus.new_method_call( + busName.c_str(), + path.c_str(), + interface.c_str(), + method.c_str()); + reqMsg.append(std::forward(args)...); + auto respMsg = bus.call(reqMsg); + + if (respMsg.is_method_error()) + { + phosphor::logging::log( + "Failed to invoke DBus method.", + phosphor::logging::entry("PATH=%s", path.c_str()), + phosphor::logging::entry( + "INTERFACE=%s", interface.c_str()), + phosphor::logging::entry("METHOD=%s", method.c_str())); + phosphor::logging::elog(); + } + + return respMsg; +} + +/** @brief Invoke a method. */ +template +static auto callMethod( + const std::string& busName, + const std::string& path, + const std::string& interface, + const std::string& method, + Args&& ... args) +{ + return callMethod( + getBus(), + busName, + path, + interface, + method, + std::forward(args)...); +} + +/** @brief Invoke a method and read the response. */ +template +static auto callMethodAndRead( + ::sdbusplus::bus::bus& bus, + const std::string& busName, + const std::string& path, + const std::string& interface, + const std::string& method, + Args&& ... args) +{ + ::sdbusplus::message::message respMsg = + callMethod( + bus, + busName, + path, + interface, + method, + std::forward(args)...); + Ret resp; + respMsg.read(resp); + return resp; +} + +/** @brief Invoke a method and read the response. */ + template +static auto callMethodAndRead( + const std::string& busName, + const std::string& path, + const std::string& interface, + const std::string& method, + Args&& ... args) +{ + return callMethodAndRead( + getBus(), + busName, + path, + interface, + method, + std::forward(args)...); +} + + +/** @brief Get service from the mapper. */ +static auto getService( + ::sdbusplus::bus::bus& bus, + const std::string& path, + const std::string& interface) +{ + using namespace std::literals::string_literals; + using GetObject = std::map>; + + auto mapperResp = callMethodAndRead( + bus, + "xyz.openbmc_project.ObjectMapper"s, + "/xyz/openbmc_project/object_mapper"s, + "xyz.openbmc_project.ObjectMapper"s, + "GetObject"s, + path, + GetObject::mapped_type{interface}); + + if (mapperResp.empty()) + { + phosphor::logging::log( + "Object not found.", + phosphor::logging::entry("PATH=%s", path.c_str()), + phosphor::logging::entry( + "INTERFACE=%s", interface.c_str())); + phosphor::logging::elog(); + } + return mapperResp.begin()->first; +} + +/** @brief Get a property without mapper lookup. */ +template +static auto getProperty( + ::sdbusplus::bus::bus& bus, + const std::string& busName, + const std::string& path, + const std::string& interface, + const std::string& property) +{ + using namespace std::literals::string_literals; + + auto msg = callMethod( + bus, + busName, + path, + "org.freedesktop.DBus.Properties"s, + "Get"s, + interface, + property); + ::sdbusplus::message::variant value; + msg.read(value); + return value.template get(); +} + +/** @brief Get a property without mapper lookup. */ +template +static auto getProperty( + const std::string& busName, + const std::string& path, + const std::string& interface, + const std::string& property) +{ + return getProperty( + getBus(), + busName, + path, + interface, + property); +} + +/** @brief Get a property with mapper lookup. */ +template +static auto getProperty( + ::sdbusplus::bus::bus& bus, + const std::string& path, + const std::string& interface, + const std::string& property) +{ + return getProperty( + bus, + getService(bus, path, interface), + path, + interface, + property); +} + +/** @brief Get a property with mapper lookup. */ +template +static auto getProperty( + const std::string& path, + const std::string& interface, + const std::string& property) +{ + return getProperty( + getBus(), + path, + interface, + property); +} + +} // namespace sdbusplus +} // namespace util diff --git a/mslverify/verify.cpp b/mslverify/verify.cpp new file mode 100644 index 0000000..1595166 --- /dev/null +++ b/mslverify/verify.cpp @@ -0,0 +1,114 @@ +/** + * Copyright © 2017 IBM Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "util.hpp" + +using namespace std::literals::string_literals; + +template +struct BusMeetsMSL +{ + std::string path; + + BusMeetsMSL(const std::string& p) + :path(p) {} + + auto operator()(const T& arg) + { + // Query each service hosting + // xyz.openbmc_project.Inventory.Decorator.MeetsMinimumShipLevel. + + const auto& busName = arg.first; + return util::sdbusplus::getProperty( + busName, + path, + "xyz.openbmc_project.Inventory." + "Decorator.MeetsMinimumShipLevel"s, + "MeetsMinimumShipLevel"s); + } +}; + +template +struct PathMeetsMSL +{ + auto operator()(const T& arg) + { + // A given path in the mapper response is composed of + // a map of services/interfaces. Validate each service + // that hosts the MSL interface meets the MSL. + + const auto& path = arg.first; + return std::all_of( + arg.second.begin(), + arg.second.end(), + BusMeetsMSL(path)); + } +}; + +int main(void) +{ + auto mslVerificationRequired = + util::sdbusplus::getProperty( + "/xyz/openbmc_project/control/minimum_ship_level_required"s, + "xyz.openbmc_project.Control.MinimumShipLevel"s, + "MinimumShipLevelRequired"s); + + if (!mslVerificationRequired) + { + return 0; + } + + // Obtain references to all objects hosting + // xyz.openbmc_project.Inventory.Decorator.MeetsMinimumShipLevel + // with a mapper subtree query. For each object, validate that + // the minimum ship level has been met. + + using SubTreeType = + std::map< + std::string, + std::map>>; + + auto subtree = + util::sdbusplus::callMethodAndRead( + "xyz.openbmc_project.ObjectMapper"s, + "/xyz/openbmc_project/object_mapper"s, + "xyz.openbmc_project.ObjectMapper"s, + "GetSubTree"s, + "/"s, + 0, + std::vector{ + "xyz.openbmc_project.Inventory" + ".Decorator.MeetsMinimumShipLevel"s}); + + auto result = std::all_of( + subtree.begin(), + subtree.end(), + PathMeetsMSL()); + + if (!result) + { + phosphor::logging::log( + "The physical system configuration does not " + "satisfy the minimum ship level."); + + return 1; + } + + return 0; +} -- cgit v1.2.1