1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Fixed a possible buffer overflow in handling CA descriptors

This commit is contained in:
Klaus Schmidinger 2016-12-23 14:08:14 +01:00
parent 736f2fed42
commit 68acf8815c
7 changed files with 118 additions and 76 deletions

View File

@ -2929,6 +2929,8 @@ Lars Hanisch <dvb@flensrocker.de>
for fixing a memory leak in case of broken Extended Event Descriptors for fixing a memory leak in case of broken Extended Event Descriptors
for adding a 'const' version of cTimers::GetTimer() for adding a 'const' version of cTimers::GetTimer()
for fixing a typo in the description of cTimers::GetTimersRead() for fixing a typo in the description of cTimers::GetTimersRead()
for suggesting to use dynamic buffering in handling CA descriptors to avoid a
possible buffer overflow
Alex Lasnier <alex@fepg.org> Alex Lasnier <alex@fepg.org>
for adding tuning support for ATSC devices for adding tuning support for ATSC devices

View File

@ -8828,7 +8828,7 @@ Video Disk Recorder Revision History
- Empty adaptation field TS packets are now skipped when recording (thanks to - Empty adaptation field TS packets are now skipped when recording (thanks to
Christopher Reimer, based on the "AFFcleaner" by Stefan Pöschel). Christopher Reimer, based on the "AFFcleaner" by Stefan Pöschel).
2016-12-22: Version 2.3.2 2016-12-23: Version 2.3.2
- Fixed a crash when deleting a recording (reported by Oliver Endriss). - Fixed a crash when deleting a recording (reported by Oliver Endriss).
- Fixed an overflow of PIDs in a receiver (thanks to Robert Hannebauer). - Fixed an overflow of PIDs in a receiver (thanks to Robert Hannebauer).
@ -8874,3 +8874,5 @@ Video Disk Recorder Revision History
- Added a 'const' version of cTimers::GetTimer() (thanks to Lars Hanisch). - Added a 'const' version of cTimers::GetTimer() (thanks to Lars Hanisch).
- Fixed a typo in the description of cTimers::GetTimersRead() (thanks to Lars - Fixed a typo in the description of cTimers::GetTimersRead() (thanks to Lars
Hanisch). Hanisch).
- Fixed a possible buffer overflow in handling CA descriptors (suggested by
Lars Hanisch).

67
ci.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: ci.c 4.2 2015/09/05 11:45:19 kls Exp $ * $Id: ci.c 4.3 2016/12/23 14:00:45 kls Exp $
*/ */
#include "ci.h" #include "ci.h"
@ -756,9 +756,9 @@ class cCiCaPmt {
friend class cCiConditionalAccessSupport; friend class cCiConditionalAccessSupport;
private: private:
uint8_t cmdId; uint8_t cmdId;
int length;
int esInfoLengthPos; int esInfoLengthPos;
uint8_t capmt[2048]; ///< XXX is there a specified maximum? cDynamicBuffer caDescriptors;
cDynamicBuffer capmt;
int source; int source;
int transponder; int transponder;
int programNumber; int programNumber;
@ -768,7 +768,7 @@ public:
cCiCaPmt(uint8_t CmdId, int Source, int Transponder, int ProgramNumber, const int *CaSystemIds); cCiCaPmt(uint8_t CmdId, int Source, int Transponder, int ProgramNumber, const int *CaSystemIds);
uint8_t CmdId(void) { return cmdId; } uint8_t CmdId(void) { return cmdId; }
void SetListManagement(uint8_t ListManagement); void SetListManagement(uint8_t ListManagement);
uint8_t ListManagement(void) { return capmt[0]; } uint8_t ListManagement(void) { return capmt.Get(0); }
void AddPid(int Pid, uint8_t StreamType); void AddPid(int Pid, uint8_t StreamType);
}; };
@ -784,55 +784,46 @@ cCiCaPmt::cCiCaPmt(uint8_t CmdId, int Source, int Transponder, int ProgramNumber
caSystemIds[i] = CaSystemIds[i]; caSystemIds[i] = CaSystemIds[i];
} }
caSystemIds[i] = 0; caSystemIds[i] = 0;
uint8_t caDescriptors[512]; GetCaDescriptors(source, transponder, programNumber, caSystemIds, caDescriptors, 0);
int caDescriptorsLength = GetCaDescriptors(source, transponder, programNumber, caSystemIds, sizeof(caDescriptors), caDescriptors, 0); capmt.Append(CPLM_ONLY);
length = 0; capmt.Append((ProgramNumber >> 8) & 0xFF);
capmt[length++] = CPLM_ONLY; capmt.Append( ProgramNumber & 0xFF);
capmt[length++] = (ProgramNumber >> 8) & 0xFF; capmt.Append(0x01); // version_number, current_next_indicator - apparently vn doesn't matter, but cni must be 1
capmt[length++] = ProgramNumber & 0xFF; esInfoLengthPos = capmt.Length();
capmt[length++] = 0x01; // version_number, current_next_indicator - apparently vn doesn't matter, but cni must be 1 capmt.Append(0x00); // program_info_length H (at program level)
esInfoLengthPos = length; capmt.Append(0x00); // program_info_length L
capmt[length++] = 0x00; // program_info_length H (at program level) AddCaDescriptors(caDescriptors.Length(), caDescriptors.Data());
capmt[length++] = 0x00; // program_info_length L
AddCaDescriptors(caDescriptorsLength, caDescriptors);
} }
void cCiCaPmt::SetListManagement(uint8_t ListManagement) void cCiCaPmt::SetListManagement(uint8_t ListManagement)
{ {
capmt[0] = ListManagement; capmt.Set(0, ListManagement);
} }
void cCiCaPmt::AddPid(int Pid, uint8_t StreamType) void cCiCaPmt::AddPid(int Pid, uint8_t StreamType)
{ {
if (Pid) { if (Pid) {
uint8_t caDescriptors[512]; GetCaDescriptors(source, transponder, programNumber, caSystemIds, caDescriptors, Pid);
int caDescriptorsLength = GetCaDescriptors(source, transponder, programNumber, caSystemIds, sizeof(caDescriptors), caDescriptors, Pid); capmt.Append(StreamType);
//XXX buffer overflow check??? capmt.Append((Pid >> 8) & 0xFF);
capmt[length++] = StreamType; capmt.Append( Pid & 0xFF);
capmt[length++] = (Pid >> 8) & 0xFF; esInfoLengthPos = capmt.Length();
capmt[length++] = Pid & 0xFF; capmt.Append(0x00); // ES_info_length H (at ES level)
esInfoLengthPos = length; capmt.Append(0x00); // ES_info_length L
capmt[length++] = 0x00; // ES_info_length H (at ES level) AddCaDescriptors(caDescriptors.Length(), caDescriptors.Data());
capmt[length++] = 0x00; // ES_info_length L
AddCaDescriptors(caDescriptorsLength, caDescriptors);
} }
} }
void cCiCaPmt::AddCaDescriptors(int Length, const uint8_t *Data) void cCiCaPmt::AddCaDescriptors(int Length, const uint8_t *Data)
{ {
if (esInfoLengthPos) { if (esInfoLengthPos) {
if (length + Length < int(sizeof(capmt))) { if (Length || cmdId == CPCI_QUERY) {
if (Length || cmdId == CPCI_QUERY) { capmt.Append(cmdId);
capmt[length++] = cmdId; capmt.Append(Data, Length);
memcpy(capmt + length, Data, Length); int l = capmt.Length() - esInfoLengthPos - 2;
length += Length; capmt.Set(esInfoLengthPos, (l >> 8) & 0xFF);
int l = length - esInfoLengthPos - 2; capmt.Set(esInfoLengthPos + 1, l & 0xFF);
capmt[esInfoLengthPos] = (l >> 8) & 0xFF;
capmt[esInfoLengthPos + 1] = l & 0xFF;
}
} }
else
esyslog("ERROR: buffer overflow in CA descriptor");
esInfoLengthPos = 0; esInfoLengthPos = 0;
} }
else else
@ -995,7 +986,7 @@ void cCiConditionalAccessSupport::SendPMT(cCiCaPmt *CaPmt)
{ {
if (CaPmt && state >= 2) { if (CaPmt && state >= 2) {
dbgprotocol("Slot %d: ==> Ca Pmt (%d) %d %d\n", Tc()->CamSlot()->SlotNumber(), SessionId(), CaPmt->ListManagement(), CaPmt->CmdId()); dbgprotocol("Slot %d: ==> Ca Pmt (%d) %d %d\n", Tc()->CamSlot()->SlotNumber(), SessionId(), CaPmt->ListManagement(), CaPmt->CmdId());
SendData(AOT_CA_PMT, CaPmt->length, CaPmt->capmt); SendData(AOT_CA_PMT, CaPmt->capmt.Length(), CaPmt->capmt.Data());
state = 4; // sent ca pmt state = 4; // sent ca pmt
} }
} }

51
pat.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: pat.c 4.2 2016/12/22 11:42:23 kls Exp $ * $Id: pat.c 4.3 2016/12/23 14:02:07 kls Exp $
*/ */
#include "pat.h" #include "pat.h"
@ -81,7 +81,7 @@ public:
bool Is(cCaDescriptors * CaDescriptors); bool Is(cCaDescriptors * CaDescriptors);
bool Empty(void) { return caDescriptors.Count() == 0; } bool Empty(void) { return caDescriptors.Count() == 0; }
void AddCaDescriptor(SI::CaDescriptor *d, int EsPid); void AddCaDescriptor(SI::CaDescriptor *d, int EsPid);
int GetCaDescriptors(const int *CaSystemIds, int BufSize, uchar *Data, int EsPid); void GetCaDescriptors(const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid);
int GetCaPids(const int *CaSystemIds, int BufSize, int *Pids); int GetCaPids(const int *CaSystemIds, int BufSize, int *Pids);
const int GetPmtPid(void) { return pmtPid; }; const int GetPmtPid(void) { return pmtPid; };
const int *CaIds(void) { return caIds; } const int *CaIds(void) { return caIds; }
@ -159,30 +159,20 @@ void cCaDescriptors::AddCaDescriptor(SI::CaDescriptor *d, int EsPid)
// =0 - common CaDescriptor // =0 - common CaDescriptor
// <0 - all CaDescriptors regardless of type (old default) // <0 - all CaDescriptors regardless of type (old default)
int cCaDescriptors::GetCaDescriptors(const int *CaSystemIds, int BufSize, uchar *Data, int EsPid) void cCaDescriptors::GetCaDescriptors(const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid)
{ {
Buffer.Clear();
if (!CaSystemIds || !*CaSystemIds) if (!CaSystemIds || !*CaSystemIds)
return 0; return;
if (BufSize > 0 && Data) { for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) {
int length = 0; if (EsPid < 0 || d->EsPid() == EsPid) {
for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) { const int *caids = CaSystemIds;
if (EsPid < 0 || d->EsPid() == EsPid) { do {
const int *caids = CaSystemIds; if (*caids == 0xFFFF || d->CaSystem() == *caids)
do { Buffer.Append(d->Data(), d->Length());
if (*caids == 0xFFFF || d->CaSystem() == *caids) { } while (*++caids);
if (length + d->Length() <= BufSize) {
memcpy(Data + length, d->Data(), d->Length());
length += d->Length();
}
else
return -1;
}
} while (*++caids);
}
} }
return length; }
}
return -1;
} }
int cCaDescriptors::GetCaPids(const int *CaSystemIds, int BufSize, int *Pids) int cCaDescriptors::GetCaPids(const int *CaSystemIds, int BufSize, int *Pids)
@ -219,7 +209,7 @@ public:
// Returns 0 if this is an already known descriptor, // Returns 0 if this is an already known descriptor,
// 1 if it is an all new descriptor with actual contents, // 1 if it is an all new descriptor with actual contents,
// and 2 if an existing descriptor was changed. // and 2 if an existing descriptor was changed.
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, uchar *Data, int EsPid); void GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid);
int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids); int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids);
int GetPmtPid(int Source, int Transponder, int ServiceId); int GetPmtPid(int Source, int Transponder, int ServiceId);
}; };
@ -242,14 +232,15 @@ int cCaDescriptorHandler::AddCaDescriptors(cCaDescriptors *CaDescriptors)
return CaDescriptors->Empty() ? 0 : 1; return CaDescriptors->Empty() ? 0 : 1;
} }
int cCaDescriptorHandler::GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, uchar *Data, int EsPid) void cCaDescriptorHandler::GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid)
{ {
cMutexLock MutexLock(&mutex); cMutexLock MutexLock(&mutex);
for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) { for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) {
if (ca->Is(Source, Transponder, ServiceId)) if (ca->Is(Source, Transponder, ServiceId)) {
return ca->GetCaDescriptors(CaSystemIds, BufSize, Data, EsPid); ca->GetCaDescriptors(CaSystemIds, Buffer, EsPid);
break;
}
} }
return 0;
} }
int cCaDescriptorHandler::GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids) int cCaDescriptorHandler::GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids)
@ -274,9 +265,9 @@ int cCaDescriptorHandler::GetPmtPid(int Source, int Transponder, int ServiceId)
cCaDescriptorHandler CaDescriptorHandler; cCaDescriptorHandler CaDescriptorHandler;
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, uchar *Data, int EsPid) void GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid)
{ {
return CaDescriptorHandler.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, BufSize, Data, EsPid); CaDescriptorHandler.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, Buffer, EsPid);
} }
int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids) int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids)

8
pat.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: pat.h 3.4 2015/01/04 13:17:22 kls Exp $ * $Id: pat.h 4.1 2016/12/23 14:03:24 kls Exp $
*/ */
#ifndef __PAT_H #ifndef __PAT_H
@ -38,14 +38,12 @@ public:
void Trigger(int Sid = -1); void Trigger(int Sid = -1);
}; };
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, uchar *Data, int EsPid); void GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid);
///< Gets all CA descriptors for a given channel. ///< Gets all CA descriptors for a given channel.
///< Copies all available CA descriptors for the given Source, Transponder and ServiceId ///< Copies all available CA descriptors for the given Source, Transponder and ServiceId
///< into the provided buffer at Data (at most BufSize bytes). Only those CA descriptors ///< into the provided buffer. Only those CA descriptors
///< are copied that match one of the given CA system IDs (or all of them, if CaSystemIds ///< are copied that match one of the given CA system IDs (or all of them, if CaSystemIds
///< is 0xFFFF). ///< is 0xFFFF).
///< Returns the number of bytes copied into Data (0 if no CA descriptors are
///< available), or -1 if BufSize was too small to hold all CA descriptors.
int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids); int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids);
///< Gets all CA pids for a given channel. ///< Gets all CA pids for a given channel.

40
tools.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.c 4.4 2015/09/10 13:17:55 kls Exp $ * $Id: tools.c 4.5 2016/12/23 14:03:40 kls Exp $
*/ */
#include "tools.h" #include "tools.h"
@ -2272,6 +2272,44 @@ void cListBase::Sort(void)
free(a); free(a);
} }
// --- cDynamicBuffer --------------------------------------------------------
cDynamicBuffer::cDynamicBuffer(int InitialSize)
{
initialSize = InitialSize;
buffer = NULL;
size = used = 0;
}
cDynamicBuffer::~cDynamicBuffer()
{
free(buffer);
}
bool cDynamicBuffer::Realloc(int NewSize)
{
if (size < NewSize) {
NewSize = max(NewSize, size ? size * 3 / 2 : initialSize); // increase size by at least 50%
if (uchar *NewBuffer = (uchar *)realloc(buffer, NewSize)) {
buffer = NewBuffer;
size = NewSize;
}
else {
esyslog("ERROR: out of memory");
return false;
}
}
return true;
}
void cDynamicBuffer::Append(const uchar *Data, int Length)
{
if (Assert(used + Length)) {
memcpy(buffer + used, Data, Length);
used += Length;
}
}
// --- cHashBase ------------------------------------------------------------- // --- cHashBase -------------------------------------------------------------
cHashBase::cHashBase(int Size) cHashBase::cHashBase(int Size)

22
tools.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.h 4.4 2016/12/13 12:13:46 kls Exp $ * $Id: tools.h 4.5 2016/12/23 13:56:35 kls Exp $
*/ */
#ifndef __TOOLS_H #ifndef __TOOLS_H
@ -775,6 +775,26 @@ public:
bool Load(const char *Directory, bool DirsOnly = false); bool Load(const char *Directory, bool DirsOnly = false);
}; };
class cDynamicBuffer {
private:
uchar *buffer;
int initialSize;
int size; // the total size of the buffer (bytes in memory)
int used; // the number of used bytes, starting at the beginning of the buffer
bool Realloc(int NewSize);
bool Assert(int NewSize) { return size < NewSize ? Realloc(NewSize) : true; } // inline for performance!
public:
cDynamicBuffer(int InitialSize = 1024);
~cDynamicBuffer();
void Append(const uchar *Data, int Length);
void Append(uchar Data) { if (Assert(used + 1)) buffer[used++] = Data; }
void Set(int Index, uchar Data) { if (Assert(Index + 1)) buffer[Index] = Data; }
uchar Get(int Index) { return Index < used ? buffer[Index] : 0; }
void Clear(void) { used = 0; }
uchar *Data(void) { return buffer; }
int Length(void) { return used; }
};
class cHashObject : public cListObject { class cHashObject : public cListObject {
friend class cHashBase; friend class cHashBase;
private: private: