Monday, 18 March 2019

Apache Nimble Bluetooth Stack

I had a quick look last night at Apache Nimble, an open source Bluetooth stack.

Here are some minor findings:

static char *
ble_gatts_flags_to_str(uint16_t flags, char *buf,

                       const char * const *names)

{
    int bit;
    bool non_empty = false;
    size_t length = 0;

    buf[0] = '\0';
    strcpy(buf, "[");
    length += 1;
    for (bit = 0; names[bit]; ++bit) {
        if (flags & (1 << bit)) {
            length += strlen(names[bit]);
            if (length + 1 >= BLE_CHR_FLAGS_STR_LEN) {
                return buf;
            }
            if (non_empty) {
                strcat(buf, "|");
                length += 1;
            }
            strcat(buf, names[bit]);
            non_empty = true;
        }
    }
    strcat(buf, "]");
    return buf;
}

The above code has an off-by-1.

There are some strncpy bugs, where strings may be left unterminated.

int bt_mesh_input_string(const char *str)
{
        BT_DBG("%s", str);

        if (!atomic_test_and_clear_bit(link.flags, WAIT_STRING)) {
                return -EINVAL;
        }

        strncpy((char *)link.auth, str, prov->input_size);

        send_input_complete();

        if (!atomic_test_bit(link.flags, HAVE_DHKEY)) {
                return 0;
        }

        if (atomic_test_and_clear_bit(link.flags, SEND_CONFIRM)) {
                send_confirm();
        }

        return 0;
}
And again,
static void input_string(u8_t *data, u16_t len)
{
        const struct mesh_input_string_cmd *cmd = (void *) data;
        u8_t status = BTP_STATUS_SUCCESS;
        u8_t str_auth[16];
        int err;

        SYS_LOG_DBG("");

        if (cmd->string_len > sizeof(str_auth)) {
                SYS_LOG_ERR("Too long input (%u chars required)", input_size);
                status = BTP_STATUS_FAILED;
                goto rsp;
        } else if (cmd->string_len < input_size) {
                SYS_LOG_ERR("Too short input (%u chars required)", input_size);
                status = BTP_STATUS_FAILED;
                goto rsp;
        }

        strncpy((char *)str_auth, (char *)cmd->string, cmd->string_len);

        err = bt_mesh_input_string((char *)str_auth);
        if (err) {
                status = BTP_STATUS_FAILED;
        }

rsp:
        tester_rsp(BTP_SERVICE_ID_MESH, MESH_INPUT_STRING, CONTROLLER_INDEX,
                   status);
}
And one more time,
struct os_mempool *
os_mempool_info_get_next(struct os_mempool *mp, struct os_mempool_info *omi)
{
    struct os_mempool *cur;

    if (mp == NULL) {
        cur = STAILQ_FIRST(&g_os_mempool_list);
    } else {
        cur = STAILQ_NEXT(mp, mp_list);
    }

    if (cur == NULL) {
        return (NULL);
    }

    omi->omi_block_size = cur->mp_block_size;
    omi->omi_num_blocks = cur->mp_num_blocks;
    omi->omi_num_free = cur->mp_num_free;
    omi->omi_min_free = cur->mp_min_free;
    strncpy(omi->omi_name, cur->name, sizeof(omi->omi_name));

    return (cur);
}
The only other use of strncpy in the code base, they write correct code.
int
ble_monitor_new_index(uint8_t bus, uint8_t *addr, const char *name)
{
    struct ble_monitor_new_index pkt;

    pkt.type = 0; /* Primary controller, we don't support other */
    pkt.bus = bus;
    memcpy(pkt.bdaddr, addr, 6);
    strncpy(pkt.name, name, sizeof(pkt.name) - 1);
    pkt.name[sizeof(pkt.name) - 1] = '\0';

    ble_monitor_send(BLE_MONITOR_OPCODE_NEW_INDEX, &pkt, sizeof(pkt));

    return 0;
}
The code in general is quite good after a quick glance.


Exploiting the Lorex 2K Indoor Wifi at Pwn2Own Ireland

Introduction In October InfoSect participated in Pwn2Own Ireland 2024 and successfully exploited the Sonos Era 300 smart speaker and Lor...