Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
v2.6.1
------
- Verify frame counters in `wsrd` and `silabs-ws-dc` to prevent replay
attacks.
- Fix occasional infinite loop in `wsbrd` with EAPoL congestion, neighbor
timeouts, and frame handle allocation failure.
- Update Singapore PHY definitions with the 2v03 specification: allow
ChanPlanId 41-43 and fix documented base frequencies.
- Fix malformed D-Bus message for `Nodes` property with new authenticator.
- Fix minor memory leak with CPC secondary version retrieval.
- Do not enable [source fortification][fortify] by default: let users
manually enable hardening features to prevent platform specific issues.
- Support MbedTLS >= 3.6.3.

[fortify]: https://sourceware.org/glibc/manual/latest/html_node/Source-Fortification.html

v2.6
------
- New authenticator implementation for `wsbrd`:
Expand Down
3 changes: 0 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,6 @@ if(CC_HAVE_WNO_STRINGOP_OVERFLOW)
add_compile_options(-Wno-stringop-overflow)
endif()

# Ask to glibc to check buffer overflows in memcpy() and friends.
add_compile_definitions(_FORTIFY_SOURCE=3)

# In come case, backtraces are not available without that flags. Increase size
# of the binary file, but can be stripped.
if(CC_HAVE_UNWIND_TABLES)
Expand Down
2 changes: 1 addition & 1 deletion app_wsbrd/app/dbus_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ void dbus_message_append_supp(sd_bus_message *m, const char *property, const voi
sd_bus_message_append(m, "y", supp->node_role);
dbus_message_close_info(m, property);
}
dbus_message_open_info(m, property, "eapol_target", "y");
dbus_message_open_info(m, property, "eapol_target", "ay");
if (!IN6_IS_ADDR_UNSPECIFIED(&supp->eapol_target)) {
sd_bus_message_append_array(m, 'y', &supp->eapol_target, 16);
} else {
Expand Down
31 changes: 25 additions & 6 deletions app_wsbrd/app/wsbr_mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,34 @@
#include "dbus.h"
#include "commandline_values.h"

struct wsbr_cnf_fail {
struct net_if *net_if;
uint8_t handle;
uint8_t status;
};

// HACK: mac_confirm_cb() may send frames. Avoid possible recursive call.
static void wsbr_cnf_fail(void *arg)
{
struct mcps_data_rx_ie_list cnf_ie = { };
const struct wsbr_cnf_fail *ctx = arg;
struct mcps_data_cnf cnf = {
.hif.handle = ctx->handle,
.hif.status = ctx->status,
};

ws_llc_mac_confirm_cb(ctx->net_if, &cnf, &cnf_ie);
}

void wsbr_data_req_ext(struct net_if *cur,
const struct mcps_data_req *data,
const struct mcps_data_req_ie_list *ie_ext)
{
struct ws_neigh *neighbor_ws;
struct mcps_data_rx_ie_list cnf_fail_ie = { };
struct mcps_data_cnf cnf_fail = {
.hif.handle = data->msduHandle,
.hif.status = HIF_STATUS_TIMEDOUT,
struct wsbr_cnf_fail cnf_fail = {
.net_if = cur,
.handle = data->msduHandle,
.status = HIF_STATUS_TIMEDOUT,
};
struct ieee802154_hdr hdr = { };
struct iobuf_write frame = { };
Expand All @@ -77,12 +96,12 @@ void wsbr_data_req_ext(struct net_if *cur,
&EUI64_FROM_BUF(data->DstAddr));
if (data->DstAddrMode && !neighbor_ws) {
WARN("%s: neighbor timeout before packet send", __func__);
ws_llc_mac_confirm_cb(cur, &cnf_fail, &cnf_fail_ie);
timer_call_later(wsbr_cnf_fail, &cnf_fail, sizeof(cnf_fail));
return;
}
if (neighbor_ws && !ws_neigh_has_us(&neighbor_ws->fhss_data_unsecured)) {
TRACE(TR_TX_ABORT, "tx-abort %-9s: unknown unicast schedule for %s", "15.4", tr_eui64(data->DstAddr));
ws_llc_mac_confirm_cb(cur, &cnf_fail, &cnf_fail_ie);
timer_call_later(wsbr_cnf_fail, &cnf_fail, sizeof(cnf_fail));
return;
}

Expand Down
2 changes: 1 addition & 1 deletion app_wsbrd/ipv6/ipv6_neigh_storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void ipv6_neigh_storage_save(struct ipv6_neighbour_cache *cache, const uint8_t *
fprintf(nvm->file, "ipv6[%d] = %s\n", i, ipv6_str);
fprintf(nvm->file, "lifetime[%d] = %u\n", i, cur->lifetime_s);
fprintf(nvm->file, "# %s\n", time_str);
fprintf(nvm->file, "expiration[%d] = %lu\n", i, ts);
fprintf(nvm->file, "expiration[%d] = %ju\n", i, (uintmax_t) ts);
i++;
}

Expand Down
11 changes: 7 additions & 4 deletions common/bus_cpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,12 @@ uint32_t cpc_secondary_app_version(struct bus *bus)

str = cpc_get_secondary_app_version(bus->cpc.handle);
BUG_ON(!str);
if (!strcmp(str, "UNDEFINED"))
return VERSION(0, 0, 0);
ret = sscanf(str, "%hhu.%hu.%hhu", &major, &minor, &patch);
BUG_ON(ret == EOF);
if (!strcmp(str, "UNDEFINED")) {
major = minor = patch = 0;
} else {
ret = sscanf(str, "%hhu.%hu.%hhu", &major, &minor, &patch);
BUG_ON(ret == EOF);
}
cpc_free_secondary_app_version((char *)str);
return VERSION(major, minor, patch);
}
1 change: 1 addition & 0 deletions common/crypto/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ void tls_init_client(struct tls_ctx *tls, struct tls_client_ctx *tls_client)

mbedtls_ssl_set_bio(&tls_client->ssl_ctx, &tls_client->io, tls_send, tls_recv, NULL);
mbedtls_ssl_set_export_keys_cb(&tls_client->ssl_ctx, tls_export_keys, tls_client);
mbedtls_ssl_set_hostname(&tls_client->ssl_ctx, NULL);
rand_get_n_bytes_random(tls_client->pmk.key, sizeof(tls_client->pmk.key));
rand_get_n_bytes_random(tls_client->ptk.key, sizeof(tls_client->ptk.key));
rand_get_n_bytes_random(tls_client->tptk.key, sizeof(tls_client->tptk.key));
Expand Down
25 changes: 25 additions & 0 deletions common/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <unistd.h>

#include "common/log.h"
#include "common/memutils.h"
#include "common/sys_queue_extra.h"

#include "timer.h"
Expand Down Expand Up @@ -197,3 +198,27 @@ void timer_stop(struct timer_group *group, struct timer_entry *timer)
if (reschedule)
timer_schedule();
}

struct timer_call {
struct timer_entry timer;
void (*func)(void *arg);
uint8_t arg[];
};

static void timer_call_cb(struct timer_group *group, struct timer_entry *timer)
{
struct timer_call *call = container_of(timer, struct timer_call, timer);

call->func(call->arg);
free(call);
}

void timer_call_later(void (*func)(void *arg), const void *arg, size_t arg_size)
{
struct timer_call *call = zalloc(sizeof(struct timer_call) + arg_size);

call->timer.callback = timer_call_cb;
call->func = func;
memcpy(call->arg, arg, arg_size);
timer_start_rel(NULL, &call->timer, 0);
}
5 changes: 5 additions & 0 deletions common/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <sys/queue.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#include "common/time_extra.h"
Expand Down Expand Up @@ -89,6 +90,10 @@ void timer_start_rel(struct timer_group *group, struct timer_entry *timer, uint6
// Stop a timer.
void timer_stop(struct timer_group *group, struct timer_entry *timer);

// Call a function after finishing executing the current call stack up to the
// main polling loop. Useful to break recursivity and complex call chains.
void timer_call_later(void (*func)(void *arg), const void *arg, size_t arg_size);

static inline bool timer_stopped(const struct timer_entry *timer)
{
return !timer->expire_ms;
Expand Down
41 changes: 33 additions & 8 deletions common/ws/ws_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "common/ieee802154_ie.h"
#include "common/string_extra.h"
#include "common/duty_cycle.h"
#include "common/mathutils.h"
#include "common/memutils.h"
#include "common/version.h"
#include "common/sl_ws.h"
Expand Down Expand Up @@ -153,10 +154,6 @@ void ws_if_recv_ind(struct rcp *rcp, const struct rcp_rx_ind *hif_ind)
&ind.hdr, &ind.ie_hdr, &ie_payload);
if (ret < 0)
return;
if (ind.hdr.key_index && ind.hdr.sec_level != IEEE802154_SEC_LEVEL_ENC_MIC64) {
TRACE(TR_DROP, "drop %-9s: unsupported security level", "15.4");
return;
}
if (!ws_wh_sl_utt_read(ind.ie_hdr.data, ind.ie_hdr.data_size, &ie_utt) &&
!ws_wh_utt_read(ind.ie_hdr.data, ind.ie_hdr.data_size, &ie_utt)) {
TRACE(TR_DROP, "drop %-9s: missing UTT-IE", "15.4");
Expand All @@ -182,6 +179,23 @@ void ws_if_recv_ind(struct rcp *rcp, const struct rcp_rx_ind *hif_ind)
ind.neigh = ws_neigh_add(&ws->neigh_table, &ind.hdr.src, WS_NR_ROLE_ROUTER, 16);
else
ws_neigh_refresh(&ws->neigh_table, ind.neigh, ind.neigh->lifetime_s);

if (ind.hdr.key_index) {
if (ind.hdr.sec_level != IEEE802154_SEC_LEVEL_ENC_MIC64) {
TRACE(TR_DROP, "drop %-9s: unsupported security level", "15.4");
return;
}
FATAL_ON(ind.hdr.key_index < 1 || ind.hdr.key_index > HIF_KEY_COUNT, 3);
if (ind.neigh->frame_counter_min[ind.hdr.key_index - 1] > ind.hdr.frame_counter ||
ind.neigh->frame_counter_min[ind.hdr.key_index - 1] == UINT32_MAX) {
TRACE(TR_DROP, "drop %-9s: frame cnt=%u cnt-min=%u for key-idx=%u",
"15.4", ind.hdr.key_index, ind.hdr.frame_counter,
ind.neigh->frame_counter_min[ind.hdr.key_index - 1]);
return;
}
ind.neigh->frame_counter_min[ind.hdr.key_index - 1] = add32sat(ind.hdr.frame_counter, 1);
}

ws_neigh_ut_update(&ind.neigh->fhss_data_unsecured, ie_utt.ufsi,
ind.hif->timestamp_us, &ind.hdr.src);
if (has_bt_ie)
Expand Down Expand Up @@ -309,11 +323,22 @@ void ws_if_recv_cnf(struct rcp *rcp, const struct rcp_tx_cnf *cnf)
WARN("%s: malformed frame", __func__);
return;
}
if (hdr.key_index && hdr.sec_level != IEEE802154_SEC_LEVEL_ENC_MIC64) {
TRACE(TR_DROP, "drop %-9s: unsupported security level", "15.4-ack");
return;
if (hdr.key_index) {
if (hdr.sec_level != IEEE802154_SEC_LEVEL_ENC_MIC64) {
TRACE(TR_DROP, "drop %-9s: unsupported security level", "15.4-ack");
return;
}
FATAL_ON(hdr.key_index < 1 || hdr.key_index > HIF_KEY_COUNT, 3);
if (neigh->frame_counter_min[hdr.key_index - 1] > hdr.frame_counter ||
neigh->frame_counter_min[hdr.key_index - 1] == UINT32_MAX) {
TRACE(TR_TX_ABORT, "tx-abort %-9s: frame cnt=%u < cnt-min=%u for key-idx=%u",
"15.4", hdr.key_index, hdr.frame_counter,
neigh->frame_counter_min[hdr.key_index - 1]);
return;
} else {
neigh->frame_counter_min[hdr.key_index - 1] = add32sat(hdr.frame_counter, 1);
}
}
// TODO: check frame counter
ws_neigh_refresh(&ws->neigh_table, neigh, neigh->lifetime_s);
neigh->rsl_in_dbm_unsecured = ws_ewma_next(neigh->rsl_in_dbm_unsecured,
cnf->rx_power_dbm, WS_EWMA_SF);
Expand Down
2 changes: 1 addition & 1 deletion common/ws/ws_neigh.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ struct ws_neigh {
struct lto_info lto_info;
uint8_t node_role;
uint32_t frame_counter_min[HIF_KEY_COUNT];
uint32_t expiration_s;
time_t expiration_s;
uint32_t lifetime_s; /*!< Life time in seconds */
uint8_t ms_phy_mode_id; /*!< PhyModeId selected for Mode Switch with this neighbor */
uint8_t ms_mode; /*!< Mode switch mode */
Expand Down
8 changes: 4 additions & 4 deletions common/ws/ws_regdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ const int valid_ws_classes[] = {
const int valid_ws_chan_plan_ids[] = {
0x01, 0x02, 0x03, 0x04, 0x05, // NA / BZ / MX
0x15, 0x16, 0x17, 0x18, // JP
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // EU / SG / IN
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x27, 0x28, // EU / IN
0x29, 0x2a, 0x2b, // SG
0x30, 0x31, // PH / NZ
0x40, 0x41, // SG / TH / VN
0x50, 0x51, // MY
0x60, 0x61, // KR
0x70, 0x71, // WW
0x80, // CN
0x90, // CN
0xa0, // CN
INT_MIN
};
Expand Down Expand Up @@ -192,8 +192,8 @@ const struct chan_params chan_params_table[] = {
{ REG_DOMAIN_PH, 2, HIF_REG_NONE, 0, 915400000, 400000, 7, { 0x05, 0x06, 0x08 }, },
{ REG_DOMAIN_PH, 0, HIF_REG_NONE, 48, 915200000, 200000, 64, { 0x02, 0x03, 0x12, 0x13 }, .chan_allowed = "0-13", },
{ REG_DOMAIN_PH, 0, HIF_REG_NONE, 49, 915400000, 400000, 32, { 0x05, 0x06, 0x08, 0x15, 0x16, 0x18 }, .chan_allowed = "0-6", },
{ REG_DOMAIN_SG, 1, HIF_REG_NONE, 41, 863100000, 100000, 29, { 0x01, 0x11 }, },
{ REG_DOMAIN_SG, 2, HIF_REG_NONE, 42, 863100000, 200000, 15, { 0x03, 0x05, 0x12, 0x15, 0x54, 0x55, 0x56 }, },
{ REG_DOMAIN_SG, 1, HIF_REG_NONE, 41, 866100000, 100000, 29, { 0x01, 0x11 }, },
{ REG_DOMAIN_SG, 2, HIF_REG_NONE, 42, 866100000, 200000, 15, { 0x03, 0x05, 0x12, 0x15, 0x54, 0x55, 0x56 }, },
{ REG_DOMAIN_SG, 3, HIF_REG_NONE, 43, 866300000, 400000, 7, { 0x06, 0x08, 0x16, 0x18 }, },
{ REG_DOMAIN_SG, 4, HIF_REG_NONE, 64, 920200000, 200000, 24, { 0x02, 0x03, 0x12, 0x13 }, },
{ REG_DOMAIN_SG, 5, HIF_REG_NONE, 65, 920400000, 400000, 12, { 0x05, 0x06, 0x08, 0x15, 0x16, 0x18 }, },
Expand Down
22 changes: 22 additions & 0 deletions tools/demo/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,26 @@ struct module {
struct timer_group timer_group;
};

static void timer_recursive(void *arg)
{
/*
* Linux typically has 8Mio of stack per process so a couple recusive calls
* would normally create a stack overflow.
*/
uint8_t buf[1024 * 1024];
int *i = arg;

if (*i < 0)
return;

buf[*i] = *i; // Use buf to prevent optimization
printf("%s() %i\n", __func__, buf[*i]);

*i = *i - 1;
//timer_call(i);
timer_call_later(timer_recursive, i, sizeof(int));
}

void timer_cb(struct timer_group *group, struct timer_entry *timer)
{
printf("%s() %"PRIu64"ms\n", __func__, timer->period_ms);
Expand Down Expand Up @@ -106,6 +126,8 @@ int main()

timer_group_init(&mod.timer_group);

timer_call_later(timer_recursive, (int[]){ 10 }, sizeof(int));

timer_start_rel(NULL, &timer_500ms, timer_500ms.period_ms);
timer_start_rel(NULL, &timer_666ms, timer_666ms.period_ms);
timer_start_rel(&mod.timer_group, &timer_exp, 0);
Expand Down