From a61ef26be1acf05afb9266117aff0fc0b50e8872 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 4 Sep 2017 11:54:18 +0800 Subject: [PATCH] nvs: check CRC of items on full pages Previously NVS did check CRC values of key-value pairs on the active page, but the check for full pages was missing. This adds the necessary check and a test for it. --- components/nvs_flash/src/nvs_page.cpp | 11 ++++++ .../nvs_flash/test_nvs_host/test_nvs.cpp | 38 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/components/nvs_flash/src/nvs_page.cpp b/components/nvs_flash/src/nvs_page.cpp index 8f562dca4..11dcb17d1 100644 --- a/components/nvs_flash/src/nvs_page.cpp +++ b/components/nvs_flash/src/nvs_page.cpp @@ -577,6 +577,17 @@ esp_err_t Page::mLoadEntryTable() } mHashList.insert(item, i); + + if (item.crc32 != item.calculateCrc32()) { + err = eraseEntryAndSpan(i); + if (err != ESP_OK) { + mState = PageState::INVALID; + return err; + } + continue; + } + + assert(item.span > 0); size_t span = item.span; i += span - 1; diff --git a/components/nvs_flash/test_nvs_host/test_nvs.cpp b/components/nvs_flash/test_nvs_host/test_nvs.cpp index 22d4c3b70..d4ec585ed 100644 --- a/components/nvs_flash/test_nvs_host/test_nvs.cpp +++ b/components/nvs_flash/test_nvs_host/test_nvs.cpp @@ -1096,6 +1096,44 @@ TEST_CASE("recovery after failure to write data", "[nvs]") } } +TEST_CASE("crc errors in item header are handled", "[nvs]") +{ + SpiFlashEmulator emu(3); + Storage storage; + // prepare some data + TEST_ESP_OK(storage.init(0, 3)); + TEST_ESP_OK(storage.writeItem(0, "ns1", static_cast(1))); + TEST_ESP_OK(storage.writeItem(1, "value1", static_cast(1))); + TEST_ESP_OK(storage.writeItem(1, "value2", static_cast(2))); + + // corrupt item header + uint32_t val = 0; + emu.write(32 * 3, &val, 4); + + // check that storage can recover + TEST_ESP_OK(storage.init(0, 3)); + TEST_ESP_OK(storage.readItem(1, "value2", val)); + CHECK(val == 2); + // check that the corrupted item is no longer present + TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, storage.readItem(1, "value1", val)); + + // add more items to make the page full + for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) { + char item_name[Item::MAX_KEY_LENGTH + 1]; + snprintf(item_name, sizeof(item_name), "item_%ld", i); + TEST_ESP_OK(storage.writeItem(1, item_name, static_cast(i))); + } + + // corrupt another item on the full page + val = 0; + emu.write(32 * 4, &val, 4); + + // check that storage can recover + TEST_ESP_OK(storage.init(0, 3)); + // check that the corrupted item is no longer present + TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, storage.readItem(1, "value2", val)); +} + TEST_CASE("crc error in variable length item is handled", "[nvs]") { SpiFlashEmulator emu(3);