blob: 7092096b68c058466aea52c402700992c076a34c [file] [log] [blame]
Vernon Mauery783dc072018-10-08 12:05:20 -07001#include <ipmid/api.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -07002#include <ipmid/utils.hpp>
Vernon Mauery783dc072018-10-08 12:05:20 -07003#include <ipmiwhitelist.hpp>
4#include <phosphor-logging/elog-errors.hpp>
5#include <phosphor-logging/log.hpp>
6#include <settings.hpp>
7#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
8
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05009#include <algorithm>
10#include <array>
11
Vernon Mauery783dc072018-10-08 12:05:20 -070012using namespace phosphor::logging;
13using namespace sdbusplus::xyz::openbmc_project::Common::Error;
14
15namespace ipmi
16{
17
18// put the filter provider in an unnamed namespace
19namespace
20{
21
22/** @class WhitelistFilter
23 *
24 * Class that implements an IPMI message filter based
25 * on incoming interface and a restriction mode setting
26 */
27class WhitelistFilter
28{
29 public:
30 WhitelistFilter();
31 ~WhitelistFilter() = default;
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050032 WhitelistFilter(const WhitelistFilter&) = delete;
Vernon Mauery783dc072018-10-08 12:05:20 -070033 WhitelistFilter(WhitelistFilter&&) = delete;
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050034 WhitelistFilter& operator=(const WhitelistFilter&) = delete;
Vernon Mauery783dc072018-10-08 12:05:20 -070035 WhitelistFilter& operator=(WhitelistFilter&&) = delete;
36
37 private:
38 void postInit();
Kumar Thangavel902d90d2022-04-11 11:51:33 +053039 void cacheRestrictedMode(const std::vector<std::string>& devices);
40 void handleRestrictedModeChange(
Patrick Williams01d14602022-11-30 02:36:04 -060041 sdbusplus::message_t& m,
Kumar Thangavel902d90d2022-04-11 11:51:33 +053042 const std::map<std::string, size_t>& deviceList);
Vernon Mauery783dc072018-10-08 12:05:20 -070043 ipmi::Cc filterMessage(ipmi::message::Request::ptr request);
44
Kumar Thangavel902d90d2022-04-11 11:51:33 +053045 std::vector<bool> restrictedMode;
Vernon Mauery783dc072018-10-08 12:05:20 -070046 std::shared_ptr<sdbusplus::asio::connection> bus;
47 std::unique_ptr<settings::Objects> objects;
Patrick Williams5d82f472022-07-22 19:26:53 -050048 std::unique_ptr<sdbusplus::bus::match_t> modeChangeMatch;
Vernon Mauery783dc072018-10-08 12:05:20 -070049
50 static constexpr const char restrictionModeIntf[] =
51 "xyz.openbmc_project.Control.Security.RestrictionMode";
52};
53
54WhitelistFilter::WhitelistFilter()
55{
56 bus = getSdBus();
57
58 log<level::INFO>("Loading whitelist filter");
Vernon Mauery783dc072018-10-08 12:05:20 -070059 ipmi::registerFilter(ipmi::prioOpenBmcBase,
60 [this](ipmi::message::Request::ptr request) {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050061 return filterMessage(request);
62 });
Vernon Mauery783dc072018-10-08 12:05:20 -070063
64 // wait until io->run is going to fetch RestrictionMode
65 post_work([this]() { postInit(); });
66}
67
Kumar Thangavel902d90d2022-04-11 11:51:33 +053068/** @brief Get RestrictionMode of the devices which has RestrictionMode support
69 * enabled
70 * @param[in] devices - vector of devices object path
71 * @returns void.
72 */
73
74void WhitelistFilter::cacheRestrictedMode(
75 const std::vector<std::string>& devices)
Vernon Mauery783dc072018-10-08 12:05:20 -070076{
77 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
78 std::string restrictionModeSetting;
79 std::string restrictionModeService;
Kumar Thangavel902d90d2022-04-11 11:51:33 +053080
81 for (auto& dev : devices)
Vernon Mauery783dc072018-10-08 12:05:20 -070082 {
Kumar Thangavel902d90d2022-04-11 11:51:33 +053083 try
84 {
85 restrictionModeSetting = dev;
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050086 restrictionModeService = objects->service(restrictionModeSetting,
87 restrictionModeIntf);
Kumar Thangavel902d90d2022-04-11 11:51:33 +053088 }
89 catch (const std::out_of_range& e)
90 {
91 log<level::ERR>(
92 "Could not look up restriction mode interface from cache");
93 return;
94 }
95
96 bus->async_method_call(
97 [this, index = std::distance(&*std::begin(devices), &dev)](
98 boost::system::error_code ec, ipmi::Value v) {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050099 if (ec)
100 {
101 log<level::ERR>("Error in RestrictionMode Get");
102 // Fail-safe to true.
103 restrictedMode[index] = true;
104 return;
105 }
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530106
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500107 auto mode = std::get<std::string>(v);
108 auto restrictionMode =
109 RestrictionMode::convertModesFromString(mode);
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530110
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500111 bool restrictMode =
112 (restrictionMode == RestrictionMode::Modes::Whitelist);
113 restrictedMode.emplace_back(restrictMode);
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530114
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500115 log<level::INFO>((restrictMode ? "Set restrictedMode = true"
116 : "Set restrictedMode = false"));
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530117 },
118 restrictionModeService, restrictionModeSetting,
119 "org.freedesktop.DBus.Properties", "Get", restrictionModeIntf,
120 "RestrictionMode");
Vernon Mauery783dc072018-10-08 12:05:20 -0700121 }
Vernon Mauery783dc072018-10-08 12:05:20 -0700122}
123
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530124/** @brief Update RestrictionMode if any changes in RestrictionMode
125 * @param[in] m - sdbusplus message. Using this to get Updated Mode dbus path
126 * @param[in] deviceList - map to store devices path and their index
127 * @returns void.
128 */
129
130void WhitelistFilter::handleRestrictedModeChange(
131 sdbusplus::message_t& m, const std::map<std::string, size_t>& deviceList)
Vernon Mauery783dc072018-10-08 12:05:20 -0700132{
133 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
Richard Marian Thomaiyar57bff012019-04-12 22:32:21 +0530134 std::string intf;
135 std::vector<std::pair<std::string, ipmi::Value>> propertyList;
136 m.read(intf, propertyList);
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530137
138 std::string path = m.get_path();
139 size_t hostId = 0;
140 auto it = deviceList.find(path);
141
142 if (it == deviceList.end())
143 {
144 log<level::ERR>("Key not found in deviceList ");
145 }
146 else
147 {
148 hostId = it->second;
149 }
150
Richard Marian Thomaiyar57bff012019-04-12 22:32:21 +0530151 for (const auto& property : propertyList)
152 {
153 if (property.first == "RestrictionMode")
154 {
155 RestrictionMode::Modes restrictionMode =
156 RestrictionMode::convertModesFromString(
157 std::get<std::string>(property.second));
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530158 bool restrictMode =
Richard Marian Thomaiyar57bff012019-04-12 22:32:21 +0530159 (restrictionMode == RestrictionMode::Modes::Whitelist);
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530160 restrictedMode[hostId] = restrictMode;
161 log<level::INFO>((restrictMode ? "Updated restrictedMode = true"
162 : "Updated restrictedMode = false"));
Richard Marian Thomaiyar57bff012019-04-12 22:32:21 +0530163 }
164 }
Vernon Mauery783dc072018-10-08 12:05:20 -0700165}
166
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530167/** @brief Get and Update RestrictionModes of supported devices
168 * @param[in] void
169 * @returns void.
170 */
171
Vernon Mauery783dc072018-10-08 12:05:20 -0700172void WhitelistFilter::postInit()
173{
174 objects = std::make_unique<settings::Objects>(
175 *bus, std::vector<settings::Interface>({restrictionModeIntf}));
176 if (!objects)
177 {
178 log<level::ERR>(
179 "Failed to create settings object; defaulting to restricted mode");
180 return;
181 }
182
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530183 std::vector<std::string> devices;
Vernon Mauery783dc072018-10-08 12:05:20 -0700184 try
185 {
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530186 devices = objects->map.at(restrictionModeIntf);
Vernon Mauery783dc072018-10-08 12:05:20 -0700187 }
188 catch (const std::out_of_range& e)
189 {
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530190 log<level::ERR>(
191 "Could not look up restriction mode interface from cache");
Vernon Mauery783dc072018-10-08 12:05:20 -0700192 return;
193 }
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530194
195 // Initialize restricted mode
196 cacheRestrictedMode(devices);
197 // Wait for changes on Restricted mode
198 std::map<std::string, size_t> deviceList;
199
200 for (size_t index = 0; index < devices.size(); index++)
201 {
202 deviceList.emplace(devices[index], index);
203 }
204
205 std::string filterStr;
206 std::string devicesDbusPath{"/xyz/openbmc_project/control"};
207
208 filterStr = sdbusplus::bus::match::rules::propertiesChangedNamespace(
209 devicesDbusPath, restrictionModeIntf);
210
Patrick Williams5d82f472022-07-22 19:26:53 -0500211 modeChangeMatch = std::make_unique<sdbusplus::bus::match_t>(
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530212 *bus, filterStr, [this, deviceList](sdbusplus::message_t& m) {
213 handleRestrictedModeChange(m, deviceList);
214 });
Vernon Mauery783dc072018-10-08 12:05:20 -0700215}
216
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530217/** @brief Filter IPMI messages with RestrictedMode
218 * @param[in] request - IPMI messahe request
219 * @returns IPMI completion code success or error.
220 */
221
Vernon Mauery783dc072018-10-08 12:05:20 -0700222ipmi::Cc WhitelistFilter::filterMessage(ipmi::message::Request::ptr request)
223{
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530224 /* Getting hostIdx for all IPMI devices like hosts, debugcard and other
225 devices from ipmi::message::Request and call postInit() to get the
226 restriction mode for all the IPMI commands */
227
228 size_t hostIdx = request->ctx->hostIdx;
229
230 if (request->ctx->channel == ipmi::channelSystemIface &&
231 restrictedMode[hostIdx])
Vernon Mauery783dc072018-10-08 12:05:20 -0700232 {
233 if (!std::binary_search(
234 whitelist.cbegin(), whitelist.cend(),
235 std::make_pair(request->ctx->netFn, request->ctx->cmd)))
236 {
237 log<level::ERR>("Net function not whitelisted",
238 entry("NETFN=0x%X", int(request->ctx->netFn)),
239 entry("CMD=0x%X", int(request->ctx->cmd)));
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530240
Vernon Mauery783dc072018-10-08 12:05:20 -0700241 return ipmi::ccInsufficientPrivilege;
242 }
243 }
244 return ipmi::ccSuccess;
245}
246
247// instantiate the WhitelistFilter when this shared object is loaded
248WhitelistFilter whitelistFilter;
249
250} // namespace
251
252} // namespace ipmi