mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-01-31 09:32:57 +00:00
obex_iterator: rewrite to avoid out-of-bounds reads, add fuzzer
This commit is contained in:
parent
3cd982f433
commit
d1769b9f48
@ -67,96 +67,97 @@ static int obex_packet_header_offset_for_opcode(uint8_t opcode){
|
||||
}
|
||||
}
|
||||
|
||||
static void obex_iterator_init(obex_iterator_t *context, int header_offset, const uint8_t * packet_data, uint16_t packet_len){
|
||||
static void obex_iterator_reset(obex_iterator_t *context){
|
||||
memset(context, 0, sizeof(obex_iterator_t));
|
||||
context->valid = false;
|
||||
}
|
||||
|
||||
// check if num bytes are available, and if not, invalidate iterator
|
||||
static bool obex_iterator_check(obex_iterator_t *context, uint32_t num_bytes){
|
||||
if ((context->offset + num_bytes) >= context->length){
|
||||
context->valid = false;
|
||||
}
|
||||
return context->valid;
|
||||
}
|
||||
|
||||
static void obex_iterator_prepare(obex_iterator_t *context){
|
||||
if (obex_iterator_check(context, 1) == false) return;
|
||||
const uint8_t * data = context->data + context->offset;
|
||||
uint8_t encoding = data[0] >> 6;
|
||||
switch (encoding){
|
||||
case 0:
|
||||
case 1:
|
||||
// 16-bit length info prefixed
|
||||
if (obex_iterator_check(context, 3) == false) return;
|
||||
context->data_size = big_endian_read_16(data, 1);
|
||||
context->header_size = 3;
|
||||
break;
|
||||
case 2:
|
||||
// 8-bit value
|
||||
context->data_size = 1;
|
||||
context->header_size = 1;
|
||||
break;
|
||||
case 3:
|
||||
// 32-bit value
|
||||
context->data_size = 4;
|
||||
context->header_size = 1;
|
||||
break;
|
||||
default:
|
||||
// avoid compiler warning about unused cases (encoding in [0..3])
|
||||
break;
|
||||
}
|
||||
(void) obex_iterator_check(context, context->header_size + context->data_size);
|
||||
}
|
||||
|
||||
static void obex_iterator_init(obex_iterator_t *context, int header_offset, const uint8_t * packet_data, uint16_t packet_len){
|
||||
if (header_offset >= packet_len) return;
|
||||
context->data = packet_data + header_offset;
|
||||
context->length = packet_len - header_offset;
|
||||
context->valid = true;
|
||||
obex_iterator_prepare(context);
|
||||
}
|
||||
|
||||
void obex_iterator_init_with_request_packet(obex_iterator_t *context, const uint8_t * packet_data, uint16_t packet_len){
|
||||
obex_iterator_reset(context);
|
||||
if (packet_len == 0) return;
|
||||
int header_offset = obex_packet_header_offset_for_opcode(packet_data[0]);
|
||||
obex_iterator_init(context, header_offset, packet_data, packet_len);
|
||||
}
|
||||
|
||||
void obex_iterator_init_with_response_packet(obex_iterator_t *context, uint8_t request_opcode, const uint8_t * packet_data, uint16_t packet_len){
|
||||
obex_iterator_reset(context);
|
||||
int header_offset = (request_opcode == OBEX_OPCODE_CONNECT) ? 7 : 3;
|
||||
obex_iterator_init(context, header_offset, packet_data, packet_len);
|
||||
}
|
||||
|
||||
int obex_iterator_has_more(const obex_iterator_t * context){
|
||||
return context->offset < context->length;
|
||||
return context->valid;
|
||||
}
|
||||
|
||||
void obex_iterator_next(obex_iterator_t * context){
|
||||
int len = 0;
|
||||
const uint8_t * data = context->data + context->offset;
|
||||
int encoding = data[0] >> 6;
|
||||
switch (encoding){
|
||||
case 0:
|
||||
case 1:
|
||||
// 16-bit length info prefixed
|
||||
len = big_endian_read_16(data, 1);
|
||||
break;
|
||||
case 2:
|
||||
// 8-bit value
|
||||
len = 2;
|
||||
break;
|
||||
case 3:
|
||||
// 32-bit value
|
||||
len = 5;
|
||||
break;
|
||||
// avoid compiler warning about unused cases (by unclever compilers)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
context->offset += len;
|
||||
if (context->valid == false) return;
|
||||
context->offset += context->header_size + context->data_size;
|
||||
obex_iterator_prepare(context);
|
||||
}
|
||||
|
||||
// OBEX packet header access functions
|
||||
|
||||
// @note BODY/END-OF-BODY headers might be incomplete
|
||||
uint8_t obex_iterator_get_hi(const obex_iterator_t * context){
|
||||
uint8_t obex_iterator_get_hi(const obex_iterator_t * context){
|
||||
return context->data[context->offset];
|
||||
}
|
||||
uint8_t obex_iterator_get_data_8(const obex_iterator_t * context){
|
||||
uint8_t obex_iterator_get_data_8(const obex_iterator_t * context){
|
||||
return context->data[context->offset+1];
|
||||
}
|
||||
uint32_t obex_iterator_get_data_32(const obex_iterator_t * context){
|
||||
uint32_t obex_iterator_get_data_32(const obex_iterator_t * context){
|
||||
return big_endian_read_32(context->data, context->offset + 1);
|
||||
}
|
||||
uint32_t obex_iterator_get_data_len(const obex_iterator_t * context){
|
||||
const uint8_t * data = context->data + context->offset;
|
||||
int encoding = data[0] >> 6;
|
||||
switch (encoding){
|
||||
case 0:
|
||||
case 1:
|
||||
// 16-bit length info prefixed
|
||||
return big_endian_read_16(data, 1) - 3;
|
||||
case 2:
|
||||
// 8-bit value
|
||||
return 1;
|
||||
case 3:
|
||||
// 32-bit value
|
||||
return 4;
|
||||
// avoid compiler warning about unused cases (by unclever compilers)
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
uint32_t obex_iterator_get_data_len(const obex_iterator_t * context){
|
||||
return context->data_size;
|
||||
}
|
||||
|
||||
const uint8_t * obex_iterator_get_data(const obex_iterator_t * context){
|
||||
const uint8_t * data = context->data + context->offset;
|
||||
int encoding = data[0] >> 6;
|
||||
switch (encoding){
|
||||
case 0:
|
||||
case 1:
|
||||
// 16-bit length info prefixed
|
||||
return &data[3];
|
||||
default:
|
||||
// 8-bit value
|
||||
// 32-bit value
|
||||
return &data[1];
|
||||
}
|
||||
return &context->data[context->offset + context->header_size];
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OBEX_DUMP
|
||||
|
@ -43,13 +43,17 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "btstack_bool.h"
|
||||
|
||||
/* API_START */
|
||||
/* API_START */
|
||||
|
||||
typedef struct obex_iterator {
|
||||
const uint8_t * data;
|
||||
uint16_t offset;
|
||||
uint16_t length;
|
||||
uint16_t header_size;
|
||||
uint16_t data_size;
|
||||
bool valid;
|
||||
} obex_iterator_t;
|
||||
|
||||
// OBEX packet header iterator
|
||||
|
16
test/fuzz/fuzz_obex_iterator.c
Normal file
16
test/fuzz/fuzz_obex_iterator.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "classic/obex_iterator.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
obex_iterator_t it;
|
||||
for (obex_iterator_init_with_request_packet(&it, data, size); obex_iterator_has_more(&it) ; obex_iterator_next(&it)){
|
||||
uint32_t len = obex_iterator_get_data_len(&it);
|
||||
const uint8_t * item = obex_iterator_get_data(&it);
|
||||
// access first and last byte
|
||||
(void) data[0];
|
||||
(void) data[len-1];
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user