mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-12 10:25:33 +00:00
pluginloader: Add a magic number and maximum size limit.
Guard against a hostile child process that sends bogus data due to memory corruption by adding a magic number to each packet, and limit the maximum size of any message to 32MB
This commit is contained in:
parent
97d6c854ae
commit
8108494a38
1 changed files with 60 additions and 8 deletions
|
@ -27,6 +27,8 @@
|
||||||
#ifndef G_OS_WIN32
|
#ifndef G_OS_WIN32
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -42,9 +44,10 @@
|
||||||
#include <gst/gstregistrybinary.h>
|
#include <gst/gstregistrybinary.h>
|
||||||
|
|
||||||
/* IMPORTANT: Bump the version number if the plugin loader packet protocol
|
/* IMPORTANT: Bump the version number if the plugin loader packet protocol
|
||||||
* changes. Changes in the binary registry format are handled by bumps
|
* changes. Changes in the binary registry format itself are handled by
|
||||||
* in the GST_MAGIC_BINARY_VERSION_STR as before */
|
* bumping the GST_MAGIC_BINARY_VERSION_STR
|
||||||
static const guint32 loader_protocol_version = 2;
|
*/
|
||||||
|
static const guint32 loader_protocol_version = 3;
|
||||||
|
|
||||||
#define GST_CAT_DEFAULT GST_CAT_PLUGIN_LOADING
|
#define GST_CAT_DEFAULT GST_CAT_PLUGIN_LOADING
|
||||||
|
|
||||||
|
@ -105,7 +108,11 @@ struct _GstPluginLoader
|
||||||
|
|
||||||
#define BUF_INIT_SIZE 512
|
#define BUF_INIT_SIZE 512
|
||||||
#define BUF_GROW_EXTRA 512
|
#define BUF_GROW_EXTRA 512
|
||||||
#define HEADER_SIZE 8
|
#define BUF_MAX_SIZE (32 * 1024 * 1024)
|
||||||
|
|
||||||
|
#define HEADER_SIZE 12
|
||||||
|
/* 4 magic hex bytes to mark each packet */
|
||||||
|
#define HEADER_MAGIC 0xbefec0ae
|
||||||
#define ALIGNMENT (sizeof (void *))
|
#define ALIGNMENT (sizeof (void *))
|
||||||
|
|
||||||
static gboolean gst_plugin_loader_spawn (GstPluginLoader * loader);
|
static gboolean gst_plugin_loader_spawn (GstPluginLoader * loader);
|
||||||
|
@ -457,10 +464,16 @@ put_packet (GstPluginLoader * l, guint type, guint32 tag,
|
||||||
|
|
||||||
out = l->tx_buf + l->tx_buf_write;
|
out = l->tx_buf + l->tx_buf_write;
|
||||||
|
|
||||||
|
/* one byte packet type */
|
||||||
out[0] = type;
|
out[0] = type;
|
||||||
|
/* 3 byte packet tag number */
|
||||||
GST_WRITE_UINT24_BE (out + 1, tag);
|
GST_WRITE_UINT24_BE (out + 1, tag);
|
||||||
|
/* 4 bytes packet length */
|
||||||
GST_WRITE_UINT32_BE (out + 4, payload_len);
|
GST_WRITE_UINT32_BE (out + 4, payload_len);
|
||||||
|
/* payload */
|
||||||
memcpy (out + HEADER_SIZE, payload, payload_len);
|
memcpy (out + HEADER_SIZE, payload, payload_len);
|
||||||
|
/* Write magic into the header */
|
||||||
|
GST_WRITE_UINT32_BE (out + 8, HEADER_MAGIC);
|
||||||
|
|
||||||
l->tx_buf_write += len;
|
l->tx_buf_write += len;
|
||||||
gst_poll_fd_ctl_write (l->fdset, &l->fd_w, TRUE);
|
gst_poll_fd_ctl_write (l->fdset, &l->fd_w, TRUE);
|
||||||
|
@ -497,14 +510,27 @@ static gboolean
|
||||||
write_one (GstPluginLoader * l)
|
write_one (GstPluginLoader * l)
|
||||||
{
|
{
|
||||||
guint8 *out;
|
guint8 *out;
|
||||||
guint32 to_write;
|
guint32 to_write, magic;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (l->tx_buf_read + HEADER_SIZE > l->tx_buf_write)
|
if (l->tx_buf_read + HEADER_SIZE > l->tx_buf_write)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
out = l->tx_buf + l->tx_buf_read;
|
out = l->tx_buf + l->tx_buf_read;
|
||||||
|
|
||||||
|
magic = GST_READ_UINT32_BE (out + 8);
|
||||||
|
if (magic != HEADER_MAGIC) {
|
||||||
|
GST_ERROR ("Packet magic number is missing. Memory corruption detected");
|
||||||
|
goto fail_and_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
to_write = GST_READ_UINT32_BE (out + 4) + HEADER_SIZE;
|
to_write = GST_READ_UINT32_BE (out + 4) + HEADER_SIZE;
|
||||||
|
/* Check that the magic is intact, and the size is sensible */
|
||||||
|
if (to_write > l->tx_buf_size) {
|
||||||
|
GST_ERROR ("Indicated packet size is too large. Corruption detected");
|
||||||
|
goto fail_and_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
l->tx_buf_read += to_write;
|
l->tx_buf_read += to_write;
|
||||||
|
|
||||||
GST_LOG ("Writing packet of size %d bytes to fd %d", to_write, l->fd_w.fd);
|
GST_LOG ("Writing packet of size %d bytes to fd %d", to_write, l->fd_w.fd);
|
||||||
|
@ -518,15 +544,19 @@ write_one (GstPluginLoader * l)
|
||||||
} while (to_write > 0 && res < 0 && (errno == EAGAIN || errno == EINTR));
|
} while (to_write > 0 && res < 0 && (errno == EAGAIN || errno == EINTR));
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
/* Failed to write -> child died */
|
/* Failed to write -> child died */
|
||||||
plugin_loader_cleanup_child (l);
|
goto fail_and_cleanup;
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l->tx_buf_read == l->tx_buf_write) {
|
if (l->tx_buf_read == l->tx_buf_write) {
|
||||||
gst_poll_fd_ctl_write (l->fdset, &l->fd_w, FALSE);
|
gst_poll_fd_ctl_write (l->fdset, &l->fd_w, FALSE);
|
||||||
l->tx_buf_read = l->tx_buf_write = 0;
|
l->tx_buf_read = l->tx_buf_write = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
fail_and_cleanup:
|
||||||
|
plugin_loader_cleanup_child (l);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -537,7 +567,7 @@ do_plugin_load (GstPluginLoader * l, const gchar * filename, guint tag)
|
||||||
|
|
||||||
GST_DEBUG ("Plugin scanner loading file %s. tag %u\n", filename, tag);
|
GST_DEBUG ("Plugin scanner loading file %s. tag %u\n", filename, tag);
|
||||||
|
|
||||||
#if 0 /* Test code - crash based on an env var */
|
#if 0 /* Test code - crash based on filename */
|
||||||
if (strstr (filename, "coreelements") == NULL) {
|
if (strstr (filename, "coreelements") == NULL) {
|
||||||
g_printerr ("Crashing on file %s\n", filename);
|
g_printerr ("Crashing on file %s\n", filename);
|
||||||
g_printerr ("%d", *(gint *) (NULL));
|
g_printerr ("%d", *(gint *) (NULL));
|
||||||
|
@ -577,6 +607,15 @@ do_plugin_load (GstPluginLoader * l, const gchar * filename, guint tag)
|
||||||
/* Store the size of the written payload */
|
/* Store the size of the written payload */
|
||||||
GST_WRITE_UINT32_BE (l->tx_buf + hdr_pos + 4, offset - HEADER_SIZE);
|
GST_WRITE_UINT32_BE (l->tx_buf + hdr_pos + 4, offset - HEADER_SIZE);
|
||||||
}
|
}
|
||||||
|
#if 0 /* Test code - corrupt the tx buffer based on filename */
|
||||||
|
if (strstr (filename, "sink") != NULL) {
|
||||||
|
int fd, res;
|
||||||
|
g_printerr ("Corrupting tx buf on file %s\n", filename);
|
||||||
|
fd = open ("/dev/urandom", O_RDONLY);
|
||||||
|
res = read (fd, l->tx_buf, l->tx_buf_size);
|
||||||
|
close (fd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
gst_object_unref (newplugin);
|
gst_object_unref (newplugin);
|
||||||
} else {
|
} else {
|
||||||
|
@ -744,6 +783,7 @@ handle_rx_packet (GstPluginLoader * l,
|
||||||
static gboolean
|
static gboolean
|
||||||
read_one (GstPluginLoader * l)
|
read_one (GstPluginLoader * l)
|
||||||
{
|
{
|
||||||
|
guint64 magic;
|
||||||
guint32 to_read, packet_len, tag;
|
guint32 to_read, packet_len, tag;
|
||||||
guint8 *in;
|
guint8 *in;
|
||||||
gint res;
|
gint res;
|
||||||
|
@ -763,7 +803,19 @@ read_one (GstPluginLoader * l)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
magic = GST_READ_UINT32_BE (l->rx_buf + 8);
|
||||||
|
if (magic != HEADER_MAGIC) {
|
||||||
|
GST_WARNING
|
||||||
|
("Invalid packet (bad magic number) received from plugin scanner subprocess");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
packet_len = GST_READ_UINT32_BE (l->rx_buf + 4);
|
packet_len = GST_READ_UINT32_BE (l->rx_buf + 4);
|
||||||
|
if (packet_len + HEADER_SIZE > BUF_MAX_SIZE) {
|
||||||
|
GST_WARNING
|
||||||
|
("Received excessively large packet for plugin scanner subprocess");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (packet_len + HEADER_SIZE >= l->rx_buf_size) {
|
if (packet_len + HEADER_SIZE >= l->rx_buf_size) {
|
||||||
l->rx_buf_size = packet_len + HEADER_SIZE + BUF_GROW_EXTRA;
|
l->rx_buf_size = packet_len + HEADER_SIZE + BUF_GROW_EXTRA;
|
||||||
|
|
Loading…
Reference in a new issue