]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.18.114/media-dvb_frontend-fix-locking-issues-at-dvb_frontend_get_event.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.18.114 / media-dvb_frontend-fix-locking-issues-at-dvb_frontend_get_event.patch
1 From 76d81243a487c09619822ef8e7201a756e58a87d Mon Sep 17 00:00:00 2001
2 From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
3 Date: Thu, 5 Apr 2018 05:30:52 -0400
4 Subject: media: dvb_frontend: fix locking issues at dvb_frontend_get_event()
5
6 From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
7
8 commit 76d81243a487c09619822ef8e7201a756e58a87d upstream.
9
10 As warned by smatch:
11 drivers/media/dvb-core/dvb_frontend.c:314 dvb_frontend_get_event() warn: inconsistent returns 'sem:&fepriv->sem'.
12 Locked on: line 288
13 line 295
14 line 306
15 line 314
16 Unlocked on: line 303
17
18 The lock implementation for get event is wrong, as, if an
19 interrupt occurs, down_interruptible() will fail, and the
20 routine will call up() twice when userspace calls the ioctl
21 again.
22
23 The bad code is there since when Linux migrated to git, in
24 2005.
25
26 Cc: stable@vger.kernel.org
27 Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
28 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
29
30 ---
31 drivers/media/dvb-core/dvb_frontend.c | 23 +++++++++++++++--------
32 1 file changed, 15 insertions(+), 8 deletions(-)
33
34 --- a/drivers/media/dvb-core/dvb_frontend.c
35 +++ b/drivers/media/dvb-core/dvb_frontend.c
36 @@ -224,8 +224,20 @@ static void dvb_frontend_add_event(struc
37 wake_up_interruptible (&events->wait_queue);
38 }
39
40 +static int dvb_frontend_test_event(struct dvb_frontend_private *fepriv,
41 + struct dvb_fe_events *events)
42 +{
43 + int ret;
44 +
45 + up(&fepriv->sem);
46 + ret = events->eventw != events->eventr;
47 + down(&fepriv->sem);
48 +
49 + return ret;
50 +}
51 +
52 static int dvb_frontend_get_event(struct dvb_frontend *fe,
53 - struct dvb_frontend_event *event, int flags)
54 + struct dvb_frontend_event *event, int flags)
55 {
56 struct dvb_frontend_private *fepriv = fe->frontend_priv;
57 struct dvb_fe_events *events = &fepriv->events;
58 @@ -243,13 +255,8 @@ static int dvb_frontend_get_event(struct
59 if (flags & O_NONBLOCK)
60 return -EWOULDBLOCK;
61
62 - up(&fepriv->sem);
63 -
64 - ret = wait_event_interruptible (events->wait_queue,
65 - events->eventw != events->eventr);
66 -
67 - if (down_interruptible (&fepriv->sem))
68 - return -ERESTARTSYS;
69 + ret = wait_event_interruptible(events->wait_queue,
70 + dvb_frontend_test_event(fepriv, events));
71
72 if (ret < 0)
73 return ret;