Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e45f4676 authored by Jeff Garzik's avatar Jeff Garzik Committed by Linus Torvalds
Browse files

[PATCH] sound/oss/emu10k1: handle userspace copy errors



Propagate copy_to/from_user() errors back through callers.

Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 91046a8a
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -111,9 +111,15 @@ static ssize_t emu10k1_audio_read(struct file *file, char __user *buffer, size_t

		if ((bytestocopy >= wiinst->buffer.fragment_size)
		    || (bytestocopy >= count)) {
			int rc;

			bytestocopy = min_t(u32, bytestocopy, count);

			emu10k1_wavein_xferdata(wiinst, (u8 __user *)buffer, &bytestocopy);
			rc = emu10k1_wavein_xferdata(wiinst,
						     (u8 __user *)buffer,
						     &bytestocopy);
			if (rc)
				return rc;

			count -= bytestocopy;
			buffer += bytestocopy;
+21 −10
Original line number Diff line number Diff line
@@ -304,11 +304,12 @@ void emu10k1_wavein_getxfersize(struct wiinst *wiinst, u32 * size)
	}
}

static void copy_block(u8 __user *dst, u8 * src, u32 str, u32 len, u8 cov)
static int copy_block(u8 __user *dst, u8 * src, u32 str, u32 len, u8 cov)
{
	if (cov == 1)
		__copy_to_user(dst, src + str, len);
	else {
	if (cov == 1) {
		if (__copy_to_user(dst, src + str, len))
			return -EFAULT;
	} else {
		u8 byte;
		u32 i;

@@ -316,22 +317,26 @@ static void copy_block(u8 __user *dst, u8 * src, u32 str, u32 len, u8 cov)

		for (i = 0; i < len; i++) {
			byte = src[2 * i] ^ 0x80;
			__copy_to_user(dst + i, &byte, 1);
			if (__copy_to_user(dst + i, &byte, 1))
				return -EFAULT;
		}
	}

	return 0;
}

void emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 __user *data, u32 * size)
int emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 __user *data, u32 * size)
{
	struct wavein_buffer *buffer = &wiinst->buffer;
	u32 sizetocopy, sizetocopy_now, start;
	unsigned long flags;
	int ret;

	sizetocopy = min_t(u32, buffer->size, *size);
	*size = sizetocopy;

	if (!sizetocopy)
		return;
		return 0;

	spin_lock_irqsave(&wiinst->lock, flags);
	start = buffer->pos;
@@ -345,11 +350,17 @@ void emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 __user *data, u32 * size)
	if (sizetocopy > sizetocopy_now) {
		sizetocopy -= sizetocopy_now;

		copy_block(data, buffer->addr, start, sizetocopy_now, buffer->cov);
		copy_block(data + sizetocopy_now, buffer->addr, 0, sizetocopy, buffer->cov);
		ret = copy_block(data, buffer->addr, start, sizetocopy_now,
				 buffer->cov);
		if (ret == 0)
			ret = copy_block(data + sizetocopy_now, buffer->addr, 0,
					 sizetocopy, buffer->cov);
	} else {
		copy_block(data, buffer->addr, start, sizetocopy, buffer->cov);
		ret = copy_block(data, buffer->addr, start, sizetocopy,
				 buffer->cov);
	}

	return ret;
}

void emu10k1_wavein_update(struct emu10k1_card *card, struct wiinst *wiinst)
+1 −1
Original line number Diff line number Diff line
@@ -83,7 +83,7 @@ void emu10k1_wavein_close(struct emu10k1_wavedevice *);
void emu10k1_wavein_start(struct emu10k1_wavedevice *);
void emu10k1_wavein_stop(struct emu10k1_wavedevice *);
void emu10k1_wavein_getxfersize(struct wiinst *, u32 *);
void emu10k1_wavein_xferdata(struct wiinst *, u8 __user *, u32 *);
int emu10k1_wavein_xferdata(struct wiinst *, u8 __user *, u32 *);
int emu10k1_wavein_setformat(struct emu10k1_wavedevice *, struct wave_format *);
void emu10k1_wavein_update(struct emu10k1_card *, struct wiinst *);

+9 −4
Original line number Diff line number Diff line
@@ -162,12 +162,15 @@ ssize_t emu10k1_pt_write(struct file *file, const char __user *buffer, size_t co

		DPD(3, "prepend size %d, prepending %d bytes\n", pt->prepend_size, needed);
		if (count < needed) {
			copy_from_user(pt->buf + pt->prepend_size, buffer, count);
			if (copy_from_user(pt->buf + pt->prepend_size,
					   buffer, count))
				return -EFAULT;
			pt->prepend_size += count;
			DPD(3, "prepend size now %d\n", pt->prepend_size);
			return count;
		}
		copy_from_user(pt->buf + pt->prepend_size, buffer, needed);
		if (copy_from_user(pt->buf + pt->prepend_size, buffer, needed))
			return -EFAULT;
		r = pt_putblock(wave_dev, (u16 *) pt->buf, nonblock);
		if (r)
			return r;
@@ -178,7 +181,8 @@ ssize_t emu10k1_pt_write(struct file *file, const char __user *buffer, size_t co
	blocks_copied = 0;
	while (blocks > 0) {
		u16 __user *bufptr = (u16 __user *) buffer + (bytes_copied/2);
		copy_from_user(pt->buf, bufptr, PT_BLOCKSIZE);
		if (copy_from_user(pt->buf, bufptr, PT_BLOCKSIZE))
			return -EFAULT;
		r = pt_putblock(wave_dev, (u16 *)pt->buf, nonblock);
		if (r) {
			if (bytes_copied)
@@ -193,7 +197,8 @@ ssize_t emu10k1_pt_write(struct file *file, const char __user *buffer, size_t co
	i = count - bytes_copied;
	if (i) {
		pt->prepend_size = i;
		copy_from_user(pt->buf, buffer + bytes_copied, i);
		if (copy_from_user(pt->buf, buffer + bytes_copied, i))
			return -EFAULT;
		bytes_copied += i;
		DPD(3, "filling prepend buffer with %d bytes", i);
	}