media: dvb_frontend: fix locking issues at dvb_frontend_get_event()
commit 76d81243a4
upstream.
As warned by smatch:
drivers/media/dvb-core/dvb_frontend.c:314 dvb_frontend_get_event() warn: inconsistent returns 'sem:&fepriv->sem'.
Locked on: line 288
line 295
line 306
line 314
Unlocked on: line 303
The lock implementation for get event is wrong, as, if an
interrupt occurs, down_interruptible() will fail, and the
routine will call up() twice when userspace calls the ioctl
again.
The bad code is there since when Linux migrated to git, in
2005.
Cc: stable@vger.kernel.org
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
1a4726ba1d
commit
dc00f08645
@ -251,8 +251,20 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe,
|
|||||||
wake_up_interruptible (&events->wait_queue);
|
wake_up_interruptible (&events->wait_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dvb_frontend_test_event(struct dvb_frontend_private *fepriv,
|
||||||
|
struct dvb_fe_events *events)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
up(&fepriv->sem);
|
||||||
|
ret = events->eventw != events->eventr;
|
||||||
|
down(&fepriv->sem);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int dvb_frontend_get_event(struct dvb_frontend *fe,
|
static int dvb_frontend_get_event(struct dvb_frontend *fe,
|
||||||
struct dvb_frontend_event *event, int flags)
|
struct dvb_frontend_event *event, int flags)
|
||||||
{
|
{
|
||||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||||
struct dvb_fe_events *events = &fepriv->events;
|
struct dvb_fe_events *events = &fepriv->events;
|
||||||
@ -270,13 +282,8 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
|
|||||||
if (flags & O_NONBLOCK)
|
if (flags & O_NONBLOCK)
|
||||||
return -EWOULDBLOCK;
|
return -EWOULDBLOCK;
|
||||||
|
|
||||||
up(&fepriv->sem);
|
ret = wait_event_interruptible(events->wait_queue,
|
||||||
|
dvb_frontend_test_event(fepriv, events));
|
||||||
ret = wait_event_interruptible (events->wait_queue,
|
|
||||||
events->eventw != events->eventr);
|
|
||||||
|
|
||||||
if (down_interruptible (&fepriv->sem))
|
|
||||||
return -ERESTARTSYS;
|
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
Reference in New Issue
Block a user