1 #include "activation.hpp" 2 #include "images.hpp" 3 #include "item_updater.hpp" 4 #include "serialize.hpp" 5 #include <phosphor-logging/log.hpp> 6 #include <sdbusplus/exception.hpp> 7 8 #ifdef WANT_SIGNATURE_VERIFY 9 #include <phosphor-logging/elog.hpp> 10 #include <phosphor-logging/elog-errors.hpp> 11 #include <xyz/openbmc_project/Common/error.hpp> 12 #include "image_verify.hpp" 13 #endif 14 15 namespace phosphor 16 { 17 namespace software 18 { 19 namespace updater 20 { 21 22 namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server; 23 24 using namespace phosphor::logging; 25 using sdbusplus::exception::SdBusError; 26 27 #ifdef WANT_SIGNATURE_VERIFY 28 using InternalFailure = 29 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 30 namespace control = sdbusplus::xyz::openbmc_project::Control::server; 31 #endif 32 33 void Activation::subscribeToSystemdSignals() 34 { 35 auto method = this->bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, 36 SYSTEMD_INTERFACE, "Subscribe"); 37 try 38 { 39 this->bus.call_noreply(method); 40 } 41 catch (const SdBusError& e) 42 { 43 if (e.name() != nullptr && 44 strcmp("org.freedesktop.systemd1.AlreadySubscribed", e.name()) == 0) 45 { 46 // If an Activation attempt fails, the Unsubscribe method is not 47 // called. This may lead to an AlreadySubscribed error if the 48 // Activation is re-attempted. 49 } 50 else 51 { 52 log<level::ERR>("Error subscribing to systemd", 53 entry("ERROR=%s", e.what())); 54 } 55 } 56 57 return; 58 } 59 60 void Activation::unsubscribeFromSystemdSignals() 61 { 62 auto method = this->bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, 63 SYSTEMD_INTERFACE, "Unsubscribe"); 64 this->bus.call_noreply(method); 65 66 return; 67 } 68 69 auto Activation::activation(Activations value) -> Activations 70 { 71 72 if ((value != softwareServer::Activation::Activations::Active) && 73 (value != softwareServer::Activation::Activations::Activating)) 74 { 75 redundancyPriority.reset(nullptr); 76 } 77 78 if (value == softwareServer::Activation::Activations::Activating) 79 { 80 #ifdef UBIFS_LAYOUT 81 if (rwVolumeCreated == false && roVolumeCreated == false) 82 { 83 // Enable systemd signals 84 Activation::subscribeToSystemdSignals(); 85 86 parent.freeSpace(); 87 88 if (!activationProgress) 89 { 90 activationProgress = 91 std::make_unique<ActivationProgress>(bus, path); 92 } 93 94 if (!activationBlocksTransition) 95 { 96 activationBlocksTransition = 97 std::make_unique<ActivationBlocksTransition>(bus, path); 98 } 99 100 #ifdef WANT_SIGNATURE_VERIFY 101 fs::path uploadDir(IMG_UPLOAD_DIR); 102 if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH)) 103 { 104 onVerifyFailed(); 105 // Stop the activation process, if fieldMode is enabled. 106 if (parent.control::FieldMode::fieldModeEnabled()) 107 { 108 // Cleanup 109 activationBlocksTransition.reset(nullptr); 110 activationProgress.reset(nullptr); 111 return softwareServer::Activation::activation( 112 softwareServer::Activation::Activations::Failed); 113 } 114 } 115 #endif 116 117 flashWrite(); 118 119 activationProgress->progress(10); 120 } 121 else if (rwVolumeCreated == true && roVolumeCreated == true) 122 { 123 if (ubootEnvVarsUpdated == false) 124 { 125 activationProgress->progress(90); 126 127 if (!redundancyPriority) 128 { 129 redundancyPriority = std::make_unique<RedundancyPriority>( 130 bus, path, *this, 0); 131 } 132 } 133 else 134 { 135 activationProgress->progress(100); 136 137 activationBlocksTransition.reset(nullptr); 138 activationProgress.reset(nullptr); 139 140 rwVolumeCreated = false; 141 roVolumeCreated = false; 142 ubootEnvVarsUpdated = false; 143 Activation::unsubscribeFromSystemdSignals(); 144 145 // Remove version object from image manager 146 Activation::deleteImageManagerObject(); 147 148 // Create active association 149 parent.createActiveAssociation(path); 150 151 return softwareServer::Activation::activation( 152 softwareServer::Activation::Activations::Active); 153 } 154 } 155 #else // !UBIFS_LAYOUT 156 157 #ifdef WANT_SIGNATURE_VERIFY 158 fs::path uploadDir(IMG_UPLOAD_DIR); 159 if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH)) 160 { 161 onVerifyFailed(); 162 // Stop the activation process, if fieldMode is enabled. 163 if (parent.control::FieldMode::fieldModeEnabled()) 164 { 165 return softwareServer::Activation::activation( 166 softwareServer::Activation::Activations::Failed); 167 } 168 } 169 #endif 170 parent.freeSpace(); 171 172 flashWrite(); 173 174 if (!redundancyPriority) 175 { 176 redundancyPriority = 177 std::make_unique<RedundancyPriority>(bus, path, *this, 0); 178 } 179 180 // Remove version object from image manager 181 Activation::deleteImageManagerObject(); 182 183 // Create active association 184 parent.createActiveAssociation(path); 185 186 log<level::INFO>("BMC image ready, need reboot to get activated."); 187 return softwareServer::Activation::activation( 188 softwareServer::Activation::Activations::Active); 189 #endif 190 } 191 else 192 { 193 activationBlocksTransition.reset(nullptr); 194 activationProgress.reset(nullptr); 195 } 196 return softwareServer::Activation::activation(value); 197 } 198 199 void Activation::deleteImageManagerObject() 200 { 201 // Call the Delete object for <versionID> inside image_manager 202 auto method = this->bus.new_method_call(VERSION_BUSNAME, path.c_str(), 203 "xyz.openbmc_project.Object.Delete", 204 "Delete"); 205 auto mapperResponseMsg = bus.call(method); 206 // Check that the bus call didn't result in an error 207 if (mapperResponseMsg.is_method_error()) 208 { 209 log<level::ERR>("Error in Deleting image from image manager", 210 entry("VERSIONPATH=%s", path.c_str())); 211 return; 212 } 213 } 214 215 auto Activation::requestedActivation(RequestedActivations value) 216 -> RequestedActivations 217 { 218 rwVolumeCreated = false; 219 roVolumeCreated = false; 220 ubootEnvVarsUpdated = false; 221 222 if ((value == softwareServer::Activation::RequestedActivations::Active) && 223 (softwareServer::Activation::requestedActivation() != 224 softwareServer::Activation::RequestedActivations::Active)) 225 { 226 if ((softwareServer::Activation::activation() == 227 softwareServer::Activation::Activations::Ready) || 228 (softwareServer::Activation::activation() == 229 softwareServer::Activation::Activations::Failed)) 230 { 231 Activation::activation( 232 softwareServer::Activation::Activations::Activating); 233 } 234 } 235 return softwareServer::Activation::requestedActivation(value); 236 } 237 238 uint8_t RedundancyPriority::priority(uint8_t value) 239 { 240 // Set the priority value so that the freePriority() function can order 241 // the versions by priority. 242 auto newPriority = softwareServer::RedundancyPriority::priority(value); 243 parent.parent.savePriority(parent.versionId, value); 244 parent.parent.freePriority(value, parent.versionId); 245 return newPriority; 246 } 247 248 uint8_t RedundancyPriority::sdbusPriority(uint8_t value) 249 { 250 parent.parent.savePriority(parent.versionId, value); 251 return softwareServer::RedundancyPriority::priority(value); 252 } 253 254 void Activation::unitStateChange(sdbusplus::message::message& msg) 255 { 256 if (softwareServer::Activation::activation() != 257 softwareServer::Activation::Activations::Activating) 258 { 259 return; 260 } 261 262 onStateChanges(msg); 263 264 return; 265 } 266 267 #ifdef WANT_SIGNATURE_VERIFY 268 bool Activation::verifySignature(const fs::path& imageDir, 269 const fs::path& confDir) 270 { 271 using Signature = phosphor::software::image::Signature; 272 273 Signature signature(imageDir, confDir); 274 275 return signature.verify(); 276 } 277 278 void Activation::onVerifyFailed() 279 { 280 log<level::ERR>("Error occurred during image validation"); 281 report<InternalFailure>(); 282 } 283 #endif 284 285 void ActivationBlocksTransition::enableRebootGuard() 286 { 287 log<level::INFO>("BMC image activating - BMC reboots are disabled."); 288 289 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, 290 SYSTEMD_INTERFACE, "StartUnit"); 291 method.append("reboot-guard-enable.service", "replace"); 292 bus.call_noreply(method); 293 } 294 295 void ActivationBlocksTransition::disableRebootGuard() 296 { 297 log<level::INFO>("BMC activation has ended - BMC reboots are re-enabled."); 298 299 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, 300 SYSTEMD_INTERFACE, "StartUnit"); 301 method.append("reboot-guard-disable.service", "replace"); 302 bus.call_noreply(method); 303 } 304 305 } // namespace updater 306 } // namespace software 307 } // namespace phosphor 308