From 547024e5bbe2294df9528738975230aca8aa8394 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sat, 14 Apr 2007 14:22:53 +0100 Subject: Reworked the channels.conf file handling in the DVB plugin. Previously, with junk content, the plugin could potentially consume lots of memory (possibly causing a local DoS). Also, a few small memory leaks have been eliminated. --- ChangeLog | 4 ++ src/input/input_dvb.c | 170 +++++++++++++++++++++++--------------------------- 2 files changed, 82 insertions(+), 92 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2b142dc4a..7f4d61774 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,10 @@ xine-lib (1.1.6) [UNRELEASED] * Improve the Mac OS X video output plugin. Thanks to Matt Messier. * Fixed the XcbXv plugin - an empty plugin would be built if "old" Xv isn't detected. + * Reworked the channels.conf file handling in the DVB plugin. Previously, + with junk content, the plugin could potentially consume lots of memory + (possibly causing a local DoS). Also, a few small memory leaks have been + eliminated. xine-lib (1.1.5) * Security fixes: diff --git a/src/input/input_dvb.c b/src/input/input_dvb.c index 10d6eca55..6b975624e 100644 --- a/src/input/input_dvb.c +++ b/src/input/input_dvb.c @@ -703,7 +703,7 @@ static int find_param(const Param *list, const char *name) return list->value;; } -static int extract_channel_from_string(channel_t * channel,char * str,fe_type_t fe_type) +static int extract_channel_from_string_internal(channel_t * channel,char * str,fe_type_t fe_type) { /* try to extract channel data from a string in the following format @@ -864,54 +864,63 @@ static int extract_channel_from_string(channel_t * channel,char * str,fe_type_t return 0; } -static channel_t *load_channels(dvb_input_plugin_t *this, int *num_ch, fe_type_t fe_type) { +static int extract_channel_from_string(channel_t *channel, char *str, fe_type_t fe_type) +{ + channel->name = NULL; + if (!extract_channel_from_string_internal(channel, str, fe_type)) + return 0; + free (channel->name); /* without this, we have a possible memleak */ + return -1; +} + +static channel_t *load_channels(xine_t *xine, xine_stream_t *stream, int *num_ch, fe_type_t fe_type) { FILE *f; char str[BUFSIZE]; char filename[BUFSIZE]; - channel_t *channels; - int num_channels; + channel_t *channels = NULL; + int num_channels = 0; + int num_alloc = 0; int i; - xine_t *xine = this->class->xine; + struct stat st; snprintf(filename, BUFSIZE, "%s/.xine/channels.conf", xine_get_homedir()); - f = fopen(filename, "rb"); + f = fopen(filename, "r"); if (!f) { xprintf(xine, XINE_VERBOSITY_LOG, _("input_dvb: failed to open dvb channel file '%s'\n"), filename); - _x_message(this->stream, XINE_MSG_FILE_NOT_FOUND, filename, "Please run the dvbscan utility.", NULL); + if (!f && stream) + _x_message(stream, XINE_MSG_FILE_NOT_FOUND, filename, "Please run the dvbscan utility.", NULL); return NULL; } /* - * count and alloc channels + * load channel list */ - num_channels = 0; - while ( fgets (str, BUFSIZE, f)) { - num_channels++; - } - fclose (f); - if(num_channels > 0) - xprintf (xine, XINE_VERBOSITY_DEBUG, "input_dvb: expecting %d channels...\n", num_channels); - else { - xprintf (xine, XINE_VERBOSITY_DEBUG, "input_dvb: no channels found in the file: giving up.\n"); - return NULL; - } + while ( fgets (str, BUFSIZE, f)) { + channel_t channel = {0}; - channels = xine_xmalloc (sizeof (channel_t) * num_channels); + /* lose trailing spaces & control characters */ + i = strlen (str); + while (i && str[i - 1] <= ' ') + --i; + if (i == 0) + continue; + str[i] = 0; - _x_assert(channels != NULL); + if (extract_channel_from_string(&channel,str,fe_type) < 0) + continue; - /* - * load channel list - */ + if (num_channels >= num_alloc) { + channel_t *new_channels = xine_xmalloc((num_alloc += 32) * sizeof (channel_t)); + _x_assert(new_channels != NULL); + memcpy(new_channels, channels, num_channels * sizeof (channel_t)); + free(channels); + channels = new_channels; + } - f = fopen (filename, "rb"); - num_channels = 0; - while ( fgets (str, BUFSIZE, f)) { - if (extract_channel_from_string(&(channels[num_channels]),str,fe_type) < 0) - continue; + channels[num_channels] = channel; /* Initially there's no EPG data in the EPG structs. */ channels[num_channels].epg_count = 0; @@ -922,6 +931,9 @@ static channel_t *load_channels(dvb_input_plugin_t *this, int *num_ch, fe_type_t } fclose(f); + /* free any trailing unused entries */ + channels = realloc (channels, num_channels * sizeof (channel_t)); + if(num_channels > 0) xprintf (xine, XINE_VERBOSITY_DEBUG, "input_dvb: found %d channels...\n", num_channels); else { @@ -934,6 +946,14 @@ static channel_t *load_channels(dvb_input_plugin_t *this, int *num_ch, fe_type_t return channels; } +static void free_channel_list (channel_t *channels, int num_channels) +{ + if (channels) + while (--num_channels >= 0) + free(channels[num_channels].name); + free(channels); +} + static int tuner_set_diseqc(tuner_t *this, channel_t *c) { struct dvb_diseqc_master_cmd cmd = @@ -2624,7 +2644,7 @@ static void dvb_plugin_dispose (input_plugin_t *this_gen) { } } if (this->channels) - free (this->channels); + free_channel_list (this->channels, this->num_channels); /* Make the EPG updater thread return. */ @@ -2719,7 +2739,7 @@ static int dvb_plugin_open(input_plugin_t * this_gen) * and assume that its format is valid for our tuner type */ - if (!(channels = load_channels(this, &num_channels, tuner->feinfo.type))) + if (!(channels = load_channels(this->class->xine, this->stream, &num_channels, tuner->feinfo.type))) { /* failed to load the channels */ tuner_dispose(tuner); @@ -3120,77 +3140,46 @@ static char **dvb_class_get_autoplay_list(input_class_t * this_gen, { dvb_input_class_t *class = (dvb_input_class_t *) this_gen; channel_t *channels=NULL; - FILE *f; - char *tmpbuffer=xine_xmalloc(BUFSIZE); - char *foobuffer=xine_xmalloc(BUFSIZE); - char *str=tmpbuffer; - int num_channels; - int nlines=0; - int default_channel; - xine_cfg_entry_t lastchannel_enable; + char foobuffer[BUFSIZE]; + int ch, apch, num_channels; + int default_channel = -1; + xine_cfg_entry_t lastchannel_enable = {0}; xine_cfg_entry_t lastchannel; - _x_assert(tmpbuffer != NULL); - _x_assert(foobuffer != NULL); - - snprintf(tmpbuffer, BUFSIZE, "%s/.xine/channels.conf", xine_get_homedir()); - num_channels = 0; - f=fopen (tmpbuffer,"rb"); - if(!f){ /* channels.conf not found in .xine */ + if (!(channels = load_channels(class->xine, NULL, &num_channels, 0))) { + /* channels.conf not found in .xine */ class->mrls[0]="Sorry, No channels.conf found"; class->mrls[1]="Please run the dvbscan utility"; class->mrls[2]="from the dvb drivers apps package"; class->mrls[3]="and place the file in ~/.xine/"; *num_files=4; - free(tmpbuffer); - free(foobuffer); return class->mrls; - } else { - while (fgets(str, BUFSIZE, f)) - nlines++; } - fclose (f); - if (xine_config_lookup_entry(class->xine, "media.dvb.remember_channel", &lastchannel_enable)) - if (lastchannel_enable.num_value){ - num_channels++; - if (xine_config_lookup_entry(class->xine, "media.dvb.last_channel", &lastchannel)) - default_channel = lastchannel.num_value; - } - - if (nlines+lastchannel_enable.num_value >= MAX_AUTOCHANNELS) - nlines = MAX_AUTOCHANNELS-lastchannel_enable.num_value; - - snprintf(tmpbuffer, BUFSIZE, "%s/.xine/channels.conf", xine_get_homedir()); - - - f=fopen (tmpbuffer,"rb"); - channels=xine_xmalloc(sizeof(channel_t)*(nlines+lastchannel_enable.num_value)); - - _x_assert(channels != NULL); - - - while (fgets(str,BUFSIZE,f) && num_channels < nlines+lastchannel_enable.num_value) { - if (extract_channel_from_string (&(channels[num_channels]), str, 0) < 0) - continue; - - sprintf(foobuffer,"dvb://%s",channels[num_channels].name); - if(class->autoplaylist[num_channels]) - free(class->autoplaylist[num_channels]); - class->autoplaylist[num_channels]=xine_xmalloc(128); + if (xine_config_lookup_entry(class->xine, "media.dvb.remember_channel", &lastchannel_enable) + && lastchannel_enable.num_value + && xine_config_lookup_entry(class->xine, "media.dvb.last_channel", &lastchannel)) + { + default_channel = lastchannel.num_value - 1; + if (default_channel < 0 || default_channel >= num_channels) + default_channel = -1; + } - _x_assert(class->autoplaylist[num_channels] != NULL); - - class->autoplaylist[num_channels]=strdup(foobuffer); - num_channels++; - } + for (ch = 0, apch = !!lastchannel_enable.num_value; + ch < num_channels && ch < MAX_AUTOCHANNELS; + ++ch, ++apch) { + snprintf(foobuffer, BUFSIZE, "dvb://%s", channels[ch].name); + free(class->autoplaylist[apch]); + class->autoplaylist[apch] = strdup(foobuffer); + _x_assert(class->autoplaylist[apch] != NULL); + } if (lastchannel_enable.num_value){ - if (lastchannel.num_value > -1 && lastchannel.num_value < num_channels) + if (default_channel != -1) /* plugin has been used before - channel is valid */ - sprintf (foobuffer, "dvb://%s", channels[lastchannel.num_value].name); + sprintf (foobuffer, "dvb://%s", channels[default_channel].name); else /* set a reasonable default - the first channel */ sprintf (foobuffer, "dvb://%s", num_channels ? channels[0].name : "0"); @@ -3198,13 +3187,10 @@ static char **dvb_class_get_autoplay_list(input_class_t * this_gen, class->autoplaylist[0]=strdup(foobuffer); } - free(tmpbuffer); - free(foobuffer); - free(channels); - fclose(f); + free_channel_list(channels, num_channels); - *num_files = num_channels; - class->numchannels=nlines; + *num_files = num_channels + lastchannel_enable.num_value; + class->numchannels = *num_files; return class->autoplaylist; } -- cgit v1.2.3