summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-Update-provisioning-mode-filter-logic.patch
blob: 5cd8b3ec4e2503439cc2bddf5488260d2e5353ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
From dcfce847654bd7e2475ad74bedf569b6120701dd Mon Sep 17 00:00:00 2001
From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
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 <richard.marian.thomaiyar@linux.intel.com>
Signed-off-by: James Feist <james.feist@linux.intel.com>
---
 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<sdbusplus::asio::connection> bus;
-    std::unique_ptr<settings::Objects> objects;
     std::unique_ptr<sdbusplus::bus::match::match> modeChangeMatch;
+    std::unique_ptr<sdbusplus::bus::match::match> 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<settings::Interface>({restrictionModeIntf}));
+        auto postCompleteObj = settings::Objects(
+            *bus, std::vector<settings::Interface>({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<level::ERR>(
-            "Could not look up restriction mode interface from cache");
+        log<level::INFO>(
+            "Could not initialize provisioning mode, defaulting to restricted");
+        return;
+    }
+    catch (const std::exception&)
+    {
+        log<level::INFO>(
+            "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<level::ERR>("Error in RestrictionMode Get");
-                // Fail-safe to true.
-                restrictedMode = true;
+                log<level::INFO>("Could not initialize provisioning mode, "
+                                 "defaulting to restricted");
                 return;
             }
             auto mode = std::get<std::string>(v);
-            auto restrictionMode =
-                RestrictionMode::convertModesFromString(mode);
-            restrictedMode =
-                (restrictionMode == RestrictionMode::Modes::Whitelist);
-            log<level::INFO>((restrictedMode ? "Set restrictedMode = true"
-                                             : "Set restrictedMode = false"));
+            restrictionMode = RestrictionMode::convertModesFromString(mode);
+            log<level::INFO>(
+                "Read restriction mode",
+                entry("VALUE=%d", static_cast<int>(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<level::ERR>("Error in OperatingSystemState Get");
+                postCompleted = true;
+                return;
+            }
+            auto value = std::get<std::string>(v);
+            if (value == "Standby")
+            {
+                postCompleted = true;
+            }
+            else
+            {
+                postCompleted = false;
+            }
+            log<level::INFO>("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<std::string>(property.second));
-            restrictedMode =
-                (restrictionMode == RestrictionMode::Modes::Whitelist);
-            log<level::INFO>((restrictedMode
-                                  ? "Updated restrictedMode = true"
-                                  : "Updated restrictedMode = false"));
+            restrictionMode = RestrictionMode::convertModesFromString(
+                std::get<std::string>(property.second));
+            log<level::INFO>(
+                "Updated restriction mode",
+                entry("VALUE=%d", static_cast<int>(restrictionMode)));
         }
     }
 }
-
-void WhitelistFilter::postInit()
+void WhitelistFilter::handlePostCompleteChange(sdbusplus::message::message& m)
 {
-    objects = std::make_unique<settings::Objects>(
-        *bus, std::vector<settings::Interface>({restrictionModeIntf}));
-    if (!objects)
+    std::string intf;
+    std::vector<std::pair<std::string, ipmi::Value>> propertyList;
+    m.read(intf, propertyList);
+    for (const auto& property : propertyList)
     {
-        log<level::ERR>(
-            "Failed to create settings object; defaulting to restricted mode");
-        return;
+        if (property.first == "OperatingSystemState")
+        {
+            std::string value = std::get<std::string>(property.second);
+            if (value == "Standby")
+            {
+                postCompleted = true;
+            }
+            else
+            {
+                postCompleted = false;
+            }
+            log<level::INFO>(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<level::ERR>("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<sdbusplus::bus::match::match>(
-        *bus, filterStr, [this](sdbusplus::message::message& m) {
+        *bus, filterStrModeChange, [this](sdbusplus::message::message& m) {
             handleRestrictedModeChange(m);
         });
+    postCompleteMatch = std::make_unique<sdbusplus::bus::match::match>(
+        *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<level::ERR>("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<level::ERR>(
+                        "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