aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2017-01-24 18:18:24 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-02-01 02:33:02 -0500
commit544160b6ea18670196d1173c099f2cced5075132 (patch)
tree00d7e6913b506d6c1ee873a110a20350e9f9473d
parent09f886dc5a6945679ed35e6acfbc746f472f0f34 (diff)
fbdev: color map copying bounds checking
commit 2dc705a9930b4806250fbf5a76e55266e59389f2 upstream. Copying color maps to userspace doesn't check the value of to->start, which will cause kernel heap buffer OOB read due to signedness wraps. CVE-2016-8405 Link: http://lkml.kernel.org/r/20170105224249.GA50925@beast Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Kees Cook <keescook@chromium.org> Reported-by: Peter Pi (@heisecode) of Trend Micro Cc: Min Chong <mchong@google.com> Cc: Dan Carpenter <dan.carpenter@oracle.com> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com> Cc: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/video/fbdev/core/fbcmap.c26
1 files changed, 14 insertions, 12 deletions
diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c
index f89245b8ba8e..68a113594808 100644
--- a/drivers/video/fbdev/core/fbcmap.c
+++ b/drivers/video/fbdev/core/fbcmap.c
@@ -163,17 +163,18 @@ void fb_dealloc_cmap(struct fb_cmap *cmap)
163 163
164int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to) 164int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to)
165{ 165{
166 int tooff = 0, fromoff = 0; 166 unsigned int tooff = 0, fromoff = 0;
167 int size; 167 size_t size;
168 168
169 if (to->start > from->start) 169 if (to->start > from->start)
170 fromoff = to->start - from->start; 170 fromoff = to->start - from->start;
171 else 171 else
172 tooff = from->start - to->start; 172 tooff = from->start - to->start;
173 size = to->len - tooff; 173 if (fromoff >= from->len || tooff >= to->len)
174 if (size > (int) (from->len - fromoff)) 174 return -EINVAL;
175 size = from->len - fromoff; 175
176 if (size <= 0) 176 size = min_t(size_t, to->len - tooff, from->len - fromoff);
177 if (size == 0)
177 return -EINVAL; 178 return -EINVAL;
178 size *= sizeof(u16); 179 size *= sizeof(u16);
179 180
@@ -187,17 +188,18 @@ int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to)
187 188
188int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to) 189int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to)
189{ 190{
190 int tooff = 0, fromoff = 0; 191 unsigned int tooff = 0, fromoff = 0;
191 int size; 192 size_t size;
192 193
193 if (to->start > from->start) 194 if (to->start > from->start)
194 fromoff = to->start - from->start; 195 fromoff = to->start - from->start;
195 else 196 else
196 tooff = from->start - to->start; 197 tooff = from->start - to->start;
197 size = to->len - tooff; 198 if (fromoff >= from->len || tooff >= to->len)
198 if (size > (int) (from->len - fromoff)) 199 return -EINVAL;
199 size = from->len - fromoff; 200
200 if (size <= 0) 201 size = min_t(size_t, to->len - tooff, from->len - fromoff);
202 if (size == 0)
201 return -EINVAL; 203 return -EINVAL;
202 size *= sizeof(u16); 204 size *= sizeof(u16);
203 205