Skip to content

Commit a0c5d28

Browse files
FWEO-1481 app_strorage: Add CRC check at initialization + unit tests
Force reset in case the storage is corrupted.
1 parent 30aca1a commit a0c5d28

File tree

5 files changed

+106
-15
lines changed

5 files changed

+106
-15
lines changed

include/decorators.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,9 @@
7272
#else
7373
#define STATIC
7474
#endif
75+
76+
#if !defined(UNIT_TESTING)
77+
#define CONST const
78+
#else
79+
#define CONST
80+
#endif

lib_standard_app/app_storage.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,34 @@
2424

2525
#define APP_STORAGE_ERASE_BLOCK_SIZE 256
2626

27-
/* In order to be used in unit testing */
28-
#if !defined(TEST)
29-
#define CONST const
30-
#else
31-
#define CONST
32-
#endif
33-
3427
CONST app_storage_t app_storage_real __attribute__((section(".storage_section")));
3528
#define app_storage (*(volatile app_storage_t *) PIC(&app_storage_real))
3629

3730
/**
38-
* @brief checks if the app storage struct is initialized
31+
* @brief checks if the app storage struct is initialized and valid
3932
*/
40-
static bool app_storage_is_initalized(void)
33+
STATIC bool app_storage_is_initalized(void)
4134
{
42-
if (memcmp((const void *) &app_storage.header.tag, APP_STORAGE_TAG, APP_STORAGE_TAG_LEN) != 0) {
43-
return false;
35+
bool is_initialized = false;
36+
if (memcmp((const void *) &app_storage.header.tag, APP_STORAGE_TAG, APP_STORAGE_TAG_LEN) == 0) {
37+
is_initialized = true;
38+
}
39+
else {
40+
goto error;
41+
}
42+
43+
uint32_t crc = cx_crc32((void *) &app_storage.header,
44+
sizeof(app_storage.header) + app_storage.header.size);
45+
if (crc != app_storage.crc) {
46+
// Invalid CRC, force reset
47+
is_initialized = false;
4448
}
45-
return true;
49+
else {
50+
is_initialized = true;
51+
}
52+
53+
error:
54+
return is_initialized;
4655
}
4756

4857
static inline void update_crc(void)

unit-tests/app_storage/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ target_compile_options(
6666
target_compile_definitions(
6767
${TEST}
6868
PRIVATE
69-
TEST
69+
UNIT_TESTING
7070
SCREEN_SIZE_WALLET
7171
USB_SEGMENT_SIZE=64
7272
HAVE_NBGL

unit-tests/app_storage/app_storage_stubs.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@
1818
#include <setjmp.h>
1919
#include <string.h>
2020

21+
#ifdef UNIT_TESTING
22+
// When defined cmocka redefine malloc/free which does not work well with
23+
// address-sanitizer
24+
#undef UNIT_TESTING
25+
#include <cmocka.h>
26+
#define UNIT_TESTING
27+
#else
28+
#include <cmocka.h>
29+
#endif
30+
2131
#include <cmocka.h>
2232
#include <malloc.h>
2333
#include <stdio.h>

unit-tests/app_storage/test_app_storage.c

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,23 @@
1717
#include <stddef.h>
1818
#include <setjmp.h>
1919
#include <string.h>
20-
21-
#include <cmocka.h>
2220
#include <stdio.h>
2321
#include <stdlib.h>
2422

23+
#ifdef UNIT_TESTING
24+
// When defined cmocka redefine malloc/free which does not work well with
25+
// address-sanitizer
26+
#undef UNIT_TESTING
27+
#include <cmocka.h>
28+
#define UNIT_TESTING
29+
#else
30+
#include <cmocka.h>
31+
#endif
32+
2533
#include "app_storage.h"
2634
#include "app_storage_internal.h"
2735
#include "app_storage_stubs.h"
36+
#include "os_nvm.h"
2837

2938
/* Defines */
3039
#define INITIAL_SIZE 20
@@ -68,6 +77,10 @@ _Static_assert(sizeof(app_storage_data_t) <= APP_STORAGE_SIZE,
6877
app_storage_read( \
6978
dst_buf, sizeof(((app_storage_data_t *) 0)->field), offsetof(app_storage_data_t, field))
7079

80+
// app_storage.h private
81+
extern app_storage_t app_storage_real;
82+
bool app_storage_is_initalized(void);
83+
7184
/* Local prototypes */
7285
static void test_write_read_from_empty(void **state __attribute__((unused)));
7386
static void test_app_style_from_empty(void **state __attribute__((unused)));
@@ -119,6 +132,55 @@ static void test_getters_from_empty(void **state __attribute__((unused)))
119132
APP_STORAGE_PROP_SETTINGS | APP_STORAGE_PROP_DATA);
120133
}
121134

135+
/* Test that corruption from empty storage is detected */
136+
static void test_corrupted_storage_from_empty(void **state __attribute__((unused)))
137+
{
138+
assert_true(app_storage_is_initalized());
139+
// --- Simulate corrupted header
140+
app_storage_header_t header = app_storage_real.header;
141+
header.data_version += 1;
142+
// Change header with no CRC update
143+
nvm_write((void *) &app_storage_real.header, &header, sizeof(header));
144+
// Ensure invalid CRC
145+
assert_false(app_storage_is_initalized());
146+
147+
// --- Simulate corrupted data
148+
setup_from_empty(NULL);
149+
assert_true(app_storage_is_initalized());
150+
uint8_t buf[20] = {0};
151+
memset(buf, 0xAA, sizeof(buf));
152+
assert_int_equal(app_storage_write(buf, sizeof(buf), 0), sizeof(buf));
153+
// Change data with no CRC update
154+
buf[sizeof(buf) - 1] = 0xAB;
155+
nvm_write((void *) &app_storage_real.data, buf, sizeof(buf));
156+
// Ensure invalid CRC
157+
assert_false(app_storage_is_initalized());
158+
}
159+
160+
/* Test that corruption from prepared storage is detected */
161+
static void test_corrupted_storage_from_prepared(void **state __attribute__((unused)))
162+
{
163+
assert_true(app_storage_is_initalized());
164+
// --- Simulate corrupted header
165+
app_storage_header_t header = app_storage_real.header;
166+
header.data_version += 1;
167+
// Change header with no CRC update
168+
nvm_write((void *) &app_storage_real.header, &header, sizeof(header));
169+
// Ensure invalid CRC
170+
assert_false(app_storage_is_initalized());
171+
172+
// --- Simulate corrupted data
173+
setup_from_prepared(NULL);
174+
assert_true(app_storage_is_initalized());
175+
uint8_t data[INITIAL_SIZE + ADDITIONALL_SIZE] = {0};
176+
app_storage_read(data, INITIAL_SIZE + ADDITIONALL_SIZE, 0);
177+
// Change data with no CRC update
178+
data[INITIAL_SIZE + ADDITIONALL_SIZE - 1]++;
179+
nvm_write((void *) &app_storage_real.data, data, INITIAL_SIZE + ADDITIONALL_SIZE);
180+
// Ensure invalid CRC
181+
assert_false(app_storage_is_initalized());
182+
}
183+
122184
/* Read error cases with initially empty storage */
123185
static void test_read_error_from_empty(void **state __attribute__((unused)))
124186
{
@@ -448,6 +510,8 @@ int main(int argc, char **argv)
448510
{
449511
const struct CMUnitTest tests[] = {
450512
cmocka_unit_test_setup_teardown(test_getters_from_empty, setup_from_empty, teardown),
513+
cmocka_unit_test_setup_teardown(
514+
test_corrupted_storage_from_empty, setup_from_empty, teardown),
451515
cmocka_unit_test_setup_teardown(test_read_error_from_empty, setup_from_empty, teardown),
452516
cmocka_unit_test_setup_teardown(test_write_error_from_empty, setup_from_empty, teardown),
453517
cmocka_unit_test_setup_teardown(test_data_version_from_empty, setup_from_empty, teardown),
@@ -456,6 +520,8 @@ int main(int argc, char **argv)
456520
test_write_big_reset_from_empty, setup_from_empty, teardown),
457521
cmocka_unit_test_setup_teardown(
458522
test_write_read_from_prepared, setup_from_prepared, teardown),
523+
cmocka_unit_test_setup_teardown(
524+
test_corrupted_storage_from_prepared, setup_from_prepared, teardown),
459525
cmocka_unit_test_setup_teardown(test_app_style_from_empty, setup_from_empty, teardown),
460526
cmocka_unit_test_setup_teardown(
461527
test_app_style_from_prepared, setup_from_prepared_app_style, teardown),

0 commit comments

Comments
 (0)