diff mbox series

[v4l-utils] libdvbv5: leaks and double free in dvb_fe_open_fname()

Message ID 20190317163220.1881-1-sean@mess.org (mailing list archive)
State New, archived
Headers show
Series [v4l-utils] libdvbv5: leaks and double free in dvb_fe_open_fname() | expand

Commit Message

Sean Young March 17, 2019, 4:32 p.m. UTC
dvb_fe_open_fname() takes ownership of fname if the function succeeds, but
also in two of the error paths (e.g. if the ioctl FE_GET_PROPERTY fails).

Adjust dvb_fe_open_fname() so it copies fname rather than taking ownership
(and passing that to params). This makes the code cleaner.

Signed-off-by: Sean Young <sean@mess.org>
---
 lib/libdvbv5/dvb-dev-local.c |  2 +-
 lib/libdvbv5/dvb-fe.c        | 18 ++++++++----------
 2 files changed, 9 insertions(+), 11 deletions(-)

Comments

Mauro Carvalho Chehab April 26, 2019, 3:13 p.m. UTC | #1
Em Sun, 17 Mar 2019 16:32:20 +0000
Sean Young <sean@mess.org> escreveu:

> dvb_fe_open_fname() takes ownership of fname if the function succeeds, but
> also in two of the error paths (e.g. if the ioctl FE_GET_PROPERTY fails).
> 
> Adjust dvb_fe_open_fname() so it copies fname rather than taking ownership
> (and passing that to params). This makes the code cleaner.

Just reverted this patch from stable-1.16, as it breaks Kaffeine.

There are two reports about the issue:

	https://bugs.kde.org/show_bug.cgi?id=406145
        https://bugzilla.redhat.com/show_bug.cgi?id=1695023

I was able to reproduce it locally.

So, better to keep a possible memory leak than to cause apps
to not function anymore.

> 
> Signed-off-by: Sean Young <sean@mess.org>
> ---
>  lib/libdvbv5/dvb-dev-local.c |  2 +-
>  lib/libdvbv5/dvb-fe.c        | 18 ++++++++----------
>  2 files changed, 9 insertions(+), 11 deletions(-)
> 
> diff --git a/lib/libdvbv5/dvb-dev-local.c b/lib/libdvbv5/dvb-dev-local.c
> index e98b967a..2de9a614 100644
> --- a/lib/libdvbv5/dvb-dev-local.c
> +++ b/lib/libdvbv5/dvb-dev-local.c
> @@ -467,7 +467,7 @@ static struct dvb_open_descriptor
>  			flags &= ~O_NONBLOCK;
>  		}
>  
> -		ret = dvb_fe_open_fname(parms, strdup(dev->path), flags);
> +		ret = dvb_fe_open_fname(parms, dev->path, flags);
>  		if (ret) {
>  			free(open_dev);
>  			return NULL;
> diff --git a/lib/libdvbv5/dvb-fe.c b/lib/libdvbv5/dvb-fe.c
> index 5dcf492e..7f634766 100644
> --- a/lib/libdvbv5/dvb-fe.c
> +++ b/lib/libdvbv5/dvb-fe.c
> @@ -133,7 +133,6 @@ struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
>  					  int flags)
>  {
>  	int ret;
> -	char *fname;
>  	struct dvb_device *dvb;
>  	struct dvb_dev_list *dvb_dev;
>  	struct dvb_v5_fe_parms_priv *parms = NULL;
> @@ -153,7 +152,6 @@ struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
>  		dvb_dev_free(dvb);
>  		return NULL;
>  	}
> -	fname = strdup(dvb_dev->path);
>  
>  	if (!strcmp(dvb_dev->bus_addr, "platform:dvbloopback")) {
>  		logfunc(LOG_WARNING, _("Detected dvbloopback"));
> @@ -161,14 +159,10 @@ struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
>  	}
>  
>  	dvb_dev_free(dvb);
> -	if (!fname) {
> -		logfunc(LOG_ERR, _("fname calloc: %s"), strerror(errno));
> -		return NULL;
> -	}
> +
>  	parms = calloc(sizeof(*parms), 1);
>  	if (!parms) {
>  		logfunc(LOG_ERR, _("parms calloc: %s"), strerror(errno));
> -		free(fname);
>  		return NULL;
>  	}
>  	parms->p.verbose = verbose;
> @@ -183,7 +177,7 @@ struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
>  	if (use_legacy_call)
>  		parms->p.legacy_fe = 1;
>  
> -	ret = dvb_fe_open_fname(parms, fname, flags);
> +	ret = dvb_fe_open_fname(parms, dvb_dev->path, flags);
>  	if (ret < 0) {
>  		dvb_v5_free(parms);
>  		return NULL;
> @@ -203,7 +197,6 @@ int dvb_fe_open_fname(struct dvb_v5_fe_parms_priv *parms, char *fname,
>  	fd = open(fname, flags, 0);
>  	if (fd == -1) {
>  		dvb_logerr(_("%s while opening %s"), strerror(errno), fname);
> -		free(fname);
>  		return -errno;
>  	}
>  
> @@ -224,7 +217,12 @@ int dvb_fe_open_fname(struct dvb_v5_fe_parms_priv *parms, char *fname,
>  		}
>  	}
>  
> -	parms->fname = fname;
> +	parms->fname = strdup(fname);
> +	if (!parms->fname) {
> +		dvb_logerr(_("fname calloc: %s"), strerror(errno));
> +		return -errno;
> +	}
> +
>  	parms->fd = fd;
>  	parms->fe_flags = flags;
>  	parms->dvb_prop[0].cmd = DTV_API_VERSION;



Thanks,
Mauro
Mauro Carvalho Chehab April 26, 2019, 3:42 p.m. UTC | #2
Gregor,

This patch messed with all branches since stable-1.12. I applied the revert
patch already on all affected stable branches.

We should probably release a new fix for them soon.

Sorry for not looking this earlier.. I got some vacations earlier 
this month.

Regards,
Mauro

Em Fri, 26 Apr 2019 12:13:44 -0300
Mauro Carvalho Chehab <mchehab+samsung@kernel.org> escreveu:

> Em Sun, 17 Mar 2019 16:32:20 +0000
> Sean Young <sean@mess.org> escreveu:
> 
> > dvb_fe_open_fname() takes ownership of fname if the function succeeds, but
> > also in two of the error paths (e.g. if the ioctl FE_GET_PROPERTY fails).
> > 
> > Adjust dvb_fe_open_fname() so it copies fname rather than taking ownership
> > (and passing that to params). This makes the code cleaner.  
> 
> Just reverted this patch from stable-1.16, as it breaks Kaffeine.
> 
> There are two reports about the issue:
> 
> 	https://bugs.kde.org/show_bug.cgi?id=406145
>         https://bugzilla.redhat.com/show_bug.cgi?id=1695023
> 
> I was able to reproduce it locally.
> 
> So, better to keep a possible memory leak than to cause apps
> to not function anymore.
> 
> > 
> > Signed-off-by: Sean Young <sean@mess.org>
> > ---
> >  lib/libdvbv5/dvb-dev-local.c |  2 +-
> >  lib/libdvbv5/dvb-fe.c        | 18 ++++++++----------
> >  2 files changed, 9 insertions(+), 11 deletions(-)
> > 
> > diff --git a/lib/libdvbv5/dvb-dev-local.c b/lib/libdvbv5/dvb-dev-local.c
> > index e98b967a..2de9a614 100644
> > --- a/lib/libdvbv5/dvb-dev-local.c
> > +++ b/lib/libdvbv5/dvb-dev-local.c
> > @@ -467,7 +467,7 @@ static struct dvb_open_descriptor
> >  			flags &= ~O_NONBLOCK;
> >  		}
> >  
> > -		ret = dvb_fe_open_fname(parms, strdup(dev->path), flags);
> > +		ret = dvb_fe_open_fname(parms, dev->path, flags);
> >  		if (ret) {
> >  			free(open_dev);
> >  			return NULL;
> > diff --git a/lib/libdvbv5/dvb-fe.c b/lib/libdvbv5/dvb-fe.c
> > index 5dcf492e..7f634766 100644
> > --- a/lib/libdvbv5/dvb-fe.c
> > +++ b/lib/libdvbv5/dvb-fe.c
> > @@ -133,7 +133,6 @@ struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
> >  					  int flags)
> >  {
> >  	int ret;
> > -	char *fname;
> >  	struct dvb_device *dvb;
> >  	struct dvb_dev_list *dvb_dev;
> >  	struct dvb_v5_fe_parms_priv *parms = NULL;
> > @@ -153,7 +152,6 @@ struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
> >  		dvb_dev_free(dvb);
> >  		return NULL;
> >  	}
> > -	fname = strdup(dvb_dev->path);
> >  
> >  	if (!strcmp(dvb_dev->bus_addr, "platform:dvbloopback")) {
> >  		logfunc(LOG_WARNING, _("Detected dvbloopback"));
> > @@ -161,14 +159,10 @@ struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
> >  	}
> >  
> >  	dvb_dev_free(dvb);
> > -	if (!fname) {
> > -		logfunc(LOG_ERR, _("fname calloc: %s"), strerror(errno));
> > -		return NULL;
> > -	}
> > +
> >  	parms = calloc(sizeof(*parms), 1);
> >  	if (!parms) {
> >  		logfunc(LOG_ERR, _("parms calloc: %s"), strerror(errno));
> > -		free(fname);
> >  		return NULL;
> >  	}
> >  	parms->p.verbose = verbose;
> > @@ -183,7 +177,7 @@ struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
> >  	if (use_legacy_call)
> >  		parms->p.legacy_fe = 1;
> >  
> > -	ret = dvb_fe_open_fname(parms, fname, flags);
> > +	ret = dvb_fe_open_fname(parms, dvb_dev->path, flags);
> >  	if (ret < 0) {
> >  		dvb_v5_free(parms);
> >  		return NULL;
> > @@ -203,7 +197,6 @@ int dvb_fe_open_fname(struct dvb_v5_fe_parms_priv *parms, char *fname,
> >  	fd = open(fname, flags, 0);
> >  	if (fd == -1) {
> >  		dvb_logerr(_("%s while opening %s"), strerror(errno), fname);
> > -		free(fname);
> >  		return -errno;
> >  	}
> >  
> > @@ -224,7 +217,12 @@ int dvb_fe_open_fname(struct dvb_v5_fe_parms_priv *parms, char *fname,
> >  		}
> >  	}
> >  
> > -	parms->fname = fname;
> > +	parms->fname = strdup(fname);
> > +	if (!parms->fname) {
> > +		dvb_logerr(_("fname calloc: %s"), strerror(errno));
> > +		return -errno;
> > +	}
> > +
> >  	parms->fd = fd;
> >  	parms->fe_flags = flags;
> >  	parms->dvb_prop[0].cmd = DTV_API_VERSION;  
> 
> 
> 
> Thanks,
> Mauro



Thanks,
Mauro
Mauro Carvalho Chehab April 26, 2019, 6:49 p.m. UTC | #3
Em Fri, 26 Apr 2019 18:08:22 +0200
Gregor Jasny <gjasny@googlemail.com> escreveu:

> Hello,
> 
> On Fri, 26 Apr 2019, 17:42 Mauro Carvalho Chehab, <
> mchehab+samsung@kernel.org> wrote:  
> 
> > Gregor,
> >
> > This patch messed with all branches since stable-1.12. I applied the revert
> > patch already on all affected stable branches.
> >
> > We should probably release a new fix for them soon.
> >
> > Sorry for not looking this earlier.. I got some vacations earlier
> > this month.
> >  
> 
> I also got a report in Debian:
> https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=927341
> 
> I'm wondering if we could improve code quality by doing some automated
> testing. 

That's my dream as well.

> Is there a dummy dvb driver like vivi available?

Unfortunately, we don't have a full dummy dvb driver. There are some
dummy DVB frontend drivers, but they're really dummy do-nothing
drivers. We would need to add more stuff there for them to work, and
then add a virtual DVB driver on the top of it.

Doable, but requires someone with time for coding that.

To be fair, a DVB dummy driver is a lot easier than a V4L2 one, as
the DVB core already handles most of the stuff. The most complex
part would likely to use the vivid image generator converting it
into some video stream supported by DVB apps (the best would be
to encode it as MPEG-2 - as all apps support). We could use, on
a first version, some previously encoded video - or - even easier
- to just stream empty frames.

Thanks,
Mauro
Mauro Carvalho Chehab May 3, 2019, 1 p.m. UTC | #4
Hi Gregor,

Em Fri, 26 Apr 2019 15:49:17 -0300
Mauro Carvalho Chehab <mchehab+samsung@kernel.org> escreveu:

> Em Fri, 26 Apr 2019 18:08:22 +0200
> Gregor Jasny <gjasny@googlemail.com> escreveu:
> 
> > Hello,
> > 
> > On Fri, 26 Apr 2019, 17:42 Mauro Carvalho Chehab, <  
> > mchehab+samsung@kernel.org> wrote:    
> >   
> > > Gregor,
> > >
> > > This patch messed with all branches since stable-1.12. I applied the revert
> > > patch already on all affected stable branches.
> > >
> > > We should probably release a new fix for them soon.
> > >
> > > Sorry for not looking this earlier.. I got some vacations earlier
> > > this month.
> > >    
> > 
> > I also got a report in Debian:
> > https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=927341


Are you planning to release a version 1.16.6 any time soon?

I could likely do it as well, but I would prefer if you can do,
as you know better the drills. We're still receiving new
complaints about this issue at Kaffeine's BZ. Just received
another one today.

Thanks,
Mauro
Gregor Jasny May 3, 2019, 1:02 p.m. UTC | #5
Hello,

On 03.05.19 15:00, Mauro Carvalho Chehab wrote:
> Are you planning to release a version 1.16.6 any time soon?
> 
> I could likely do it as well, but I would prefer if you can do,
> as you know better the drills. We're still receiving new
> complaints about this issue at Kaffeine's BZ. Just received
> another one today.

Yes, I'll do it over the weekend. Spend the last week hiking in Austria 
and had to catch up at work.

Thanks,
Gregor
diff mbox series

Patch

diff --git a/lib/libdvbv5/dvb-dev-local.c b/lib/libdvbv5/dvb-dev-local.c
index e98b967a..2de9a614 100644
--- a/lib/libdvbv5/dvb-dev-local.c
+++ b/lib/libdvbv5/dvb-dev-local.c
@@ -467,7 +467,7 @@  static struct dvb_open_descriptor
 			flags &= ~O_NONBLOCK;
 		}
 
-		ret = dvb_fe_open_fname(parms, strdup(dev->path), flags);
+		ret = dvb_fe_open_fname(parms, dev->path, flags);
 		if (ret) {
 			free(open_dev);
 			return NULL;
diff --git a/lib/libdvbv5/dvb-fe.c b/lib/libdvbv5/dvb-fe.c
index 5dcf492e..7f634766 100644
--- a/lib/libdvbv5/dvb-fe.c
+++ b/lib/libdvbv5/dvb-fe.c
@@ -133,7 +133,6 @@  struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
 					  int flags)
 {
 	int ret;
-	char *fname;
 	struct dvb_device *dvb;
 	struct dvb_dev_list *dvb_dev;
 	struct dvb_v5_fe_parms_priv *parms = NULL;
@@ -153,7 +152,6 @@  struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
 		dvb_dev_free(dvb);
 		return NULL;
 	}
-	fname = strdup(dvb_dev->path);
 
 	if (!strcmp(dvb_dev->bus_addr, "platform:dvbloopback")) {
 		logfunc(LOG_WARNING, _("Detected dvbloopback"));
@@ -161,14 +159,10 @@  struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
 	}
 
 	dvb_dev_free(dvb);
-	if (!fname) {
-		logfunc(LOG_ERR, _("fname calloc: %s"), strerror(errno));
-		return NULL;
-	}
+
 	parms = calloc(sizeof(*parms), 1);
 	if (!parms) {
 		logfunc(LOG_ERR, _("parms calloc: %s"), strerror(errno));
-		free(fname);
 		return NULL;
 	}
 	parms->p.verbose = verbose;
@@ -183,7 +177,7 @@  struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
 	if (use_legacy_call)
 		parms->p.legacy_fe = 1;
 
-	ret = dvb_fe_open_fname(parms, fname, flags);
+	ret = dvb_fe_open_fname(parms, dvb_dev->path, flags);
 	if (ret < 0) {
 		dvb_v5_free(parms);
 		return NULL;
@@ -203,7 +197,6 @@  int dvb_fe_open_fname(struct dvb_v5_fe_parms_priv *parms, char *fname,
 	fd = open(fname, flags, 0);
 	if (fd == -1) {
 		dvb_logerr(_("%s while opening %s"), strerror(errno), fname);
-		free(fname);
 		return -errno;
 	}
 
@@ -224,7 +217,12 @@  int dvb_fe_open_fname(struct dvb_v5_fe_parms_priv *parms, char *fname,
 		}
 	}
 
-	parms->fname = fname;
+	parms->fname = strdup(fname);
+	if (!parms->fname) {
+		dvb_logerr(_("fname calloc: %s"), strerror(errno));
+		return -errno;
+	}
+
 	parms->fd = fd;
 	parms->fe_flags = flags;
 	parms->dvb_prop[0].cmd = DTV_API_VERSION;