[poky,zeus] qemu: CVE-2020-12829

Submitted by Li Wang on Sept. 22, 2020, 2:35 a.m. | Patch ID: 176686

Details

Message ID 20200922023518.9926-1-li.wang@windriver.com
State New
Headers show

Commit Message

Li Wang Sept. 22, 2020, 2:35 a.m.
Backport CVE patch from the upstream:
https://git.qemu.org/?p=qemu.git;a=commit;h=b15a22bbcbe6a78dc3d88fe3134985e4cdd87de4

Signed-off-by: Li Wang <li.wang@windriver.com>
---
 meta/recipes-devtools/qemu/qemu.inc           |   1 +
 .../qemu/qemu/CVE-2020-12829.patch            | 267 ++++++++++++++++++
 2 files changed, 268 insertions(+)
 create mode 100644 meta/recipes-devtools/qemu/qemu/CVE-2020-12829.patch

Patch hide | download patch | download mbox

diff --git a/meta/recipes-devtools/qemu/qemu.inc b/meta/recipes-devtools/qemu/qemu.inc
index ec32c90ad5..cbade92ac9 100644
--- a/meta/recipes-devtools/qemu/qemu.inc
+++ b/meta/recipes-devtools/qemu/qemu.inc
@@ -43,6 +43,7 @@  SRC_URI = "https://download.qemu.org/${BPN}-${PV}.tar.xz \
            file://CVE-2020-10756.patch \
            file://CVE-2020-15863.patch \
            file://CVE-2020-14364.patch \
+           file://CVE-2020-12829.patch \
 	   "
 UPSTREAM_CHECK_REGEX = "qemu-(?P<pver>\d+(\.\d+)+)\.tar"
 
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-12829.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829.patch
new file mode 100644
index 0000000000..46e494dec0
--- /dev/null
+++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829.patch
@@ -0,0 +1,267 @@ 
+From b15a22bbcbe6a78dc3d88fe3134985e4cdd87de4 Mon Sep 17 00:00:00 2001
+From: BALATON Zoltan <balaton@eik.bme.hu>
+Date: Thu, 21 May 2020 21:39:44 +0200
+Subject: [PATCH] sm501: Replace hand written implementation with pixman
+where possible
+
+Besides being faster this should also prevent malicious guests to
+abuse 2D engine to overwrite data or cause a crash.
+
+Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
+Message-id:
+58666389b6cae256e4e972a32c05cf8aa51bffc0.1590089984.git.balaton@eik.bme.hu
+Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
+
+Upstream-Status: Backport
+CVE: CVE-2020-12829
+[https://git.qemu.org/?p=qemu.git;a=commit;h=b15a22bbcbe6a78dc3d88fe3134985e4cdd87de4]
+Signed-off-by: Li Wang <li.wang@windriver.com>
+---
+ hw/display/sm501.c | 205 ++++++++++++++++++++++++++-------------------
+ 1 file changed, 118 insertions(+), 87 deletions(-)
+
+diff --git a/hw/display/sm501.c b/hw/display/sm501.c
+index 5918f59..b52c7e8 100644
+--- a/hw/display/sm501.c
++++ b/hw/display/sm501.c
+@@ -702,12 +702,12 @@ static void sm501_2d_operation(SM501State *s)
+     /* obtain operation parameters */
+     int operation = (s->twoD_control >> 16) & 0x1f;
+     int rtl = s->twoD_control & 0x8000000;
+-    int src_x = (s->twoD_source >> 16) & 0x01FFF;
+-    int src_y = s->twoD_source & 0xFFFF;
+-    int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
+-    int dst_y = s->twoD_destination & 0xFFFF;
+-    int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
+-    int operation_height = s->twoD_dimension & 0xFFFF;
++    unsigned int src_x = (s->twoD_source >> 16) & 0x01FFF;
++    unsigned int src_y = s->twoD_source & 0xFFFF;
++    unsigned int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
++    unsigned int dst_y = s->twoD_destination & 0xFFFF;
++    unsigned int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
++    unsigned int operation_height = s->twoD_dimension & 0xFFFF;
+     uint32_t color = s->twoD_foreground;
+     int format_flags = (s->twoD_stretch >> 20) & 0x3;
+     int addressing = (s->twoD_stretch >> 16) & 0xF;
+@@ -719,10 +719,8 @@ static void sm501_2d_operation(SM501State *s)
+     uint32_t dst_base = s->twoD_destination_base & 0x03FFFFFF;
+ 
+     /* get frame buffer info */
+-    uint8_t *src = s->local_mem + src_base;
+-    uint8_t *dst = s->local_mem + dst_base;
+-    int src_width = s->twoD_pitch & 0x1FFF;
+-    int dst_width = (s->twoD_pitch >> 16) & 0x1FFF;
++    unsigned int src_width = s->twoD_pitch & 0x1FFF;
++    unsigned int dst_width = (s->twoD_pitch >> 16) & 0x1FFF;
+     int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0;
+     int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt);
+ 
+@@ -731,95 +729,128 @@ static void sm501_2d_operation(SM501State *s)
+         abort();
+     }
+ 
+-    if (rop_mode == 0) {
+-        if (rop != 0xcc) {
+-            /* Anything other than plain copies are not supported */
+-            qemu_log_mask(LOG_UNIMP, "sm501: rop3 mode with rop %x is not "
+-                          "supported.\n", rop);
+-        }
+-    } else {
+-        if (rop2_source_is_pattern && rop != 0x5) {
+-            /* For pattern source, we support only inverse dest */
+-            qemu_log_mask(LOG_UNIMP, "sm501: rop2 source being the pattern and "
+-                          "rop %x is not supported.\n", rop);
+-        } else {
+-            if (rop != 0x5 && rop != 0xc) {
+-                /* Anything other than plain copies or inverse dest is not
+-                 * supported */
+-                qemu_log_mask(LOG_UNIMP, "sm501: rop mode %x is not "
+-                              "supported.\n", rop);
+-            }
+-        }
+-    }
+-
+     if ((s->twoD_source_base & 0x08000000) ||
+         (s->twoD_destination_base & 0x08000000)) {
+         printf("%s: only local memory is supported.\n", __func__);
+         abort();
+     }
+ 
+-    switch (operation) {
+-    case 0x00: /* copy area */
+-#define COPY_AREA(_bpp, _pixel_type, rtl) {                                   \
+-        int y, x, index_d, index_s;                                           \
+-        for (y = 0; y < operation_height; y++) {                              \
+-            for (x = 0; x < operation_width; x++) {                           \
+-                _pixel_type val;                                              \
+-                                                                              \
+-                if (rtl) {                                                    \
+-                    index_s = ((src_y - y) * src_width + src_x - x) * _bpp;   \
+-                    index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp;   \
+-                } else {                                                      \
+-                    index_s = ((src_y + y) * src_width + src_x + x) * _bpp;   \
+-                    index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp;   \
+-                }                                                             \
+-                if (rop_mode == 1 && rop == 5) {                              \
+-                    /* Invert dest */                                         \
+-                    val = ~*(_pixel_type *)&dst[index_d];                     \
+-                } else {                                                      \
+-                    val = *(_pixel_type *)&src[index_s];                      \
+-                }                                                             \
+-                *(_pixel_type *)&dst[index_d] = val;                          \
+-            }                                                                 \
+-        }                                                                     \
++    if (!dst_width) {
++        qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero dest pitch.\n");
++        return;
+     }
+-        switch (format_flags) {
+-        case 0:
+-            COPY_AREA(1, uint8_t, rtl);
+-            break;
+-        case 1:
+-            COPY_AREA(2, uint16_t, rtl);
+-            break;
+-        case 2:
+-            COPY_AREA(4, uint32_t, rtl);
+-            break;
+-        }
+-        break;
+ 
+-    case 0x01: /* fill rectangle */
+-#define FILL_RECT(_bpp, _pixel_type) {                                      \
+-        int y, x;                                                           \
+-        for (y = 0; y < operation_height; y++) {                            \
+-            for (x = 0; x < operation_width; x++) {                         \
+-                int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp;   \
+-                *(_pixel_type *)&dst[index] = (_pixel_type)color;           \
+-            }                                                               \
+-        }                                                                   \
++    if (!operation_width || !operation_height) {
++        qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero size 2D op.\n");
++        return;
+     }
+ 
+-        switch (format_flags) {
+-        case 0:
+-            FILL_RECT(1, uint8_t);
+-            break;
+-        case 1:
+-            color = cpu_to_le16(color);
+-            FILL_RECT(2, uint16_t);
+-            break;
+-        case 2:
++    if (rtl) {
++        dst_x -= operation_width - 1;
++        dst_y -= operation_height - 1;
++    }
++
++    if (dst_base >= get_local_mem_size(s) || dst_base +
++        (dst_x + operation_width + (dst_y + operation_height) * (dst_width + operation_width)) *
++        (1 << format_flags) >= get_local_mem_size(s)) {
++        qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op dest is outside vram.\n");
++        return;
++    }
++
++    switch (operation) {
++    case 0: /* BitBlt */
++        if (!src_width) {
++            qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero src pitch.\n");
++            return;
++        }
++
++        if (rtl) {
++            src_x -= operation_width - 1;
++            src_y -= operation_height - 1;
++        }
++
++        if (src_base >= get_local_mem_size(s) || src_base +
++            (src_x + operation_width + (src_y + operation_height) * (src_width + operation_width)) *
++            (1 << format_flags) >= get_local_mem_size(s)) {
++            qemu_log_mask(LOG_GUEST_ERROR,
++                          "sm501: 2D op src is outside vram.\n");
++            return;
++        }
++
++        if ((rop_mode && rop == 0x5) || (!rop_mode && rop == 0x55)) {
++            /* Invert dest, is there a way to do this with pixman? */
++            unsigned int x, y, i;
++            uint8_t *d = s->local_mem + dst_base;
++
++            for (y = 0; y < operation_height; y++) {
++                i = (dst_x + (dst_y + y) * dst_width) * (1 << format_flags);
++                for (x = 0; x < operation_width; x++, i += (1 << format_flags)) {
++                    switch (format_flags) {
++                    case 0:
++                        d[i] = ~d[i];
++                        break;
++                    case 1:
++                        *(uint16_t *)&d[i] = ~*(uint16_t *)&d[i];
++                        break;
++                    case 2:
++                        *(uint32_t *)&d[i] = ~*(uint32_t *)&d[i];
++                        break;
++                    }
++                }
++            }
++        } else {
++            /* Do copy src for unimplemented ops, better than unpainted area */
++            if ((rop_mode && (rop != 0xc || rop2_source_is_pattern)) ||
++                (!rop_mode && rop != 0xcc)) {
++                qemu_log_mask(LOG_UNIMP,
++                              "sm501: rop%d op %x%s not implemented\n",
++                              (rop_mode ? 2 : 3), rop,
++                              (rop2_source_is_pattern ?
++                                  " with pattern source" : ""));
++            }
++            /* Check for overlaps, this could be made more exact */
++            uint32_t sb, se, db, de;
++            sb = src_base + src_x + src_y * (operation_width + src_width);
++            se = sb + operation_width + operation_height * (operation_width + src_width);
++            db = dst_base + dst_x + dst_y * (operation_width + dst_width);
++            de = db + operation_width + operation_height * (operation_width + dst_width);
++            if (rtl && ((db >= sb && db <= se) || (de >= sb && de <= se))) {
++                /* regions may overlap: copy via temporary */
++                int llb = operation_width * (1 << format_flags);
++                int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t));
++                uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) *
++                                         operation_height);
++                pixman_blt((uint32_t *)&s->local_mem[src_base], tmp,
++                           src_width * (1 << format_flags) / sizeof(uint32_t),
++                           tmp_stride, 8 * (1 << format_flags), 8 * (1 << format_flags),
++                           src_x, src_y, 0, 0, operation_width, operation_height);
++                pixman_blt(tmp, (uint32_t *)&s->local_mem[dst_base],
++                           tmp_stride,
++                           dst_width * (1 << format_flags) / sizeof(uint32_t),
++                           8 * (1 << format_flags), 8 * (1 << format_flags),
++                           0, 0, dst_x, dst_y, operation_width, operation_height);
++                g_free(tmp);
++            } else {
++                pixman_blt((uint32_t *)&s->local_mem[src_base],
++                           (uint32_t *)&s->local_mem[dst_base],
++                           src_width * (1 << format_flags) / sizeof(uint32_t),
++                           dst_width * (1 << format_flags) / sizeof(uint32_t),
++                           8 * (1 << format_flags), 8 * (1 << format_flags),
++                           src_x, src_y, dst_x, dst_y, operation_width, operation_height);
++            }
++        }
++        break;
++
++    case 1: /* Rectangle Fill */
++        if (format_flags == 2) {
+             color = cpu_to_le32(color);
+-            FILL_RECT(4, uint32_t);
+-            break;
++        } else if (format_flags == 1) {
++            color = cpu_to_le16(color);
+         }
++
++        pixman_fill((uint32_t *)&s->local_mem[dst_base],
++                    dst_width * (1 << format_flags) / sizeof(uint32_t),
++                    8 * (1 << format_flags), dst_x, dst_y, operation_width, operation_height, color);
+         break;
+ 
+     default:
+-- 
+2.17.1
+