
From: Kenneth Sumrall <ken@mvista.com>

In lp_write(), copy_from_user() is called to copy data into a statically
allocated kernel buffer before down_interruptible() is called.  If a second
thread of execution comes in between the copy_from_user() and the
down_interruptible() calls, silent data corruption could result.

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/drivers/char/lp.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

diff -puN drivers/char/lp.c~drivers-char-lpc-race-fix drivers/char/lp.c
--- 25/drivers/char/lp.c~drivers-char-lpc-race-fix	2005-03-07 20:41:39.000000000 -0800
+++ 25-akpm/drivers/char/lp.c	2005-03-07 20:41:39.000000000 -0800
@@ -314,12 +314,14 @@ static ssize_t lp_write(struct file * fi
 	if (copy_size > LP_BUFFER_SIZE)
 		copy_size = LP_BUFFER_SIZE;
 
-	if (copy_from_user (kbuf, buf, copy_size))
-		return -EFAULT;
-
 	if (down_interruptible (&lp_table[minor].port_mutex))
 		return -EINTR;
 
+	if (copy_from_user (kbuf, buf, copy_size)) {
+		retv = -EFAULT;
+		goto out_unlock;
+	}
+
  	/* Claim Parport or sleep until it becomes available
  	 */
 	lp_claim_parport_or_block (&lp_table[minor]);
@@ -398,7 +400,7 @@ static ssize_t lp_write(struct file * fi
 		lp_table[minor].current_mode = IEEE1284_MODE_COMPAT;
 		lp_release_parport (&lp_table[minor]);
 	}
-
+out_unlock:
 	up (&lp_table[minor].port_mutex);
 
  	return retv;
_
