-
Notifications
You must be signed in to change notification settings - Fork 514
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change DCT read access to lock()/unlock() or read-with-copy #1307
Conversation
Added DCT and flash locking support for Photon/P1
…ynalib import dct functions from system-part2, let's at least leave the source tree in a working state
9521db6
to
9ed574c
Compare
hal/src/photon/dct_hal.cpp
Outdated
} | ||
|
||
const void* dct_read_app_data(uint32_t offset) { | ||
return ((const void*)((uint32_t)wiced_dct_get_current_address(DCT_APP_SECTION) + offset)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's simplify this:
return ((const char*)wiced_dct_get_current_address(DCT_APP_SECTION) + offset);
I know this function is going to be deprecated, but still, how about adding a critical section here, just to avoid concurrent initialization/swapping of the DCTs?
hal/src/photon/softap.cpp
Outdated
@@ -524,7 +525,9 @@ int decrypt(char* plaintext, int max_plaintext_len, char* hex_encoded_ciphertext | |||
hex_decode(buf, len, hex_encoded_ciphertext); | |||
|
|||
// reuse the hex encoded buffer | |||
int plaintext_len = decrypt_rsa(buf, fetch_device_private_key(), (uint8_t*)plaintext, max_plaintext_len); | |||
const uint8_t *key = fetch_device_private_key(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would split this into two functions or at least add a comment to improve readability
fetch_device_private_key(1); // Lock key data
fetch_device_private_key(0); // Unlock key data
hal/src/photon/wlan_hal.cpp
Outdated
const eap_config_t* eap_conf = (eap_config_t*)dct_read_app_data(DCT_EAP_CONFIG_OFFSET); | ||
uint8_t eap_type = WLAN_EAP_TYPE_NONE; | ||
|
||
const eap_config_t* eap_conf = (const eap_config_t*)dct_read_app_data_lock(DCT_EAP_CONFIG_OFFSET); | ||
if (!is_eap_configuration_valid(eap_conf)) { | ||
return 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dct_read_app_data_unlock()
is missing here. I think we need to implement a RAII-based locker for DCT and avoid using dct_read_app_data_lock/unlock()
in C++ code whenever possible
hal/src/photon/wlan_hal.cpp
Outdated
|
||
wiced_country_code_t result = | ||
wiced_country_code_t(MK_CNTRY(code[0], code[1], hex_nibble(code[2]))); | ||
|
||
dct_read_app_data_unlock(DCT_COUNTRY_CODE_OFFSET); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code
is dereferenced after unlocking DCT, later in this function:
if (code[0] == 0xFF || code[0] == 0)
...
@@ -441,6 +452,8 @@ int wlan_supplicant_start() | |||
LOG(TRACE, "Supplicant started %d", (int)result); | |||
} | |||
|
|||
dct_read_app_data_unlock(DCT_EAP_CONFIG_OFFSET); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it safe that a lot of WICED's stuff gets called while DCT is locked?
hal/src/photon/wlan_hal.cpp
Outdated
static_ip_config_t config; | ||
memcpy(&config, pconfig, sizeof(config)); | ||
memcpy(&config, &pconfig, sizeof(config)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary copying
} | ||
|
||
wiced_result_t wiced_dct_lock() | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add HAL_IsISR()
check here?
@@ -284,7 +284,8 @@ void HAL_OTA_Flashed_ResetStatus(void) | |||
|
|||
void HAL_FLASH_Read_ServerPublicKey(uint8_t *keyBuffer) | |||
{ | |||
fetch_device_public_key(); | |||
fetch_device_public_key(1); | |||
fetch_device_public_key(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about adding a separate function, e.g. init_device_public_key()
, and making fetch_device_public_key()
to call it internally? These calls look weird :)
services/inc/atomic_flag_mutex.h
Outdated
void unlock() { | ||
flag.clear(std::memory_order_release); | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to see this AtomicFlagMutex
implementation supporting recursive locking, possibly in next versions of the firmware. For example:
void lock() {
acquire_flag();
if (!mutex_is_initialized && mutex_can_be_initialized) { // Heap is initialized, etc.
init_recursive_mutex();
mutex_is_initialized = true;
}
if (mutex_is_initialized) {
lock_mutex();
release_flag();
}
}
void unlock() {
if (mutex_is_initialized) {
unlock_mutex();
} else {
release_flag();
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about something like this?
template <typename R, R(*spin)()>
class AtomicRecursiveMutex {
std::atomic<std::thread::id> owner;
std::atomic_int refcount{0};
public:
int lock() {
SPARK_ASSERT(!HAL_IsISR());
std::thread::id no_id = std::thread::id();
std::thread::id self = std::this_thread::get_id();
while ((no_id != std::thread::id() && no_id != self) || !owner.compare_exchange_weak(no_id, self)) {
if (no_id == self) {
// To avoid spinning
break;
}
else if (no_id != std::thread::id()) {
no_id = std::thread::id();
}
spin();
}
return ++refcount;
}
int unlock() {
SPARK_ASSERT(!HAL_IsISR());
SPARK_ASSERT(owner.load() == std::this_thread::get_id());
int c = --refcount;
SPARK_ASSERT(c >= 0);
if (c == 0) {
// Unlock
owner.store(std::thread::id());
}
return c;
}
};
We can also add additional assertions to wiced_dct_lock/wiced_dct_unlock
that will help us track issues with such an implementation.
wiced_result_t wiced_dct_lock(int exclusive)
{
SPARK_ASSERT(!HAL_IsISR());
int refcount = dctLock.lock();
SPARK_ASSERT(!exclusive || refcount == 1);
return WICED_SUCCESS;
}
wiced_result_t wiced_dct_unlock(int exclusive)
{
SPARK_ASSERT(!HAL_IsISR());
int refcount = dctLock.unlock();
SPARK_ASSERT(!exclusive || refcount == 0);
return WICED_SUCCESS;
}
exclusive
would be set to 1
when writing to dct, as we cannot guarantee data validity after a dct sector swap.
result = wiced_dct_write(&expected, DCT_WIFI_CONFIG_SECTION, OFFSETOF(platform_dct_wifi_config_t, soft_ap_settings), sizeof(wiced_config_soft_ap_t)); | ||
} else { | ||
wiced_dct_read_unlock( soft_ap, WICED_FALSE ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! 👍 I've just checked other places where we use non-copying variant of wiced_dct_read_lock()
, and haven't found anything suspicious.
Closing due to changes being in |
Do not merge. Review only. Superseded by #1320
Problem
When using
dct_read_app_data
the returned pointer might become invalid in case a different thread writes into DCT causing a DCT swap.Photon/P1 should have a critical section around flash operations and around DCT operations.
Solution
This branched is based on #1295 and then rebased on #1289.
dct_read_app_data_lock()
,dct_read_app_data_unlock()
,dct_read_app_data_copy()
.NOTE: Photon/P1 bootloader builds should overflow. It's intended, as we are removing DCT implementation out of it and importing it from system-part2 instead in https://github.com/spark/firmware/tree/feature/bootloader_dct
Steps to Test
N/A
Example App
N/A
References
Completeness
Enhancement
[PR #1307]
[Photon/P1]
New version of WICED adds CRC checking to the DCT implementation so that write errors are detected. Added a critical section around flash operations and around DCT operations to make them thread safe.