blob: dfd2a1920b0183035830214199bf0d32f4f38efd [file] [log] [blame]
Vernon Mauery783dc072018-10-08 12:05:20 -07001#include <algorithm>
2#include <array>
3#include <ipmid/api.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -07004#include <ipmid/utils.hpp>
Vernon Mauery783dc072018-10-08 12:05:20 -07005#include <ipmiwhitelist.hpp>
6#include <phosphor-logging/elog-errors.hpp>
7#include <phosphor-logging/log.hpp>
8#include <settings.hpp>
9#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
10
11using namespace phosphor::logging;
12using namespace sdbusplus::xyz::openbmc_project::Common::Error;
13
14namespace ipmi
15{
16
17// put the filter provider in an unnamed namespace
18namespace
19{
20
21/** @class WhitelistFilter
22 *
23 * Class that implements an IPMI message filter based
24 * on incoming interface and a restriction mode setting
25 */
26class WhitelistFilter
27{
28 public:
29 WhitelistFilter();
30 ~WhitelistFilter() = default;
31 WhitelistFilter(WhitelistFilter const&) = delete;
32 WhitelistFilter(WhitelistFilter&&) = delete;
33 WhitelistFilter& operator=(WhitelistFilter const&) = delete;
34 WhitelistFilter& operator=(WhitelistFilter&&) = delete;
35
36 private:
37 void postInit();
Kumar Thangavel902d90d2022-04-11 11:51:33 +053038 void cacheRestrictedMode(const std::vector<std::string>& devices);
39 void handleRestrictedModeChange(
Patrick Williams01d14602022-11-30 02:36:04 -060040 sdbusplus::message_t& m,
Kumar Thangavel902d90d2022-04-11 11:51:33 +053041 const std::map<std::string, size_t>& deviceList);
Vernon Mauery783dc072018-10-08 12:05:20 -070042 ipmi::Cc filterMessage(ipmi::message::Request::ptr request);
43
Kumar Thangavel902d90d2022-04-11 11:51:33 +053044 std::vector<bool> restrictedMode;
Vernon Mauery783dc072018-10-08 12:05:20 -070045 std::shared_ptr<sdbusplus::asio::connection> bus;
46 std::unique_ptr<settings::Objects> objects;
Patrick Williams5d82f472022-07-22 19:26:53 -050047 std::unique_ptr<sdbusplus::bus::match_t> modeChangeMatch;
Vernon Mauery783dc072018-10-08 12:05:20 -070048
49 static constexpr const char restrictionModeIntf[] =
50 "xyz.openbmc_project.Control.Security.RestrictionMode";
51};
52
53WhitelistFilter::WhitelistFilter()
54{
55 bus = getSdBus();
56
57 log<level::INFO>("Loading whitelist filter");
Vernon Mauery783dc072018-10-08 12:05:20 -070058 ipmi::registerFilter(ipmi::prioOpenBmcBase,
59 [this](ipmi::message::Request::ptr request) {
60 return filterMessage(request);
61 });
62
63 // wait until io->run is going to fetch RestrictionMode
64 post_work([this]() { postInit(); });
65}
66
Kumar Thangavel902d90d2022-04-11 11:51:33 +053067/** @brief Get RestrictionMode of the devices which has RestrictionMode support
68 * enabled
69 * @param[in] devices - vector of devices object path
70 * @returns void.
71 */
72
73void WhitelistFilter::cacheRestrictedMode(
74 const std::vector<std::string>& devices)
Vernon Mauery783dc072018-10-08 12:05:20 -070075{
76 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
77 std::string restrictionModeSetting;
78 std::string restrictionModeService;
Kumar Thangavel902d90d2022-04-11 11:51:33 +053079
80 for (auto& dev : devices)
Vernon Mauery783dc072018-10-08 12:05:20 -070081 {
Kumar Thangavel902d90d2022-04-11 11:51:33 +053082 try
83 {
84 restrictionModeSetting = dev;
85 restrictionModeService =
86 objects->service(restrictionModeSetting, restrictionModeIntf);
87 }
88 catch (const std::out_of_range& e)
89 {
90 log<level::ERR>(
91 "Could not look up restriction mode interface from cache");
92 return;
93 }
94
95 bus->async_method_call(
96 [this, index = std::distance(&*std::begin(devices), &dev)](
97 boost::system::error_code ec, ipmi::Value v) {
98 if (ec)
99 {
100 log<level::ERR>("Error in RestrictionMode Get");
101 // Fail-safe to true.
102 restrictedMode[index] = true;
103 return;
104 }
105
106 auto mode = std::get<std::string>(v);
107 auto restrictionMode =
108 RestrictionMode::convertModesFromString(mode);
109
110 bool restrictMode =
111 (restrictionMode == RestrictionMode::Modes::Whitelist);
112 restrictedMode.emplace_back(restrictMode);
113
114 log<level::INFO>((restrictMode ? "Set restrictedMode = true"
115 : "Set restrictedMode = false"));
116 },
117 restrictionModeService, restrictionModeSetting,
118 "org.freedesktop.DBus.Properties", "Get", restrictionModeIntf,
119 "RestrictionMode");
Vernon Mauery783dc072018-10-08 12:05:20 -0700120 }
Vernon Mauery783dc072018-10-08 12:05:20 -0700121}
122
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530123/** @brief Update RestrictionMode if any changes in RestrictionMode
124 * @param[in] m - sdbusplus message. Using this to get Updated Mode dbus path
125 * @param[in] deviceList - map to store devices path and their index
126 * @returns void.
127 */
128
129void WhitelistFilter::handleRestrictedModeChange(
130 sdbusplus::message_t& m, const std::map<std::string, size_t>& deviceList)
Vernon Mauery783dc072018-10-08 12:05:20 -0700131{
132 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
Richard Marian Thomaiyar57bff012019-04-12 22:32:21 +0530133 std::string intf;
134 std::vector<std::pair<std::string, ipmi::Value>> propertyList;
135 m.read(intf, propertyList);
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530136
137 std::string path = m.get_path();
138 size_t hostId = 0;
139 auto it = deviceList.find(path);
140
141 if (it == deviceList.end())
142 {
143 log<level::ERR>("Key not found in deviceList ");
144 }
145 else
146 {
147 hostId = it->second;
148 }
149
Richard Marian Thomaiyar57bff012019-04-12 22:32:21 +0530150 for (const auto& property : propertyList)
151 {
152 if (property.first == "RestrictionMode")
153 {
154 RestrictionMode::Modes restrictionMode =
155 RestrictionMode::convertModesFromString(
156 std::get<std::string>(property.second));
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530157 bool restrictMode =
Richard Marian Thomaiyar57bff012019-04-12 22:32:21 +0530158 (restrictionMode == RestrictionMode::Modes::Whitelist);
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530159 restrictedMode[hostId] = restrictMode;
160 log<level::INFO>((restrictMode ? "Updated restrictedMode = true"
161 : "Updated restrictedMode = false"));
Richard Marian Thomaiyar57bff012019-04-12 22:32:21 +0530162 }
163 }
Vernon Mauery783dc072018-10-08 12:05:20 -0700164}
165
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530166/** @brief Get and Update RestrictionModes of supported devices
167 * @param[in] void
168 * @returns void.
169 */
170
Vernon Mauery783dc072018-10-08 12:05:20 -0700171void WhitelistFilter::postInit()
172{
173 objects = std::make_unique<settings::Objects>(
174 *bus, std::vector<settings::Interface>({restrictionModeIntf}));
175 if (!objects)
176 {
177 log<level::ERR>(
178 "Failed to create settings object; defaulting to restricted mode");
179 return;
180 }
181
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530182 std::vector<std::string> devices;
Vernon Mauery783dc072018-10-08 12:05:20 -0700183 try
184 {
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530185 devices = objects->map.at(restrictionModeIntf);
Vernon Mauery783dc072018-10-08 12:05:20 -0700186 }
187 catch (const std::out_of_range& e)
188 {
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530189 log<level::ERR>(
190 "Could not look up restriction mode interface from cache");
Vernon Mauery783dc072018-10-08 12:05:20 -0700191 return;
192 }
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530193
194 // Initialize restricted mode
195 cacheRestrictedMode(devices);
196 // Wait for changes on Restricted mode
197 std::map<std::string, size_t> deviceList;
198
199 for (size_t index = 0; index < devices.size(); index++)
200 {
201 deviceList.emplace(devices[index], index);
202 }
203
204 std::string filterStr;
205 std::string devicesDbusPath{"/xyz/openbmc_project/control"};
206
207 filterStr = sdbusplus::bus::match::rules::propertiesChangedNamespace(
208 devicesDbusPath, restrictionModeIntf);
209
Patrick Williams5d82f472022-07-22 19:26:53 -0500210 modeChangeMatch = std::make_unique<sdbusplus::bus::match_t>(
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530211 *bus, filterStr, [this, deviceList](sdbusplus::message_t& m) {
212 handleRestrictedModeChange(m, deviceList);
213 });
Vernon Mauery783dc072018-10-08 12:05:20 -0700214}
215
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530216/** @brief Filter IPMI messages with RestrictedMode
217 * @param[in] request - IPMI messahe request
218 * @returns IPMI completion code success or error.
219 */
220
Vernon Mauery783dc072018-10-08 12:05:20 -0700221ipmi::Cc WhitelistFilter::filterMessage(ipmi::message::Request::ptr request)
222{
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530223 /* Getting hostIdx for all IPMI devices like hosts, debugcard and other
224 devices from ipmi::message::Request and call postInit() to get the
225 restriction mode for all the IPMI commands */
226
227 size_t hostIdx = request->ctx->hostIdx;
228
229 if (request->ctx->channel == ipmi::channelSystemIface &&
230 restrictedMode[hostIdx])
Vernon Mauery783dc072018-10-08 12:05:20 -0700231 {
232 if (!std::binary_search(
233 whitelist.cbegin(), whitelist.cend(),
234 std::make_pair(request->ctx->netFn, request->ctx->cmd)))
235 {
236 log<level::ERR>("Net function not whitelisted",
237 entry("NETFN=0x%X", int(request->ctx->netFn)),
238 entry("CMD=0x%X", int(request->ctx->cmd)));
Kumar Thangavel902d90d2022-04-11 11:51:33 +0530239
Vernon Mauery783dc072018-10-08 12:05:20 -0700240 return ipmi::ccInsufficientPrivilege;
241 }
242 }
243 return ipmi::ccSuccess;
244}
245
246// instantiate the WhitelistFilter when this shared object is loaded
247WhitelistFilter whitelistFilter;
248
249} // namespace
250
251} // namespace ipmi