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/misc | |
| 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/misc')
| -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); |
