Bug 1599168 (CVE-2018-13406) - CVE-2018-13406 kernel: Integer overflow in drivers/video/fbdev/uvesafb.c:uvesafb_setcmap() allows for potential denial of service
Summary: CVE-2018-13406 kernel: Integer overflow in drivers/video/fbdev/uvesafb.c:uves...
Status: CLOSED NOTABUG
Alias: CVE-2018-13406
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Red Hat Product Security
QA Contact:
URL:
Whiteboard: impact=none,public=20180706,reported=...
Keywords: Security
Depends On: 1599169 1599170
Blocks: 1599177
TreeView+ depends on / blocked
 
Reported: 2018-07-09 06:11 UTC by Sam Fowler
Modified: 2019-06-08 23:00 UTC (History)
50 users (show)

(edit)
The Linux kernel was found vulnerable to an integer overflow in the drivers/video/fbdev/uvesafb.c:uvesafb_setcmap() function. The vulnerability could result in local attackers being able to crash the kernel or potentially elevate privileges.
Clone Of:
(edit)
Last Closed: 2018-08-03 12:04:01 UTC


Attachments (Terms of Use)

Description Sam Fowler 2018-07-09 06:11:34 UTC
The Linux kernel was found vulnerable to an integer overflow in the drivers/video/fbdev/uvesafb.c:uvesafb_setcmap() function that could result in local attackers being able to crash the kernel or potentially elevate privileges.

References:

https://cdn.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.17.4

An upstream patch:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9f645bcc566a1e9f921bdae7528a01ced5bc3713

Comment 1 Sam Fowler 2018-07-09 06:12:37 UTC
Created kernel tracking bugs for this issue:

Affects: fedora-all [bug 1599169]

Comment 5 Vladis Dronov 2018-08-03 12:04:01 UTC
Notes:

the flaw is not triggerable in the Red Hat products.

1) an attacker must be able to do ioctl() to /dev/fb0 and most probably he can not due to the permissions. namespaces or containers won't help attacker with this.

$ ls -l /dev/fb0
crw-rw---- 1 root video 29, 0 Jul 28 19:35 /dev/fb0

2) for the overflow to happen size_t must be 32-bit, as cmap->len is __u32:

[include/uapi/linux/fb.h]
struct fb_cmap {
        __u32 start;                    /* First entry  */
        __u32 len;                      /* Number of entries */

and kmalloc() accepts size_t and type of sizeof() is size_t too:

void *kmalloc(size_t size, gfp_t flags)

[drivers/video/fbdev/uvesafb.c]
entries = kmalloc(sizeof(*entries) * cmap->len, GFP_KERNEL);

if size_t is 64-bit then multiplication is also 64-bit and there is no overflow. this means that only 32-bit systems are vulnerable.

3) even with a 32-bit system there is a check in fb_set_user_cmap():

[drivers/video/fbdev/core/fbcmap.c]
int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
{
        int rc, size = cmap->len * sizeof(u16);
        if (size < 0 || size < cmap->len)
                return -E2BIG;

this especially limits cmap->len to be less-or-equal to UINT_MAX/4 i.e. 0x3fffffff. so later when multipying it to sizeof(*entries) == 4 it can be as maximum as:

3FFFFFFF * 4 = FFFFFFFC i.e. no 32-bit overflow.

4) the check above is from the upstream commit 1e7c7804884fc which is present since v2.6.37-rc4 and so is present in all versions of RHEL-7 and later but not in RHEL-6.

still, fb_set_user_cmap() calls fb_alloc_cmap():

[drivers/video/fbcmap.c]
int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
{
        int rc, size = cmap->len * sizeof(u16);
        rc = fb_alloc_cmap(&umap, cmap->len, cmap->transp != NULL);

int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
{
    int size = len*sizeof(u16);
    if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
        goto fail;

and kmalloc() will fail for the sizes > 32 Mb (theoretically) and > 2^22 = 4Mb (in practice):

[include/linux/slab.h]
/* The largest kmalloc size supported by the slab allocators is
   32 megabyte (2^25) or the maximum allocatable page order if that is
   less than 32 MB. */
#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? \
                           (MAX_ORDER + PAGE_SHIFT - 1) : 25)
#define KMALLOC_MAX_SIZE (1UL << KMALLOC_SHIFT_HIGH)

[include/linux/mmzone.h]
#ifndef CONFIG_FORCE_MAX_ZONEORDER
#define MAX_ORDER 11
#else
#define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER
#endif

$ grep CONFIG_FORCE_MAX_ZONEORDER *
config-2.6.32-754.el6.ppc64:CONFIG_FORCE_MAX_ZONEORDER=9
config-2.6.32-754.el6.s390x:CONFIG_FORCE_MAX_ZONEORDER=9

Comment 6 Hans de Goede 2018-08-04 10:40:18 UTC
Note that for Fedora the long analysis is not needed, Fedora is not vulnerable because the uvesafb driver is not enabled:

[hans@shalem ~]$ grep CONFIG_FB_UVESA /boot/config-4.18.0-0.rc7.git1.1.fc29.x86_64
# CONFIG_FB_UVESA is not set


Note You need to log in before you can comment on or make changes to this bug.