Coverage Report

Created: 2026-07-12 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gstreamer/ci/fuzzing/gst-subparse.c
Line
Count
Source
1
/*
2
 * Copyright 2026 Google Inc.
3
 * author: Arthur SC Chan <arthur.chan@adalogics.com>
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
#ifdef HAVE_CONFIG_H
20
#include "config.h"
21
#endif
22
23
#include <locale.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <glib.h>
27
#include <gst/gst.h>
28
29
/* Subtitle parsing fuzzing target
30
 *
31
 * This application can be compiled with libFuzzer to fuzz
32
 * subtitle parsing in gst-plugins-base/gst/subparse/
33
 *
34
 * The goal is to cover subtitle parsing code for:
35
 * - SubRip (SRT) - Most common subtitle format with timestamps
36
 * - WebVTT - Web Video Text Tracks with cue settings
37
 * - SSA/ASS - Advanced SubStation Alpha with styling
38
 * - MicroDVD - Frame-based format with {frame}{frame} syntax
39
 * - SAMI - Microsoft HTML-based subtitle format
40
 * - SubViewer - Another time-based format
41
 * - MPSub - MPlayer subtitle format
42
 * - TMPlayer - Frame/time based format
43
 * - MPL2 - Frame-based variant
44
 * - DKS - Frame-based format
45
 * - QuickTime Text - Apple subtitle format
46
 * - LRC - Lyrics format with embedded timestamps
47
 *
48
 * All parsers handle complex text/binary formats with potential for:
49
 * - Memory corruption (buffer overflows)
50
 * - Regular expression DoS (ReDoS) attacks
51
 * - Integer overflows in timestamp parsing
52
 * - HTML/XML injection in tag handling
53
 * - Logic errors in format detection
54
 * - Encoding conversion vulnerabilities
55
 **/
56
57
static void
58
custom_logger (const gchar * log_domain, GLogLevelFlags log_level,
59
    const gchar * message, gpointer unused_data)
60
2
{
61
2
  if (log_level & G_LOG_LEVEL_CRITICAL) {
62
0
    g_printerr ("CRITICAL ERROR : %s\n", message);
63
0
    abort ();
64
2
  } else if (log_level & G_LOG_LEVEL_WARNING) {
65
1
    g_printerr ("WARNING : %s\n", message);
66
1
  }
67
2
}
68
69
static void
70
test_subtitle_parsing_direct_pad_chain (const guint8 * data, size_t size)
71
6.18k
{
72
6.18k
  GstElement *subparse, *fakesink;
73
6.18k
  GstPad *sinkpad, *srcpad, *fakesink_pad;
74
6.18k
  GstBuffer *buffer;
75
6.18k
  GstCaps *caps;
76
6.18k
  GstSegment segment;
77
78
  /* Create subparse element */
79
6.18k
  subparse = gst_element_factory_make ("subparse", NULL);
80
6.18k
  g_assert (subparse != NULL);
81
82
  /* Create fakesink to receive output */
83
6.18k
  fakesink = gst_element_factory_make ("fakesink", NULL);
84
6.18k
  g_assert (fakesink != NULL);
85
86
  /* Get pads */
87
6.18k
  sinkpad = gst_element_get_static_pad (subparse, "sink");
88
6.18k
  srcpad = gst_element_get_static_pad (subparse, "src");
89
6.18k
  fakesink_pad = gst_element_get_static_pad (fakesink, "sink");
90
91
6.18k
  g_assert (sinkpad);
92
6.18k
  g_assert (srcpad);
93
6.18k
  g_assert (fakesink_pad);
94
95
  /* Link subparse to fakesink */
96
6.18k
  g_assert (gst_pad_link (srcpad, fakesink_pad) == GST_PAD_LINK_OK);
97
98
  /* Set elements to PLAYING state (sink to source order) */
99
6.18k
  gst_element_set_state (fakesink, GST_STATE_PLAYING);
100
6.18k
  gst_element_set_state (subparse, GST_STATE_PLAYING);
101
102
  /* Send stream-start event */
103
6.18k
  gst_pad_send_event (sinkpad, gst_event_new_stream_start ("fuzz-stream"));
104
105
  /* Send segment event */
106
6.18k
  gst_segment_init (&segment, GST_FORMAT_TIME);
107
6.18k
  gst_pad_send_event (sinkpad, gst_event_new_segment (&segment));
108
109
  /* Create buffer with fuzzer data */
110
6.18k
  buffer =
111
6.18k
      gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, (gpointer) data,
112
6.18k
      size, 0, size, NULL, NULL);
113
6.18k
  if (buffer) {
114
    /* Chain buffer directly to pad - errors are expected with bad data */
115
6.18k
    gst_pad_chain (sinkpad, buffer);
116
117
    /* Send EOS event */
118
6.18k
    gst_pad_send_event (sinkpad, gst_event_new_eos ());
119
6.18k
  }
120
121
  /* Cleanup (source to sink order) */
122
6.18k
  gst_element_set_state (subparse, GST_STATE_NULL);
123
6.18k
  gst_element_set_state (fakesink, GST_STATE_NULL);
124
6.18k
  gst_object_unref (sinkpad);
125
6.18k
  gst_object_unref (srcpad);
126
6.18k
  gst_object_unref (fakesink_pad);
127
6.18k
  gst_object_unref (subparse);
128
6.18k
  gst_object_unref (fakesink);
129
6.18k
}
130
131
int
132
LLVMFuzzerTestOneInput (const guint8 * data, size_t size)
133
6.18k
{
134
6.18k
  static gboolean initialized = FALSE;
135
136
6.18k
  if (!initialized) {
137
1
    g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);
138
1
    g_log_set_default_handler (custom_logger, NULL);
139
140
1
    gst_init (NULL, NULL);
141
142
1
    initialized = TRUE;
143
1
  }
144
145
6.18k
  if (size == 0)
146
0
    return 0;
147
148
  /* Test direct pad chain approach */
149
6.18k
  test_subtitle_parsing_direct_pad_chain (data, size);
150
151
6.18k
  return 0;
152
6.18k
}