Bug 981869 - Blacklist crashy flump3dec gstreamer plugin - r=kinetik

This commit is contained in:
Edwin Flores 2013-07-15 19:39:00 +12:00
parent e29d8e1845
commit 3aeced5479
6 changed files with 139 additions and 14 deletions

View File

@ -8,6 +8,7 @@
#include "nsCharSeparatedTokenizer.h"
#include "nsString.h"
#include "GStreamerLoader.h"
#include "mozilla/Preferences.h"
#define ENTRY_FORMAT(entry) entry[0]
#define ENTRY_CAPS(entry) entry[1]
@ -64,6 +65,10 @@ static char const * const sDefaultCodecCaps[][2] = {
{"audio/mpeg", "audio/mpeg, layer=(int)3"}
};
static char const * const sPluginBlacklist[] = {
"flump3dec",
};
GStreamerFormatHelper::GStreamerFormatHelper()
: mFactories(nullptr),
mCookie(static_cast<uint32_t>(-1))
@ -203,21 +208,58 @@ GstCaps* GStreamerFormatHelper::ConvertFormatsToCaps(const char* aMIMEType,
return caps;
}
/* static */ bool
GStreamerFormatHelper::IsBlacklistEnabled()
{
static bool sBlacklistEnabled;
static bool sBlacklistEnabledCached = false;
if (!sBlacklistEnabledCached) {
Preferences::AddBoolVarCache(&sBlacklistEnabled,
"media.gstreamer.enable-blacklist", true);
sBlacklistEnabledCached = true;
}
return sBlacklistEnabled;
}
/* static */ bool
GStreamerFormatHelper::IsPluginFeatureBlacklisted(GstPluginFeature *aFeature,
FactoryType aTypes)
{
if (!IsBlacklistEnabled()) {
return false;
}
const gchar *className =
gst_element_factory_get_klass(GST_ELEMENT_FACTORY_CAST(aFeature));
const gchar *factoryName =
gst_plugin_feature_get_name(aFeature);
if ((!(aTypes & FactoryTypeDecoder) && strstr(className, "Decoder")) ||
(!(aTypes & FactoryTypeDemuxer) && strstr(className, "Demuxer")) ||
(!(aTypes & FactoryTypeParser) && strstr(className, "Parser"))) {
return false;
}
for (unsigned int i = 0; i < G_N_ELEMENTS(sPluginBlacklist); i++) {
if (!strcmp(factoryName, sPluginBlacklist[i])) {
return true;
}
}
return false;
}
static gboolean FactoryFilter(GstPluginFeature *aFeature, gpointer)
{
if (!GST_IS_ELEMENT_FACTORY(aFeature)) {
return FALSE;
}
// TODO _get_klass doesn't exist in 1.0
const gchar *className =
gst_element_factory_get_klass(GST_ELEMENT_FACTORY_CAST(aFeature));
if (!strstr(className, "Decoder") && !strstr(className, "Demux")) {
return FALSE;
}
return gst_plugin_feature_get_rank(aFeature) >= GST_RANK_MARGINAL;
return !GStreamerFormatHelper::IsPluginFeatureBlacklisted(aFeature,
(FactoryType)(FactoryTypeDecoder|FactoryTypeDemuxer));
}
/**

View File

@ -13,6 +13,13 @@
namespace mozilla {
enum FactoryType {
FactoryTypeDecoder = 1 << 0,
FactoryTypeDemuxer = 1 << 1,
FactoryTypeParser = 1 << 2,
FactoryTypeAll = FactoryTypeDecoder|FactoryTypeDemuxer|FactoryTypeParser
};
class GStreamerFormatHelper {
/* This class can be used to query the GStreamer registry for the required
* demuxers/decoders from nsHTMLMediaElement::CanPlayType.
@ -29,6 +36,10 @@ class GStreamerFormatHelper {
bool CanHandleContainerCaps(GstCaps* aCaps);
bool CanHandleCodecCaps(GstCaps* aCaps);
static bool IsBlacklistEnabled();
static bool IsPluginFeatureBlacklisted(GstPluginFeature *aFeature,
FactoryType aTypes = FactoryTypeAll);
static GstCaps* ConvertFormatsToCaps(const char* aMIMEType,
const nsAString* aCodecs);

View File

@ -62,6 +62,7 @@ GST_FUNC(LIBGSTREAMER, gst_parse_bin_from_description)
GST_FUNC(LIBGSTREAMER, gst_pipeline_get_bus)
GST_FUNC(LIBGSTREAMER, gst_pipeline_get_type)
GST_FUNC(LIBGSTREAMER, gst_plugin_feature_get_rank)
GST_FUNC(LIBGSTREAMER, gst_plugin_feature_get_type)
GST_FUNC(LIBGSTREAMER, gst_registry_feature_filter)
GST_FUNC(LIBGSTREAMER, gst_registry_get_feature_list_cookie)
GST_FUNC(LIBGSTREAMER, gst_segment_init)
@ -88,6 +89,7 @@ GST_FUNC(LIBGSTREAMER, gst_pad_add_event_probe)
GST_FUNC(LIBGSTREAMER, gst_pad_alloc_buffer)
GST_FUNC(LIBGSTREAMER, gst_pad_get_negotiated_caps)
GST_FUNC(LIBGSTREAMER, gst_pad_set_bufferalloc_function)
GST_FUNC(LIBGSTREAMER, gst_plugin_feature_get_name)
GST_FUNC(LIBGSTREAMER, gst_registry_get_default)
GST_FUNC(LIBGSTREAMER, gst_segment_set_newsegment)
GST_FUNC(LIBGSTVIDEO, gst_video_format_get_component_height)

View File

@ -195,6 +195,9 @@ nsresult GStreamerReader::Init(MediaDecoderReader* aCloneDonor)
g_signal_connect(G_OBJECT(mPlayBin), "element-added",
G_CALLBACK(GStreamerReader::PlayElementAddedCb), this);
g_signal_connect(G_OBJECT(mPlayBin), "element-added",
G_CALLBACK(GStreamerReader::ElementAddedCb), this);
return NS_OK;
}
@ -214,6 +217,47 @@ GStreamerReader::Error(GstBus *aBus, GstMessage *aMessage)
return GST_BUS_PASS;
}
void GStreamerReader::ElementAddedCb(GstBin *aPlayBin,
GstElement *aElement,
gpointer aUserData)
{
const gchar *name =
gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(gst_element_get_factory(aElement)));
if (!strcmp(name, "uridecodebin")) {
g_signal_connect(G_OBJECT(aElement), "autoplug-sort",
G_CALLBACK(GStreamerReader::ElementFilterCb), aUserData);
}
}
GValueArray *GStreamerReader::ElementFilterCb(GstURIDecodeBin *aBin,
GstPad *aPad,
GstCaps *aCaps,
GValueArray *aFactories,
gpointer aUserData)
{
return ((GStreamerReader*)aUserData)->ElementFilter(aBin, aPad, aCaps, aFactories);
}
GValueArray *GStreamerReader::ElementFilter(GstURIDecodeBin *aBin,
GstPad *aPad,
GstCaps *aCaps,
GValueArray *aFactories)
{
GValueArray *filtered = g_value_array_new(aFactories->n_values);
for (unsigned int i = 0; i < aFactories->n_values; i++) {
GValue *value = &aFactories->values[i];
GstPluginFeature *factory = GST_PLUGIN_FEATURE(g_value_peek_pointer(value));
if (!GStreamerFormatHelper::IsPluginFeatureBlacklisted(factory)) {
g_value_array_append(filtered, value);
}
}
return filtered;
}
void GStreamerReader::PlayBinSourceSetupCb(GstElement* aPlayBin,
GParamSpec* pspec,
gpointer aUserData)
@ -1148,7 +1192,7 @@ void GStreamerReader::Eos(GstAppSink* aSink)
* This callback is called while the pipeline is automatically built, after a
* new element has been added to the pipeline. We use it to find the
* uridecodebin instance used by playbin and connect to it to apply our
* whitelist.
* blacklist.
*/
void
GStreamerReader::PlayElementAddedCb(GstBin *aBin, GstElement *aElement,
@ -1185,9 +1229,8 @@ GStreamerReader::ShouldAutoplugFactory(GstElementFactory* aFactory, GstCaps* aCa
/**
* This is called by uridecodebin (running inside playbin), after it has found
* candidate factories to continue decoding the stream. We apply the whitelist
* here, allowing only demuxers and decoders that output the formats we want to
* support.
* candidate factories to continue decoding the stream. We apply the blacklist
* here, disallowing known-crashy plugins.
*/
GValueArray*
GStreamerReader::AutoplugSortCb(GstElement* aElement, GstPad* aPad,

View File

@ -25,6 +25,8 @@
#include "ImageContainer.h"
#include "nsRect.h"
struct GstURIDecodeBin;
namespace mozilla {
namespace dom {
@ -90,6 +92,30 @@ private:
static GstBusSyncReply ErrorCb(GstBus *aBus, GstMessage *aMessage, gpointer aUserData);
GstBusSyncReply Error(GstBus *aBus, GstMessage *aMessage);
/*
* We attach this callback to playbin so that when uridecodebin is
* constructed, we can then list for its autoplug-sort signal to blacklist
* the elements it can construct.
*/
static void ElementAddedCb(GstBin *aPlayBin,
GstElement *aElement,
gpointer aUserData);
/*
* Called on the autoplug-sort signal emitted by uridecodebin for filtering
* the elements it uses.
*/
static GValueArray *ElementFilterCb(GstURIDecodeBin *aBin,
GstPad *aPad,
GstCaps *aCaps,
GValueArray *aFactories,
gpointer aUserData);
GValueArray *ElementFilter(GstURIDecodeBin *aBin,
GstPad *aPad,
GstCaps *aCaps,
GValueArray *aFactories);
/* Called on the source-setup signal emitted by playbin. Used to
* configure appsrc .
*/
@ -169,7 +195,7 @@ private:
static bool ShouldAutoplugFactory(GstElementFactory* aFactory, GstCaps* aCaps);
/* Called by decodebin during autoplugging. We use it to apply our
* container/codec whitelist.
* container/codec blacklist.
*/
static GValueArray* AutoplugSortCb(GstElement* aElement,
GstPad* aPad, GstCaps* aCaps,

View File

@ -307,6 +307,7 @@ pref("media.webm.intel_decoder.enabled", false);
#endif
#ifdef MOZ_GSTREAMER
pref("media.gstreamer.enabled", true);
pref("media.gstreamer.enable-blacklist", true);
#endif
#ifdef MOZ_APPLEMEDIA
pref("media.apple.mp3.enabled", true);