* [PATCH 0/3] hw/display/artist: Fix out-of-buffer accesses found while fuzzing
@ 2020-05-23 19:15 Philippe Mathieu-Daudé
2020-05-23 19:15 ` [PATCH 1/3] hw/display/artist: Check offset in draw_line to avoid buffer over-run Philippe Mathieu-Daudé
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-05-23 19:15 UTC (permalink / raw)
To: Helge Deller, qemu-devel, Richard Henderson, Sven Schnelle
Cc: Alexander Bulekov, Philippe Mathieu-Daudé
Fix various out-of-range buffer access in the artist device
emulation. Bugs found using libFuzzer (docs/devel/fuzzing.txt).
Philippe Mathieu-Daudé (3):
hw/display/artist: Check offset in draw_line to avoid buffer over-run
hw/display/artist: Refactor artist_rop8() to avoid buffer over-run
hw/display/artist: Check offset in block_move to avoid buffer
over-read
hw/display/artist.c | 54 +++++++++++++++++++++++++++++++--------------
1 file changed, 37 insertions(+), 17 deletions(-)
--
2.21.3
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/3] hw/display/artist: Check offset in draw_line to avoid buffer over-run
2020-05-23 19:15 [PATCH 0/3] hw/display/artist: Fix out-of-buffer accesses found while fuzzing Philippe Mathieu-Daudé
@ 2020-05-23 19:15 ` Philippe Mathieu-Daudé
2020-05-23 19:15 ` [PATCH 2/3] hw/display/artist: Refactor artist_rop8() " Philippe Mathieu-Daudé
2020-05-23 19:15 ` [PATCH 3/3] hw/display/artist: Check offset in block_move to avoid buffer over-read Philippe Mathieu-Daudé
2 siblings, 0 replies; 4+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-05-23 19:15 UTC (permalink / raw)
To: Helge Deller, qemu-devel, Richard Henderson, Sven Schnelle
Cc: Alexander Bulekov, Philippe Mathieu-Daudé
Invalid I/O writes can craft an offset out of the vram_buffer
range.
We avoid:
Program terminated with signal SIGSEGV, Segmentation fault.
284 *dst &= ~plane_mask;
(gdb) bt
#0 0x000055d5dccdc5c0 in artist_rop8 (s=0x55d5defee510, dst=0x7f8e84ed8216 <error: Cannot access memory at address 0x7f8e84ed8216>, val=0 '\000') at hw/display/artist.c:284
#1 0x000055d5dccdcf83 in fill_window (s=0x55d5defee510, startx=22, starty=5674, width=65, height=5697) at hw/display/artist.c:551
#2 0x000055d5dccddfb9 in artist_reg_write (opaque=0x55d5defee510, addr=1051140, val=4265537, size=4) at hw/display/artist.c:902
#3 0x000055d5dcb42a7c in memory_region_write_accessor (mr=0x55d5defeea10, addr=1051140, value=0x7ffe57db08c8, size=4, shift=0, mask=4294967295, attrs=...) at memory.c:483
Reported-by: LLVM libFuzzer
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
hw/display/artist.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/hw/display/artist.c b/hw/display/artist.c
index 6261bfe65b..3c2550f6db 100644
--- a/hw/display/artist.c
+++ b/hw/display/artist.c
@@ -557,7 +557,7 @@ static void fill_window(ARTISTState *s, int startx, int starty,
static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2,
bool update_start, int skip_pix, int max_pix)
{
- struct vram_buffer *buf;
+ struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
uint8_t color;
int dx, dy, t, e, x, y, incy, diago, horiz;
bool c1;
@@ -565,6 +565,12 @@ static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2,
trace_artist_draw_line(x1, y1, x2, y2);
+ if (x1 * y1 >= buf->size || x2 * y2 >= buf->size) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "draw_line (%d,%d) (%d,%d)\n", x1, y1, x2, y2);
+ return;
+ }
+
if (update_start) {
s->vram_start = (x2 << 16) | y2;
}
@@ -622,7 +628,6 @@ static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2,
x = x1;
y = y1;
color = artist_get_color(s);
- buf = &s->vram_buffer[ARTIST_BUFFER_AP];
do {
if (c1) {
--
2.21.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/3] hw/display/artist: Refactor artist_rop8() to avoid buffer over-run
2020-05-23 19:15 [PATCH 0/3] hw/display/artist: Fix out-of-buffer accesses found while fuzzing Philippe Mathieu-Daudé
2020-05-23 19:15 ` [PATCH 1/3] hw/display/artist: Check offset in draw_line to avoid buffer over-run Philippe Mathieu-Daudé
@ 2020-05-23 19:15 ` Philippe Mathieu-Daudé
2020-05-23 19:15 ` [PATCH 3/3] hw/display/artist: Check offset in block_move to avoid buffer over-read Philippe Mathieu-Daudé
2 siblings, 0 replies; 4+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-05-23 19:15 UTC (permalink / raw)
To: Helge Deller, qemu-devel, Richard Henderson, Sven Schnelle
Cc: Alexander Bulekov, Philippe Mathieu-Daudé
Invalid I/O writes can craft an offset out of the vram_buffer
range.
Instead of passing an unsafe pointer to artist_rop8(), pass the
vram_buffer and the offset. We can now check if the offset is
in range before accessing it.
We avoid:
Program terminated with signal SIGSEGV, Segmentation fault.
284 *dst &= ~plane_mask;
(gdb) bt
#0 0x000056367b2085c0 in artist_rop8 (s=0x56367d38b510, dst=0x7f9f972fffff <error: Cannot access memory at address 0x7f9f972fffff>, val=0 '\000') at hw/display/artist.c:284
#1 0x000056367b209325 in draw_line (s=0x56367d38b510, x1=-20480, y1=-1, x2=0, y2=17920, update_start=true, skip_pix=-1, max_pix=-1) at hw/display/artist.c:646
Reported-by: LLVM libFuzzer
Buglink: https://bugs.launchpad.net/qemu/+bug/1880326
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
hw/display/artist.c | 40 +++++++++++++++++++++++++---------------
1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/hw/display/artist.c b/hw/display/artist.c
index 3c2550f6db..6f61b85a24 100644
--- a/hw/display/artist.c
+++ b/hw/display/artist.c
@@ -273,11 +273,20 @@ static artist_rop_t artist_get_op(ARTISTState *s)
return (s->image_bitmap_op >> 8) & 0xf;
}
-static void artist_rop8(ARTISTState *s, uint8_t *dst, uint8_t val)
+static void artist_rop8(ARTISTState *s, struct vram_buffer *buf,
+ int offset, uint8_t val)
{
-
const artist_rop_t op = artist_get_op(s);
- uint8_t plane_mask = s->plane_mask & 0xff;
+ uint8_t plane_mask;
+ uint8_t *dst;
+
+ if (offset < 0 || offset >= buf->size) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "rop8 offset:%d bufsize:%u\n", offset, buf->size);
+ return;
+ }
+ dst = buf->data + offset;
+ plane_mask = s->plane_mask & 0xff;
switch (op) {
case ARTIST_ROP_CLEAR:
@@ -381,7 +390,7 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x,
}
for (i = 0; i < pix_count; i++) {
- artist_rop8(s, p + offset + pix_count - 1 - i,
+ artist_rop8(s, buf, offset + pix_count - 1 - i,
(data & 1) ? (s->plane_mask >> 24) : 0);
data >>= 1;
}
@@ -398,7 +407,7 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x,
for (i = 3; i >= 0; i--) {
if (!(s->image_bitmap_op & 0x20000000) ||
s->vram_bitmask & (1 << (28 + i))) {
- artist_rop8(s, p + offset + 3 - i, data8[ROP8OFF(i)]);
+ artist_rop8(s, buf, offset + 3 - i, data8[ROP8OFF(i)]);
}
}
memory_region_set_dirty(&buf->mr, offset, 3);
@@ -426,10 +435,10 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x,
if (!(s->image_bitmap_op & 0x20000000) ||
(vram_bitmask & mask)) {
if (data & mask) {
- artist_rop8(s, p + offset + i, s->fg_color);
+ artist_rop8(s, buf, offset + i, s->fg_color);
} else {
if (!(s->image_bitmap_op & 0x10000002)) {
- artist_rop8(s, p + offset + i, s->bg_color);
+ artist_rop8(s, buf, offset + i, s->bg_color);
}
}
}
@@ -507,7 +516,7 @@ static void block_move(ARTISTState *s, int source_x, int source_y, int dest_x,
if (dst + column > buf->size || src + column > buf->size) {
continue;
}
- artist_rop8(s, buf->data + dst + column, buf->data[src + column]);
+ artist_rop8(s, buf, dst + column, buf->data[src + column]);
}
}
@@ -548,7 +557,7 @@ static void fill_window(ARTISTState *s, int startx, int starty,
offset = y * s->width;
for (x = startx; x < startx + width; x++) {
- artist_rop8(s, buf->data + offset + x, color);
+ artist_rop8(s, buf, offset + x, color);
}
}
artist_invalidate_lines(buf, starty, height);
@@ -561,7 +570,6 @@ static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2,
uint8_t color;
int dx, dy, t, e, x, y, incy, diago, horiz;
bool c1;
- uint8_t *p;
trace_artist_draw_line(x1, y1, x2, y2);
@@ -630,16 +638,18 @@ static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2,
color = artist_get_color(s);
do {
+ int ofs;
+
if (c1) {
- p = buf->data + x * s->width + y;
+ ofs = x * s->width + y;
} else {
- p = buf->data + y * s->width + x;
+ ofs = y * s->width + x;
}
if (skip_pix > 0) {
skip_pix--;
} else {
- artist_rop8(s, p, color);
+ artist_rop8(s, buf, ofs, color);
}
if (e > 0) {
@@ -773,10 +783,10 @@ static void font_write16(ARTISTState *s, uint16_t val)
for (i = 0; i < 16; i++) {
mask = 1 << (15 - i);
if (val & mask) {
- artist_rop8(s, buf->data + offset + i, color);
+ artist_rop8(s, buf, offset + i, color);
} else {
if (!(s->image_bitmap_op & 0x20000000)) {
- artist_rop8(s, buf->data + offset + i, s->bg_color);
+ artist_rop8(s, buf, offset + i, s->bg_color);
}
}
}
--
2.21.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 3/3] hw/display/artist: Check offset in block_move to avoid buffer over-read
2020-05-23 19:15 [PATCH 0/3] hw/display/artist: Fix out-of-buffer accesses found while fuzzing Philippe Mathieu-Daudé
2020-05-23 19:15 ` [PATCH 1/3] hw/display/artist: Check offset in draw_line to avoid buffer over-run Philippe Mathieu-Daudé
2020-05-23 19:15 ` [PATCH 2/3] hw/display/artist: Refactor artist_rop8() " Philippe Mathieu-Daudé
@ 2020-05-23 19:15 ` Philippe Mathieu-Daudé
2 siblings, 0 replies; 4+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-05-23 19:15 UTC (permalink / raw)
To: Helge Deller, qemu-devel, Richard Henderson, Sven Schnelle
Cc: Alexander Bulekov, Philippe Mathieu-Daudé
Invalid I/O writes can craft an offset out of the vram_buffer
range.
We avoid:
Program terminated with signal SIGSEGV, Segmentation fault.
519 artist_rop8(s, buf, dst + column, buf->data[src + column]);
(gdb) bt
#0 0x000055fa83b05e0a in block_move (s=0x55fa8647e510, source_x=0, source_y=0, dest_x=255, dest_y=-5, width=22, height=16705) at hw/display/artist.c:519
#1 0x000055fa83b071da in artist_reg_write (opaque=0x55fa8647e510, addr=1051392, val=16777211, size=4) at hw/display/artist.c:954
Reported-by: LLVM libFuzzer
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
hw/display/artist.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/hw/display/artist.c b/hw/display/artist.c
index 6f61b85a24..320e3c5050 100644
--- a/hw/display/artist.c
+++ b/hw/display/artist.c
@@ -513,6 +513,11 @@ static void block_move(ARTISTState *s, int source_x, int source_y, int dest_x,
dst = dest_x + ((line + dest_y) * buf->width);
for (column = startcolumn; column != endcolumn; column += columnincr) {
+ if ((int)src + column < 0 || src + column >= buf->size) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "block_move src:%d column:%d\n", src, column);
+ continue; /* FIXME */
+ }
if (dst + column > buf->size || src + column > buf->size) {
continue;
}
--
2.21.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2020-05-23 19:17 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-23 19:15 [PATCH 0/3] hw/display/artist: Fix out-of-buffer accesses found while fuzzing Philippe Mathieu-Daudé
2020-05-23 19:15 ` [PATCH 1/3] hw/display/artist: Check offset in draw_line to avoid buffer over-run Philippe Mathieu-Daudé
2020-05-23 19:15 ` [PATCH 2/3] hw/display/artist: Refactor artist_rop8() " Philippe Mathieu-Daudé
2020-05-23 19:15 ` [PATCH 3/3] hw/display/artist: Check offset in block_move to avoid buffer over-read Philippe Mathieu-Daudé
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).