aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2018-07-12 18:29:36 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-07-16 04:04:11 -0400
commitb96fba8d5855c3617adbfb43ca4723a808cac954 (patch)
tree893160b3923fce357d34268d3b0bdcce6f2e91e3
parenteb37430d402de7d1cb2f37a5fdc80620dd98dc1d (diff)
staging: speakup: fix wraparound in uaccess length check
If softsynthx_read() is called with `count < 3`, `count - 3` wraps, causing the loop to copy as much data as available to the provided buffer. If softsynthx_read() is invoked through sys_splice(), this causes an unbounded kernel write; but even when userspace just reads from it normally, a small size could cause userspace crashes. Fixes: 425e586cf95b ("speakup: add unicode variant of /dev/softsynth") Cc: stable@vger.kernel.org Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> Signed-off-by: Jann Horn <jannh@google.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/staging/speakup/speakup_soft.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/drivers/staging/speakup/speakup_soft.c b/drivers/staging/speakup/speakup_soft.c
index a61bc41b82d7..947c79532e10 100644
--- a/drivers/staging/speakup/speakup_soft.c
+++ b/drivers/staging/speakup/speakup_soft.c
@@ -198,11 +198,15 @@ static ssize_t softsynthx_read(struct file *fp, char __user *buf, size_t count,
198 int chars_sent = 0; 198 int chars_sent = 0;
199 char __user *cp; 199 char __user *cp;
200 char *init; 200 char *init;
201 size_t bytes_per_ch = unicode ? 3 : 1;
201 u16 ch; 202 u16 ch;
202 int empty; 203 int empty;
203 unsigned long flags; 204 unsigned long flags;
204 DEFINE_WAIT(wait); 205 DEFINE_WAIT(wait);
205 206
207 if (count < bytes_per_ch)
208 return -EINVAL;
209
206 spin_lock_irqsave(&speakup_info.spinlock, flags); 210 spin_lock_irqsave(&speakup_info.spinlock, flags);
207 while (1) { 211 while (1) {
208 prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE); 212 prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE);
@@ -228,7 +232,7 @@ static ssize_t softsynthx_read(struct file *fp, char __user *buf, size_t count,
228 init = get_initstring(); 232 init = get_initstring();
229 233
230 /* Keep 3 bytes available for a 16bit UTF-8-encoded character */ 234 /* Keep 3 bytes available for a 16bit UTF-8-encoded character */
231 while (chars_sent <= count - 3) { 235 while (chars_sent <= count - bytes_per_ch) {
232 if (speakup_info.flushing) { 236 if (speakup_info.flushing) {
233 speakup_info.flushing = 0; 237 speakup_info.flushing = 0;
234 ch = '\x18'; 238 ch = '\x18';