* [PATCH][zeus 1/7] qemu: fix CVE-2019-20382
2020-03-16 16:30 [PATCH][zeus 0/7] zeus review Anuj Mittal
@ 2020-03-16 16:30 ` Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 2/7] libpcre2: fix CVE-2019-20454 Anuj Mittal
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Anuj Mittal @ 2020-03-16 16:30 UTC (permalink / raw)
To: openembedded-core
From: Lee Chee Yang <chee.yang.lee@intel.com>
Signed-off-by: Lee Chee Yang <chee.yang.lee@intel.com>
Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
---
meta/recipes-devtools/qemu/qemu.inc | 1 +
.../qemu/qemu/CVE-2019-20382.patch | 1018 +++++++++++++++++
2 files changed, 1019 insertions(+)
create mode 100644 meta/recipes-devtools/qemu/qemu/CVE-2019-20382.patch
diff --git a/meta/recipes-devtools/qemu/qemu.inc b/meta/recipes-devtools/qemu/qemu.inc
index d394db8a41..f451017f6d 100644
--- a/meta/recipes-devtools/qemu/qemu.inc
+++ b/meta/recipes-devtools/qemu/qemu.inc
@@ -30,6 +30,7 @@ SRC_URI = "https://download.qemu.org/${BPN}-${PV}.tar.xz \
file://CVE-2019-15890.patch \
file://CVE-2019-12068.patch \
file://CVE-2020-1711.patch \
+ file://CVE-2019-20382.patch \
"
UPSTREAM_CHECK_REGEX = "qemu-(?P<pver>\d+(\.\d+)+)\.tar"
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2019-20382.patch b/meta/recipes-devtools/qemu/qemu/CVE-2019-20382.patch
new file mode 100644
index 0000000000..183d100398
--- /dev/null
+++ b/meta/recipes-devtools/qemu/qemu/CVE-2019-20382.patch
@@ -0,0 +1,1018 @@
+From 6bf21f3d83e95bcc4ba35a7a07cc6655e8b010b0 Mon Sep 17 00:00:00 2001
+From: Li Qiang <liq3ea@163.com>
+Date: Sat, 31 Aug 2019 08:39:22 -0700
+Subject: [PATCH] vnc: fix memory leak when vnc disconnect
+
+Currently when qemu receives a vnc connect, it creates a 'VncState' to
+represent this connection. In 'vnc_worker_thread_loop' it creates a
+local 'VncState'. The connection 'VcnState' and local 'VncState' exchange
+data in 'vnc_async_encoding_start' and 'vnc_async_encoding_end'.
+In 'zrle_compress_data' it calls 'deflateInit2' to allocate the libz library
+opaque data. The 'VncState' used in 'zrle_compress_data' is the local
+'VncState'. In 'vnc_zrle_clear' it calls 'deflateEnd' to free the libz
+library opaque data. The 'VncState' used in 'vnc_zrle_clear' is the connection
+'VncState'. In currently implementation there will be a memory leak when the
+vnc disconnect. Following is the asan output backtrack:
+
+Direct leak of 29760 byte(s) in 5 object(s) allocated from:
+ 0 0xffffa67ef3c3 in __interceptor_calloc (/lib64/libasan.so.4+0xd33c3)
+ 1 0xffffa65071cb in g_malloc0 (/lib64/libglib-2.0.so.0+0x571cb)
+ 2 0xffffa5e968f7 in deflateInit2_ (/lib64/libz.so.1+0x78f7)
+ 3 0xaaaacec58613 in zrle_compress_data ui/vnc-enc-zrle.c:87
+ 4 0xaaaacec58613 in zrle_send_framebuffer_update ui/vnc-enc-zrle.c:344
+ 5 0xaaaacec34e77 in vnc_send_framebuffer_update ui/vnc.c:919
+ 6 0xaaaacec5e023 in vnc_worker_thread_loop ui/vnc-jobs.c:271
+ 7 0xaaaacec5e5e7 in vnc_worker_thread ui/vnc-jobs.c:340
+ 8 0xaaaacee4d3c3 in qemu_thread_start util/qemu-thread-posix.c:502
+ 9 0xffffa544e8bb in start_thread (/lib64/libpthread.so.0+0x78bb)
+ 10 0xffffa53965cb in thread_start (/lib64/libc.so.6+0xd55cb)
+
+This is because the opaque allocated in 'deflateInit2' is not freed in
+'deflateEnd'. The reason is that the 'deflateEnd' calls 'deflateStateCheck'
+and in the latter will check whether 's->strm != strm'(libz's data structure).
+This check will be true so in 'deflateEnd' it just return 'Z_STREAM_ERROR' and
+not free the data allocated in 'deflateInit2'.
+
+The reason this happens is that the 'VncState' contains the whole 'VncZrle',
+so when calling 'deflateInit2', the 's->strm' will be the local address.
+So 's->strm != strm' will be true.
+
+To fix this issue, we need to make 'zrle' of 'VncState' to be a pointer.
+Then the connection 'VncState' and local 'VncState' exchange mechanism will
+work as expection. The 'tight' of 'VncState' has the same issue, let's also turn
+it to a pointer.
+
+Reported-by: Ying Fang <fangying1@huawei.com>
+Signed-off-by: Li Qiang <liq3ea@163.com>
+Message-id: 20190831153922.121308-1-liq3ea@163.com
+Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
+
+Upstream-Status: Backport [https://git.qemu.org/?p=qemu.git;a=commit;h=6bf21f3d83e95bcc4ba35a7a07cc6655e8b010b0]
+CVE: CVE-2019-20382
+Signed-off-by: Lee Chee Yang <chee.yang.lee@intel.com>
+
+---
+ ui/vnc-enc-tight.c | 219 +++++++++++++++++++++++++-------------------------
+ ui/vnc-enc-zlib.c | 11 +--
+ ui/vnc-enc-zrle.c | 68 ++++++++--------
+ ui/vnc-enc-zrle.inc.c | 2 +-
+ ui/vnc.c | 28 ++++---
+ ui/vnc.h | 4 +-
+ 6 files changed, 170 insertions(+), 162 deletions(-)
+
+diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
+index 9084c22..1e08518 100644
+--- a/ui/vnc-enc-tight.c
++++ b/ui/vnc-enc-tight.c
+@@ -116,7 +116,7 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
+
+ static bool tight_can_send_png_rect(VncState *vs, int w, int h)
+ {
+- if (vs->tight.type != VNC_ENCODING_TIGHT_PNG) {
++ if (vs->tight->type != VNC_ENCODING_TIGHT_PNG) {
+ return false;
+ }
+
+@@ -144,7 +144,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
+ int pixels = 0;
+ int pix, left[3];
+ unsigned int errors;
+- unsigned char *buf = vs->tight.tight.buffer;
++ unsigned char *buf = vs->tight->tight.buffer;
+
+ /*
+ * If client is big-endian, color samples begin from the second
+@@ -215,7 +215,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
+ int pixels = 0; \
+ int sample, sum, left[3]; \
+ unsigned int errors; \
+- unsigned char *buf = vs->tight.tight.buffer; \
++ unsigned char *buf = vs->tight->tight.buffer; \
+ \
+ endian = 0; /* FIXME */ \
+ \
+@@ -296,8 +296,8 @@ static int
+ tight_detect_smooth_image(VncState *vs, int w, int h)
+ {
+ unsigned int errors;
+- int compression = vs->tight.compression;
+- int quality = vs->tight.quality;
++ int compression = vs->tight->compression;
++ int quality = vs->tight->quality;
+
+ if (!vs->vd->lossy) {
+ return 0;
+@@ -309,7 +309,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
+ return 0;
+ }
+
+- if (vs->tight.quality != (uint8_t)-1) {
++ if (vs->tight->quality != (uint8_t)-1) {
+ if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) {
+ return 0;
+ }
+@@ -320,9 +320,9 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
+ }
+
+ if (vs->client_pf.bytes_per_pixel == 4) {
+- if (vs->tight.pixel24) {
++ if (vs->tight->pixel24) {
+ errors = tight_detect_smooth_image24(vs, w, h);
+- if (vs->tight.quality != (uint8_t)-1) {
++ if (vs->tight->quality != (uint8_t)-1) {
+ return (errors < tight_conf[quality].jpeg_threshold24);
+ }
+ return (errors < tight_conf[compression].gradient_threshold24);
+@@ -352,7 +352,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
+ uint##bpp##_t c0, c1, ci; \
+ int i, n0, n1; \
+ \
+- data = (uint##bpp##_t *)vs->tight.tight.buffer; \
++ data = (uint##bpp##_t *)vs->tight->tight.buffer; \
+ \
+ c0 = data[0]; \
+ i = 1; \
+@@ -423,9 +423,9 @@ static int tight_fill_palette(VncState *vs, int x, int y,
+ {
+ int max;
+
+- max = count / tight_conf[vs->tight.compression].idx_max_colors_divisor;
++ max = count / tight_conf[vs->tight->compression].idx_max_colors_divisor;
+ if (max < 2 &&
+- count >= tight_conf[vs->tight.compression].mono_min_rect_size) {
++ count >= tight_conf[vs->tight->compression].mono_min_rect_size) {
+ max = 2;
+ }
+ if (max >= 256) {
+@@ -558,7 +558,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
+ int x, y, c;
+
+ buf32 = (uint32_t *)buf;
+- memset(vs->tight.gradient.buffer, 0, w * 3 * sizeof(int));
++ memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int));
+
+ if (1 /* FIXME */) {
+ shift[0] = vs->client_pf.rshift;
+@@ -575,7 +575,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
+ upper[c] = 0;
+ here[c] = 0;
+ }
+- prev = (int *)vs->tight.gradient.buffer;
++ prev = (int *)vs->tight->gradient.buffer;
+ for (x = 0; x < w; x++) {
+ pix32 = *buf32++;
+ for (c = 0; c < 3; c++) {
+@@ -615,7 +615,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
+ int prediction; \
+ int x, y, c; \
+ \
+- memset (vs->tight.gradient.buffer, 0, w * 3 * sizeof(int)); \
++ memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int)); \
+ \
+ endian = 0; /* FIXME */ \
+ \
+@@ -631,7 +631,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
+ upper[c] = 0; \
+ here[c] = 0; \
+ } \
+- prev = (int *)vs->tight.gradient.buffer; \
++ prev = (int *)vs->tight->gradient.buffer; \
+ for (x = 0; x < w; x++) { \
+ pix = *buf; \
+ if (endian) { \
+@@ -785,7 +785,7 @@ static void extend_solid_area(VncState *vs, int x, int y, int w, int h,
+ static int tight_init_stream(VncState *vs, int stream_id,
+ int level, int strategy)
+ {
+- z_streamp zstream = &vs->tight.stream[stream_id];
++ z_streamp zstream = &vs->tight->stream[stream_id];
+
+ if (zstream->opaque == NULL) {
+ int err;
+@@ -803,15 +803,15 @@ static int tight_init_stream(VncState *vs, int stream_id,
+ return -1;
+ }
+
+- vs->tight.levels[stream_id] = level;
++ vs->tight->levels[stream_id] = level;
+ zstream->opaque = vs;
+ }
+
+- if (vs->tight.levels[stream_id] != level) {
++ if (vs->tight->levels[stream_id] != level) {
+ if (deflateParams(zstream, level, strategy) != Z_OK) {
+ return -1;
+ }
+- vs->tight.levels[stream_id] = level;
++ vs->tight->levels[stream_id] = level;
+ }
+ return 0;
+ }
+@@ -839,11 +839,11 @@ static void tight_send_compact_size(VncState *vs, size_t len)
+ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
+ int level, int strategy)
+ {
+- z_streamp zstream = &vs->tight.stream[stream_id];
++ z_streamp zstream = &vs->tight->stream[stream_id];
+ int previous_out;
+
+ if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) {
+- vnc_write(vs, vs->tight.tight.buffer, vs->tight.tight.offset);
++ vnc_write(vs, vs->tight->tight.buffer, vs->tight->tight.offset);
+ return bytes;
+ }
+
+@@ -852,13 +852,13 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
+ }
+
+ /* reserve memory in output buffer */
+- buffer_reserve(&vs->tight.zlib, bytes + 64);
++ buffer_reserve(&vs->tight->zlib, bytes + 64);
+
+ /* set pointers */
+- zstream->next_in = vs->tight.tight.buffer;
+- zstream->avail_in = vs->tight.tight.offset;
+- zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset;
+- zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset;
++ zstream->next_in = vs->tight->tight.buffer;
++ zstream->avail_in = vs->tight->tight.offset;
++ zstream->next_out = vs->tight->zlib.buffer + vs->tight->zlib.offset;
++ zstream->avail_out = vs->tight->zlib.capacity - vs->tight->zlib.offset;
+ previous_out = zstream->avail_out;
+ zstream->data_type = Z_BINARY;
+
+@@ -868,14 +868,14 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
+ return -1;
+ }
+
+- vs->tight.zlib.offset = vs->tight.zlib.capacity - zstream->avail_out;
++ vs->tight->zlib.offset = vs->tight->zlib.capacity - zstream->avail_out;
+ /* ...how much data has actually been produced by deflate() */
+ bytes = previous_out - zstream->avail_out;
+
+ tight_send_compact_size(vs, bytes);
+- vnc_write(vs, vs->tight.zlib.buffer, bytes);
++ vnc_write(vs, vs->tight->zlib.buffer, bytes);
+
+- buffer_reset(&vs->tight.zlib);
++ buffer_reset(&vs->tight->zlib);
+
+ return bytes;
+ }
+@@ -927,16 +927,17 @@ static int send_full_color_rect(VncState *vs, int x, int y, int w, int h)
+
+ vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
+
+- if (vs->tight.pixel24) {
+- tight_pack24(vs, vs->tight.tight.buffer, w * h, &vs->tight.tight.offset);
++ if (vs->tight->pixel24) {
++ tight_pack24(vs, vs->tight->tight.buffer, w * h,
++ &vs->tight->tight.offset);
+ bytes = 3;
+ } else {
+ bytes = vs->client_pf.bytes_per_pixel;
+ }
+
+ bytes = tight_compress_data(vs, stream, w * h * bytes,
+- tight_conf[vs->tight.compression].raw_zlib_level,
+- Z_DEFAULT_STRATEGY);
++ tight_conf[vs->tight->compression].raw_zlib_level,
++ Z_DEFAULT_STRATEGY);
+
+ return (bytes >= 0);
+ }
+@@ -947,14 +948,14 @@ static int send_solid_rect(VncState *vs)
+
+ vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */
+
+- if (vs->tight.pixel24) {
+- tight_pack24(vs, vs->tight.tight.buffer, 1, &vs->tight.tight.offset);
++ if (vs->tight->pixel24) {
++ tight_pack24(vs, vs->tight->tight.buffer, 1, &vs->tight->tight.offset);
+ bytes = 3;
+ } else {
+ bytes = vs->client_pf.bytes_per_pixel;
+ }
+
+- vnc_write(vs, vs->tight.tight.buffer, bytes);
++ vnc_write(vs, vs->tight->tight.buffer, bytes);
+ return 1;
+ }
+
+@@ -963,7 +964,7 @@ static int send_mono_rect(VncState *vs, int x, int y,
+ {
+ ssize_t bytes;
+ int stream = 1;
+- int level = tight_conf[vs->tight.compression].mono_zlib_level;
++ int level = tight_conf[vs->tight->compression].mono_zlib_level;
+
+ #ifdef CONFIG_VNC_PNG
+ if (tight_can_send_png_rect(vs, w, h)) {
+@@ -991,26 +992,26 @@ static int send_mono_rect(VncState *vs, int x, int y,
+ uint32_t buf[2] = {bg, fg};
+ size_t ret = sizeof (buf);
+
+- if (vs->tight.pixel24) {
++ if (vs->tight->pixel24) {
+ tight_pack24(vs, (unsigned char*)buf, 2, &ret);
+ }
+ vnc_write(vs, buf, ret);
+
+- tight_encode_mono_rect32(vs->tight.tight.buffer, w, h, bg, fg);
++ tight_encode_mono_rect32(vs->tight->tight.buffer, w, h, bg, fg);
+ break;
+ }
+ case 2:
+ vnc_write(vs, &bg, 2);
+ vnc_write(vs, &fg, 2);
+- tight_encode_mono_rect16(vs->tight.tight.buffer, w, h, bg, fg);
++ tight_encode_mono_rect16(vs->tight->tight.buffer, w, h, bg, fg);
+ break;
+ default:
+ vnc_write_u8(vs, bg);
+ vnc_write_u8(vs, fg);
+- tight_encode_mono_rect8(vs->tight.tight.buffer, w, h, bg, fg);
++ tight_encode_mono_rect8(vs->tight->tight.buffer, w, h, bg, fg);
+ break;
+ }
+- vs->tight.tight.offset = bytes;
++ vs->tight->tight.offset = bytes;
+
+ bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
+ return (bytes >= 0);
+@@ -1040,7 +1041,7 @@ static void write_palette(int idx, uint32_t color, void *opaque)
+ static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
+ {
+ int stream = 3;
+- int level = tight_conf[vs->tight.compression].gradient_zlib_level;
++ int level = tight_conf[vs->tight->compression].gradient_zlib_level;
+ ssize_t bytes;
+
+ if (vs->client_pf.bytes_per_pixel == 1) {
+@@ -1050,23 +1051,23 @@ static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
+ vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
+ vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
+
+- buffer_reserve(&vs->tight.gradient, w * 3 * sizeof (int));
++ buffer_reserve(&vs->tight->gradient, w * 3 * sizeof(int));
+
+- if (vs->tight.pixel24) {
+- tight_filter_gradient24(vs, vs->tight.tight.buffer, w, h);
++ if (vs->tight->pixel24) {
++ tight_filter_gradient24(vs, vs->tight->tight.buffer, w, h);
+ bytes = 3;
+ } else if (vs->client_pf.bytes_per_pixel == 4) {
+- tight_filter_gradient32(vs, (uint32_t *)vs->tight.tight.buffer, w, h);
++ tight_filter_gradient32(vs, (uint32_t *)vs->tight->tight.buffer, w, h);
+ bytes = 4;
+ } else {
+- tight_filter_gradient16(vs, (uint16_t *)vs->tight.tight.buffer, w, h);
++ tight_filter_gradient16(vs, (uint16_t *)vs->tight->tight.buffer, w, h);
+ bytes = 2;
+ }
+
+- buffer_reset(&vs->tight.gradient);
++ buffer_reset(&vs->tight->gradient);
+
+ bytes = w * h * bytes;
+- vs->tight.tight.offset = bytes;
++ vs->tight->tight.offset = bytes;
+
+ bytes = tight_compress_data(vs, stream, bytes,
+ level, Z_FILTERED);
+@@ -1077,7 +1078,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
+ int w, int h, VncPalette *palette)
+ {
+ int stream = 2;
+- int level = tight_conf[vs->tight.compression].idx_zlib_level;
++ int level = tight_conf[vs->tight->compression].idx_zlib_level;
+ int colors;
+ ssize_t bytes;
+
+@@ -1104,12 +1105,12 @@ static int send_palette_rect(VncState *vs, int x, int y,
+ palette_iter(palette, write_palette, &priv);
+ vnc_write(vs, header, sizeof(header));
+
+- if (vs->tight.pixel24) {
++ if (vs->tight->pixel24) {
+ tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset);
+ vs->output.offset = old_offset + offset;
+ }
+
+- tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
++ tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h, palette);
+ break;
+ }
+ case 2:
+@@ -1119,7 +1120,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
+
+ palette_iter(palette, write_palette, &priv);
+ vnc_write(vs, header, sizeof(header));
+- tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
++ tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h, palette);
+ break;
+ }
+ default:
+@@ -1127,7 +1128,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
+ break;
+ }
+ bytes = w * h;
+- vs->tight.tight.offset = bytes;
++ vs->tight->tight.offset = bytes;
+
+ bytes = tight_compress_data(vs, stream, bytes,
+ level, Z_DEFAULT_STRATEGY);
+@@ -1146,7 +1147,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
+ static void jpeg_init_destination(j_compress_ptr cinfo)
+ {
+ VncState *vs = cinfo->client_data;
+- Buffer *buffer = &vs->tight.jpeg;
++ Buffer *buffer = &vs->tight->jpeg;
+
+ cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset;
+ cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset);
+@@ -1156,7 +1157,7 @@ static void jpeg_init_destination(j_compress_ptr cinfo)
+ static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
+ {
+ VncState *vs = cinfo->client_data;
+- Buffer *buffer = &vs->tight.jpeg;
++ Buffer *buffer = &vs->tight->jpeg;
+
+ buffer->offset = buffer->capacity;
+ buffer_reserve(buffer, 2048);
+@@ -1168,7 +1169,7 @@ static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
+ static void jpeg_term_destination(j_compress_ptr cinfo)
+ {
+ VncState *vs = cinfo->client_data;
+- Buffer *buffer = &vs->tight.jpeg;
++ Buffer *buffer = &vs->tight->jpeg;
+
+ buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer;
+ }
+@@ -1187,7 +1188,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
+ return send_full_color_rect(vs, x, y, w, h);
+ }
+
+- buffer_reserve(&vs->tight.jpeg, 2048);
++ buffer_reserve(&vs->tight->jpeg, 2048);
+
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+@@ -1222,9 +1223,9 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
+
+ vnc_write_u8(vs, VNC_TIGHT_JPEG << 4);
+
+- tight_send_compact_size(vs, vs->tight.jpeg.offset);
+- vnc_write(vs, vs->tight.jpeg.buffer, vs->tight.jpeg.offset);
+- buffer_reset(&vs->tight.jpeg);
++ tight_send_compact_size(vs, vs->tight->jpeg.offset);
++ vnc_write(vs, vs->tight->jpeg.buffer, vs->tight->jpeg.offset);
++ buffer_reset(&vs->tight->jpeg);
+
+ return 1;
+ }
+@@ -1240,7 +1241,7 @@ static void write_png_palette(int idx, uint32_t pix, void *opaque)
+ VncState *vs = priv->vs;
+ png_colorp color = &priv->png_palette[idx];
+
+- if (vs->tight.pixel24)
++ if (vs->tight->pixel24)
+ {
+ color->red = (pix >> vs->client_pf.rshift) & vs->client_pf.rmax;
+ color->green = (pix >> vs->client_pf.gshift) & vs->client_pf.gmax;
+@@ -1267,10 +1268,10 @@ static void png_write_data(png_structp png_ptr, png_bytep data,
+ {
+ VncState *vs = png_get_io_ptr(png_ptr);
+
+- buffer_reserve(&vs->tight.png, vs->tight.png.offset + length);
+- memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length);
++ buffer_reserve(&vs->tight->png, vs->tight->png.offset + length);
++ memcpy(vs->tight->png.buffer + vs->tight->png.offset, data, length);
+
+- vs->tight.png.offset += length;
++ vs->tight->png.offset += length;
+ }
+
+ static void png_flush_data(png_structp png_ptr)
+@@ -1295,8 +1296,8 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
+ png_infop info_ptr;
+ png_colorp png_palette = NULL;
+ pixman_image_t *linebuf;
+- int level = tight_png_conf[vs->tight.compression].png_zlib_level;
+- int filters = tight_png_conf[vs->tight.compression].png_filters;
++ int level = tight_png_conf[vs->tight->compression].png_zlib_level;
++ int filters = tight_png_conf[vs->tight->compression].png_filters;
+ uint8_t *buf;
+ int dy;
+
+@@ -1340,21 +1341,23 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
+ png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
+
+ if (vs->client_pf.bytes_per_pixel == 4) {
+- tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
++ tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h,
++ palette);
+ } else {
+- tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
++ tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h,
++ palette);
+ }
+ }
+
+ png_write_info(png_ptr, info_ptr);
+
+- buffer_reserve(&vs->tight.png, 2048);
++ buffer_reserve(&vs->tight->png, 2048);
+ linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, w);
+ buf = (uint8_t *)pixman_image_get_data(linebuf);
+ for (dy = 0; dy < h; dy++)
+ {
+ if (color_type == PNG_COLOR_TYPE_PALETTE) {
+- memcpy(buf, vs->tight.tight.buffer + (dy * w), w);
++ memcpy(buf, vs->tight->tight.buffer + (dy * w), w);
+ } else {
+ qemu_pixman_linebuf_fill(linebuf, vs->vd->server, w, x, y + dy);
+ }
+@@ -1372,27 +1375,27 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
+
+ vnc_write_u8(vs, VNC_TIGHT_PNG << 4);
+
+- tight_send_compact_size(vs, vs->tight.png.offset);
+- vnc_write(vs, vs->tight.png.buffer, vs->tight.png.offset);
+- buffer_reset(&vs->tight.png);
++ tight_send_compact_size(vs, vs->tight->png.offset);
++ vnc_write(vs, vs->tight->png.buffer, vs->tight->png.offset);
++ buffer_reset(&vs->tight->png);
+ return 1;
+ }
+ #endif /* CONFIG_VNC_PNG */
+
+ static void vnc_tight_start(VncState *vs)
+ {
+- buffer_reset(&vs->tight.tight);
++ buffer_reset(&vs->tight->tight);
+
+ // make the output buffer be the zlib buffer, so we can compress it later
+- vs->tight.tmp = vs->output;
+- vs->output = vs->tight.tight;
++ vs->tight->tmp = vs->output;
++ vs->output = vs->tight->tight;
+ }
+
+ static void vnc_tight_stop(VncState *vs)
+ {
+ // switch back to normal output/zlib buffers
+- vs->tight.tight = vs->output;
+- vs->output = vs->tight.tmp;
++ vs->tight->tight = vs->output;
++ vs->output = vs->tight->tmp;
+ }
+
+ static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h,
+@@ -1426,9 +1429,9 @@ static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h,
+ int ret;
+
+ if (colors == 0) {
+- if (force || (tight_jpeg_conf[vs->tight.quality].jpeg_full &&
++ if (force || (tight_jpeg_conf[vs->tight->quality].jpeg_full &&
+ tight_detect_smooth_image(vs, w, h))) {
+- int quality = tight_conf[vs->tight.quality].jpeg_quality;
++ int quality = tight_conf[vs->tight->quality].jpeg_quality;
+
+ ret = send_jpeg_rect(vs, x, y, w, h, quality);
+ } else {
+@@ -1440,9 +1443,9 @@ static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h,
+ ret = send_mono_rect(vs, x, y, w, h, bg, fg);
+ } else if (colors <= 256) {
+ if (force || (colors > 96 &&
+- tight_jpeg_conf[vs->tight.quality].jpeg_idx &&
++ tight_jpeg_conf[vs->tight->quality].jpeg_idx &&
+ tight_detect_smooth_image(vs, w, h))) {
+- int quality = tight_conf[vs->tight.quality].jpeg_quality;
++ int quality = tight_conf[vs->tight->quality].jpeg_quality;
+
+ ret = send_jpeg_rect(vs, x, y, w, h, quality);
+ } else {
+@@ -1480,20 +1483,20 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
+ qemu_thread_atexit_add(&vnc_tight_cleanup_notifier);
+ }
+
+- vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
++ vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type);
+
+ vnc_tight_start(vs);
+ vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+ vnc_tight_stop(vs);
+
+ #ifdef CONFIG_VNC_JPEG
+- if (!vs->vd->non_adaptive && vs->tight.quality != (uint8_t)-1) {
++ if (!vs->vd->non_adaptive && vs->tight->quality != (uint8_t)-1) {
+ double freq = vnc_update_freq(vs, x, y, w, h);
+
+- if (freq < tight_jpeg_conf[vs->tight.quality].jpeg_freq_min) {
++ if (freq < tight_jpeg_conf[vs->tight->quality].jpeg_freq_min) {
+ allow_jpeg = false;
+ }
+- if (freq >= tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
++ if (freq >= tight_jpeg_conf[vs->tight->quality].jpeg_freq_threshold) {
+ force_jpeg = true;
+ vnc_sent_lossy_rect(vs, x, y, w, h);
+ }
+@@ -1503,7 +1506,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
+ colors = tight_fill_palette(vs, x, y, w * h, &bg, &fg, color_count_palette);
+
+ #ifdef CONFIG_VNC_JPEG
+- if (allow_jpeg && vs->tight.quality != (uint8_t)-1) {
++ if (allow_jpeg && vs->tight->quality != (uint8_t)-1) {
+ ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors,
+ color_count_palette, force_jpeg);
+ } else {
+@@ -1520,7 +1523,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
+
+ static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
+ {
+- vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
++ vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type);
+
+ vnc_tight_start(vs);
+ vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+@@ -1538,8 +1541,8 @@ static int send_rect_simple(VncState *vs, int x, int y, int w, int h,
+ int rw, rh;
+ int n = 0;
+
+- max_size = tight_conf[vs->tight.compression].max_rect_size;
+- max_width = tight_conf[vs->tight.compression].max_rect_width;
++ max_size = tight_conf[vs->tight->compression].max_rect_size;
++ max_width = tight_conf[vs->tight->compression].max_rect_width;
+
+ if (split && (w > max_width || w * h > max_size)) {
+ max_sub_width = (w > max_width) ? max_width : w;
+@@ -1648,16 +1651,16 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
+
+ if (vs->client_pf.bytes_per_pixel == 4 && vs->client_pf.rmax == 0xFF &&
+ vs->client_pf.bmax == 0xFF && vs->client_pf.gmax == 0xFF) {
+- vs->tight.pixel24 = true;
++ vs->tight->pixel24 = true;
+ } else {
+- vs->tight.pixel24 = false;
++ vs->tight->pixel24 = false;
+ }
+
+ #ifdef CONFIG_VNC_JPEG
+- if (vs->tight.quality != (uint8_t)-1) {
++ if (vs->tight->quality != (uint8_t)-1) {
+ double freq = vnc_update_freq(vs, x, y, w, h);
+
+- if (freq > tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
++ if (freq > tight_jpeg_conf[vs->tight->quality].jpeg_freq_threshold) {
+ return send_rect_simple(vs, x, y, w, h, false);
+ }
+ }
+@@ -1669,8 +1672,8 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
+
+ /* Calculate maximum number of rows in one non-solid rectangle. */
+
+- max_rows = tight_conf[vs->tight.compression].max_rect_size;
+- max_rows /= MIN(tight_conf[vs->tight.compression].max_rect_width, w);
++ max_rows = tight_conf[vs->tight->compression].max_rect_size;
++ max_rows /= MIN(tight_conf[vs->tight->compression].max_rect_width, w);
+
+ return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
+ }
+@@ -1678,33 +1681,33 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
+ int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
+ int w, int h)
+ {
+- vs->tight.type = VNC_ENCODING_TIGHT;
++ vs->tight->type = VNC_ENCODING_TIGHT;
+ return tight_send_framebuffer_update(vs, x, y, w, h);
+ }
+
+ int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
+ int w, int h)
+ {
+- vs->tight.type = VNC_ENCODING_TIGHT_PNG;
++ vs->tight->type = VNC_ENCODING_TIGHT_PNG;
+ return tight_send_framebuffer_update(vs, x, y, w, h);
+ }
+
+ void vnc_tight_clear(VncState *vs)
+ {
+ int i;
+- for (i=0; i<ARRAY_SIZE(vs->tight.stream); i++) {
+- if (vs->tight.stream[i].opaque) {
+- deflateEnd(&vs->tight.stream[i]);
++ for (i = 0; i < ARRAY_SIZE(vs->tight->stream); i++) {
++ if (vs->tight->stream[i].opaque) {
++ deflateEnd(&vs->tight->stream[i]);
+ }
+ }
+
+- buffer_free(&vs->tight.tight);
+- buffer_free(&vs->tight.zlib);
+- buffer_free(&vs->tight.gradient);
++ buffer_free(&vs->tight->tight);
++ buffer_free(&vs->tight->zlib);
++ buffer_free(&vs->tight->gradient);
+ #ifdef CONFIG_VNC_JPEG
+- buffer_free(&vs->tight.jpeg);
++ buffer_free(&vs->tight->jpeg);
+ #endif
+ #ifdef CONFIG_VNC_PNG
+- buffer_free(&vs->tight.png);
++ buffer_free(&vs->tight->png);
+ #endif
+ }
+diff --git a/ui/vnc-enc-zlib.c b/ui/vnc-enc-zlib.c
+index 33e9df2..900ae5b 100644
+--- a/ui/vnc-enc-zlib.c
++++ b/ui/vnc-enc-zlib.c
+@@ -76,7 +76,8 @@ static int vnc_zlib_stop(VncState *vs)
+ zstream->zalloc = vnc_zlib_zalloc;
+ zstream->zfree = vnc_zlib_zfree;
+
+- err = deflateInit2(zstream, vs->tight.compression, Z_DEFLATED, MAX_WBITS,
++ err = deflateInit2(zstream, vs->tight->compression, Z_DEFLATED,
++ MAX_WBITS,
+ MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+ if (err != Z_OK) {
+@@ -84,16 +85,16 @@ static int vnc_zlib_stop(VncState *vs)
+ return -1;
+ }
+
+- vs->zlib.level = vs->tight.compression;
++ vs->zlib.level = vs->tight->compression;
+ zstream->opaque = vs;
+ }
+
+- if (vs->tight.compression != vs->zlib.level) {
+- if (deflateParams(zstream, vs->tight.compression,
++ if (vs->tight->compression != vs->zlib.level) {
++ if (deflateParams(zstream, vs->tight->compression,
+ Z_DEFAULT_STRATEGY) != Z_OK) {
+ return -1;
+ }
+- vs->zlib.level = vs->tight.compression;
++ vs->zlib.level = vs->tight->compression;
+ }
+
+ // reserve memory in output buffer
+diff --git a/ui/vnc-enc-zrle.c b/ui/vnc-enc-zrle.c
+index 7493a84..17fd28a 100644
+--- a/ui/vnc-enc-zrle.c
++++ b/ui/vnc-enc-zrle.c
+@@ -37,18 +37,18 @@ static const int bits_per_packed_pixel[] = {
+
+ static void vnc_zrle_start(VncState *vs)
+ {
+- buffer_reset(&vs->zrle.zrle);
++ buffer_reset(&vs->zrle->zrle);
+
+ /* make the output buffer be the zlib buffer, so we can compress it later */
+- vs->zrle.tmp = vs->output;
+- vs->output = vs->zrle.zrle;
++ vs->zrle->tmp = vs->output;
++ vs->output = vs->zrle->zrle;
+ }
+
+ static void vnc_zrle_stop(VncState *vs)
+ {
+ /* switch back to normal output/zlib buffers */
+- vs->zrle.zrle = vs->output;
+- vs->output = vs->zrle.tmp;
++ vs->zrle->zrle = vs->output;
++ vs->output = vs->zrle->tmp;
+ }
+
+ static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h,
+@@ -56,24 +56,24 @@ static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h,
+ {
+ Buffer tmp;
+
+- buffer_reset(&vs->zrle.fb);
+- buffer_reserve(&vs->zrle.fb, w * h * bpp + bpp);
++ buffer_reset(&vs->zrle->fb);
++ buffer_reserve(&vs->zrle->fb, w * h * bpp + bpp);
+
+ tmp = vs->output;
+- vs->output = vs->zrle.fb;
++ vs->output = vs->zrle->fb;
+
+ vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+
+- vs->zrle.fb = vs->output;
++ vs->zrle->fb = vs->output;
+ vs->output = tmp;
+- return vs->zrle.fb.buffer;
++ return vs->zrle->fb.buffer;
+ }
+
+ static int zrle_compress_data(VncState *vs, int level)
+ {
+- z_streamp zstream = &vs->zrle.stream;
++ z_streamp zstream = &vs->zrle->stream;
+
+- buffer_reset(&vs->zrle.zlib);
++ buffer_reset(&vs->zrle->zlib);
+
+ if (zstream->opaque != vs) {
+ int err;
+@@ -93,13 +93,13 @@ static int zrle_compress_data(VncState *vs, int level)
+ }
+
+ /* reserve memory in output buffer */
+- buffer_reserve(&vs->zrle.zlib, vs->zrle.zrle.offset + 64);
++ buffer_reserve(&vs->zrle->zlib, vs->zrle->zrle.offset + 64);
+
+ /* set pointers */
+- zstream->next_in = vs->zrle.zrle.buffer;
+- zstream->avail_in = vs->zrle.zrle.offset;
+- zstream->next_out = vs->zrle.zlib.buffer + vs->zrle.zlib.offset;
+- zstream->avail_out = vs->zrle.zlib.capacity - vs->zrle.zlib.offset;
++ zstream->next_in = vs->zrle->zrle.buffer;
++ zstream->avail_in = vs->zrle->zrle.offset;
++ zstream->next_out = vs->zrle->zlib.buffer + vs->zrle->zlib.offset;
++ zstream->avail_out = vs->zrle->zlib.capacity - vs->zrle->zlib.offset;
+ zstream->data_type = Z_BINARY;
+
+ /* start encoding */
+@@ -108,8 +108,8 @@ static int zrle_compress_data(VncState *vs, int level)
+ return -1;
+ }
+
+- vs->zrle.zlib.offset = vs->zrle.zlib.capacity - zstream->avail_out;
+- return vs->zrle.zlib.offset;
++ vs->zrle->zlib.offset = vs->zrle->zlib.capacity - zstream->avail_out;
++ return vs->zrle->zlib.offset;
+ }
+
+ /* Try to work out whether to use RLE and/or a palette. We do this by
+@@ -259,14 +259,14 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
+ size_t bytes;
+ int zywrle_level;
+
+- if (vs->zrle.type == VNC_ENCODING_ZYWRLE) {
+- if (!vs->vd->lossy || vs->tight.quality == (uint8_t)-1
+- || vs->tight.quality == 9) {
++ if (vs->zrle->type == VNC_ENCODING_ZYWRLE) {
++ if (!vs->vd->lossy || vs->tight->quality == (uint8_t)-1
++ || vs->tight->quality == 9) {
+ zywrle_level = 0;
+- vs->zrle.type = VNC_ENCODING_ZRLE;
+- } else if (vs->tight.quality < 3) {
++ vs->zrle->type = VNC_ENCODING_ZRLE;
++ } else if (vs->tight->quality < 3) {
+ zywrle_level = 3;
+- } else if (vs->tight.quality < 6) {
++ } else if (vs->tight->quality < 6) {
+ zywrle_level = 2;
+ } else {
+ zywrle_level = 1;
+@@ -337,30 +337,30 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
+
+ vnc_zrle_stop(vs);
+ bytes = zrle_compress_data(vs, Z_DEFAULT_COMPRESSION);
+- vnc_framebuffer_update(vs, x, y, w, h, vs->zrle.type);
++ vnc_framebuffer_update(vs, x, y, w, h, vs->zrle->type);
+ vnc_write_u32(vs, bytes);
+- vnc_write(vs, vs->zrle.zlib.buffer, vs->zrle.zlib.offset);
++ vnc_write(vs, vs->zrle->zlib.buffer, vs->zrle->zlib.offset);
+ return 1;
+ }
+
+ int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+ {
+- vs->zrle.type = VNC_ENCODING_ZRLE;
++ vs->zrle->type = VNC_ENCODING_ZRLE;
+ return zrle_send_framebuffer_update(vs, x, y, w, h);
+ }
+
+ int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+ {
+- vs->zrle.type = VNC_ENCODING_ZYWRLE;
++ vs->zrle->type = VNC_ENCODING_ZYWRLE;
+ return zrle_send_framebuffer_update(vs, x, y, w, h);
+ }
+
+ void vnc_zrle_clear(VncState *vs)
+ {
+- if (vs->zrle.stream.opaque) {
+- deflateEnd(&vs->zrle.stream);
++ if (vs->zrle->stream.opaque) {
++ deflateEnd(&vs->zrle->stream);
+ }
+- buffer_free(&vs->zrle.zrle);
+- buffer_free(&vs->zrle.fb);
+- buffer_free(&vs->zrle.zlib);
++ buffer_free(&vs->zrle->zrle);
++ buffer_free(&vs->zrle->fb);
++ buffer_free(&vs->zrle->zlib);
+ }
+diff --git a/ui/vnc-enc-zrle.inc.c b/ui/vnc-enc-zrle.inc.c
+index abf6b86..c107d8a 100644
+--- a/ui/vnc-enc-zrle.inc.c
++++ b/ui/vnc-enc-zrle.inc.c
+@@ -96,7 +96,7 @@ static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h,
+ static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
+ int zywrle_level)
+ {
+- VncPalette *palette = &vs->zrle.palette;
++ VncPalette *palette = &vs->zrle->palette;
+
+ int runs = 0;
+ int single_pixels = 0;
+diff --git a/ui/vnc.c b/ui/vnc.c
+index bc43c4c..87b8045 100644
+--- a/ui/vnc.c
++++ b/ui/vnc.c
+@@ -1307,6 +1307,8 @@ void vnc_disconnect_finish(VncState *vs)
+ object_unref(OBJECT(vs->sioc));
+ vs->sioc = NULL;
+ vs->magic = 0;
++ g_free(vs->zrle);
++ g_free(vs->tight);
+ g_free(vs);
+ }
+
+@@ -2058,8 +2060,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
+
+ vs->features = 0;
+ vs->vnc_encoding = 0;
+- vs->tight.compression = 9;
+- vs->tight.quality = -1; /* Lossless by default */
++ vs->tight->compression = 9;
++ vs->tight->quality = -1; /* Lossless by default */
+ vs->absolute = -1;
+
+ /*
+@@ -2127,11 +2129,11 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
+ vs->features |= VNC_FEATURE_LED_STATE_MASK;
+ break;
+ case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
+- vs->tight.compression = (enc & 0x0F);
++ vs->tight->compression = (enc & 0x0F);
+ break;
+ case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
+ if (vs->vd->lossy) {
+- vs->tight.quality = (enc & 0x0F);
++ vs->tight->quality = (enc & 0x0F);
+ }
+ break;
+ default:
+@@ -3034,6 +3036,8 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
+ int i;
+
+ trace_vnc_client_connect(vs, sioc);
++ vs->zrle = g_new0(VncZrle, 1);
++ vs->tight = g_new0(VncTight, 1);
+ vs->magic = VNC_MAGIC;
+ vs->sioc = sioc;
+ object_ref(OBJECT(vs->sioc));
+@@ -3045,19 +3049,19 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
+ buffer_init(&vs->output, "vnc-output/%p", sioc);
+ buffer_init(&vs->jobs_buffer, "vnc-jobs_buffer/%p", sioc);
+
+- buffer_init(&vs->tight.tight, "vnc-tight/%p", sioc);
+- buffer_init(&vs->tight.zlib, "vnc-tight-zlib/%p", sioc);
+- buffer_init(&vs->tight.gradient, "vnc-tight-gradient/%p", sioc);
++ buffer_init(&vs->tight->tight, "vnc-tight/%p", sioc);
++ buffer_init(&vs->tight->zlib, "vnc-tight-zlib/%p", sioc);
++ buffer_init(&vs->tight->gradient, "vnc-tight-gradient/%p", sioc);
+ #ifdef CONFIG_VNC_JPEG
+- buffer_init(&vs->tight.jpeg, "vnc-tight-jpeg/%p", sioc);
++ buffer_init(&vs->tight->jpeg, "vnc-tight-jpeg/%p", sioc);
+ #endif
+ #ifdef CONFIG_VNC_PNG
+- buffer_init(&vs->tight.png, "vnc-tight-png/%p", sioc);
++ buffer_init(&vs->tight->png, "vnc-tight-png/%p", sioc);
+ #endif
+ buffer_init(&vs->zlib.zlib, "vnc-zlib/%p", sioc);
+- buffer_init(&vs->zrle.zrle, "vnc-zrle/%p", sioc);
+- buffer_init(&vs->zrle.fb, "vnc-zrle-fb/%p", sioc);
+- buffer_init(&vs->zrle.zlib, "vnc-zrle-zlib/%p", sioc);
++ buffer_init(&vs->zrle->zrle, "vnc-zrle/%p", sioc);
++ buffer_init(&vs->zrle->fb, "vnc-zrle-fb/%p", sioc);
++ buffer_init(&vs->zrle->zlib, "vnc-zrle-zlib/%p", sioc);
+
+ if (skipauth) {
+ vs->auth = VNC_AUTH_NONE;
+diff --git a/ui/vnc.h b/ui/vnc.h
+index 8643860..fea79c2 100644
+--- a/ui/vnc.h
++++ b/ui/vnc.h
+@@ -338,10 +338,10 @@ struct VncState
+ /* Encoding specific, if you add something here, don't forget to
+ * update vnc_async_encoding_start()
+ */
+- VncTight tight;
++ VncTight *tight;
+ VncZlib zlib;
+ VncHextile hextile;
+- VncZrle zrle;
++ VncZrle *zrle;
+ VncZywrle zywrle;
+
+ Notifier mouse_mode_notifier;
+--
+1.8.3.1
--
2.24.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH][zeus 4/7] aspell: CVE-2019-20433
2020-03-16 16:30 [PATCH][zeus 0/7] zeus review Anuj Mittal
` (2 preceding siblings ...)
2020-03-16 16:31 ` [PATCH][zeus 3/7] sqlite: fix numerous CVEs Anuj Mittal
@ 2020-03-16 16:31 ` Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 5/7] python3: Upgrade 3.7.6 -> 3.7.7 Anuj Mittal
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Anuj Mittal @ 2020-03-16 16:31 UTC (permalink / raw)
To: openembedded-core
From: Stefan Ghinea <stefan.ghinea@windriver.com>
libaspell.a in GNU Aspell before 0.60.8 has a buffer over-read for a string
ending with a single '\0' byte, if the encoding is set to ucs-2 or ucs-4
outside of the application, as demonstrated by the ASPELL_CONF environment
variable.
References:
https://nvd.nist.gov/vuln/detail/CVE-2019-20433
Upstream patches:
https://github.com/GNUAspell/aspell/commit/de29341638833ba7717bd6b5e6850998454b044b
https://github.com/GNUAspell/aspell/commit/cefd447e5528b08bb0cd6656bc52b4255692cefc
Signed-off-by: Stefan Ghinea <stefan.ghinea@windriver.com>
Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
---
.../aspell/aspell/CVE-2019-20433-0001.patch | 999 ++++++++++++++++++
.../aspell/aspell/CVE-2019-20433-0002.patch | 68 ++
meta/recipes-support/aspell/aspell_0.60.7.bb | 2 +
3 files changed, 1069 insertions(+)
create mode 100644 meta/recipes-support/aspell/aspell/CVE-2019-20433-0001.patch
create mode 100644 meta/recipes-support/aspell/aspell/CVE-2019-20433-0002.patch
diff --git a/meta/recipes-support/aspell/aspell/CVE-2019-20433-0001.patch b/meta/recipes-support/aspell/aspell/CVE-2019-20433-0001.patch
new file mode 100644
index 0000000000..fd68461e32
--- /dev/null
+++ b/meta/recipes-support/aspell/aspell/CVE-2019-20433-0001.patch
@@ -0,0 +1,999 @@
+From de29341638833ba7717bd6b5e6850998454b044b Mon Sep 17 00:00:00 2001
+From: Kevin Atkinson <kevina@gnu.org>
+Date: Sat, 17 Aug 2019 17:06:53 -0400
+Subject: [PATCH 1/2] Don't allow null-terminated UCS-2/4 strings using the
+ original API.
+
+Detect if the encoding is UCS-2/4 and the length is -1 in affected API
+functions and refuse to convert the string. If the string ends up
+being converted somehow, abort with an error message in DecodeDirect
+and ConvDirect. To convert a null terminated string in
+Decode/ConvDirect, a negative number corresponding to the width of the
+underlying character type for the encoding is expected; for example,
+if the encoding is "ucs-2" then a the size is expected to be -2.
+
+Also fix a 1-3 byte over-read in DecodeDirect when reading UCS-2/4
+strings when a size is provided (found by OSS-Fuzz).
+
+Also fix a bug in DecodeDirect that caused DocumentChecker to return
+the wrong offsets when working with UCS-2/4 strings.
+
+CVE: CVE-2019-20433
+Upstream-Status: Backport [https://github.com/GNUAspell/aspell/commit/de29341638833ba7717bd6b5e6850998454b044b]
+
+[SG: - adjusted context
+ - discarded test changes as test framework is not available
+ - discarded manual entry changes for features that aren't backported]
+Signed-off-by: Stefan Ghinea <stefan.ghinea@windriver.com>
+---
+ auto/MkSrc/CcHelper.pm | 99 ++++++++++++++++++++++++++++++++++---
+ auto/MkSrc/Create.pm | 5 +-
+ auto/MkSrc/Info.pm | 5 +-
+ auto/MkSrc/ProcCc.pm | 24 +++++----
+ auto/MkSrc/ProcImpl.pm | 57 +++++++++++++++------
+ auto/MkSrc/Read.pm | 4 +-
+ auto/mk-src.in | 44 +++++++++++++++--
+ common/convert.cpp | 39 ++++++++++++---
+ common/convert.hpp | 38 +++++++++++++-
+ common/document_checker.cpp | 17 ++++++-
+ common/document_checker.hpp | 1 +
+ common/version.cpp | 15 ++++--
+ configure.ac | 8 +++
+ manual/aspell.texi | 58 ++++++++++++++++------
+ manual/readme.texi | 70 +++++++++++++++++++++-----
+ 15 files changed, 409 insertions(+), 75 deletions(-)
+
+diff --git a/auto/MkSrc/CcHelper.pm b/auto/MkSrc/CcHelper.pm
+index f2de991..0044335 100644
+--- a/auto/MkSrc/CcHelper.pm
++++ b/auto/MkSrc/CcHelper.pm
+@@ -10,8 +10,8 @@ BEGIN {
+ use Exporter;
+ our @ISA = qw(Exporter);
+ our @EXPORT = qw(to_c_return_type c_error_cond
+- to_type_name make_desc make_func call_func
+- make_c_method call_c_method form_c_method
++ to_type_name make_desc make_func call_func get_c_func_name
++ make_c_method make_wide_macro call_c_method form_c_method
+ make_cxx_method);
+ }
+
+@@ -90,6 +90,69 @@ sub make_func ( $ \@ $ ; \% ) {
+ ')'));
+ }
+
++=item make_wide_version NAME @TYPES PARMS ; %ACCUM
++
++Creates the wide character version of the function if needed
++
++=cut
++
++sub make_wide_version ( $ \@ $ ; \% ) {
++ my ($name, $d, $p, $accum) = @_;
++ my @d = @$d;
++ shift @d;
++ return '' unless grep {$_->{type} eq 'encoded string'} @d;
++ $accum->{sys_headers}{'stddef.h'} = true;
++ $accum->{suffix}[5] = <<'---';
++
++/******************* private implemantion details *********************/
++
++#ifdef __cplusplus
++# define aspell_cast_(type, expr) (static_cast<type>(expr))
++# define aspell_cast_from_wide_(str) (static_cast<const void *>(str))
++#else
++# define aspell_cast_(type, expr) ((type)(expr))
++# define aspell_cast_from_wide_(str) ((const char *)(str))
++#endif
++---
++ my @parms = map {$_->{type} eq 'encoded string'
++ ? ($_->{name}, $_->{name}.'_size')
++ : $_->{name}} @d;
++ $name = to_lower $name;
++ $accum->{suffix}[0] = <<'---';
++/**********************************************************************/
++
++#ifdef ASPELL_ENCODE_SETTING_SECURE
++---
++ $accum->{suffix}[2] = "#endif\n";
++ my @args = map {$_->{type} eq 'encoded string'
++ ? ($_->{name}, "$_->{name}_size", '-1')
++ : $_->{name}} @d;
++ $accum->{suffix}[1] .=
++ (join '',
++ "#define $name",
++ '(', join(', ', @parms), ')',
++ "\\\n ",
++ $name, '_wide',
++ '(', join(', ', @args), ')',
++ "\n");
++ @args = map {$_->{type} eq 'encoded string'
++ ? ("aspell_cast_from_wide_($_->{name})",
++ "$_->{name}_size*aspell_cast_(int,sizeof(*($_->{name})))",
++ "sizeof(*($_->{name}))")
++ : $_->{name}} @d;
++ return (join '',
++ "\n",
++ "/* version of $name that is safe to use with (null terminated) wide characters */\n",
++ '#define ',
++ $name, '_w',
++ '(', join(', ', @parms), ')',
++ "\\\n ",
++ $name, '_wide',
++ '(', join(', ', @args), ')',
++ "\n");
++}
++
++
+ =item call_func NAME @TYPES PARMS ; %ACCUM
+
+ Return a string to call a func. Will prefix the function with return
+@@ -103,7 +166,6 @@ Parms can be any of:
+
+ sub call_func ( $ \@ $ ; \% ) {
+ my ($name, $d, $p, $accum) = @_;
+- $accum = {} unless defined $accum;
+ my @d = @$d;
+ my $func_ret = to_type_name(shift @d, {%$p,pos=>'return'}, %$accum);
+ return (join '',
+@@ -148,8 +210,14 @@ sub to_type_name ( $ $ ; \% ) {
+ my $name = $t->{name};
+ my $type = $t->{type};
+
+- return ( (to_type_name {%$d, type=>'string'}, $p, %$accum) ,
+- (to_type_name {%$d, type=>'int', name=>"$d->{name}_size"}, $p, %$accum) )
++ if ($name eq 'encoded string' && $is_cc && $pos eq 'parm') {
++ my @types = ((to_type_name {%$d, type=>($p->{wide}?'const void pointer':'string')}, $p, %$accum),
++ (to_type_name {%$d, type=>'int', name=>"$d->{name}_size"}, $p, %$accum));
++ push @types, (to_type_name {%$d, type=>'int', name=>"$d->{name}_type_width"}, $p, %$accum) if $p->{wide};
++ return @types;
++ }
++ return ( (to_type_name {%$d, type=>($p->{wide}?'const void pointer':'string')}, $p, %$accum) ,
++ (to_type_name {%$d, type=>'int', name=>"$d->{name}_size"}, $p, %$accum) )
+ if $name eq 'encoded string' && $is_cc && $pos eq 'parm';
+
+ my $str;
+@@ -174,7 +242,7 @@ sub to_type_name ( $ $ ; \% ) {
+ $str .= "String";
+ }
+ } elsif ($name eq 'encoded string') {
+- $str .= "const char *";
++ $str .= $p->{wide} ? "const void *" : "const char *";
+ } elsif ($name eq '') {
+ $str .= "void";
+ } elsif ($name eq 'bool' && $is_cc) {
+@@ -186,7 +254,7 @@ sub to_type_name ( $ $ ; \% ) {
+ if ($t->{pointer}) {
+ $accum->{types}->{$name} = $t;
+ } else {
+- $accum->{headers}->{$t->{created_in}} = true;
++ $accum->{headers}->{$t->{created_in}} = true unless $mode eq 'cc';
+ }
+ $str .= "$c_type Aspell" if $mode eq 'cc';
+ $str .= to_mixed($name);
+@@ -214,6 +282,7 @@ sub to_type_name ( $ $ ; \% ) {
+ return $str;
+ }
+
++
+ =item make_desc DESC ; LEVEL
+
+ Make a C comment out of DESC optionally indenting it LEVEL spaces.
+@@ -286,6 +355,7 @@ sub form_c_method ($ $ $ ; \% )
+ } else {
+ $func = "aspell $class $name";
+ }
++ $func .= " wide" if $p->{wide};
+ if (exists $d->{'const'}) {
+ splice @data, 1, 0, {type => "const $class", name=> $this_name};
+ } else {
+@@ -306,6 +376,21 @@ sub make_c_method ($ $ $ ; \%)
+ return &make_func(@ret);
+ }
+
++sub get_c_func_name ($ $ $)
++{
++ my @ret = &form_c_method(@_);
++ return undef unless @ret > 0;
++ return to_lower $ret[0];
++}
++
++sub make_wide_macro ($ $ $ ; \%)
++{
++ my @ret = &form_c_method(@_);
++ return undef unless @ret > 0;
++ my $str = &make_wide_version(@ret);
++ return $str;
++}
++
+ sub call_c_method ($ $ $ ; \%)
+ {
+ my @ret = &form_c_method(@_);
+diff --git a/auto/MkSrc/Create.pm b/auto/MkSrc/Create.pm
+index d39b60e..630ede5 100644
+--- a/auto/MkSrc/Create.pm
++++ b/auto/MkSrc/Create.pm
+@@ -77,8 +77,10 @@ sub create_cc_file ( % ) {
+ $file .= "#include \"aspell.h\"\n" if $p{type} eq 'cxx';
+ $file .= "#include \"settings.h\"\n" if $p{type} eq 'native_impl' && $p{name} eq 'errors';
+ $file .= "#include \"gettext.h\"\n" if $p{type} eq 'native_impl' && $p{name} eq 'errors';
++ $file .= cmap {"#include <$_>\n"} sort keys %{$accum{sys_headers}};
+ $file .= cmap {"#include \"".to_lower($_).".hpp\"\n"} sort keys %{$accum{headers}};
+- $file .= "#ifdef __cplusplus\nextern \"C\" {\n#endif\n" if $p{header} && !$p{cxx};
++ $file .= "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n" if $p{header} && !$p{cxx};
++ $file .= join('', grep {defined $_} @{$accum{prefix}});
+ $file .= "\nnamespace $p{namespace} {\n\n" if $p{cxx};
+ if (defined $info{forward}{proc}{$p{type}}) {
+ my @types = sort {$a->{name} cmp $b->{name}} (values %{$accum{types}});
+@@ -86,6 +88,7 @@ sub create_cc_file ( % ) {
+ }
+ $file .= "\n";
+ $file .= $body;
++ $file .= join('', grep {defined $_} @{$accum{suffix}});
+ $file .= "\n\n}\n\n" if $p{cxx};
+ $file .= "#ifdef __cplusplus\n}\n#endif\n" if $p{header} && !$p{cxx};
+ $file .= "#endif /* $hm */\n" if $p{header};
+diff --git a/auto/MkSrc/Info.pm b/auto/MkSrc/Info.pm
+index c644028..ace8e21 100644
+--- a/auto/MkSrc/Info.pm
++++ b/auto/MkSrc/Info.pm
+@@ -60,6 +60,7 @@ each proc sub should take the following argv
+ the object from which it is a member of
+ no native: do not attempt to create a native implementation
+ treat as object: treat as a object rather than a pointer
++ no conv: do not converted an encoded string
+
+ The %info structure is initialized as follows:
+
+@@ -104,8 +105,8 @@ The %info structure is initialized as follows:
+ errors => {}, # possible errors
+ method => {
+ # A class method
+- options => ['desc', 'posib err', 'c func', 'const',
+- 'c only', 'c impl', 'cxx impl'],
++ options => ['desc', 'posib err', 'c func', 'const', 'no conv', 'on conv error',
++ 'c only', 'c impl', 'cxx impl', 'cc extra'],
+ groups => undef},
+ constructor => {
+ # A class constructor
+diff --git a/auto/MkSrc/ProcCc.pm b/auto/MkSrc/ProcCc.pm
+index 47c4338..98cc435 100644
+--- a/auto/MkSrc/ProcCc.pm
++++ b/auto/MkSrc/ProcCc.pm
+@@ -23,7 +23,7 @@ use MkSrc::Info;
+ sub make_c_object ( $ @ );
+
+ $info{group}{proc}{cc} = sub {
+- my ($data) = @_;
++ my ($data,@rest) = @_;
+ my $ret;
+ my $stars = (70 - length $data->{name})/2;
+ $ret .= "/";
+@@ -33,14 +33,14 @@ $info{group}{proc}{cc} = sub {
+ $ret .= "/\n";
+ foreach my $d (@{$data->{data}}) {
+ $ret .= "\n\n";
+- $ret .= $info{$d->{type}}{proc}{cc}->($d);
++ $ret .= $info{$d->{type}}{proc}{cc}->($d,@rest);
+ }
+ $ret .= "\n\n";
+ return $ret;
+ };
+
+ $info{enum}{proc}{cc} = sub {
+- my ($d) = @_;
++ my ($d,@rest) = @_;
+ my $n = "Aspell".to_mixed($d->{name});
+ return ("\n".
+ make_desc($d->{desc}).
+@@ -58,21 +58,26 @@ $info{struct}{proc}{cc} = sub {
+ };
+
+ $info{union}{proc}{cc} = sub {
+- return make_c_object "union", $_[0];
++ return make_c_object "union", @_;
+ };
+
+ $info{class}{proc}{cc} = sub {
+- my ($d) = @_;
++ my ($d,$accum) = @_;
+ my $class = $d->{name};
+ my $classname = "Aspell".to_mixed($class);
+ my $ret = "";
+ $ret .= "typedef struct $classname $classname;\n\n";
+ foreach (@{$d->{data}}) {
+- my $s = make_c_method($class, $_, {mode=>'cc'});
++ my $s = make_c_method($class, $_, {mode=>'cc'}, %$accum);
+ next unless defined $s;
+ $ret .= "\n";
+ $ret .= make_desc($_->{desc});
+- $ret .= make_c_method($class, $_, {mode=>'cc'}).";\n";
++ $ret .= make_c_method($class, $_, {mode=>'cc'}, %$accum).";\n";
++ if (grep {$_->{type} eq 'encoded string'} @{$_->{data}}) {
++ $ret .= make_c_method($class, $_, {mode=>'cc', wide=>true}, %$accum).";\n";
++ $ret .= make_wide_macro($class, $_, {mode=>'cc'}, %$accum);
++ }
++ $ret .= "\n".$_->{'cc extra'}."\n" if defined $_->{'cc extra'};
+ }
+ $ret .= "\n";
+ return $ret;
+@@ -105,7 +110,8 @@ $info{errors}{proc}{cc} = sub {
+ };
+
+ sub make_c_object ( $ @ ) {
+- my ($t, $d) = @_;
++ my ($t, $d, $accum) = @_;
++ $accum = {} unless defined $accum;
+ my $struct;
+ $struct .= "Aspell";
+ $struct .= to_mixed($d->{name});
+@@ -120,7 +126,7 @@ sub make_c_object ( $ @ ) {
+ "\n};\n"),
+ "typedef $t $struct $struct;",
+ join ("\n",
+- map {make_c_method($d->{name}, $_, {mode=>'cc'}).";"}
++ map {make_c_method($d->{name}, $_, {mode=>'cc'}, %$accum).";"}
+ grep {$_->{type} eq 'method'}
+ @{$d->{data}})
+ )."\n";
+diff --git a/auto/MkSrc/ProcImpl.pm b/auto/MkSrc/ProcImpl.pm
+index b8628fd..3d0f220 100644
+--- a/auto/MkSrc/ProcImpl.pm
++++ b/auto/MkSrc/ProcImpl.pm
+@@ -45,10 +45,13 @@ $info{class}{proc}{impl} = sub {
+ foreach (grep {$_ ne ''} split /\s*,\s*/, $data->{'c impl headers'}) {
+ $accum->{headers}{$_} = true;
+ }
+- foreach my $d (@{$data->{data}}) {
++ my @d = @{$data->{data}};
++ while (@d) {
++ my $d = shift @d;
++ my $need_wide = false;
+ next unless one_of $d->{type}, qw(method constructor destructor);
+ my @parms = @{$d->{data}} if exists $d->{data};
+- my $m = make_c_method $data->{name}, $d, {mode=>'cc_cxx', use_name=>true}, %$accum;
++ my $m = make_c_method $data->{name}, $d, {mode=>'cc_cxx', use_name=>true, wide=>$d->{wide}}, %$accum;
+ next unless defined $m;
+ $ret .= "extern \"C\" $m\n";
+ $ret .= "{\n";
+@@ -57,24 +60,49 @@ $info{class}{proc}{impl} = sub {
+ } else {
+ if ($d->{type} eq 'method') {
+ my $ret_type = shift @parms;
+- my $ret_native = to_type_name $ret_type, {mode=>'native_no_err', pos=>'return'}, %$accum;
++ my $ret_native = to_type_name $ret_type, {mode=>'native_no_err', pos=>'return', wide=>$d->{wide}}, %$accum;
+ my $snum = 0;
++ my $call_fun = $d->{name};
++ my @call_parms;
+ foreach (@parms) {
+ my $n = to_lower($_->{name});
+- if ($_->{type} eq 'encoded string') {
+- $accum->{headers}{'mutable string'} = true;
+- $accum->{headers}{'convert'} = true;
+- $ret .= " ths->temp_str_$snum.clear();\n";
+- $ret .= " ths->to_internal_->convert($n, ${n}_size, ths->temp_str_$snum);\n";
+- $ret .= " unsigned int s$snum = ths->temp_str_$snum.size();\n";
+- $_ = "MutableString(ths->temp_str_$snum.mstr(), s$snum)";
+- $snum++;
++ if ($_->{type} eq 'encoded string' && !exists($d->{'no conv'})) {
++ $need_wide = true unless $d->{wide};
++ die unless exists $d->{'posib err'};
++ $accum->{headers}{'mutable string'} = true;
++ $accum->{headers}{'convert'} = true;
++ my $name = get_c_func_name $data->{name}, $d, {mode=>'cc_cxx', use_name=>true, wide=>$d->{wide}};
++ $ret .= " ths->temp_str_$snum.clear();\n";
++ if ($d->{wide}) {
++ $ret .= " ${n}_size = get_correct_size(\"$name\", ths->to_internal_->in_type_width(), ${n}_size, ${n}_type_width);\n";
++ } else {
++ $ret .= " PosibErr<int> ${n}_fixed_size = get_correct_size(\"$name\", ths->to_internal_->in_type_width(), ${n}_size);\n";
++ if (exists($d->{'on conv error'})) {
++ $ret .= " if (${n}_fixed_size.get_err()) {\n";
++ $ret .= " ".$d->{'on conv error'}."\n";
++ $ret .= " } else {\n";
++ $ret .= " ${n}_size = ${n}_fixed_size;\n";
++ $ret .= " }\n";
++ } else {
++ $ret .= " ths->err_.reset(${n}_fixed_size.release_err());\n";
++ $ret .= " if (ths->err_ != 0) return ".(c_error_cond $ret_type).";\n";
++ }
++ }
++ $ret .= " ths->to_internal_->convert($n, ${n}_size, ths->temp_str_$snum);\n";
++ $ret .= " unsigned int s$snum = ths->temp_str_$snum.size();\n";
++ push @call_parms, "MutableString(ths->temp_str_$snum.mstr(), s$snum)";
++ $snum++;
++ } elsif ($_->{type} eq 'encoded string') {
++ $need_wide = true unless $d->{wide};
++ push @call_parms, $n, "${n}_size";
++ push @call_parms, "${n}_type_width" if $d->{wide};
++ $call_fun .= " wide" if $d->{wide};
+ } else {
+- $_ = $n;
++ push @call_parms, $n;
+ }
+ }
+- my $parms = '('.(join ', ', @parms).')';
+- my $exp = "ths->".to_lower($d->{name})."$parms";
++ my $parms = '('.(join ', ', @call_parms).')';
++ my $exp = "ths->".to_lower($call_fun)."$parms";
+ if (exists $d->{'posib err'}) {
+ $accum->{headers}{'posib err'} = true;
+ $ret .= " PosibErr<$ret_native> ret = $exp;\n";
+@@ -118,6 +146,7 @@ $info{class}{proc}{impl} = sub {
+ }
+ }
+ $ret .= "}\n\n";
++ unshift @d,{%$d, wide=>true} if $need_wide;
+ }
+ return $ret;
+ };
+diff --git a/auto/MkSrc/Read.pm b/auto/MkSrc/Read.pm
+index 4b3d1d0..4bf640e 100644
+--- a/auto/MkSrc/Read.pm
++++ b/auto/MkSrc/Read.pm
+@@ -88,13 +88,13 @@ sub advance ( ) {
+ $in_pod = $1 if $line =~ /^\=(\w+)/;
+ $line = '' if $in_pod;
+ $in_pod = undef if $in_pod && $in_pod eq 'cut';
+- $line =~ s/\#.*$//;
++ $line =~ s/(?<!\\)\#.*$//;
+ $line =~ s/^(\t*)//;
+ $level = $base_level + length($1);
+ $line =~ s/\s*$//;
+ ++$base_level if $line =~ s/^\{$//;
+ --$base_level if $line =~ s/^\}$//;
+- $line =~ s/\\([{}])/$1/g;
++ $line =~ s/\\([{}#\\])/$1/g;
+ } while ($line eq '');
+ #print "$level:$line\n";
+ }
+diff --git a/auto/mk-src.in b/auto/mk-src.in
+index 0e7833a..eb3353f 100644
+--- a/auto/mk-src.in
++++ b/auto/mk-src.in
+@@ -608,6 +608,7 @@ errors:
+ invalid expression
+ mesg => "%expression" is not a valid regular expression.
+ parms => expression
++
+ }
+ group: speller
+ {
+@@ -650,6 +651,7 @@ class: speller
+ posib err
+ desc => Returns 0 if it is not in the dictionary,
+ 1 if it is, or -1 on error.
++ on conv error => return 0;
+ /
+ bool
+ encoded string: word
+@@ -715,6 +717,8 @@ class: speller
+ desc => Return NULL on error.
+ The word list returned by suggest is only
+ valid until the next call to suggest.
++ on conv error =>
++ word = NULL; word_size = 0;
+ /
+ const word list
+ encoded string: word
+@@ -840,7 +844,6 @@ class: document checker
+ void
+
+ method: process
+-
+ desc => Process a string.
+ The string passed in should only be split on
+ white space characters. Furthermore, between
+@@ -849,10 +852,10 @@ class: document checker
+ in the document. Passing in strings out of
+ order, skipping strings or passing them in
+ more than once may lead to undefined results.
++ no conv
+ /
+ void
+- string: str
+- int: size
++ encoded string: str
+
+ method: next misspelling
+
+@@ -860,9 +863,23 @@ class: document checker
+ processed string. If there are no more
+ misspelled words, then token.word will be
+ NULL and token.size will be 0
++ cc extra =>
++ \#define aspell_document_checker_next_misspelling_w(type, ths) \\
++ aspell_document_checker_next_misspelling_adj(ths, sizeof(type))
+ /
+ token object
+
++ method: next misspelling adj
++ desc => internal: do not use
++ c impl =>
++ Token res = ths->next_misspelling();
++ res.offset /= type_width;
++ res.len /= type_width;
++ return res;
++ /
++ token object
++ int: type_width
++
+ method: filter
+
+ desc => Returns the underlying filter class.
+@@ -922,9 +939,30 @@ class: string enumeration
+ ths->from_internal_->append_null(ths->temp_str);
+ return ths->temp_str.data();
+ \}
++ cc extra =>
++ \#define aspell_string_enumeration_next_w(type, ths) \\
++ aspell_cast_(const type *, aspell_string_enumeration_next_wide(ths, sizeof(type)))
+ /
+ const string
+
++ method: next wide
++ c impl =>
++ const char * s = ths->next();
++ if (s == 0) {
++ return s;
++ } else if (ths->from_internal_ == 0) \{
++ assert(type_width == 1);
++ return s;
++ \} else \{
++ assert(type_width == ths->from_internal_->out_type_width());
++ ths->temp_str.clear();
++ ths->from_internal_->convert(s,-1,ths->temp_str);
++ ths->from_internal_->append_null(ths->temp_str);
++ return ths->temp_str.data();
++ \}
++ /
++ const void pointer
++ int: type_width
+ }
+ group: info
+ {
+diff --git a/common/convert.cpp b/common/convert.cpp
+index 1add95a..7ae0317 100644
+--- a/common/convert.cpp
++++ b/common/convert.cpp
+@@ -541,18 +541,25 @@ namespace acommon {
+ // Trivial Conversion
+ //
+
++ const char * unsupported_null_term_wide_string_msg =
++ "Null-terminated wide-character strings unsupported when used this way.";
++
+ template <typename Chr>
+ struct DecodeDirect : public Decode
+ {
++ DecodeDirect() {type_width = sizeof(Chr);}
+ void decode(const char * in0, int size, FilterCharVector & out) const {
+ const Chr * in = reinterpret_cast<const Chr *>(in0);
+- if (size == -1) {
++ if (size == -sizeof(Chr)) {
+ for (;*in; ++in)
+- out.append(*in);
++ out.append(*in, sizeof(Chr));
++ } else if (size <= -1) {
++ fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg);
++ abort();
+ } else {
+- const Chr * stop = reinterpret_cast<const Chr *>(in0 +size);
++ const Chr * stop = reinterpret_cast<const Chr *>(in0) + size/sizeof(Chr);
+ for (;in != stop; ++in)
+- out.append(*in);
++ out.append(*in, sizeof(Chr));
+ }
+ }
+ PosibErr<void> decode_ec(const char * in0, int size,
+@@ -565,6 +572,7 @@ namespace acommon {
+ template <typename Chr>
+ struct EncodeDirect : public Encode
+ {
++ EncodeDirect() {type_width = sizeof(Chr);}
+ void encode(const FilterChar * in, const FilterChar * stop,
+ CharVector & out) const {
+ for (; in != stop; ++in) {
+@@ -594,11 +602,15 @@ namespace acommon {
+ template <typename Chr>
+ struct ConvDirect : public DirectConv
+ {
++ ConvDirect() {type_width = sizeof(Chr);}
+ void convert(const char * in0, int size, CharVector & out) const {
+- if (size == -1) {
++ if (size == -sizeof(Chr)) {
+ const Chr * in = reinterpret_cast<const Chr *>(in0);
+ for (;*in != 0; ++in)
+ out.append(in, sizeof(Chr));
++ } else if (size <= -1) {
++ fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg);
++ abort();
+ } else {
+ out.append(in0, size);
+ }
+@@ -1121,5 +1133,20 @@ namespace acommon {
+ }
+ return 0;
+ }
+-
++
++ PosibErr<void> unsupported_null_term_wide_string_err_(const char * func) {
++ static bool reported_to_stderr = false;
++ PosibErr<void> err = make_err(other_error, unsupported_null_term_wide_string_msg);
++ if (!reported_to_stderr) {
++ CERR.printf("ERROR: %s: %s\n", func, unsupported_null_term_wide_string_msg);
++ reported_to_stderr = true;
++ }
++ return err;
++ }
++
++ void unsupported_null_term_wide_string_abort_(const char * func) {
++ CERR.printf("%s: %s\n", unsupported_null_term_wide_string_msg);
++ abort();
++ }
++
+ }
+diff --git a/common/convert.hpp b/common/convert.hpp
+index 76332ee..c948973 100644
+--- a/common/convert.hpp
++++ b/common/convert.hpp
+@@ -7,6 +7,8 @@
+ #ifndef ASPELL_CONVERT__HPP
+ #define ASPELL_CONVERT__HPP
+
++#include "settings.h"
++
+ #include "string.hpp"
+ #include "posib_err.hpp"
+ #include "char_vector.hpp"
+@@ -25,8 +27,9 @@ namespace acommon {
+ typedef const Config CacheConfig;
+ typedef const char * CacheKey;
+ String key;
++ int type_width; // type width in bytes
+ bool cache_key_eq(const char * l) const {return key == l;}
+- ConvBase() {}
++ ConvBase() : type_width(1) {}
+ private:
+ ConvBase(const ConvBase &);
+ void operator=(const ConvBase &);
+@@ -56,6 +59,8 @@ namespace acommon {
+ virtual ~Encode() {}
+ };
+ struct DirectConv { // convert directly from in_code to out_code.
++ int type_width; // type width in bytes
++ DirectConv() : type_width(1) {}
+ // should not take ownership of decode and encode.
+ // decode and encode guaranteed to stick around for the life
+ // of the object.
+@@ -126,6 +131,9 @@ namespace acommon {
+ const char * in_code() const {return decode_->key.c_str();}
+ const char * out_code() const {return encode_->key.c_str();}
+
++ int in_type_width() const {return decode_->type_width;}
++ int out_type_width() const {return encode_->type_width;}
++
+ void append_null(CharVector & out) const
+ {
+ const char nul[4] = {0,0,0,0}; // 4 should be enough
+@@ -191,6 +199,10 @@ namespace acommon {
+ }
+ }
+
++ void convert(const void * in, int size, CharVector & out) {
++ convert(static_cast<const char *>(in), size, out);
++ }
++
+ void generic_convert(const char * in, int size, CharVector & out);
+
+ };
+@@ -412,6 +424,30 @@ namespace acommon {
+ return operator()(str, str + byte_size);}
+ };
+
++#ifdef SLOPPY_NULL_TERM_STRINGS
++ static const bool sloppy_null_term_strings = true;
++#else
++ static const bool sloppy_null_term_strings = false;
++#endif
++
++ PosibErr<void> unsupported_null_term_wide_string_err_(const char * func);
++ void unsupported_null_term_wide_string_abort_(const char * func);
++
++ static inline PosibErr<int> get_correct_size(const char * func, int conv_type_width, int size) {
++ if (sloppy_null_term_strings && size <= -1)
++ return -conv_type_width;
++ if (size <= -1 && -conv_type_width != size)
++ return unsupported_null_term_wide_string_err_(func);
++ return size;
++ }
++ static inline int get_correct_size(const char * func, int conv_type_width, int size, int type_width) {
++ if ((sloppy_null_term_strings || type_width <= -1) && size <= -1)
++ return -conv_type_width;
++ if (size <= -1 && conv_type_width != type_width)
++ unsupported_null_term_wide_string_abort_(func);
++ return size;
++ }
++
+ }
+
+ #endif
+diff --git a/common/document_checker.cpp b/common/document_checker.cpp
+index 5e510c4..0ccf1cd 100644
+--- a/common/document_checker.cpp
++++ b/common/document_checker.cpp
+@@ -44,7 +44,9 @@ namespace acommon {
+ void DocumentChecker::process(const char * str, int size)
+ {
+ proc_str_.clear();
+- conv_->decode(str, size, proc_str_);
++ PosibErr<int> fixed_size = get_correct_size("aspell_document_checker_process", conv_->in_type_width(), size);
++ if (!fixed_size.has_err())
++ conv_->decode(str, fixed_size, proc_str_);
+ proc_str_.append(0);
+ FilterChar * begin = proc_str_.pbegin();
+ FilterChar * end = proc_str_.pend() - 1;
+@@ -53,6 +55,19 @@ namespace acommon {
+ tokenizer_->reset(begin, end);
+ }
+
++ void DocumentChecker::process_wide(const void * str, int size, int type_width)
++ {
++ proc_str_.clear();
++ int fixed_size = get_correct_size("aspell_document_checker_process", conv_->in_type_width(), size, type_width);
++ conv_->decode(static_cast<const char *>(str), fixed_size, proc_str_);
++ proc_str_.append(0);
++ FilterChar * begin = proc_str_.pbegin();
++ FilterChar * end = proc_str_.pend() - 1;
++ if (filter_)
++ filter_->process(begin, end);
++ tokenizer_->reset(begin, end);
++ }
++
+ Token DocumentChecker::next_misspelling()
+ {
+ bool correct;
+diff --git a/common/document_checker.hpp b/common/document_checker.hpp
+index d35bb88..11a3c73 100644
+--- a/common/document_checker.hpp
++++ b/common/document_checker.hpp
+@@ -36,6 +36,7 @@ namespace acommon {
+ PosibErr<void> setup(Tokenizer *, Speller *, Filter *);
+ void reset();
+ void process(const char * str, int size);
++ void process_wide(const void * str, int size, int type_width);
+ Token next_misspelling();
+
+ Filter * filter() {return filter_;}
+diff --git a/common/version.cpp b/common/version.cpp
+index 414d938..9e60b75 100644
+--- a/common/version.cpp
++++ b/common/version.cpp
+@@ -1,8 +1,17 @@
+ #include "settings.h"
+
+-extern "C" const char * aspell_version_string() {
+ #ifdef NDEBUG
+- return VERSION " NDEBUG";
++# define NDEBUG_STR " NDEBUG"
++#else
++# define NDEBUG_STR
++#endif
++
++#ifdef SLOPPY_NULL_TERM_STRINGS
++# define SLOPPY_STR " SLOPPY"
++#else
++# define SLOPPY_STR
+ #endif
+- return VERSION;
++
++extern "C" const char * aspell_version_string() {
++ return VERSION NDEBUG_STR SLOPPY_STR;
+ }
+diff --git a/configure.ac b/configure.ac
+index 60e3b39..a5d51e3 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -73,6 +73,9 @@ AC_ARG_ENABLE(filter-version-control,
+ AC_ARG_ENABLE(32-bit-hash-fun,
+ AS_HELP_STRING([--enable-32-bit-hash-fun],[use 32-bit hash function for compiled dictionaries]))
+
++AC_ARG_ENABLE(sloppy-null-term-strings,
++ AS_HELP_STRING([--enable-sloppy-null-term-strings],[allows allow null terminated UCS-2 and UCS-4 strings]))
++
+ AC_ARG_ENABLE(pspell-compatibility,
+ AS_HELP_STRING([--disable-pspell-compatibility],[don't install pspell compatibility libraries]))
+
+@@ -141,6 +144,11 @@ then
+ AC_DEFINE(USE_32_BIT_HASH_FUN, 1, [Defined if 32-bit hash function should be used for compiled dictionaries.])
+ fi
+
++if test "$enable_sloppy_null_term_strings" = "yes"
++then
++ AC_DEFINE(SLOPPY_NULL_TERM_STRINGS, 1, [Defined if null-terminated UCS-2 and UCS-4 strings should always be allowed.])
++fi
++
+ AM_CONDITIONAL(PSPELL_COMPATIBILITY,
+ [test "$enable_pspell_compatibility" != "no"])
+ AM_CONDITIONAL(INCREMENTED_SONAME,
+diff --git a/manual/aspell.texi b/manual/aspell.texi
+index 45fa091..f400e06 100644
+--- a/manual/aspell.texi
++++ b/manual/aspell.texi
+@@ -158,7 +158,8 @@ Installing
+
+ * Generic Install Instructions::
+ * HTML Manuals and "make clean"::
+-* Curses Notes::
++* Curses Notes::
++* Upgrading from Aspell 0.60.7::
+ * Loadable Filter Notes::
+ * Upgrading from Aspell 0.50::
+ * Upgrading from Aspell .33/Pspell .12::
+@@ -2206,18 +2207,26 @@ int correct = aspell_speller_check(spell_checker, @var{word}, @var{size});
+ @end smallexample
+
+ @noindent
+-@var{word} is expected to be a @code{const char *} character
+-string. If the encoding is set to be @code{ucs-2} or
+-@code{ucs-4} @var{word} is expected to be a cast
+-from either @code{const u16int *} or @code{const u32int *}
+-respectively. @code{u16int} and @code{u32int} are generally
+-@code{unsigned short} and @code{unsigned int} respectively.
+-@var{size} is the length of the string or @code{-1} if the string
+-is null terminated. If the string is a cast from @code{const u16int
+-*} or @code{const u32int *} then @code{@i{size}} is the amount of
+-space in bytes the string takes up after being cast to @code{const
+-char *} and not the true size of the string. @code{sspell_speller_check}
+-will return @code{0} if it is not found and non-zero otherwise.
++@var{word} is expected to be a @code{const char *} character string.
++@var{size} is the length of the string or @code{-1} if the string is
++null terminated. @code{aspell_speller_check} will return @code{0} if it is not found
++and non-zero otherwise.
++
++If you are using the @code{ucs-2} or @code{ucs-4} encoding then the
++string is expected to be either a 2 or 4 byte wide integer
++(respectively) and the @code{_w} macro vesion should be used:
++
++@smallexample
++int correct = aspell_speller_check_w(spell_checker, @var{word}, @var{size});
++@end smallexample
++
++The macro will cast the string to to the correct type and convert
++@var{size} into bytes for you and then a call the special wide version of the
++function that will make sure the encoding is correct for the type
++passed in. For compatibility with older versions of Aspell the normal
++non-wide functions can still be used provided that the size of the
++string, in bytes, is also passed in. Null terminated @code{ucs-2} or
++@code{ucs-4} are no longer supported when using the non-wide functions.
+
+ If the word is not correct, then the @code{suggest} method can be used
+ to come up with likely replacements.
+@@ -2236,7 +2245,28 @@ delete_aspell_string_enumeration(elements);
+
+ Notice how @code{elements} is deleted but @code{suggestions} is not.
+ The value returned by @code{suggestions} is only valid to the next
+-call to @code{suggest}. Once a replacement is made the
++call to @code{suggest}.
++
++If you are using the @code{ucs-2} or @code{ucs-4} encoding then, in
++addition to using the @code{_w} macro for the @code{suggest} method, you
++should also use the @code{_w} macro with the @code{next} method which
++will cast the string to the correct type for you. For example, if you
++are using the @code{ucs-2} encoding and the string is a @code{const
++uint16_t *} then you should use:
++
++@smallexample
++AspellWordList * suggestions = aspell_speller_suggest_w(spell_checker,
++ @var{word}, @var{size});
++AspellStringEnumeration * elements = aspell_word_list_elements(suggestions);
++const uint16_t * word;
++while ( (word = aspell_string_enumeration_next_w(uint16_t, aspell_elements)) != NULL )
++@{
++ // add to suggestion list
++@}
++delete_aspell_string_enumeration(elements);
++@end smallexample
++
++Once a replacement is made the
+ @code{store_repl} method should be used to communicate the replacement
+ pair back to the spell checker (for the reason, @pxref{Notes on
+ Storing Replacement Pairs}). Its usage is as follows:
+diff --git a/manual/readme.texi b/manual/readme.texi
+index 669ab8e..531721f 100644
+--- a/manual/readme.texi
++++ b/manual/readme.texi
+@@ -15,15 +15,16 @@ The latest version can always be found at GNU Aspell's home page at
+ @uref{http://aspell.net}.
+
+ @menu
+-* Generic Install Instructions::
+-* HTML Manuals and "make clean"::
+-* Curses Notes::
+-* Loadable Filter Notes::
+-* Using 32-Bit Dictionaries on a 64-Bit System::
+-* Upgrading from Aspell 0.50::
+-* Upgrading from Aspell .33/Pspell .12::
+-* Upgrading from a Pre-0.50 snapshot::
+-* WIN32 Notes::
++* Generic Install Instructions::
++* HTML Manuals and "make clean"::
++* Curses Notes::
++* Upgrading from Aspell 0.60.7::
++* Loadable Filter Notes::
++* Using 32-Bit Dictionaries on a 64-Bit System::
++* Upgrading from Aspell 0.50::
++* Upgrading from Aspell .33/Pspell .12::
++* Upgrading from a Pre-0.50 snapshot::
++* WIN32 Notes::
+ @end menu
+
+ @node Generic Install Instructions
+@@ -121,17 +122,62 @@ In addition your system must also support the @code{mblen} function.
+ Although this function was defined in the ISO C89 standard (ANSI
+ X3.159-1989), not all systems have it.
+
++@node Upgrading from Aspell 0.60.7
++@appendixsec Upgrading from Aspell 0.60.7
++
++To prevent a potentially unbounded buffer over-read, Aspell no longer
++supports null-terminated UCS-2 and UCS-4 encoded strings with the
++original C API. Null-termianted 8-bit or UTF-8 encoded strings are
++still supported, as are UCS-2 and UCS-4 encoded strings when the
++length is passed in.
++
++As of Aspell 0.60.8 a function from the original API that expects an
++encoded string as a parameter will return meaningless results (or an
++error code) if string is null terminated and the encoding is set to
++@code{ucs-2} or @code{ucs-4}. In addition, a single:
++@example
++ERROR: aspell_speller_check: Null-terminated wide-character strings unsupported when used this way.
++@end example
++will be printed to standard error the first time one of those
++functions is called.
++
++Application that use null-terminated UCS-2/4 strings should either (1)
++use the interface intended for working with wide-characters
++(@xref{Through the C API}); or (2) define
++@code{ASPELL_ENCODE_SETTING_SECURE} before including @code{aspell.h}.
++In the latter case is is important that the application explicitly
++sets the encoding to a known value. Defining
++@code{ASPELL_ENCODE_SETTING_SECURE} and not setting the encoding
++explicitly or allowing user of the application to set the encoding
++could result in an unbounded buffer over-read.
++
++If it is necessary to preserve binary compatibility with older
++versions of Aspell, the easiest thing would be to determine the length
++of the UCS-2/4 string---in bytes---and pass that in. Due to an
++implemenation detail, existing API functions can be made to work with
++null-terminated UCS-2/4 strings safely by passing in either @code{-2}
++or @code{-4} (corresponding to the width of the character type) as the
++size. Doing so, however, will cause a buffer over-read for unpatched
++version of Aspell. To avoid this it will be necessary to parse the
++version string to determine the correct value to use. However, no
++official support will be provided for the latter method.
++
++If the application can not be recompiled, then Aspell can be configured
++to preserve the old behavior by passing
++@option{--enable-sloppy-null-term-strings} to @command{configure}. When Aspell
++is compiled this way the version string will include the string
++@samp{ SLOPPY}.
++
+ @node Loadable Filter Notes
+ @appendixsec Loadable Filter Notes
+-
++
+ Support for being able to load additional filter modules at run-time
+ has only been verified to work on Linux platforms. If you get linker
+ errors when trying to use a filter, then it is likely that loadable
+ filter support is not working yet on your platform. Thus, in order to
+ get Aspell to work correctly you will need to avoid compiling the
+ filters as individual modules by using the
+-@option{--enable-compile-in-filters} when configuring Aspell with
+-@command{./configure}.
++@option{--enable-compile-in-filters} @command{configure} option.
+
+ @node Using 32-Bit Dictionaries on a 64-Bit System
+ @appendixsec Using 32-Bit Dictionaries on a 64-Bit System
+--
+2.17.1
+
diff --git a/meta/recipes-support/aspell/aspell/CVE-2019-20433-0002.patch b/meta/recipes-support/aspell/aspell/CVE-2019-20433-0002.patch
new file mode 100644
index 0000000000..9569ddeebe
--- /dev/null
+++ b/meta/recipes-support/aspell/aspell/CVE-2019-20433-0002.patch
@@ -0,0 +1,68 @@
+From cefd447e5528b08bb0cd6656bc52b4255692cefc Mon Sep 17 00:00:00 2001
+From: Kevin Atkinson <kevina@gnu.org>
+Date: Sat, 17 Aug 2019 20:25:21 -0400
+Subject: [PATCH 2/2] Increment library version to reflect API changes.
+
+CVE: CVE-2019-20433
+Upstream-Status: Backport [https://github.com/GNUAspell/aspell/commit/cefd447e5528b08bb0cd6656bc52b4255692cefc]
+
+Signed-off-by: Stefan Ghinea <stefan.ghinea@windriver.com>
+---
+ Makefile.am | 31 +++++++++++++++++--------------
+ 1 file changed, 17 insertions(+), 14 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 7e15851..19dc044 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -94,18 +94,25 @@ libaspell_la_SOURCES =\
+
+ libaspell_la_LIBADD = $(LTLIBINTL) $(PTHREAD_LIB)
+
+-## Libtool to so name
+-## C:R:A => (C-A).(A).(R)
+-## 16:5:0 => 16.0.5
+-## 16:5:1 => 15.1.5
+-## 18:0:2 => 16.2.0
+-## 17:0:2 => 15.2.0
+-
++## The version string is current[:revision[:age]]
++##
++## Before a release that has changed the source code at all
++## increment revision.
++##
++## After merging changes that have changed the API in a backwards
++## comptable way set revision to 0 and bump both current and age.
++##
++## Do not change the API in a backwards incompatible way.
++##
++## See "Libtool: Updating version info"
++## (https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html)
++## for more into
++##
+ if INCREMENTED_SONAME
+-libaspell_la_LDFLAGS = -version-info 18:0:2 -no-undefined
++libaspell_la_LDFLAGS = -version-info 19:0:3 -no-undefined
+ else
+ ## Use C-1:R:A
+-libaspell_la_LDFLAGS = -version-info 17:0:2 -no-undefined
++libaspell_la_LDFLAGS = -version-info 18:0:3 -no-undefined
+ endif
+
+ if PSPELL_COMPATIBILITY
+@@ -113,11 +120,7 @@ libpspell_la_SOURCES = lib/dummy.cpp
+
+ libpspell_la_LIBADD = libaspell.la
+
+-if INCREMENTED_SONAME
+-libpspell_la_LDFLAGS = -version-info 18:0:2 -no-undefined
+-else
+-libpspell_la_LDFLAGS = -version-info 17:0:2 -no-undefined
+-endif
++libpspell_la_LDFLAGS = $(libaspell_la_LDFLAGS)
+
+ endif
+
+--
+2.17.1
+
diff --git a/meta/recipes-support/aspell/aspell_0.60.7.bb b/meta/recipes-support/aspell/aspell_0.60.7.bb
index b565cb3c6e..1e104c263c 100644
--- a/meta/recipes-support/aspell/aspell_0.60.7.bb
+++ b/meta/recipes-support/aspell/aspell_0.60.7.bb
@@ -8,6 +8,8 @@ PR = "r1"
SRC_URI = "${GNU_MIRROR}/aspell/aspell-${PV}.tar.gz \
file://0001-Fix-various-bugs-found-by-OSS-Fuze.patch \
+ file://CVE-2019-20433-0001.patch \
+ file://CVE-2019-20433-0002.patch \
"
SRC_URI[md5sum] = "8ef2252609c511cd2bb26f3a3932ef28"
SRC_URI[sha256sum] = "5ca8fc8cb0370cc6c9eb5b64c6d1bc5d57b3750dbf17887726c3407d833b70e4"
--
2.24.1
^ permalink raw reply related [flat|nested] 8+ messages in thread