From cb1a9b4055159af785fe12c2ad4291ebf786d9f4 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Thu, 6 Aug 2020 14:38:35 +0200 Subject: [PATCH 1/3] Fix some typos and improve some text. Signed-off-by: Patrick Vacek --- include/libaktualizr/aktualizr.h | 2 +- include/libaktualizr/campaign.h | 2 +- include/libaktualizr/types.h | 4 ++-- src/libaktualizr/crypto/keymanager.cc | 12 ++++++------ src/libaktualizr/crypto/p11engine.cc | 14 +++++++------- src/libaktualizr/primary/sotauptaneclient.cc | 2 -- src/libaktualizr/utilities/utils.cc | 2 +- 7 files changed, 18 insertions(+), 20 deletions(-) diff --git a/include/libaktualizr/aktualizr.h b/include/libaktualizr/aktualizr.h index aab873f58f..18ae091c3e 100644 --- a/include/libaktualizr/aktualizr.h +++ b/include/libaktualizr/aktualizr.h @@ -142,7 +142,7 @@ class Aktualizr { /** * SetInstallationRawReport allows setting a custom raw report field in the device installation result. * - * @note An invocation of this method will have effect only after call of Aktualizr::Install and before calling + * @note An invocation of this method will have effect only after call of Aktualizr::Install and before calling * Aktualizr::SendManifest member function. * @param custom_raw_report is intended to replace a default value in the device installation report. * @return true if the custom raw report was successfully applied to the device installation result. diff --git a/include/libaktualizr/campaign.h b/include/libaktualizr/campaign.h index 42b6bfab96..5c2ff71eaa 100644 --- a/include/libaktualizr/campaign.h +++ b/include/libaktualizr/campaign.h @@ -34,7 +34,7 @@ static inline Cmd cmdFromName(const std::string &name) { .at(name); } -// Out of uptane concept: update campaign for a device +// Out of Uptane concept: update campaign for a device class Campaign { public: static std::vector campaignsFromJson(const Json::Value &json); diff --git a/include/libaktualizr/types.h b/include/libaktualizr/types.h index 90078e00c9..2b4064ff76 100644 --- a/include/libaktualizr/types.h +++ b/include/libaktualizr/types.h @@ -360,10 +360,10 @@ class EcuSerial { static EcuSerial Unknown() { return EcuSerial("Unknown"); } explicit EcuSerial(const std::string &ecu_serial) : ecu_serial_(ecu_serial) { if (ecu_serial.length() < kMinLength) { - throw std::out_of_range("Ecu serial identifier is too short"); + throw std::out_of_range("ECU serial identifier is too short"); } if (kMaxLength < ecu_serial.length()) { - throw std::out_of_range("Ecu serial identifier is too long"); + throw std::out_of_range("ECU serial identifier is too long"); } } diff --git a/src/libaktualizr/crypto/keymanager.cc b/src/libaktualizr/crypto/keymanager.cc index 817a65fb5d..d84ae5941f 100644 --- a/src/libaktualizr/crypto/keymanager.cc +++ b/src/libaktualizr/crypto/keymanager.cc @@ -320,11 +320,11 @@ std::string KeyManager::generateUptaneKeyPair() { } } if (primary_public.empty() && primary_private.empty()) { - throw std::runtime_error("Could not get uptane keys"); + throw std::runtime_error("Could not get Uptane keys"); } } else { if (!built_with_p11) { - throw std::runtime_error("Aktualizr was built without pkcs11 support!"); + throw std::runtime_error("Aktualizr was built without PKCS#11 support!"); } // dummy read to check if the key is present if (!(*p11_)->readUptanePublicKey(&primary_public)) { @@ -332,7 +332,7 @@ std::string KeyManager::generateUptaneKeyPair() { } // really read the key if (primary_public.empty() && !(*p11_)->readUptanePublicKey(&primary_public)) { - throw std::runtime_error("Could not get uptane keys"); + throw std::runtime_error("Could not get Uptane keys"); } } return primary_public; @@ -342,15 +342,15 @@ PublicKey KeyManager::UptanePublicKey() const { std::string primary_public; if (config_.uptane_key_source == CryptoSource::kFile) { if (!backend_->loadPrimaryPublic(&primary_public)) { - throw std::runtime_error("Could not get uptane public key!"); + throw std::runtime_error("Could not get Uptane public key!"); } } else { if (!built_with_p11) { - throw std::runtime_error("Aktualizr was built without pkcs11 support!"); + throw std::runtime_error("Aktualizr was built without PKCS#11 support!"); } // dummy read to check if the key is present if (!(*p11_)->readUptanePublicKey(&primary_public)) { - throw std::runtime_error("Could not get uptane public key!"); + throw std::runtime_error("Could not get Uptane public key!"); } } return PublicKey(primary_public, config_.uptane_key_type); diff --git a/src/libaktualizr/crypto/p11engine.cc b/src/libaktualizr/crypto/p11engine.cc index b89727de00..547ecfdd40 100644 --- a/src/libaktualizr/crypto/p11engine.cc +++ b/src/libaktualizr/crypto/p11engine.cc @@ -90,31 +90,31 @@ P11Engine::P11Engine(P11Config config) : config_(std::move(config)), ctx_(config const boost::filesystem::path pkcs11Path = findPkcsLibrary(); LOG_INFO << "Loading PKCS#11 engine library: " << pkcs11Path.string(); if (ENGINE_ctrl_cmd_string(engine, "SO_PATH", pkcs11Path.c_str(), 0) == 0) { - throw std::runtime_error(std::string("Engine command failed: SO_PATH ") + pkcs11Path.string()); + throw std::runtime_error(std::string("P11 engine command failed: SO_PATH ") + pkcs11Path.string()); } if (ENGINE_ctrl_cmd_string(engine, "ID", "pkcs11", 0) == 0) { - throw std::runtime_error("Engine command failed: ID pksc11"); + throw std::runtime_error("P11 engine command failed: ID pksc11"); } if (ENGINE_ctrl_cmd_string(engine, "LIST_ADD", "1", 0) == 0) { - throw std::runtime_error("Engine command failed: LIST_ADD 1"); + throw std::runtime_error("P11 engine command failed: LIST_ADD 1"); } if (ENGINE_ctrl_cmd_string(engine, "LOAD", nullptr, 0) == 0) { - throw std::runtime_error("Engine command failed: LOAD"); + throw std::runtime_error("P11 engine command failed: LOAD"); } if (ENGINE_ctrl_cmd_string(engine, "MODULE_PATH", config_.module.c_str(), 0) == 0) { - throw std::runtime_error(std::string("Engine command failed: MODULE_PATH ") + config_.module.string()); + throw std::runtime_error(std::string("P11 engine command failed: MODULE_PATH ") + config_.module.string()); } if (ENGINE_ctrl_cmd_string(engine, "PIN", config_.pass.c_str(), 0) == 0) { - throw std::runtime_error(std::string("Engine command failed: PIN")); + throw std::runtime_error(std::string("P11 engine command failed: PIN")); } if (ENGINE_init(engine) == 0) { - throw std::runtime_error("Engine initialization failed"); + throw std::runtime_error("P11 engine initialization failed"); } } catch (const std::runtime_error& exc) { // Note: treat these in a special case, as ENGINE_finish cannot be called on diff --git a/src/libaktualizr/primary/sotauptaneclient.cc b/src/libaktualizr/primary/sotauptaneclient.cc index 74044dd9fd..f13d63b307 100644 --- a/src/libaktualizr/primary/sotauptaneclient.cc +++ b/src/libaktualizr/primary/sotauptaneclient.cc @@ -670,8 +670,6 @@ void SotaUptaneClient::reportResume() { std::pair SotaUptaneClient::downloadImage(const Uptane::Target &target, const api::FlowControlToken *token) { - // TODO: support downloading encrypted targets from director - const std::string &correlation_id = director_repo.getCorrelationId(); // send an event for all ECUs that are touched by this target for (const auto &ecu : target.ecus()) { diff --git a/src/libaktualizr/utilities/utils.cc b/src/libaktualizr/utilities/utils.cc index f33f21e722..b721fb3102 100644 --- a/src/libaktualizr/utilities/utils.cc +++ b/src/libaktualizr/utilities/utils.cc @@ -849,7 +849,7 @@ class SafeTempRoot { } boost::filesystem::path p = prefix / boost::filesystem::unique_path("aktualizr-%%%%-%%%%-%%%%-%%%%"); if (mkdir(p.c_str(), S_IRWXU) == -1) { - throw std::runtime_error(std::string("could not create temporary directory root: ").append(p.native())); + throw std::runtime_error(std::string("Could not create temporary directory root: ").append(p.native())); } path = boost::filesystem::path(p); From c76a9cb4ccab00e671b2998f96f3d11164c72de6 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Thu, 6 Aug 2020 14:39:33 +0200 Subject: [PATCH 2/3] Minor exception refactoring. Signed-off-by: Patrick Vacek --- src/libaktualizr/primary/sotauptaneclient.cc | 4 ++-- src/libaktualizr/storage/sql_utils.h | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libaktualizr/primary/sotauptaneclient.cc b/src/libaktualizr/primary/sotauptaneclient.cc index f13d63b307..0e800abaab 100644 --- a/src/libaktualizr/primary/sotauptaneclient.cc +++ b/src/libaktualizr/primary/sotauptaneclient.cc @@ -833,8 +833,8 @@ result::UpdateCheck SotaUptaneClient::checkUpdates() { std::string director_targets; if (!storage->loadNonRoot(&director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets())) { - // TODO: this kind of exception should come directly from the storage? - throw std::runtime_error("Could not get Director's Targets from storage"); + result = result::UpdateCheck({}, 0, result::UpdateStatus::kError, Json::nullValue, "Could not update metadata."); + return result; } if (updates.empty()) { diff --git a/src/libaktualizr/storage/sql_utils.h b/src/libaktualizr/storage/sql_utils.h index cedf63f1ab..c4cce8e898 100644 --- a/src/libaktualizr/storage/sql_utils.h +++ b/src/libaktualizr/storage/sql_utils.h @@ -68,14 +68,14 @@ class SQLiteStatement { void bindArgument(int v) { if (sqlite3_bind_int(stmt_.get(), bind_cnt_, v) != SQLITE_OK) { LOG_ERROR << "Could not bind: " << sqlite3_errmsg(db_); - throw std::runtime_error("SQLite bind error"); + throw SQLException("SQLite bind error"); } } void bindArgument(int64_t v) { if (sqlite3_bind_int64(stmt_.get(), bind_cnt_, v) != SQLITE_OK) { LOG_ERROR << "Could not bind: " << sqlite3_errmsg(db_); - throw std::runtime_error("SQLite bind error"); + throw SQLException("SQLite bind error"); } } @@ -85,7 +85,7 @@ class SQLiteStatement { if (sqlite3_bind_text(stmt_.get(), bind_cnt_, oe.c_str(), -1, nullptr) != SQLITE_OK) { LOG_ERROR << "Could not bind: " << sqlite3_errmsg(db_); - throw std::runtime_error("SQLite bind error"); + throw SQLException("SQLite bind error"); } } @@ -98,7 +98,7 @@ class SQLiteStatement { if (sqlite3_bind_blob(stmt_.get(), bind_cnt_, oe.c_str(), static_cast(oe.size()), SQLITE_STATIC) != SQLITE_OK) { LOG_ERROR << "Could not bind: " << sqlite3_errmsg(db_); - throw std::runtime_error("SQLite bind error"); + throw SQLException("SQLite bind error"); } } @@ -133,7 +133,7 @@ class SQLite3Guard { m_->lock(); } if (sqlite3_threadsafe() == 0) { - throw std::runtime_error("sqlite3 has been compiled without multitheading support"); + throw SQLException("sqlite3 has been compiled without multitheading support"); } sqlite3* h; if (readonly) { From c2c54d557b5a35ffe3ea1d3870548c7e68338f99 Mon Sep 17 00:00:00 2001 From: Patrick Vacek Date: Thu, 6 Aug 2020 14:39:49 +0200 Subject: [PATCH 3/3] Document exceptions thrown through the API. This list is not exhaustive, but should give a high-level view of what to expect. Signed-off-by: Patrick Vacek --- include/libaktualizr/aktualizr.h | 107 +++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 6 deletions(-) diff --git a/include/libaktualizr/aktualizr.h b/include/libaktualizr/aktualizr.h index 18ae091c3e..4edc02df05 100644 --- a/include/libaktualizr/aktualizr.h +++ b/include/libaktualizr/aktualizr.h @@ -24,8 +24,15 @@ class CommandQueue; class Aktualizr { public: /** Aktualizr requires a configuration object. Examples can be found in the - * config directory. */ + * config directory. + * + * @throw SQLException + * @throw boost::filesystem::filesystem_error + * @throw std::bad_alloc + * @throw std::runtime_error (filesystem and json parsing failures; libsodium initialization failure) + */ explicit Aktualizr(const Config& config); + Aktualizr(const Aktualizr&) = delete; Aktualizr& operator=(const Aktualizr&) = delete; ~Aktualizr(); @@ -34,6 +41,18 @@ class Aktualizr { * Initialize aktualizr. Any Secondaries should be added before making this * call. This will provision with the server if required. This must be called * before using any other aktualizr functions except AddSecondary. + * + * @throw Initializer::Error and subclasses + * @throw Uptane::Exception and subclasses + * @throw SQLException + * @throw boost::filesystem::filesystem_error + * @throw std::system_error (failure to lock a mutex) + * @throw std::bad_alloc (memory allocation failure) + * @throw std::runtime_error (curl, P11, SQL, filesystem, credentials archive + * parsing, certificate parsing, json parsing + * failures; missing ECU serials or device ID; + * database inconsistency with pending updates; + * invalid OSTree deployment) */ void Initialize(); @@ -41,11 +60,21 @@ class Aktualizr { * Asynchronously run aktualizr indefinitely until Shutdown is called. * @param custom_hwinfo if not empty will be sent to the backend instead of `lshw` output * @return Empty std::future object + * + * @throw SQLException + * @throw boost::filesystem::filesystem_error + * @throw std::system_error (failure to lock a mutex) + * @throw std::bad_alloc + * @throw std::runtime_error (curl, SQL, filesystem, and json parsing failures; + * database inconsistency with pending updates; + * error getting metadata from database or filesystem) */ std::future RunForever(const Json::Value& custom_hwinfo = Json::nullValue); /** * Shuts down currently running `RunForever()` method + * + * @throw std::system_error (failure to lock a mutex) */ void Shutdown(); @@ -54,6 +83,8 @@ class Aktualizr { * Campaigns are a concept outside of Uptane, and allow for user approval of * updates before the contents of the update are known. * @return std::future object with data about available campaigns. + * + * @throw std::runtime_error (curl and json parsing failures) */ std::future CampaignCheck(); @@ -66,6 +97,8 @@ class Aktualizr { * @param campaign_id Campaign ID as provided by CampaignCheck. * @param cmd action to apply on the campaign: accept, decline or postpone * @return Empty std::future object + * + * @throw std::bad_alloc (memory allocation failure) */ std::future CampaignControl(const std::string& campaign_id, campaign::Cmd cmd); @@ -74,6 +107,11 @@ class Aktualizr { * This includes network status, installed packages, hardware etc. * @param custom_hwinfo if not empty will be sent to the backend instead of `lshw` output * @return Empty std::future object + * + * @throw SQLException + * @throw boost::filesystem::filesystem_error + * @throw std::bad_alloc + * @throw std::runtime_error (curl, filesystem, and json parsing failures) */ std::future SendDeviceData(const Json::Value& custom_hwinfo = Json::nullValue); @@ -83,6 +121,12 @@ class Aktualizr { * Uptane metadata (including root and targets), and then checks the metadata * for target updates. * @return Information about available updates. + * + * @throw SQLException + * @throw boost::filesystem::filesystem_error + * @throw std::bad_alloc + * @throw std::runtime_error (curl, SQL, filesystem, and json parsing failures; + * database inconsistency with pending updates) */ std::future CheckUpdates(); @@ -90,20 +134,28 @@ class Aktualizr { * Download targets. * @param updates Vector of targets to download as provided by CheckUpdates. * @return std::future object with information about download results. + * + * @throw SQLException + * @throw std::system_error (failure to lock a mutex) */ std::future Download(const std::vector& updates); + struct InstallationLogEntry { + Uptane::EcuSerial ecu; + std::vector installs; + }; + using InstallationLog = std::vector; + /** * Get log of installations. The log is indexed for every ECU and contains * every change of versions ordered by time. It may contain duplicates in * case of rollbacks. * @return installation log + * + * @throw SQLException + * @throw std::bad_alloc (memory allocation failure) + * @throw std::runtime_error (failure to load ECU serials) */ - struct InstallationLogEntry { - Uptane::EcuSerial ecu; - std::vector installs; - }; - using InstallationLog = std::vector; InstallationLog GetInstallationLog(); /** @@ -111,6 +163,10 @@ class Aktualizr { * DeleteStoredTarget and targets are not guaranteed to be verified and * up-to-date with current metadata. * @return std::vector of target objects + * + * @throw SQLException + * @throw std::bad_alloc (memory allocation failure) + * @throw std::runtime_error (error getting targets from database) */ std::vector GetStoredTargets(); @@ -120,6 +176,9 @@ class Aktualizr { * current metadata. * @param target Target object matching the desired target in the storage * @return true if successful + * + * @throw SQLException + * @throw std::runtime_error (error getting targets from database or filesystem) */ void DeleteStoredTarget(const Uptane::Target& target); @@ -128,6 +187,9 @@ class Aktualizr { * according to the Uptane metadata downloaded in CheckUpdates call. * @param target Target object matching the desired target in the storage. * @return Handle to the stored binary. nullptr if none is found. + * + * @throw SQLException + * @throw std::runtime_error (error getting targets from database or filesystem) */ std::ifstream OpenStoredTarget(const Uptane::Target& target); @@ -136,6 +198,9 @@ class Aktualizr { * @param updates Vector of targets to install as provided by CheckUpdates or * Download. * @return std::future object with information about installation results. + * + * @throw SQLException + * @throw std::runtime_error (error getting metadata from database or filesystem) */ std::future Install(const std::vector& updates); @@ -147,6 +212,8 @@ class Aktualizr { * @param custom_raw_report is intended to replace a default value in the device installation report. * @return true if the custom raw report was successfully applied to the device installation result. * If there is no installation report in the storage the function will always return false. + * + * @throw SQLException */ bool SetInstallationRawReport(const std::string& custom_raw_report); @@ -160,6 +227,9 @@ class Aktualizr { * * @param custom Project-specific data to put in the custom field of Uptane manifest * @return std::future object with manifest update result (true on success). + * + * @throw SQLException + * @throw std::runtime_error (curl failures; database inconsistency with pending updates) */ std::future SendManifest(const Json::Value& custom = Json::nullValue); @@ -168,6 +238,9 @@ class Aktualizr { * In progress target downloads will be paused and API calls will be deferred. * * @return Information about pause results. + * + * @throw std::system_error (failure to lock a mutex) + * @throw std::bad_alloc */ result::Pause Pause(); @@ -177,6 +250,9 @@ class Aktualizr { * execute in fifo order. * * @return Information about resume results. + * + * @throw std::system_error (failure to lock a mutex) + * @throw std::bad_alloc */ result::Pause Resume(); @@ -186,6 +262,8 @@ class Aktualizr { * This doesn't reset the `Paused` state, i.e. if the queue was previously * paused, it will remain paused, but with an emptied queue. * The call is blocking. + * + * @throw std::system_error (failure to lock a mutex) */ void Abort(); @@ -194,18 +272,32 @@ class Aktualizr { * targets, install them, and send a manifest back to the server. * * @return `false`, if the restart is required to continue, `true` otherwise + * + * @throw SQLException + * @throw boost::filesystem::filesystem_error + * @throw std::system_error (failure to lock a mutex) + * @throw std::bad_alloc + * @throw std::runtime_error (curl, SQL, filesystem, and json parsing failures; + * database inconsistency with pending updates; + * error getting metadata from database or filesystem) */ bool UptaneCycle(); /** * Add new Secondary to aktualizr. Must be called before Initialize. * @param secondary An object to perform installation on a Secondary ECU. + * + * @throw std::bad_alloc (memory allocation failure) + * @throw std::runtime_error (multiple Secondaries with the same serial) */ void AddSecondary(const std::shared_ptr& secondary); /** * Store some free-form data to be associated with a particular Secondary, to * be retrieved later through `GetSecondaries` + * + * @throw SQLException + * @throw std::runtime_error (SQL failure) */ void SetSecondaryData(const Uptane::EcuSerial& ecu, const std::string& data); @@ -214,6 +306,9 @@ class Aktualizr { * metadata * * @return vector of SecondaryInfo objects + * + * @throw SQLException + * @throw std::bad_alloc (memory allocation failure) */ std::vector GetSecondaries() const;