diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-12-06 23:35:34 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-07 11:39:31 -0500 |
commit | e45f4676108d19ae93918f06cb6731c86108341a (patch) | |
tree | 66811c091d94f77697835e53d6d9b052af143982 | |
parent | 91046a8a693823d434f0aa70419c48ebeb8e1b11 (diff) |
[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>
-rw-r--r-- | sound/oss/emu10k1/audio.c | 8 | ||||
-rw-r--r-- | sound/oss/emu10k1/cardwi.c | 31 | ||||
-rw-r--r-- | sound/oss/emu10k1/cardwi.h | 2 | ||||
-rw-r--r-- | sound/oss/emu10k1/passthrough.c | 13 |
4 files changed, 38 insertions, 16 deletions
diff --git a/sound/oss/emu10k1/audio.c b/sound/oss/emu10k1/audio.c index 86dd23974e05..49f902f35c28 100644 --- a/sound/oss/emu10k1/audio.c +++ b/sound/oss/emu10k1/audio.c | |||
@@ -111,9 +111,15 @@ static ssize_t emu10k1_audio_read(struct file *file, char __user *buffer, size_t | |||
111 | 111 | ||
112 | if ((bytestocopy >= wiinst->buffer.fragment_size) | 112 | if ((bytestocopy >= wiinst->buffer.fragment_size) |
113 | || (bytestocopy >= count)) { | 113 | || (bytestocopy >= count)) { |
114 | int rc; | ||
115 | |||
114 | bytestocopy = min_t(u32, bytestocopy, count); | 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 | count -= bytestocopy; | 124 | count -= bytestocopy; |
119 | buffer += bytestocopy; | 125 | buffer += bytestocopy; |
diff --git a/sound/oss/emu10k1/cardwi.c b/sound/oss/emu10k1/cardwi.c index 8bbf44b881b4..060d1be94d33 100644 --- a/sound/oss/emu10k1/cardwi.c +++ b/sound/oss/emu10k1/cardwi.c | |||
@@ -304,11 +304,12 @@ void emu10k1_wavein_getxfersize(struct wiinst *wiinst, u32 * size) | |||
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) | 309 | if (cov == 1) { |
310 | __copy_to_user(dst, src + str, len); | 310 | if (__copy_to_user(dst, src + str, len)) |
311 | else { | 311 | return -EFAULT; |
312 | } else { | ||
312 | u8 byte; | 313 | u8 byte; |
313 | u32 i; | 314 | u32 i; |
314 | 315 | ||
@@ -316,22 +317,26 @@ static void copy_block(u8 __user *dst, u8 * src, u32 str, u32 len, u8 cov) | |||
316 | 317 | ||
317 | for (i = 0; i < len; i++) { | 318 | for (i = 0; i < len; i++) { |
318 | byte = src[2 * i] ^ 0x80; | 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 | struct wavein_buffer *buffer = &wiinst->buffer; | 330 | struct wavein_buffer *buffer = &wiinst->buffer; |
327 | u32 sizetocopy, sizetocopy_now, start; | 331 | u32 sizetocopy, sizetocopy_now, start; |
328 | unsigned long flags; | 332 | unsigned long flags; |
333 | int ret; | ||
329 | 334 | ||
330 | sizetocopy = min_t(u32, buffer->size, *size); | 335 | sizetocopy = min_t(u32, buffer->size, *size); |
331 | *size = sizetocopy; | 336 | *size = sizetocopy; |
332 | 337 | ||
333 | if (!sizetocopy) | 338 | if (!sizetocopy) |
334 | return; | 339 | return 0; |
335 | 340 | ||
336 | spin_lock_irqsave(&wiinst->lock, flags); | 341 | spin_lock_irqsave(&wiinst->lock, flags); |
337 | start = buffer->pos; | 342 | start = buffer->pos; |
@@ -345,11 +350,17 @@ void emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 __user *data, u32 * size) | |||
345 | if (sizetocopy > sizetocopy_now) { | 350 | if (sizetocopy > sizetocopy_now) { |
346 | sizetocopy -= sizetocopy_now; | 351 | sizetocopy -= sizetocopy_now; |
347 | 352 | ||
348 | copy_block(data, buffer->addr, start, sizetocopy_now, buffer->cov); | 353 | ret = copy_block(data, buffer->addr, start, sizetocopy_now, |
349 | copy_block(data + sizetocopy_now, buffer->addr, 0, sizetocopy, buffer->cov); | 354 | buffer->cov); |
355 | if (ret == 0) | ||
356 | ret = copy_block(data + sizetocopy_now, buffer->addr, 0, | ||
357 | sizetocopy, buffer->cov); | ||
350 | } else { | 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 | void emu10k1_wavein_update(struct emu10k1_card *card, struct wiinst *wiinst) | 366 | void emu10k1_wavein_update(struct emu10k1_card *card, struct wiinst *wiinst) |
diff --git a/sound/oss/emu10k1/cardwi.h b/sound/oss/emu10k1/cardwi.h index 15cfb9b35596..e82029b46ad1 100644 --- a/sound/oss/emu10k1/cardwi.h +++ b/sound/oss/emu10k1/cardwi.h | |||
@@ -83,7 +83,7 @@ void emu10k1_wavein_close(struct emu10k1_wavedevice *); | |||
83 | void emu10k1_wavein_start(struct emu10k1_wavedevice *); | 83 | void emu10k1_wavein_start(struct emu10k1_wavedevice *); |
84 | void emu10k1_wavein_stop(struct emu10k1_wavedevice *); | 84 | void emu10k1_wavein_stop(struct emu10k1_wavedevice *); |
85 | void emu10k1_wavein_getxfersize(struct wiinst *, u32 *); | 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 | int emu10k1_wavein_setformat(struct emu10k1_wavedevice *, struct wave_format *); | 87 | int emu10k1_wavein_setformat(struct emu10k1_wavedevice *, struct wave_format *); |
88 | void emu10k1_wavein_update(struct emu10k1_card *, struct wiinst *); | 88 | void emu10k1_wavein_update(struct emu10k1_card *, struct wiinst *); |
89 | 89 | ||
diff --git a/sound/oss/emu10k1/passthrough.c b/sound/oss/emu10k1/passthrough.c index 4e3baca7d41f..6d21d4368dec 100644 --- a/sound/oss/emu10k1/passthrough.c +++ b/sound/oss/emu10k1/passthrough.c | |||
@@ -162,12 +162,15 @@ ssize_t emu10k1_pt_write(struct file *file, const char __user *buffer, size_t co | |||
162 | 162 | ||
163 | DPD(3, "prepend size %d, prepending %d bytes\n", pt->prepend_size, needed); | 163 | DPD(3, "prepend size %d, prepending %d bytes\n", pt->prepend_size, needed); |
164 | if (count < needed) { | 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 | pt->prepend_size += count; | 168 | pt->prepend_size += count; |
167 | DPD(3, "prepend size now %d\n", pt->prepend_size); | 169 | DPD(3, "prepend size now %d\n", pt->prepend_size); |
168 | return count; | 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 | r = pt_putblock(wave_dev, (u16 *) pt->buf, nonblock); | 174 | r = pt_putblock(wave_dev, (u16 *) pt->buf, nonblock); |
172 | if (r) | 175 | if (r) |
173 | return r; | 176 | return r; |
@@ -178,7 +181,8 @@ ssize_t emu10k1_pt_write(struct file *file, const char __user *buffer, size_t co | |||
178 | blocks_copied = 0; | 181 | blocks_copied = 0; |
179 | while (blocks > 0) { | 182 | while (blocks > 0) { |
180 | u16 __user *bufptr = (u16 __user *) buffer + (bytes_copied/2); | 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 | r = pt_putblock(wave_dev, (u16 *)pt->buf, nonblock); | 186 | r = pt_putblock(wave_dev, (u16 *)pt->buf, nonblock); |
183 | if (r) { | 187 | if (r) { |
184 | if (bytes_copied) | 188 | if (bytes_copied) |
@@ -193,7 +197,8 @@ ssize_t emu10k1_pt_write(struct file *file, const char __user *buffer, size_t co | |||
193 | i = count - bytes_copied; | 197 | i = count - bytes_copied; |
194 | if (i) { | 198 | if (i) { |
195 | pt->prepend_size = i; | 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 | bytes_copied += i; | 202 | bytes_copied += i; |
198 | DPD(3, "filling prepend buffer with %d bytes", i); | 203 | DPD(3, "filling prepend buffer with %d bytes", i); |
199 | } | 204 | } |