Commit b96fba8d authored by Samuel Thibault's avatar Samuel Thibault Committed by Greg Kroah-Hartman

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: 425e586c ("speakup: add unicode variant of /dev/softsynth")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarSamuel Thibault <samuel.thibault@ens-lyon.org>
Signed-off-by: default avatarJann Horn <jannh@google.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent eb37430d
...@@ -198,11 +198,15 @@ static ssize_t softsynthx_read(struct file *fp, char __user *buf, size_t count, ...@@ -198,11 +198,15 @@ static ssize_t softsynthx_read(struct file *fp, char __user *buf, size_t count,
int chars_sent = 0; int chars_sent = 0;
char __user *cp; char __user *cp;
char *init; char *init;
size_t bytes_per_ch = unicode ? 3 : 1;
u16 ch; u16 ch;
int empty; int empty;
unsigned long flags; unsigned long flags;
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
if (count < bytes_per_ch)
return -EINVAL;
spin_lock_irqsave(&speakup_info.spinlock, flags); spin_lock_irqsave(&speakup_info.spinlock, flags);
while (1) { while (1) {
prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE); 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,7 +232,7 @@ static ssize_t softsynthx_read(struct file *fp, char __user *buf, size_t count,
init = get_initstring(); init = get_initstring();
/* Keep 3 bytes available for a 16bit UTF-8-encoded character */ /* Keep 3 bytes available for a 16bit UTF-8-encoded character */
while (chars_sent <= count - 3) { while (chars_sent <= count - bytes_per_ch) {
if (speakup_info.flushing) { if (speakup_info.flushing) {
speakup_info.flushing = 0; speakup_info.flushing = 0;
ch = '\x18'; ch = '\x18';
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment