]>
Commit | Line | Data |
---|---|---|
0f714131 GKH |
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 | @@ -275,8 +275,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 | @@ -294,13 +306,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; |