diff options
author | Kees Cook <keescook@chromium.org> | 2017-01-24 18:18:24 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-02-01 02:33:02 -0500 |
commit | 544160b6ea18670196d1173c099f2cced5075132 (patch) | |
tree | 00d7e6913b506d6c1ee873a110a20350e9f9473d | |
parent | 09f886dc5a6945679ed35e6acfbc746f472f0f34 (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.c | 26 |
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 | ||
164 | int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to) | 164 | int 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 | ||
188 | int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to) | 189 | int 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 | ||