aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.de>2014-05-19 07:53:55 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-27 19:03:57 -0400
commit552e1f2679b7b766b8b8de3dc6d83d9cd28f28b2 (patch)
tree1e696b32dccada97e0aa1431daf1f8c8a23a0d75 /drivers/usb
parentd846b7650db3fcca7901b6e23f6416c3601a3dfe (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.c13
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
86static atomic_t count_displays = ATOMIC_INIT(0); 87static 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
163static int appledisplay_bl_get_brightness(struct backlight_device *bd) 166static 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
184static const struct backlight_ops appledisplay_bl_data = { 190static 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);