Added check on boundary condition

This commit is contained in:
Anshul Maheshwari 2015-05-25 18:48:20 +05:30
parent 89ee62ea14
commit f1cf6c7be8

View File

@ -642,13 +642,22 @@ void EPG_decode_extended_event_descriptor(uint8_t *offset, uint32_t descriptor_l
// only handles single segment, single language ANSI string! // only handles single segment, single language ANSI string!
void EPG_ATSC_decode_multiple_string(uint8_t *offset, uint32_t length, struct EPG_event *event) void EPG_ATSC_decode_multiple_string(uint8_t *offset, uint32_t length, struct EPG_event *event)
{ {
uint8_t number_strings = offset[0]; uint8_t number_strings;
int i, j; int i, j;
char ISO_639_language_code[4]; char ISO_639_language_code[4];
uint8_t *offset_end = offset + length;
#define CHECK_OFFSET(val) if(offset + val < offset_end) return
CHECK_OFFSET(1);
number_strings = offset[0];
offset++; offset++;
for(i=0; i<number_strings; i++) for(i=0; i<number_strings; i++)
{ {
uint8_t number_segments = offset[3]; uint8_t number_segments;
CHECK_OFFSET(4);
number_segments = offset[3];
ISO_639_language_code[0] = offset[0]; ISO_639_language_code[0] = offset[0];
ISO_639_language_code[1] = offset[1]; ISO_639_language_code[1] = offset[1];
ISO_639_language_code[2] = offset[2]; ISO_639_language_code[2] = offset[2];
@ -656,12 +665,17 @@ void EPG_ATSC_decode_multiple_string(uint8_t *offset, uint32_t length, struct EP
offset+=4; offset+=4;
for (j=0; j< number_segments; j++) for (j=0; j< number_segments; j++)
{ {
uint8_t compression_type = offset[0]; uint8_t compression_type;
uint8_t mode = offset[1]; uint8_t mode;
uint8_t number_bytes = offset[2]; uint8_t number_bytes;
CHECK_OFFSET(3);
compression_type = offset[0];
mode = offset[1];
number_bytes = offset[2];
offset+=3; offset+=3;
if(mode==0 && compression_type==0 && j==0) if(mode==0 && compression_type==0 && j==0)
{ {
CHECK_OFFSET(number_bytes);
event->has_simple=true; event->has_simple=true;
event->ISO_639_language_code[0]=ISO_639_language_code[0]; event->ISO_639_language_code[0]=ISO_639_language_code[0];
event->ISO_639_language_code[1]=ISO_639_language_code[1]; event->ISO_639_language_code[1]=ISO_639_language_code[1];
@ -681,19 +695,27 @@ void EPG_ATSC_decode_multiple_string(uint8_t *offset, uint32_t length, struct EP
offset+=number_bytes; offset+=number_bytes;
} }
} }
#undef CHECK_OFFSET
} }
// decode ATSC EIT table. // decode ATSC EIT table.
void EPG_ATSC_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_t size) void EPG_ATSC_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_t size)
{ {
uint8_t table_id = payload_start[0]; uint8_t table_id;
struct EPG_event event; struct EPG_event event;
uint8_t num_events_in_section; uint8_t num_events_in_section;
uint8_t *offset; uint8_t *offset;
int hasnew=false; int hasnew=false;
int i, j; int i, j;
uint16_t source_id = ((payload_start[3]) << 8) | payload_start[4]; uint16_t source_id;
int32_t pmt_map = -1; int32_t pmt_map = -1;
if (size < 11)
return;
table_id = payload_start[0];
source_id = ((payload_start[3]) << 8) | payload_start[4];
event.has_simple=false; event.has_simple=false;
event.extended_text=NULL; event.extended_text=NULL;
event.num_ratings=0; event.num_ratings=0;
@ -710,14 +732,20 @@ void EPG_ATSC_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32
pmt_map=TS_PMT_MAP_SIZE; pmt_map=TS_PMT_MAP_SIZE;
num_events_in_section = payload_start[9]; num_events_in_section = payload_start[9];
#define CHECK_OFFSET(val) if(offset + val < (payload_start + size) ) return
offset=&payload_start[10]; offset=&payload_start[10];
for(j = 0; j < num_events_in_section; j++) for(j = 0; j < num_events_in_section && offset < payload_start + size; j++)
{ {
uint16_t descriptors_loop_length; uint16_t descriptors_loop_length;
uint8_t title_length, emt_location; uint8_t title_length, emt_location;
uint32_t length_in_seconds, start_time, full_id; uint32_t length_in_seconds, start_time, full_id;
uint16_t event_id = ((offset[0]&0x3F) << 8) | offset[1]; uint16_t event_id;
CHECK_OFFSET(10);
event_id = ((offset[0]&0x3F) << 8) | offset[1];
full_id = (source_id << 16) | event_id; full_id = (source_id << 16) | event_id;
event.id=full_id; event.id=full_id;
event.service_id=source_id; event.service_id=source_id;
@ -726,33 +754,54 @@ void EPG_ATSC_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32
emt_location = (offset[6]&0x30)>>4; emt_location = (offset[6]&0x30)>>4;
length_in_seconds = (((offset[6]&0x0F) << 16) | (offset[7] << 8) | (offset[8] << 0)); length_in_seconds = (((offset[6]&0x0F) << 16) | (offset[7] << 8) | (offset[8] << 0));
EPG_ATSC_calc_time(event.end_time_string, start_time+length_in_seconds); EPG_ATSC_calc_time(event.end_time_string, start_time+length_in_seconds);
title_length = offset[9]; title_length = offset[9];
//XXX cant decode data more then size of payload
CHECK_OFFSET(11 + title_length);
EPG_ATSC_decode_multiple_string(&offset[10], title_length, &event); EPG_ATSC_decode_multiple_string(&offset[10], title_length, &event);
descriptors_loop_length = ((offset[10+title_length] & 0x0f) << 8) | offset[10+title_length+1]; descriptors_loop_length = ((offset[10+title_length] & 0x0f) << 8) | offset[10+title_length+1];
hasnew |= EPG_add_event(ctx, pmt_map, &event); hasnew |= EPG_add_event(ctx, pmt_map, &event);
offset+=12+descriptors_loop_length+title_length; offset += 12 + descriptors_loop_length + title_length;
} }
if((ccx_options.xmltv==1 || ccx_options.xmltv==3) && ccx_options.xmltvoutputinterval==0 && hasnew) if((ccx_options.xmltv==1 || ccx_options.xmltv==3) && ccx_options.xmltvoutputinterval==0 && hasnew)
EPG_output(ctx); EPG_output(ctx);
#undef CHECK_OFFSET
} }
// decode ATSC VCT table. // decode ATSC VCT table.
void EPG_ATSC_decode_VCT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_t size) void EPG_ATSC_decode_VCT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_t size)
{ {
uint8_t table_id = payload_start[0]; uint8_t table_id;
uint8_t num_channels_in_section = payload_start[9]; uint8_t num_channels_in_section;
uint8_t *offset = &payload_start[10]; uint8_t *offset;
int i; int i;
if (size <= 10)
return;
table_id = payload_start[0];
num_channels_in_section = payload_start[9];
offset = &payload_start[10];
for (i=0; i< num_channels_in_section; i++) for (i=0; i< num_channels_in_section; i++)
{ {
char short_name[7*2]; char short_name[7*2];
uint16_t program_number = offset[24]<<8 | offset[25]; uint16_t program_number;
uint16_t source_id = offset[28]<<8 | offset[29]; uint16_t source_id;
uint16_t descriptors_loop_length = ((offset[30] & 0x03) << 8) | offset[31]; uint16_t descriptors_loop_length;
if(offset + 31 > payload_start+size)
break;
program_number = offset[24]<<8 | offset[25];
source_id = offset[28]<<8 | offset[29];
descriptors_loop_length = ((offset[30] & 0x03) << 8) | offset[31];
memcpy(short_name, &offset[0], 7*2); memcpy(short_name, &offset[0], 7*2);
offset+=32+descriptors_loop_length; offset += 32 + descriptors_loop_length;
ctx->ATSC_source_pg_map[source_id]=program_number; ctx->ATSC_source_pg_map[source_id]=program_number;
} }
} }
@ -761,20 +810,36 @@ void EPG_ATSC_decode_VCT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32
void EPG_DVB_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_t size) void EPG_DVB_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_t size)
{ {
uint8_t table_id = payload_start[0]; uint8_t table_id;
//uint8_t section_syntax_indicator = (0xf1&0x80)>>7; //uint8_t section_syntax_indicator = (0xf1&0x80)>>7;
uint16_t section_length = (payload_start[1]&0x0F)<<8 | payload_start[2]; uint16_t section_length;
uint16_t service_id = (payload_start[3] << 8) | payload_start[4]; uint16_t service_id;
int32_t pmt_map = -1; int32_t pmt_map = -1;
int i; int i;
int hasnew=false; int hasnew=false;
struct EPG_event event; struct EPG_event event;
uint8_t section_number = payload_start[6]; uint8_t section_number;
uint8_t last_section_number = payload_start[7]; uint8_t last_section_number;
uint8_t segment_last_section_number = payload_start[12]; uint8_t segment_last_section_number;
uint32_t events_length = section_length - 11; uint32_t events_length = section_length - 11;
uint8_t *offset=payload_start; uint8_t *offset=payload_start;
uint32_t remaining=events_length; uint32_t remaining=events_length;
if(size < 13)
return;
table_id = payload_start[0];
//section_syntax_indicator = (0xf1&0x80)>>7;
section_length = (payload_start[1]&0x0F)<<8 | payload_start[2];
service_id = (payload_start[3] << 8) | payload_start[4];
section_number = payload_start[6];
last_section_number = payload_start[7];
segment_last_section_number = payload_start[12];
events_length = section_length - 11;
offset = payload_start;
remaining = events_length;
for (i = 0; i < pmt_array_length; i++) for (i = 0; i < pmt_array_length; i++)
{ {
if (pmt_array[i].program_number == service_id) if (pmt_array[i].program_number == service_id)
@ -788,21 +853,23 @@ void EPG_DVB_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_
if(events_length>size-14) if(events_length>size-14)
{ {
dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT packet size detected.\n"); dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Invalid EIT packet size detected.\n");
//XXX hack to override segfault, we should concat packets instead
remaining = size - 14;
} }
while(remaining>4) while(remaining > 4)
{ {
uint16_t descriptors_loop_length; uint16_t descriptors_loop_length;
uint8_t *descp; uint8_t *descp;
uint32_t duration; uint32_t duration;
uint64_t start_time; uint64_t start_time;
event.id=(offset[14] << 8) | offset[15]; event.id = (offset[14] << 8) | offset[15];
event.has_simple=false; event.has_simple = false;
event.extended_text=NULL; event.extended_text = NULL;
event.num_ratings=0; event.num_ratings = 0;
event.num_categories=0; event.num_categories = 0;
event.live_output=false; event.live_output = false;
event.service_id=service_id; event.service_id = service_id;
//40 bits //40 bits
start_time = ((uint64_t)offset[16] << 32) | ((uint64_t)offset[17] << 24) | ((uint64_t)offset[18] << 16) | ((uint64_t)offset[19] << 8)| ((uint64_t)offset[20] << 0); start_time = ((uint64_t)offset[16] << 32) | ((uint64_t)offset[17] << 24) | ((uint64_t)offset[18] << 16) | ((uint64_t)offset[19] << 8)| ((uint64_t)offset[20] << 0);
@ -842,8 +909,8 @@ void EPG_DVB_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_
} }
descp=descp+(descp[1]+2); descp=descp+(descp[1]+2);
} }
remaining=remaining-(descriptors_loop_length+12); remaining = remaining - (descriptors_loop_length + 12);
offset=offset+descriptors_loop_length+12; offset = offset + descriptors_loop_length + 12;
hasnew |= EPG_add_event(ctx, pmt_map, &event); hasnew |= EPG_add_event(ctx, pmt_map, &event);
if(hasnew && section_number==0 && table_id==0x4e) if(hasnew && section_number==0 && table_id==0x4e)
@ -852,7 +919,6 @@ void EPG_DVB_decode_EIT(struct lib_ccx_ctx *ctx, uint8_t *payload_start, uint32_
if((ccx_options.xmltv==1 || ccx_options.xmltv==3) && ccx_options.xmltvoutputinterval==0 && hasnew) if((ccx_options.xmltv==1 || ccx_options.xmltv==3) && ccx_options.xmltvoutputinterval==0 && hasnew)
EPG_output(ctx); EPG_output(ctx);
} }
//handle outputing to xml files //handle outputing to xml files
void EPG_handle_output(struct lib_ccx_ctx *ctx) void EPG_handle_output(struct lib_ccx_ctx *ctx)
@ -879,20 +945,26 @@ void EPG_handle_output(struct lib_ccx_ctx *ctx)
//determin table type and call the correct function to handle it //determin table type and call the correct function to handle it
void EPG_parse_table(struct lib_ccx_ctx *ctx, uint8_t *b, uint32_t size) void EPG_parse_table(struct lib_ccx_ctx *ctx, uint8_t *b, uint32_t size)
{ {
uint8_t pointer_field=b[0]; uint8_t pointer_field = b[0];
uint8_t *payload_start = &b[pointer_field + 1]; uint8_t *payload_start;
uint8_t table_id = payload_start[0]; uint8_t table_id;
//XXX hack, should accumalate data
if(pointer_field + 2 > size) {
return;
}
payload_start = &b[pointer_field + 1];
table_id = payload_start[0];
switch (table_id) { switch (table_id) {
case 0x0cb: case 0x0cb:
EPG_ATSC_decode_EIT(ctx, payload_start, size); EPG_ATSC_decode_EIT(ctx, payload_start, size - (payload_start - b));
break; break;
case 0xc8: case 0xc8:
EPG_ATSC_decode_VCT(ctx, payload_start, size); EPG_ATSC_decode_VCT(ctx, payload_start, size - (payload_start - b));
break; break;
default: default:
if (table_id>=0x4e && table_id<=0x6f) if (table_id>=0x4e && table_id<=0x6f)
EPG_DVB_decode_EIT(ctx, payload_start, size); EPG_DVB_decode_EIT(ctx, payload_start, size - (payload_start - b));
break; break;
} }
EPG_handle_output(ctx); EPG_handle_output(ctx);