diff --git a/subsys/bluetooth/host/classic/obex.c b/subsys/bluetooth/host/classic/obex.c index e21ee241da40..0907ace71401 100644 --- a/subsys/bluetooth/host/classic/obex.c +++ b/subsys/bluetooth/host/classic/obex.c @@ -1769,6 +1769,72 @@ int bt_obex_action_rsp(struct bt_obex *obex, uint8_t rsp_code, struct net_buf *b return err; } +#define BT_OBEX_HEADER_ENCODING(header_id) (0xc0 & (header_id)) +#define BT_OBEX_HEADER_ENCODING_UNICODE 0x00 +#define BT_OBEX_HEADER_ENCODING_BYTE_SEQ 0x40 +#define BT_OBEX_HEADER_ENCODING_1_BYTE 0x80 +#define BT_OBEX_HEADER_ENCODING_4_BYTES 0xc0 + +#define BT_OBEX_UFT16_LEAD_SURROGATE_START 0xd800 +#define BT_OBEX_UFT16_LEAD_SURROGATE_END 0xdbff +#define BT_OBEX_UFT16_TRAIL_SURROGATE_START 0xdc00 +#define BT_OBEX_UFT16_TRAIL_SURROGATE_END 0xdfff + +#define BT_OBEX_UFT16_NULL_TERMINATED 0x0000 + +static bool bt_obex_unicode_is_valid(uint16_t len, const uint8_t *str) +{ + uint16_t index = 0; + uint16_t code; + + if ((len < 2) || (len % 2)) { + LOG_WRN("Invalid string length %d", len); + return false; + } + + code = sys_get_be16(&str[len - 2]); + if (code != BT_OBEX_UFT16_NULL_TERMINATED) { + LOG_WRN("Invalid terminated unicode %04x", code); + return false; + } + + while ((index + 1) < len) { + code = sys_get_be16(&str[index]); + if ((code >= BT_OBEX_UFT16_LEAD_SURROGATE_START) && + (code <= BT_OBEX_UFT16_LEAD_SURROGATE_END)) { + /* Find the trail surrogate */ + index += 2; + if ((index + 1) >= len) { + LOG_WRN("Invalid length, trail surrogate missing"); + return false; + } + + code = sys_get_be16(&str[index]); + if ((code < BT_OBEX_UFT16_TRAIL_SURROGATE_START) || + (code > BT_OBEX_UFT16_TRAIL_SURROGATE_END)) { + LOG_WRN("Invalid trail surrogate %04x at %d", code, index); + return false; + } + } else if ((code >= BT_OBEX_UFT16_TRAIL_SURROGATE_START) && + (code <= BT_OBEX_UFT16_TRAIL_SURROGATE_END)) { + LOG_WRN("Abnormal trail surrogate %04x at %d", code, index); + return false; + } + index += 2; + } + + return true; +} + +static bool bt_obex_string_is_valid(uint8_t id, uint16_t len, const uint8_t *str) +{ + if (BT_OBEX_HEADER_ENCODING(id) == BT_OBEX_HEADER_ENCODING_UNICODE) { + return bt_obex_unicode_is_valid(len, str); + } + + return true; +} + int bt_obex_add_header_count(struct net_buf *buf, uint32_t count) { size_t total; @@ -1792,8 +1858,8 @@ int bt_obex_add_header_name(struct net_buf *buf, uint16_t len, const uint8_t *na { size_t total; - if (!buf || !name) { - LOG_WRN("Invalid buf"); + if (!buf || !name || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -1802,6 +1868,11 @@ int bt_obex_add_header_name(struct net_buf *buf, uint16_t len, const uint8_t *na return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_NAME, len, name)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_NAME); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, name, len); @@ -1812,8 +1883,8 @@ int bt_obex_add_header_type(struct net_buf *buf, uint16_t len, const uint8_t *ty { size_t total; - if (!buf || !type) { - LOG_WRN("Invalid buf"); + if (!buf || !type || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -1822,6 +1893,11 @@ int bt_obex_add_header_type(struct net_buf *buf, uint16_t len, const uint8_t *ty return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_TYPE, len, type)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_TYPE); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, type, len); @@ -1851,8 +1927,8 @@ int bt_obex_add_header_time_iso_8601(struct net_buf *buf, uint16_t len, const ui { size_t total; - if (!buf || !t) { - LOG_WRN("Invalid buf"); + if (!buf || !t || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -1861,6 +1937,11 @@ int bt_obex_add_header_time_iso_8601(struct net_buf *buf, uint16_t len, const ui return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_TIME_ISO_8601, len, t)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_TIME_ISO_8601); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, t, len); @@ -1890,8 +1971,8 @@ int bt_obex_add_header_description(struct net_buf *buf, uint16_t len, const uint { size_t total; - if (!buf || !dec) { - LOG_WRN("Invalid buf"); + if (!buf || !dec || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -1900,6 +1981,11 @@ int bt_obex_add_header_description(struct net_buf *buf, uint16_t len, const uint return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_DES, len, dec)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_DES); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, dec, len); @@ -1910,8 +1996,8 @@ int bt_obex_add_header_target(struct net_buf *buf, uint16_t len, const uint8_t * { size_t total; - if (!buf || !target) { - LOG_WRN("Invalid buf"); + if (!buf || !target || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -1920,6 +2006,11 @@ int bt_obex_add_header_target(struct net_buf *buf, uint16_t len, const uint8_t * return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_TARGET, len, target)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_TARGET); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, target, len); @@ -1930,8 +2021,8 @@ int bt_obex_add_header_http(struct net_buf *buf, uint16_t len, const uint8_t *ht { size_t total; - if (!buf || !http) { - LOG_WRN("Invalid buf"); + if (!buf || !http || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -1940,6 +2031,11 @@ int bt_obex_add_header_http(struct net_buf *buf, uint16_t len, const uint8_t *ht return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_HTTP, len, http)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_HTTP); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, http, len); @@ -1950,8 +2046,8 @@ int bt_obex_add_header_body(struct net_buf *buf, uint16_t len, const uint8_t *bo { size_t total; - if (!buf || !body) { - LOG_WRN("Invalid buf"); + if (!buf || !body || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -1960,6 +2056,11 @@ int bt_obex_add_header_body(struct net_buf *buf, uint16_t len, const uint8_t *bo return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_BODY, len, body)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_BODY); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, body, len); @@ -1970,8 +2071,8 @@ int bt_obex_add_header_end_body(struct net_buf *buf, uint16_t len, const uint8_t { size_t total; - if (!buf || !body) { - LOG_WRN("Invalid buf"); + if (!buf || !body || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -1980,6 +2081,11 @@ int bt_obex_add_header_end_body(struct net_buf *buf, uint16_t len, const uint8_t return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_END_BODY, len, body)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_END_BODY); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, body, len); @@ -1990,8 +2096,8 @@ int bt_obex_add_header_who(struct net_buf *buf, uint16_t len, const uint8_t *who { size_t total; - if (!buf || !who) { - LOG_WRN("Invalid buf"); + if (!buf || !who || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -2000,6 +2106,11 @@ int bt_obex_add_header_who(struct net_buf *buf, uint16_t len, const uint8_t *who return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_WHO, len, who)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_WHO); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, who, len); @@ -2029,8 +2140,8 @@ int bt_obex_add_header_app_param(struct net_buf *buf, uint16_t len, const uint8_ { size_t total; - if (!buf || !app_param) { - LOG_WRN("Invalid buf"); + if (!buf || !app_param || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -2039,6 +2150,11 @@ int bt_obex_add_header_app_param(struct net_buf *buf, uint16_t len, const uint8_ return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_APP_PARAM, len, app_param)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_APP_PARAM); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, app_param, len); @@ -2049,8 +2165,8 @@ int bt_obex_add_header_auth_challenge(struct net_buf *buf, uint16_t len, const u { size_t total; - if (!buf || !auth) { - LOG_WRN("Invalid buf"); + if (!buf || !auth || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -2059,6 +2175,11 @@ int bt_obex_add_header_auth_challenge(struct net_buf *buf, uint16_t len, const u return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_AUTH_CHALLENGE, len, auth)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_AUTH_CHALLENGE); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, auth, len); @@ -2069,8 +2190,8 @@ int bt_obex_add_header_auth_rsp(struct net_buf *buf, uint16_t len, const uint8_t { size_t total; - if (!buf || !auth) { - LOG_WRN("Invalid buf"); + if (!buf || !auth || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -2079,6 +2200,11 @@ int bt_obex_add_header_auth_rsp(struct net_buf *buf, uint16_t len, const uint8_t return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_AUTH_RSP, len, auth)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_AUTH_RSP); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, auth, len); @@ -2108,8 +2234,8 @@ int bt_obex_add_header_wan_uuid(struct net_buf *buf, uint16_t len, const uint8_t { size_t total; - if (!buf || !uuid) { - LOG_WRN("Invalid buf"); + if (!buf || !uuid || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -2118,6 +2244,11 @@ int bt_obex_add_header_wan_uuid(struct net_buf *buf, uint16_t len, const uint8_t return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_WAN_UUID, len, uuid)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_WAN_UUID); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, uuid, len); @@ -2128,8 +2259,8 @@ int bt_obex_add_header_obj_class(struct net_buf *buf, uint16_t len, const uint8_ { size_t total; - if (!buf || !obj_class) { - LOG_WRN("Invalid buf"); + if (!buf || !obj_class || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -2138,6 +2269,11 @@ int bt_obex_add_header_obj_class(struct net_buf *buf, uint16_t len, const uint8_ return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_OBJECT_CLASS, len, obj_class)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_OBJECT_CLASS); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, obj_class, len); @@ -2149,8 +2285,8 @@ int bt_obex_add_header_session_param(struct net_buf *buf, uint16_t len, { size_t total; - if (!buf || !session_param) { - LOG_WRN("Invalid buf"); + if (!buf || !session_param || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -2159,6 +2295,11 @@ int bt_obex_add_header_session_param(struct net_buf *buf, uint16_t len, return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_SESSION_PARAM, len, session_param)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_SESSION_PARAM); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, session_param, len); @@ -2207,8 +2348,8 @@ int bt_obex_add_header_dest_name(struct net_buf *buf, uint16_t len, const uint8_ { size_t total; - if (!buf || !dest_name) { - LOG_WRN("Invalid buf"); + if (!buf || !dest_name || !len) { + LOG_WRN("Invalid parameter"); return -EINVAL; } @@ -2217,6 +2358,11 @@ int bt_obex_add_header_dest_name(struct net_buf *buf, uint16_t len, const uint8_ return -ENOMEM; } + if (!bt_obex_string_is_valid(BT_OBEX_HEADER_ID_DEST_NAME, len, dest_name)) { + LOG_WRN("Invalid string"); + return -EINVAL; + } + net_buf_add_u8(buf, BT_OBEX_HEADER_ID_DEST_NAME); net_buf_add_be16(buf, (uint16_t)total); net_buf_add_mem(buf, dest_name, len); @@ -2280,12 +2426,6 @@ int bt_obex_add_header_srm_param(struct net_buf *buf, uint8_t srm_param) return 0; } -#define BT_OBEX_HEADER_ENCODING(header_id) (0xc0 & (header_id)) -#define BT_OBEX_HEADER_ENCODING_UNICODE 0x00 -#define BT_OBEX_HEADER_ENCODING_BYTE_SEQ 0x40 -#define BT_OBEX_HEADER_ENCODING_1_BYTE 0x80 -#define BT_OBEX_HEADER_ENCODING_4_BYTES 0xc0 - int bt_obex_header_parse(struct net_buf *buf, bool (*func)(struct bt_obex_hdr *hdr, void *user_data), void *user_data) {