Skip to content
This repository has been archived by the owner on May 21, 2024. It is now read-only.

Fix/ota 2451/empty targets #1186

Merged
merged 8 commits into from
Apr 18, 2019
2 changes: 2 additions & 0 deletions src/libaktualizr/primary/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ add_aktualizr_test(NAME aktualizr SOURCES aktualizr_test.cc PROJECT_WORKING_DIRE
add_dependencies(t_aktualizr uptane_repo_full_no_correlation_id)

add_aktualizr_test(NAME reportqueue SOURCES reportqueue_test.cc PROJECT_WORKING_DIRECTORY)
add_aktualizr_test(NAME emptytargets SOURCES empty_targets_test.cc PROJECT_WORKING_DIRECTORY
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsequential but this source file is introduced in a later commit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops. If anything else comes up, I can fix that, but I'm not going to rebase just for that.

ARGS "$<TARGET_FILE:aktualizr-repo>")

aktualizr_source_file_checks(${SOURCES} ${HEADERS} ${TEST_SOURCES})
1 change: 1 addition & 0 deletions src/libaktualizr/primary/aktualizr.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ class Aktualizr {
FRIEND_TEST(Aktualizr, UpdateCheckCompleteError);
FRIEND_TEST(Aktualizr, PauseResumeQueue);
FRIEND_TEST(Aktualizr, AddSecondary);
FRIEND_TEST(Aktualizr, EmptyTargets);
FRIEND_TEST(Delegation, Basic);
FRIEND_TEST(Delegation, RevokeAfterCheckUpdates);
FRIEND_TEST(Delegation, RevokeAfterInstall);
Expand Down
1 change: 1 addition & 0 deletions src/libaktualizr/primary/sotauptaneclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class SotaUptaneClient {
FRIEND_TEST(Aktualizr, FinalizationFailure);
FRIEND_TEST(Aktualizr, InstallationFailure);
FRIEND_TEST(Aktualizr, AutoRebootAfterUpdate);
FRIEND_TEST(Aktualizr, EmptyTargets);
FRIEND_TEST(Uptane, AssembleManifestGood);
FRIEND_TEST(Uptane, AssembleManifestBad);
FRIEND_TEST(Uptane, InstallFake);
Expand Down
12 changes: 9 additions & 3 deletions src/libaktualizr/uptane/directorrepository.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ void DirectorRepository::resetMeta() {
bool DirectorRepository::verifyTargets(const std::string& targets_raw) {
try {
// Verify the signature:
targets = Targets(RepositoryType::Director(), Role::Targets(), Utils::parseJSON(targets_raw),
std::make_shared<MetaWithKeys>(root));
latest_targets = Targets(RepositoryType::Director(), Role::Targets(), Utils::parseJSON(targets_raw),
std::make_shared<MetaWithKeys>(root));
if (!usePreviousTargets()) {
targets = latest_targets;
}
} catch (const Uptane::Exception& e) {
LOG_ERROR << "Signature verification for director targets metadata failed";
last_exception = e;
Expand Down Expand Up @@ -122,6 +125,9 @@ bool DirectorRepository::updateMeta(INvStorage& storage, Fetcher& fetcher) {
std::string director_targets_stored;
if (storage.loadNonRoot(&director_targets_stored, RepositoryType::Director(), Role::Targets())) {
local_version = extractVersionUntrusted(director_targets_stored);
if (!verifyTargets(director_targets_stored)) {
LOG_WARNING << "Unable to verify stored director targets metadata.";
}
} else {
local_version = -1;
}
Expand All @@ -132,7 +138,7 @@ bool DirectorRepository::updateMeta(INvStorage& storage, Fetcher& fetcher) {

if (local_version > remote_version) {
return false;
} else if (local_version < remote_version) {
} else if (local_version < remote_version && !usePreviousTargets()) {
storage.storeNonRoot(director_targets, RepositoryType::Director(), Role::Targets());
}

Expand Down
11 changes: 9 additions & 2 deletions src/libaktualizr/uptane/directorrepository.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,21 @@ class DirectorRepository : public RepositoryCommon {
bool verifyTargets(const std::string& targets_raw);
const std::vector<Target>& getTargets() const { return targets.targets; }
const std::string& getCorrelationId() const { return targets.correlation_id(); }
bool targetsExpired() const { return targets.isExpired(TimeStamp::Now()); }
bool targetsExpired() const { return latest_targets.isExpired(TimeStamp::Now()); }
// Don't store the new targets if they are empty and we've previously received
// a non-empty list.
bool usePreviousTargets() const { return !targets.targets.empty() && latest_targets.targets.empty(); }
bool checkMetaOffline(INvStorage& storage);

Exception getLastException() const { return last_exception; }
bool updateMeta(INvStorage& storage, Fetcher& fetcher);

private:
Uptane::Targets targets;
// Since the Director can send us an empty targets list to mean "no new
// updates", we have to persist the previous targets list. Use the latest for
// checking expiration but the most recent non-empty list for everything else.
Uptane::Targets targets; // Only empty if we've never received non-empty targets.
Uptane::Targets latest_targets; // Can be an empty list.
Exception last_exception{"", ""};
};

Expand Down