diff options
author | Oliver Neukum <oneukum@suse.de> | 2014-05-19 07:53:55 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-27 19:03:57 -0400 |
commit | 552e1f2679b7b766b8b8de3dc6d83d9cd28f28b2 (patch) | |
tree | 1e696b32dccada97e0aa1431daf1f8c8a23a0d75 /drivers/usb | |
parent | d846b7650db3fcca7901b6e23f6416c3601a3dfe (diff) |
USB: appledisplay: fix race between reading and writing from the device
The workqueue handler may call appledisplay_bl_get_brightness() while
user space calls appledisplay_bl_update_status(). As they share a
buffer that must not happen. Use a mutex for mutual exclusion.
Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/misc/appledisplay.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index f37c78d1bdf4..b3d245ef46ef 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c | |||
@@ -81,6 +81,7 @@ struct appledisplay { | |||
81 | struct delayed_work work; | 81 | struct delayed_work work; |
82 | int button_pressed; | 82 | int button_pressed; |
83 | spinlock_t lock; | 83 | spinlock_t lock; |
84 | struct mutex sysfslock; /* concurrent read and write */ | ||
84 | }; | 85 | }; |
85 | 86 | ||
86 | static atomic_t count_displays = ATOMIC_INIT(0); | 87 | static atomic_t count_displays = ATOMIC_INIT(0); |
@@ -144,6 +145,7 @@ static int appledisplay_bl_update_status(struct backlight_device *bd) | |||
144 | struct appledisplay *pdata = bl_get_data(bd); | 145 | struct appledisplay *pdata = bl_get_data(bd); |
145 | int retval; | 146 | int retval; |
146 | 147 | ||
148 | mutex_lock(&pdata->sysfslock); | ||
147 | pdata->msgdata[0] = 0x10; | 149 | pdata->msgdata[0] = 0x10; |
148 | pdata->msgdata[1] = bd->props.brightness; | 150 | pdata->msgdata[1] = bd->props.brightness; |
149 | 151 | ||
@@ -156,15 +158,17 @@ static int appledisplay_bl_update_status(struct backlight_device *bd) | |||
156 | 0, | 158 | 0, |
157 | pdata->msgdata, 2, | 159 | pdata->msgdata, 2, |
158 | ACD_USB_TIMEOUT); | 160 | ACD_USB_TIMEOUT); |
159 | 161 | mutex_unlock(&pdata->sysfslock); | |
162 | |||
160 | return retval; | 163 | return retval; |
161 | } | 164 | } |
162 | 165 | ||
163 | static int appledisplay_bl_get_brightness(struct backlight_device *bd) | 166 | static int appledisplay_bl_get_brightness(struct backlight_device *bd) |
164 | { | 167 | { |
165 | struct appledisplay *pdata = bl_get_data(bd); | 168 | struct appledisplay *pdata = bl_get_data(bd); |
166 | int retval; | 169 | int retval, brightness; |
167 | 170 | ||
171 | mutex_lock(&pdata->sysfslock); | ||
168 | retval = usb_control_msg( | 172 | retval = usb_control_msg( |
169 | pdata->udev, | 173 | pdata->udev, |
170 | usb_rcvctrlpipe(pdata->udev, 0), | 174 | usb_rcvctrlpipe(pdata->udev, 0), |
@@ -174,11 +178,13 @@ static int appledisplay_bl_get_brightness(struct backlight_device *bd) | |||
174 | 0, | 178 | 0, |
175 | pdata->msgdata, 2, | 179 | pdata->msgdata, 2, |
176 | ACD_USB_TIMEOUT); | 180 | ACD_USB_TIMEOUT); |
181 | brightness = pdata->msgdata[1]; | ||
182 | mutex_unlock(&pdata->sysfslock); | ||
177 | 183 | ||
178 | if (retval < 0) | 184 | if (retval < 0) |
179 | return retval; | 185 | return retval; |
180 | else | 186 | else |
181 | return pdata->msgdata[1]; | 187 | return brightness; |
182 | } | 188 | } |
183 | 189 | ||
184 | static const struct backlight_ops appledisplay_bl_data = { | 190 | static const struct backlight_ops appledisplay_bl_data = { |
@@ -241,6 +247,7 @@ static int appledisplay_probe(struct usb_interface *iface, | |||
241 | 247 | ||
242 | spin_lock_init(&pdata->lock); | 248 | spin_lock_init(&pdata->lock); |
243 | INIT_DELAYED_WORK(&pdata->work, appledisplay_work); | 249 | INIT_DELAYED_WORK(&pdata->work, appledisplay_work); |
250 | mutex_init(&pdata->sysfslock); | ||
244 | 251 | ||
245 | /* Allocate buffer for control messages */ | 252 | /* Allocate buffer for control messages */ |
246 | pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL); | 253 | pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL); |