diff options
author | Jochen Dolze <vdr@dolze.de> | 2009-10-06 00:36:26 +0200 |
---|---|---|
committer | Jochen Dolze <vdr@dolze.de> | 2009-10-06 00:36:26 +0200 |
commit | c11caab8aa7f1e296694e2eaa4477d299adcd1e6 (patch) | |
tree | 64adfc0dbab11a45f804489f9f4bddbef720fb0c | |
parent | c69708374c62615009e2b92783dcea696166470e (diff) | |
download | vdr-plugin-markad-c11caab8aa7f1e296694e2eaa4477d299adcd1e6.tar.gz vdr-plugin-markad-c11caab8aa7f1e296694e2eaa4477d299adcd1e6.tar.bz2 |
Fixed TS packet processing (buffer overflows)
Added packet injection
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | demux.cpp | 19 | ||||
-rw-r--r-- | markad-standalone.cpp | 121 | ||||
-rw-r--r-- | markad-standalone.h | 14 | ||||
-rw-r--r-- | pes2es.cpp | 7 | ||||
-rw-r--r-- | recv.cpp | 17 | ||||
-rw-r--r-- | recv.h | 1 | ||||
-rw-r--r-- | tools.cpp | 30 | ||||
-rw-r--r-- | tools.h | 2 | ||||
-rw-r--r-- | ts2pkt.cpp | 47 | ||||
-rw-r--r-- | ts2pkt.h | 47 |
11 files changed, 238 insertions, 69 deletions
@@ -14,4 +14,4 @@ See the file COPYING for more information. Description: -Noad marks advertisements in VDR recordings. +MarkAd marks advertisements in VDR recordings. @@ -48,7 +48,6 @@ void cMarkAdDemux::ProcessVDR(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt if (!pes2audioes) pes2audioes=new cMarkAdPES2ES(recvnumber,"PES2ES audio"); if (!pes2audioes) return; pes2audioes->Process(Pid,pkt,pktlen,Pkt,PktLen); - return; } if ((Pid.Type==MARKAD_PIDTYPE_VIDEO_H262) || (Pid.Type==MARKAD_PIDTYPE_VIDEO_H264)) @@ -56,14 +55,14 @@ void cMarkAdDemux::ProcessVDR(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt if (!pes2videoes) pes2videoes=new cMarkAdPES2ES(recvnumber,"PES2ES video",65536); if (!pes2videoes) return; pes2videoes->Process(Pid,pkt,pktlen,Pkt,PktLen); - return; } + return; } void cMarkAdDemux::ProcessTS(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt, int *PktLen) { - if ((!Pkt) || (!PktLen) || (!Data)) return; + if ((!Pkt) || (!PktLen)) return; *Pkt=NULL; *PktLen=0; @@ -80,14 +79,24 @@ void cMarkAdDemux::ProcessTS(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt, if (!pes2audioes) pes2audioes=new cMarkAdPES2ES(recvnumber,"PES2ES audio"); if (!pes2audioes) return; pes2audioes->Process(Pid,pkt,pktlen,Pkt,PktLen); - return; } - if (pkt) + if ((Pid.Type==MARKAD_PIDTYPE_VIDEO_H262) || (Pid.Type==MARKAD_PIDTYPE_VIDEO_H264)) + { + if ((pkt) && ((pkt[3] & 0xF0)==0xE0) && (pkt[4]!=0) && (pkt[5]!=0)) + { + ts2pkt->InjectVideoPES(pkt,pktlen); + pkt=NULL; + pktlen=0; + } + } + + if ((pkt) && (!*Pkt)) { *Pkt=pkt; *PktLen=pktlen; } + return; } diff --git a/markad-standalone.cpp b/markad-standalone.cpp index 53b400f..94c0d22 100644 --- a/markad-standalone.cpp +++ b/markad-standalone.cpp @@ -8,6 +8,8 @@ #include "markad-standalone.h" +cMarkAdStandalone *cmasta=NULL; + void syslog_with_tid(int priority, const char *format, ...) { va_list ap; @@ -57,7 +59,7 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) while ((dataread=read(f,data,datalen))>0) { - + if (abort) break; MarkAdMark *mark; if (common) @@ -172,13 +174,19 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) void cMarkAdStandalone::Process(const char *Directory) { + if (abort) return; for (int i=1; i<=MaxFiles; i++) { + if (abort) break; if (!ProcessFile(Directory,i)) { break; } } + if (abort) + { + isyslog("markad [%i]: aborted",recvnumber); + } } bool cMarkAdStandalone::CheckTS(const char *Directory) @@ -216,60 +224,59 @@ bool cMarkAdStandalone::CheckTS(const char *Directory) return true; } -void cMarkAdStandalone::CheckPATPMT(const char *Directory) +bool cMarkAdStandalone::CheckPATPMT(const char *Directory) { char *buf; - if (asprintf(&buf,"%s/00001.ts",Directory)==-1) return; + if (asprintf(&buf,"%s/00001.ts",Directory)==-1) return false; int fd=open(buf,O_RDONLY); free(buf); - if (fd==-1) return; + if (fd==-1) return false; uchar patpmt[376]; if (read(fd,patpmt,sizeof(patpmt))!=sizeof(patpmt)) { close(fd); - return; + return false; } close(fd); // some checks - if ((patpmt[0]!=0x47) || (patpmt[188]!=0x47)) return; // no TS-Sync - if (((patpmt[1] & 0x5F)!=0x40) && (patpmt[2]!=0)) return; // no PAT - if ((patpmt[3] & 0x10)!=0x10) return; // PAT not without AFC - if ((patpmt[191] & 0x10)!=0x10) return; // PMT not without AFC + if ((patpmt[0]!=0x47) || (patpmt[188]!=0x47)) return false; // no TS-Sync + if (((patpmt[1] & 0x5F)!=0x40) && (patpmt[2]!=0)) return false; // no PAT + if ((patpmt[3] & 0x10)!=0x10) return false; // PAT not without AFC + if ((patpmt[191] & 0x10)!=0x10) return false; // PMT not without AFC struct PAT *pat = (struct PAT *) &patpmt[5]; // more checks - if (pat->reserved1!=3) return; // is always 11 - if (pat->reserved3!=7) return; // is always 111 + if (pat->reserved1!=3) return false; // is always 11 + if (pat->reserved3!=7) return false; // is always 111 int pid=pat->pid_L+(pat->pid_H<<8); int pmtpid=((patpmt[189] & 0x1f)<<8)+patpmt[190]; - if (pid!=pmtpid) return; // pid in PAT differs from pid in PMT + if (pid!=pmtpid) return false; // pid in PAT differs from pid in PMT struct PMT *pmt = (struct PMT *) &patpmt[193]; // still more checks - if (pmt->reserved1!=3) return; // is always 11 - if (pmt->reserved2!=3) return; // is always 11 - if (pmt->reserved3!=7) return; // is always 111 - if (pmt->reserved4!=15) return; // is always 1111 + if (pmt->reserved1!=3) return false; // is always 11 + if (pmt->reserved2!=3) return false; // is always 11 + if (pmt->reserved3!=7) return false; // is always 111 + if (pmt->reserved4!=15) return false; // is always 1111 if ((pmt->program_number_H!=pat->program_number_H) || - (pmt->program_number_L!=pat->program_number_L)) return; + (pmt->program_number_L!=pat->program_number_L)) return false; int desc_len=(pmt->program_info_length_H<<8)+pmt->program_info_length_L; - if (desc_len>166) return; // beyond patpmt buffer + if (desc_len>166) return false; // beyond patpmt buffer int section_end = 196+(pmt->section_length_H<<8)+pmt->section_length_L; section_end-=4; // we don't care about the CRC32 - if (section_end>376) return; //beyond patpmt buffer + if (section_end>376) return false; //beyond patpmt buffer int i=205+desc_len; - while (i<section_end) { struct ES_DESCRIPTOR *es=NULL; @@ -281,8 +288,8 @@ void cMarkAdStandalone::CheckPATPMT(const char *Directory) } // oh no -> more checks! - if (si->reserved1!=7) return; - if (si->reserved2!=15) return; + if (si->reserved1!=7) return false; + if (si->reserved2!=15) return false; int pid=(si->PID_H<<8)+si->PID_L; @@ -318,12 +325,13 @@ void cMarkAdStandalone::CheckPATPMT(const char *Directory) i+=(sizeof(struct STREAMINFO)+esinfo_len); } - return; + return true; } cMarkAdStandalone::cMarkAdStandalone(const char *Directory) { recvnumber=255; + abort=false; memset(&macontext,0,sizeof(macontext)); macontext.General.StartTime=0; @@ -345,12 +353,15 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory) if (isTS) { - CheckPATPMT(Directory); + if (!CheckPATPMT(Directory)) + { + esyslog("markad [%i]: no PAT/PMT found -> nothing to process",recvnumber); + abort=true; + } macontext.General.APid.Num=0; } else { - macontext.General.APid.Num=0; macontext.General.DPid.Num=-1; macontext.General.VPid.Num=-1; macontext.General.VPid.Type=MARKAD_PIDTYPE_VIDEO_H262; @@ -369,7 +380,7 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory) if (macontext.General.APid.Num) { - dsyslog("markad [%i]: using mp2 (0x%04x)",recvnumber,macontext.General.APid.Num); + dsyslog("markad [%i]: using MP2 (0x%04x)",recvnumber,macontext.General.APid.Num); mp2_demux = new cMarkAdDemux(recvnumber); } else @@ -379,7 +390,7 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory) if (macontext.General.DPid.Num) { - dsyslog("markad [%i]: using ac3 (0x%04x)",recvnumber,macontext.General.DPid.Num); + dsyslog("markad [%i]: using AC3 (0x%04x)",recvnumber,macontext.General.DPid.Num); ac3_demux = new cMarkAdDemux(recvnumber); } else @@ -451,6 +462,21 @@ int usage() return -1; } +void signal_handler(int sig) +{ + if (sig==SIGUSR1) + { + // TODO: what we are supposed to do? + } + else + { + if (cmasta) + { + cmasta->SetAbort(); + } + } +} + int main(int argc, char *argv[]) { int c; @@ -518,14 +544,17 @@ int main(int argc, char *argv[]) break; case 'O': -// osdMsg = 1; + // --OSD + break; + + case 'o': + // --overlap break; case 's': case 'l': case 'c': case 'j': - case 'o': case 'a': case 'S': case 'B': @@ -552,9 +581,10 @@ int main(int argc, char *argv[]) //setMarkfileName(optarg); // TODO: implement this break; - case 2: // --verbose - //if (isnumber(optarg)) - // verbosity = atoi(optarg); + case 2: // --loglevel + SysLogLevel=atoi(optarg); + if (SysLogLevel>10) SysLogLevel=10; + if (SysLogLevel<0) SysLogLevel=2; break; case 3: // --testmode @@ -717,15 +747,6 @@ int main(int argc, char *argv[]) } } - // catch some signals - /* - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); - signal(SIGABRT, signal_handler); - signal(SIGSEGV, signal_handler); - signal(SIGUSR1, signal_handler); - */ - // now do the work... struct stat statbuf; if (stat(recDir,&statbuf)==-1) @@ -740,13 +761,19 @@ int main(int argc, char *argv[]) return -1; } - cMarkAdStandalone *cmasta = new cMarkAdStandalone(recDir); - if (cmasta) - { - cmasta->Process(recDir); - delete cmasta; - } + cmasta = new cMarkAdStandalone(recDir); + if (!cmasta) return -1; + + // ignore some signals + signal(SIGHUP, SIG_IGN); + + // catch some signals + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGUSR1, signal_handler); + cmasta->Process(recDir); + delete cmasta; return 0; } diff --git a/markad-standalone.h b/markad-standalone.h index b1dc0ce..145a9ea 100644 --- a/markad-standalone.h +++ b/markad-standalone.h @@ -131,15 +131,16 @@ unsigned reserved2: 4; unsigned ES_info_length_L: 8; -}; + }; #pragma pack() -struct ES_DESCRIPTOR { + struct ES_DESCRIPTOR + { unsigned Descriptor_Tag: 8; unsigned Descriptor_Length: 8; -}; + }; cMarkAdDemux *video_demux; @@ -156,13 +157,18 @@ unsigned Descriptor_Length: bool isTS; int MaxFiles; int framecnt; + bool abort; void AddMark(MarkAdMark *Mark); - void CheckPATPMT(const char *Directory); + bool CheckPATPMT(const char *Directory); bool CheckTS(const char *Directory); bool ProcessFile(const char *Directory, int Number); public: + void SetAbort() + { + abort=true; + } void Process(const char *Directory); cMarkAdStandalone(const char *Directory); ~cMarkAdStandalone(); @@ -41,9 +41,13 @@ void cMarkAdPES2ES::Process(MarkAdPid Pid, uchar *PESData, int PESSize, uchar ** return; } - int Length=(peshdr->LenH<<8)+peshdr->LenL+sizeof(PESHDR); + if (peshdr->StreamID<=0xBC) return; + + int Length=(peshdr->LenH<<8)+peshdr->LenL; + if (Length) Length+=sizeof(PESHDR); if (Length!=PESSize) { + if ((peshdr->StreamID & 0xF0)==0xE0) return; Reset(); return; } @@ -87,7 +91,6 @@ void cMarkAdPES2ES::Process(MarkAdPid Pid, uchar *PESData, int PESSize, uchar ** buf=&PESData[bpos]; buflen=PESSize-bpos; } - queue->Put(buf,buflen); } if (type) *ESData=queue->GetPacket(ESSize,type); @@ -74,7 +74,7 @@ cMarkAdReceiver::cMarkAdReceiver(int RecvNumber, const char *Filename, cTimer *T if (macontext.General.APid.Num) { - dsyslog("markad [%i]: using mp2",recvnumber); + dsyslog("markad [%i]: using MP2",recvnumber); mp2_demux = new cMarkAdDemux(RecvNumber); } else @@ -84,7 +84,7 @@ cMarkAdReceiver::cMarkAdReceiver(int RecvNumber, const char *Filename, cTimer *T if (macontext.General.DPid.Num) { - dsyslog("markad [%i]: using ac3",recvnumber); + dsyslog("markad [%i]: using AC3",recvnumber); ac3_demux = new cMarkAdDemux(RecvNumber); } else @@ -107,6 +107,7 @@ cMarkAdReceiver::cMarkAdReceiver(int RecvNumber, const char *Filename, cTimer *T marks.Load(Filename); Index=NULL; lastiframe=0; + framecnt=-1; } cMarkAdReceiver::~cMarkAdReceiver() @@ -324,9 +325,17 @@ void cMarkAdReceiver::Action() { if (macontext.Video.Info.Pict_Type==MA_I_TYPE) { - mark=video->Process(lastiframe); - AddMark(mark,3); + if (framecnt==-1) + { + framecnt=0; + } + else + { + mark=video->Process(lastiframe); + AddMark(mark,3); + } } + if (framecnt!=-1) framecnt++; } } tspkt+=len; @@ -57,6 +57,7 @@ private: int recvnumber; char *filename; int lastiframe; + int framecnt; char *strcatrealloc(char *dest, const char *src); cMarks marks; @@ -26,6 +26,36 @@ cMarkAdPaketQueue::~cMarkAdPaketQueue() if (buffer) free(buffer); } +bool cMarkAdPaketQueue::Inject(uchar *Data, int Size) +{ + if (!buffer) return false; + if (outptr>Size) + { + uchar temp[Size+1]; + memcpy(temp,Data,Size); + outptr-=Size; + memcpy(&buffer[outptr],temp,Size); + pktinfo.pkthdr=-1; + } + else + { + int oldSize=Length(); + uchar tempold[oldSize+1]; + memcpy(tempold,&buffer[outptr],oldSize); + + uchar temp[Size+1]; + memcpy(temp,Data,Size); + + memcpy(buffer,temp,Size); + memcpy(buffer+Size,tempold,oldSize); + + inptr=Size+oldSize; + outptr=0; + pktinfo.pkthdr=-1; + } + return true; +} + bool cMarkAdPaketQueue::Put(uchar *Data, int Size) { if (!buffer) return false; @@ -129,7 +129,9 @@ public: void Clear() { inptr=outptr=0; + pktinfo.pkthdr=-1; } + bool Inject(uchar *Data, int Size); bool Put(uchar *Data, int Size); uchar *Get(int *Size); @@ -24,8 +24,8 @@ void cMarkAdTS2Pkt::Reset(int ErrIndex) { switch (ErrIndex) { - case MA_ERR_TOSMALL: - dsyslog("markad [%i]: input to small",recvnumber); + case MA_ERR_TSSIZE: + dsyslog("markad [%i]: inbuf not 188 bytes",recvnumber); break; case MA_ERR_NOSYNC: dsyslog("markad [%i]: found no sync",recvnumber); @@ -37,16 +37,53 @@ void cMarkAdTS2Pkt::Reset(int ErrIndex) dsyslog("markad [%i]: wrong AFC value",recvnumber); break; case MA_ERR_TOBIG: - dsyslog("markad [%i]: buflen > 188",recvnumber); + dsyslog("markad [%i]: buflen > 188 bytes",recvnumber); break; case MA_ERR_NEG: - dsyslog("markad [%i]: buflen < 0",recvnumber); + dsyslog("markad [%i]: buflen negative",recvnumber); break; } counter=-1; if (queue) queue->Clear(); } +bool cMarkAdTS2Pkt::InjectVideoPES(uchar *PESData, int PESSize) +{ + if ((!PESData) || (!PESSize)) return false; + + struct PESHDR *peshdr=(struct PESHDR *) PESData; + + // first check some simple things + if ((peshdr->Sync1!=0) && (peshdr->Sync2!=0) && (peshdr->Sync3!=1)) return false; + if ((peshdr->StreamID & 0xF0)!=0xE0) return false; + + int Length=(peshdr->LenH<<8)+peshdr->LenL; + if (Length) Length+=sizeof(PESHDR); + if (Length!=PESSize) return false; + + struct PESHDROPT *peshdropt=(struct PESHDROPT *) &PESData[sizeof(struct PESHDR)]; + + uchar *buf; + int buflen; + + if (peshdropt->MarkerBits==0x2) + { + // we have an optional PES header + int bpos=sizeof(struct PESHDR)+sizeof(struct PESHDROPT)+ + peshdropt->Length; + buf=&PESData[bpos]; + buflen=PESSize-bpos; + } + else + { + int bpos=sizeof(struct PESHDR); + buf=&PESData[bpos]; + buflen=PESSize-bpos; + } + queue->Inject(buf,buflen); + return true; +} + void cMarkAdTS2Pkt::Process(MarkAdPid Pid, uchar *TSData, int TSSize, uchar **PktData, int *PktSize) { if ((!PktData) || (!PktSize) || (!queue)) return; @@ -57,7 +94,7 @@ void cMarkAdTS2Pkt::Process(MarkAdPid Pid, uchar *TSData, int TSSize, uchar **Pk { if (TSSize!=TS_SIZE) { - Reset(MA_ERR_TOSMALL); + Reset(MA_ERR_TSSIZE); return; // we need a full packet } @@ -58,13 +58,57 @@ unsigned Flags: 8; }; + struct PESHDR + { + uchar Sync1; + uchar Sync2; + uchar Sync3; + uchar StreamID; + uchar LenH; + uchar LenL; + }; + +#pragma pack(1) + struct PESHDROPT + { +unsigned OOC: + 1; +unsigned CY: + 1; +unsigned DAI: + 1; +unsigned PESP: + 1; +unsigned PESSC: + 2; +unsigned MarkerBits: + 2; +unsigned EXT: + 1; +unsigned CRC: + 1; +unsigned ACI: + 1; +unsigned TM: + 1; +unsigned RATE: + 1; +unsigned ESCR: + 1; +unsigned TSF: + 2; +unsigned Length: + 8; + }; +#pragma pack() + int recvnumber; int counter; cMarkAdPaketQueue *queue; #define MA_ERR_STARTUP 0 -#define MA_ERR_TOSMALL 1 +#define MA_ERR_TSSIZE 1 #define MA_ERR_NOSYNC 2 #define MA_ERR_SEQ 3 #define MA_ERR_AFC 4 @@ -75,6 +119,7 @@ public: cMarkAdTS2Pkt(int RecvNumber, const char *QueueName="TS2Pkt", int QueueSize=32768); ~cMarkAdTS2Pkt(); void Process(MarkAdPid Pid,uchar *TSData, int TSSize, uchar **PktData, int *PktSize); + bool InjectVideoPES(uchar *PESData, int PESSize); }; #endif |