From 50f254ab9f9a804513c291b19bedfc3bdb94abeb Mon Sep 17 00:00:00 2001 From: Nikita Egorov Date: Sat, 14 Oct 2023 23:05:06 +0300 Subject: [PATCH 1/3] Fix issue with panic with WV-CYPHER-VERSION tag --- reader.go | 6 ++-- reader_test.go | 90 +++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 88 insertions(+), 8 deletions(-) diff --git a/reader.go b/reader.go index b19324eb..746b5a63 100644 --- a/reader.go +++ b/reader.go @@ -26,8 +26,8 @@ var reKeyValue = regexp.MustCompile(`([a-zA-Z0-9_-]+)=("[^"]+"|[^",]+)`) // TimeParse allows globally apply and/or override Time Parser function. // Available variants: -// * FullTimeParse - implements full featured ISO/IEC 8601:2004 -// * StrictTimeParse - implements only RFC3339 Nanoseconds format +// - FullTimeParse - implements full featured ISO/IEC 8601:2004 +// - StrictTimeParse - implements only RFC3339 Nanoseconds format var TimeParse func(value string) (time.Time, error) = FullTimeParse // Decode parses a master playlist passed from the buffer. If `strict` @@ -759,7 +759,7 @@ func decodeLineOfMediaPlaylist(p *MediaPlaylist, wv *WV, state *decodingState, l if err == nil { state.tagWV = true } - case strings.HasPrefix(line, "#WV-CYPHER-VERSION"): + case strings.HasPrefix(line, "#WV-CYPHER-VERSION "): state.listType = MEDIA wv.CypherVersion = line[19:] state.tagWV = true diff --git a/reader_test.go b/reader_test.go index 8d60b16c..076f6074 100644 --- a/reader_test.go +++ b/reader_test.go @@ -1,11 +1,11 @@ /* - Playlist parsing tests. +Playlist parsing tests. - Copyright 2013-2019 The Project Developers. - See the AUTHORS and LICENSE files at the top-level directory of this distribution - and at https://github.com/grafov/m3u8/ +Copyright 2013-2019 The Project Developers. +See the AUTHORS and LICENSE files at the top-level directory of this distribution +and at https://github.com/grafov/m3u8/ - ॐ तारे तुत्तारे तुरे स्व +ॐ तारे तुत्तारे तुरे स्व */ package m3u8 @@ -972,6 +972,86 @@ func TestDecodeMediaPlaylistStartTime(t *testing.T) { } } +/******************** + * Bad data tests * + ********************/ + +// Test mallformed playlist +func TestMalformedMasterPlaylis(t *testing.T) { + data := []byte("#EXT-X-START:\n#EXTM3U") + _, _, err := DecodeFrom(bytes.NewReader(data), true) + if err != nil { + if !errors.Is(err, ErrorNoEXTM3U) { + t.Errorf("Wrong error type at DecodeFrom: %s", err) + } + } else { + t.Error("No error on malformed playlist on DecodeFrome") + } + if _, _, err := DecodeFrom(bytes.NewReader(data), false); err != nil { + t.Errorf("Unexpected error on not strict mode of parsing: %s", err) + } + + var master = new(MasterPlaylist) + err = master.DecodeFrom(bytes.NewReader(data), true) + if err != nil { + if !errors.Is(err, ErrorNoEXTM3U) { + t.Errorf("Wrong error type at (*MasterPlaylist).DecodeFrom: %s", + err) + } + } else { + t.Error("No error on malformed playlist on (*MasterPlaylist).DecodeFrome") + } + + if err := master.DecodeFrom(bytes.NewReader(data), false); err != nil { + t.Errorf("Unexpected error on not strict mode of parsing: %s", err) + } + + var media = new(MediaPlaylist) + err = media.DecodeFrom(bytes.NewReader(data), true) + if err != nil { + if !errors.Is(err, ErrorNoEXTM3U) { + t.Errorf("Wrong error type at (*MediaPlaylist).DecodeFrom: %s", + err) + } + } else { + // TODO: There is probably an error here. The + // tag EXT-X-START should only appear in the master playlist. + t.Error("No error on malformed playlist on (*MediaPlaylist).DecodeFrome") + } + if err := media.DecodeFrom(bytes.NewReader(data), false); err != nil { + t.Errorf("Unexpected error on not strict mode of parsing: %s", err) + } + +} + +func TestDecodeMediaPlaylistDicontinuityAtBegin(t *testing.T) { + f, err := os.Open("sample-playlists/media-with-discontinuity-at-start.m3u8") + if err != nil { + t.Fatal(err) + } + p, listType, err := DecodeFrom(bufio.NewReader(f), true) + if err != nil { + t.Fatal(err) + } + pp := p.(*MediaPlaylist) + CheckType(t, pp) + if listType != MEDIA { + t.Error("Sample not recognized as media playlist.") + } + if pp.StartTime != float64(0.0) { + t.Errorf("Media segment StartTime != 0: %f", pp.StartTime) + } +} + +// Test for https://github.com/khenarghot/m3u8/issues/3 +func TestMellformedPanicIssue3(t *testing.T) { + bad := bytes.NewBuffer([]byte(`#WV-CYPHER-VERSION`)) + _, _, err := DecodeFrom(bad, true) + if err == nil { + t.Fail() + } +} + /**************** * Benchmarks * ****************/ From 325e59ed9f87f697b9d9749e14f287db9fb26532 Mon Sep 17 00:00:00 2001 From: Nikita Egorov Date: Sun, 15 Oct 2023 00:37:50 +0300 Subject: [PATCH 2/3] Fix panic on malformed playlist with WV-VIDEO-RESOLUTION --- reader.go | 2 +- reader_test.go | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/reader.go b/reader.go index 746b5a63..6eb8cccd 100644 --- a/reader.go +++ b/reader.go @@ -803,7 +803,7 @@ func decodeLineOfMediaPlaylist(p *MediaPlaylist, wv *WV, state *decodingState, l if err == nil { state.tagWV = true } - case strings.HasPrefix(line, "#WV-VIDEO-RESOLUTION"): + case strings.HasPrefix(line, "#WV-VIDEO-RESOLUTION "): state.listType = MEDIA wv.VideoResolution = line[21:] state.tagWV = true diff --git a/reader_test.go b/reader_test.go index 076f6074..eac9e918 100644 --- a/reader_test.go +++ b/reader_test.go @@ -1052,6 +1052,15 @@ func TestMellformedPanicIssue3(t *testing.T) { } } +// Test for https://github.com/khenarghot/m3u8/issues/1 +func TestMellformedPanicIssue1(t *testing.T) { + bad := bytes.NewBuffer([]byte(`#WV-VIDEO-RESOLUTION`)) + _, _, err := DecodeFrom(bad, true) + if err == nil { + t.Fail() + } +} + /**************** * Benchmarks * ****************/ From c28ec30a6eeed6fc96a76b5ff87338b58de59240 Mon Sep 17 00:00:00 2001 From: Nikita Egorov Date: Mon, 16 Oct 2023 09:52:34 +0300 Subject: [PATCH 3/3] Fix panic for malformed playlists Fix the panic that appear in case of bad tags EXT-X-KEY, EXT-X-MAP and custom tags. --- reader.go | 12 +++++++++--- reader_test.go | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/reader.go b/reader.go index 6eb8cccd..d28dd2f0 100644 --- a/reader.go +++ b/reader.go @@ -536,7 +536,9 @@ func decodeLineOfMediaPlaylist(p *MediaPlaylist, wv *WV, state *decodingState, l } // If EXT-X-KEY appeared before reference to segment (EXTINF) then it linked to this segment if state.tagKey { - p.Segments[p.last()].Key = &Key{state.xkey.Method, state.xkey.URI, state.xkey.IV, state.xkey.Keyformat, state.xkey.Keyformatversions} + if segment := p.Segments[p.last()]; segment != nil { + segment.Key = &Key{state.xkey.Method, state.xkey.URI, state.xkey.IV, state.xkey.Keyformat, state.xkey.Keyformatversions} + } // First EXT-X-KEY may appeared in the header of the playlist and linked to first segment // but for convenient playlist generation it also linked as default playlist key if p.Key == nil { @@ -546,7 +548,9 @@ func decodeLineOfMediaPlaylist(p *MediaPlaylist, wv *WV, state *decodingState, l } // If EXT-X-MAP appeared before reference to segment (EXTINF) then it linked to this segment if state.tagMap { - p.Segments[p.last()].Map = &Map{state.xmap.URI, state.xmap.Limit, state.xmap.Offset} + if segment := p.Segments[p.last()]; segment != nil { + segment.Map = &Map{state.xmap.URI, state.xmap.Limit, state.xmap.Offset} + } // First EXT-X-MAP may appeared in the header of the playlist and linked to first segment // but for convenient playlist generation it also linked as default playlist map if p.Map == nil { @@ -557,7 +561,9 @@ func decodeLineOfMediaPlaylist(p *MediaPlaylist, wv *WV, state *decodingState, l // if segment custom tag appeared before EXTINF then it links to this segment if state.tagCustom { - p.Segments[p.last()].Custom = state.custom + if segment := p.Segments[p.last()]; segment != nil { + segment.Custom = state.custom + } state.custom = make(map[string]CustomTag) state.tagCustom = false } diff --git a/reader_test.go b/reader_test.go index eac9e918..d5c520e2 100644 --- a/reader_test.go +++ b/reader_test.go @@ -1061,6 +1061,24 @@ func TestMellformedPanicIssue1(t *testing.T) { } } +// Test for https://github.com/khenarghot/m3u8/issues/2 +func TestMellformedPanicIssue2(t *testing.T) { + bad := bytes.NewBuffer([]byte("#EXT-X-KEY:\n0")) + _, _, err := DecodeFrom(bad, false) + if err != nil { + t.Fail() + } +} + +// Test for https://github.com/khenarghot/m3u8/issues/2 +func TestMellformedPanicIssue2AltMAP(t *testing.T) { + bad := bytes.NewBuffer([]byte("#EXT-X-MAP:\n0")) + _, _, err := DecodeFrom(bad, false) + if err != nil { + t.Fail() + } +} + /**************** * Benchmarks * ****************/