diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2018-07-12 18:29:36 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-07-16 04:04:11 -0400 |
commit | b96fba8d5855c3617adbfb43ca4723a808cac954 (patch) | |
tree | 893160b3923fce357d34268d3b0bdcce6f2e91e3 | |
parent | eb37430d402de7d1cb2f37a5fdc80620dd98dc1d (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.c | 6 |
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'; |