From 81dd4d1dd0af273c7ad83290d59ebd03c86b4191 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 9 Jun 2014 19:03:05 +0200 Subject: [PATCH] descrambler: add time-based check for valid ECM key responses --- src/descrambler.h | 10 ++++ src/descrambler/capmt.c | 5 +- src/descrambler/descrambler.c | 99 +++++++++++++++++++++++++---------- src/service.h | 3 +- 4 files changed, 84 insertions(+), 33 deletions(-) diff --git a/src/descrambler.h b/src/descrambler.h index 587b1853..26143b3d 100755 --- a/src/descrambler.h +++ b/src/descrambler.h @@ -52,6 +52,16 @@ typedef struct th_descrambler { } th_descrambler_t; +typedef struct th_descrambler_runtime { + uint32_t dr_key:1; + uint32_t dr_key_first:1; + uint8_t dr_key_index; + time_t dr_key_start; + time_t dr_ecm_start; + time_t dr_ecm_key_time; + sbuf_t dr_buf; +} th_descrambler_runtime_t; + typedef void (*descrambler_section_callback_t) (void *opaque, int pid, const uint8_t *section, int section_len); diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c index 34437ea3..897b614c 100644 --- a/src/descrambler/capmt.c +++ b/src/descrambler/capmt.c @@ -784,7 +784,7 @@ capmt_set_filter(capmt_t *capmt, int adapter, sbuf_t *sb, int offset) cf->adapter = adapter; filter = &cf->dmx[filter_index]; filter->pid = pid; - memcpy(&filter->filter, sbuf_peek(sb, offset + 10), sizeof(filter->filter)); + memcpy(&filter->filter, sbuf_peek(sb, offset + 8), sizeof(filter->filter)); filter->flags = 0; /* ECM messages have the higher priority */ t = NULL; @@ -1433,12 +1433,11 @@ capmt_table_input(void *opaque, int pid, const uint8_t *data, int len) if ((data[i] & f->mask[i]) != f->filter[i]) break; } - if (i >= DMX_FILTER_SIZE && i <= len) { + if (i >= DMX_FILTER_SIZE && i <= len) capmt_filter_data(capmt, o->adapter, demux_index, filter_index, data, len, cf->dmx[filter_index].flags); - } } } diff --git a/src/descrambler/descrambler.c b/src/descrambler/descrambler.c index 08da260e..32eed830 100755 --- a/src/descrambler/descrambler.c +++ b/src/descrambler/descrambler.c @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +#include "tvheadend.h" #include "descrambler.h" #include "cwc.h" #include "capmt.h" @@ -132,28 +133,32 @@ descrambler_done ( void ) void descrambler_service_start ( service_t *t ) { - t->s_descramble_key = 0; + th_descrambler_runtime_t *dr; + #if ENABLE_CWC cwc_service_start(t); #endif #if ENABLE_CAPMT capmt_service_start(t); #endif - t->s_descramble_buf = calloc(1, sizeof(sbuf_t)); - sbuf_init(t->s_descramble_buf); + t->s_descramble = dr = calloc(1, sizeof(th_descrambler_runtime_t)); + sbuf_init(&dr->dr_buf); + dr->dr_key_index = 0xff; } void descrambler_service_stop ( service_t *t ) { th_descrambler_t *td; + th_descrambler_runtime_t *dr = t->s_descramble; while ((td = LIST_FIRST(&t->s_descramblers)) != NULL) td->td_stop(td); - if (t->s_descramble_buf) { - sbuf_free(t->s_descramble_buf); - t->s_descramble_buf = NULL; + if (dr) { + sbuf_free(&dr->dr_buf); + free(dr); } + t->s_descramble = NULL; } void @@ -171,33 +176,56 @@ void descrambler_keys ( th_descrambler_t *td, const uint8_t *even, const uint8_t *odd ) { - int i; + th_descrambler_runtime_t *dr = td->td_service->s_descramble; + int i, j = 0; for (i = 0; i < 8; i++) if (even[i]) { + j++; tvhcsa_set_key_even(td->td_csa, even); break; } for (i = 0; i < 8; i++) if (odd[i]) { + j++; tvhcsa_set_key_odd(td->td_csa, odd); break; } + if (j == 0) { + tvhlog(LOG_DEBUG, "descrambler", "Empty keys received for service \"%s\"", + ((mpegts_service_t *)td->td_service)->s_dvb_svcname); + return; + } + if (td->td_keystate != DS_RESOLVED) tvhlog(LOG_DEBUG, "descrambler", "Obtained key for service \"%s\"", ((mpegts_service_t *)td->td_service)->s_dvb_svcname); + + dr->dr_ecm_key_time = dispatch_clock; td->td_keystate = DS_RESOLVED; } +static inline void +key_update( th_descrambler_runtime_t *dr, uint8_t key ) +{ + /* set the even (0) or odd (0x40) key index */ + dr->dr_key_index = key & 0x40; + dr->dr_key_start = dispatch_clock; +} + int descrambler_descramble ( service_t *t, elementary_stream_t *st, const uint8_t *tsb ) { th_descrambler_t *td; + th_descrambler_runtime_t *dr = t->s_descramble; int count, failed, off, size; + uint8_t *tsb2; + if (dr == NULL) + return -1; count = failed = 0; LIST_FOREACH(td, &t->s_descramblers, td_service_link) { count++; @@ -207,34 +235,47 @@ descrambler_descramble ( service_t *t, } if (td->td_keystate != DS_RESOLVED) continue; - if (t->s_descramble_buf) { - for (off = 0, size = t->s_descramble_buf->sb_ptr; off < size; off += 188) + if (dr->dr_buf.sb_ptr > 0) { + for (off = 0, size = dr->dr_buf.sb_ptr; off < size; off += 188) { + tsb2 = dr->dr_buf.sb_data + off; + if ((tsb2[3] & 0x80) != 0x00 && dr->dr_key_index != (tsb2[3] & 0x40)) { + if (dr->dr_ecm_key_time < dr->dr_key_start) { + sbuf_free(&dr->dr_buf); + goto forbid; + } + key_update(dr, tsb[3]); + } tvhcsa_descramble(td->td_csa, (mpegts_service_t *)td->td_service, - st, t->s_descramble_buf->sb_data + off); - sbuf_free(t->s_descramble_buf); - free(t->s_descramble_buf); - t->s_descramble_buf = NULL; + st, tsb2); + } + sbuf_free(&dr->dr_buf); + } + if ((tsb[3] & 0x80) != 0x00 && dr->dr_key_index != (tsb[3] & 0x40)) { + if (dr->dr_ecm_key_time < dr->dr_key_start) { +forbid: + td->td_keystate = DS_FORBIDDEN; + failed++; + continue; + } + key_update(dr, tsb[3]); } tvhcsa_descramble(td->td_csa, (mpegts_service_t *)td->td_service, st, tsb); return 1; } - if (t->s_descramble_key && count != failed) { - /* - * Fill a temporary buffer until the keys are known to make - * streaming faster. - */ - if (t->s_descramble_buf == NULL) { - t->s_descramble_buf = calloc(1, sizeof(sbuf_t)); - if (t->s_descramble_buf) - sbuf_init(t->s_descramble_buf); - } - if (t->s_descramble_buf) { - if (t->s_descramble_buf->sb_ptr >= 3000 * 188) - sbuf_cut(t->s_descramble_buf, 300 * 188); - sbuf_append(t->s_descramble_buf, tsb, 188); + if (dr->dr_ecm_start) { /* ECM sent */ + if ((tsb[3] & 0x80) != 0x00 && dr->dr_key_start == 0) + key_update(dr, tsb[3]); + if (count != failed) { + /* + * Fill a temporary buffer until the keys are known to make + * streaming faster. + */ + if (dr->dr_buf.sb_ptr >= 3000 * 188) + sbuf_cut(&dr->dr_buf, 300 * 188); + sbuf_append(&dr->dr_buf, tsb, 188); } } return count && count == failed ? -1 : count; @@ -246,6 +287,7 @@ descrambler_table_callback { descrambler_table_t *dt = mt->mt_opaque; descrambler_section_t *ds; + th_descrambler_runtime_t *dr; pthread_mutex_lock(&mt->mt_mux->mm_descrambler_lock); TAILQ_FOREACH(ds, &dt->sections, link) @@ -263,7 +305,8 @@ descrambler_table_callback if ((mt->mt_flags & MT_FAST) != 0) { /* ECM */ if (mt->mt_service) { /* The keys are requested from this moment */ - mt->mt_service->s_descramble_key |= 1; + dr = mt->mt_service->s_descramble; + dr->dr_ecm_start = dispatch_clock; } } } diff --git a/src/service.h b/src/service.h index 1a322b3e..977d2912 100644 --- a/src/service.h +++ b/src/service.h @@ -401,8 +401,7 @@ typedef struct service { struct th_descrambler_list s_descramblers; uint16_t s_scrambled_seen; - uint16_t s_descramble_key; - sbuf_t *s_descramble_buf; + th_descrambler_runtime_t *s_descramble; /** * List of all and filtered components.