Commit e45f4676108d19ae93918f06cb6731c86108341a
Committed by
Linus Torvalds
1 parent
91046a8a69
Exists in
master
and in
7 other branches
[PATCH] sound/oss/emu10k1: handle userspace copy errors
Propagate copy_to/from_user() errors back through callers. Signed-off-by: Jeff Garzik <jeff@garzik.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 4 changed files with 38 additions and 16 deletions Side-by-side Diff
sound/oss/emu10k1/audio.c
... | ... | @@ -111,9 +111,15 @@ |
111 | 111 | |
112 | 112 | if ((bytestocopy >= wiinst->buffer.fragment_size) |
113 | 113 | || (bytestocopy >= count)) { |
114 | + int rc; | |
115 | + | |
114 | 116 | bytestocopy = min_t(u32, bytestocopy, count); |
115 | 117 | |
116 | - emu10k1_wavein_xferdata(wiinst, (u8 __user *)buffer, &bytestocopy); | |
118 | + rc = emu10k1_wavein_xferdata(wiinst, | |
119 | + (u8 __user *)buffer, | |
120 | + &bytestocopy); | |
121 | + if (rc) | |
122 | + return rc; | |
117 | 123 | |
118 | 124 | count -= bytestocopy; |
119 | 125 | buffer += bytestocopy; |
sound/oss/emu10k1/cardwi.c
... | ... | @@ -304,11 +304,12 @@ |
304 | 304 | } |
305 | 305 | } |
306 | 306 | |
307 | -static void copy_block(u8 __user *dst, u8 * src, u32 str, u32 len, u8 cov) | |
307 | +static int copy_block(u8 __user *dst, u8 * src, u32 str, u32 len, u8 cov) | |
308 | 308 | { |
309 | - if (cov == 1) | |
310 | - __copy_to_user(dst, src + str, len); | |
311 | - else { | |
309 | + if (cov == 1) { | |
310 | + if (__copy_to_user(dst, src + str, len)) | |
311 | + return -EFAULT; | |
312 | + } else { | |
312 | 313 | u8 byte; |
313 | 314 | u32 i; |
314 | 315 | |
315 | 316 | |
316 | 317 | |
317 | 318 | |
318 | 319 | |
... | ... | @@ -316,22 +317,26 @@ |
316 | 317 | |
317 | 318 | for (i = 0; i < len; i++) { |
318 | 319 | byte = src[2 * i] ^ 0x80; |
319 | - __copy_to_user(dst + i, &byte, 1); | |
320 | + if (__copy_to_user(dst + i, &byte, 1)) | |
321 | + return -EFAULT; | |
320 | 322 | } |
321 | 323 | } |
324 | + | |
325 | + return 0; | |
322 | 326 | } |
323 | 327 | |
324 | -void emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 __user *data, u32 * size) | |
328 | +int emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 __user *data, u32 * size) | |
325 | 329 | { |
326 | 330 | struct wavein_buffer *buffer = &wiinst->buffer; |
327 | 331 | u32 sizetocopy, sizetocopy_now, start; |
328 | 332 | unsigned long flags; |
333 | + int ret; | |
329 | 334 | |
330 | 335 | sizetocopy = min_t(u32, buffer->size, *size); |
331 | 336 | *size = sizetocopy; |
332 | 337 | |
333 | 338 | if (!sizetocopy) |
334 | - return; | |
339 | + return 0; | |
335 | 340 | |
336 | 341 | spin_lock_irqsave(&wiinst->lock, flags); |
337 | 342 | start = buffer->pos; |
338 | 343 | |
339 | 344 | |
... | ... | @@ -345,11 +350,17 @@ |
345 | 350 | if (sizetocopy > sizetocopy_now) { |
346 | 351 | sizetocopy -= sizetocopy_now; |
347 | 352 | |
348 | - copy_block(data, buffer->addr, start, sizetocopy_now, buffer->cov); | |
349 | - copy_block(data + sizetocopy_now, buffer->addr, 0, sizetocopy, buffer->cov); | |
353 | + ret = copy_block(data, buffer->addr, start, sizetocopy_now, | |
354 | + buffer->cov); | |
355 | + if (ret == 0) | |
356 | + ret = copy_block(data + sizetocopy_now, buffer->addr, 0, | |
357 | + sizetocopy, buffer->cov); | |
350 | 358 | } else { |
351 | - copy_block(data, buffer->addr, start, sizetocopy, buffer->cov); | |
359 | + ret = copy_block(data, buffer->addr, start, sizetocopy, | |
360 | + buffer->cov); | |
352 | 361 | } |
362 | + | |
363 | + return ret; | |
353 | 364 | } |
354 | 365 | |
355 | 366 | void emu10k1_wavein_update(struct emu10k1_card *card, struct wiinst *wiinst) |
sound/oss/emu10k1/cardwi.h
... | ... | @@ -83,7 +83,7 @@ |
83 | 83 | void emu10k1_wavein_start(struct emu10k1_wavedevice *); |
84 | 84 | void emu10k1_wavein_stop(struct emu10k1_wavedevice *); |
85 | 85 | void emu10k1_wavein_getxfersize(struct wiinst *, u32 *); |
86 | -void emu10k1_wavein_xferdata(struct wiinst *, u8 __user *, u32 *); | |
86 | +int emu10k1_wavein_xferdata(struct wiinst *, u8 __user *, u32 *); | |
87 | 87 | int emu10k1_wavein_setformat(struct emu10k1_wavedevice *, struct wave_format *); |
88 | 88 | void emu10k1_wavein_update(struct emu10k1_card *, struct wiinst *); |
89 | 89 |
sound/oss/emu10k1/passthrough.c
... | ... | @@ -162,12 +162,15 @@ |
162 | 162 | |
163 | 163 | DPD(3, "prepend size %d, prepending %d bytes\n", pt->prepend_size, needed); |
164 | 164 | if (count < needed) { |
165 | - copy_from_user(pt->buf + pt->prepend_size, buffer, count); | |
165 | + if (copy_from_user(pt->buf + pt->prepend_size, | |
166 | + buffer, count)) | |
167 | + return -EFAULT; | |
166 | 168 | pt->prepend_size += count; |
167 | 169 | DPD(3, "prepend size now %d\n", pt->prepend_size); |
168 | 170 | return count; |
169 | 171 | } |
170 | - copy_from_user(pt->buf + pt->prepend_size, buffer, needed); | |
172 | + if (copy_from_user(pt->buf + pt->prepend_size, buffer, needed)) | |
173 | + return -EFAULT; | |
171 | 174 | r = pt_putblock(wave_dev, (u16 *) pt->buf, nonblock); |
172 | 175 | if (r) |
173 | 176 | return r; |
... | ... | @@ -178,7 +181,8 @@ |
178 | 181 | blocks_copied = 0; |
179 | 182 | while (blocks > 0) { |
180 | 183 | u16 __user *bufptr = (u16 __user *) buffer + (bytes_copied/2); |
181 | - copy_from_user(pt->buf, bufptr, PT_BLOCKSIZE); | |
184 | + if (copy_from_user(pt->buf, bufptr, PT_BLOCKSIZE)) | |
185 | + return -EFAULT; | |
182 | 186 | r = pt_putblock(wave_dev, (u16 *)pt->buf, nonblock); |
183 | 187 | if (r) { |
184 | 188 | if (bytes_copied) |
... | ... | @@ -193,7 +197,8 @@ |
193 | 197 | i = count - bytes_copied; |
194 | 198 | if (i) { |
195 | 199 | pt->prepend_size = i; |
196 | - copy_from_user(pt->buf, buffer + bytes_copied, i); | |
200 | + if (copy_from_user(pt->buf, buffer + bytes_copied, i)) | |
201 | + return -EFAULT; | |
197 | 202 | bytes_copied += i; |
198 | 203 | DPD(3, "filling prepend buffer with %d bytes", i); |
199 | 204 | } |