* [PATCH][zeus 0/7] zeus review
@ 2020-03-16 16:30 Anuj Mittal
2020-03-16 16:30 ` [PATCH][zeus 1/7] qemu: fix CVE-2019-20382 Anuj Mittal
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Anuj Mittal @ 2020-03-16 16:30 UTC (permalink / raw)
To: openembedded-core
This series includes some CVE fixes for zeus. Please review.
Thanks,
Anuj
The following changes since commit d8cfc309f9dd0dc8904ab18e5898770502ee2540:
cve-check: fix ValueError (2020-03-15 13:33:19 -0700)
are available in the Git repository at:
git://push.openembedded.org/openembedded-core-contrib anujm/zeus
Adrian Bunk (1):
python3: Upgrade 3.7.6 -> 3.7.7
Anuj Mittal (1):
bluez: fix CVE-2020-0556
Lee Chee Yang (2):
qemu: fix CVE-2019-20382
libpcre2: fix CVE-2019-20454
Ross Burton (1):
sqlite: fix numerous CVEs
Stefan Ghinea (1):
aspell: CVE-2019-20433
Wenlin Kang (1):
libarchive: Fix CVE-2020-9308
meta/recipes-connectivity/bluez5/bluez5.inc | 2 +
.../bluez5/bluez5/CVE-2020-0556-1.patch | 35 +
.../bluez5/bluez5/CVE-2020-0556-2.patch | 143 +++
.../{python3_3.7.6.bb => python3_3.7.7.bb} | 6 +-
meta/recipes-devtools/qemu/qemu.inc | 1 +
.../qemu/qemu/CVE-2019-20382.patch | 1018 +++++++++++++++++
...ct-files-that-declare-invalid-header.patch | 124 ++
.../libarchive/libarchive_3.4.0.bb | 1 +
.../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 +
.../libpcre/libpcre2/CVE-2019-20454.patch | 19 +
.../recipes-support/libpcre/libpcre2_10.33.bb | 1 +
.../sqlite/sqlite3/CVE-2019-19244.patch | 33 +
.../sqlite/sqlite3/CVE-2019-19923.patch | 50 +
.../sqlite/sqlite3/CVE-2019-19924.patch | 65 ++
.../sqlite/sqlite3/CVE-2019-19925.patch | 33 +
.../sqlite/sqlite3/CVE-2019-19926.patch | 31 +
.../sqlite/sqlite3/CVE-2019-19959.patch | 46 +
.../sqlite/sqlite3/CVE-2019-20218.patch | 31 +
meta/recipes-support/sqlite/sqlite3_3.29.0.bb | 10 +-
21 files changed, 2714 insertions(+), 4 deletions(-)
create mode 100644 meta/recipes-connectivity/bluez5/bluez5/CVE-2020-0556-1.patch
create mode 100644 meta/recipes-connectivity/bluez5/bluez5/CVE-2020-0556-2.patch
rename meta/recipes-devtools/python/{python3_3.7.6.bb => python3_3.7.7.bb} (98%)
create mode 100644 meta/recipes-devtools/qemu/qemu/CVE-2019-20382.patch
create mode 100644 meta/recipes-extended/libarchive/libarchive/0001-RAR5-reader-reject-files-that-declare-invalid-header.patch
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
create mode 100644 meta/recipes-support/libpcre/libpcre2/CVE-2019-20454.patch
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-19244.patch
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-19923.patch
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-19924.patch
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-19925.patch
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-19926.patch
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-19959.patch
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-20218.patch
--
2.24.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [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 2/7] libpcre2: fix CVE-2019-20454
2020-03-16 16:30 [PATCH][zeus 0/7] zeus review Anuj Mittal
2020-03-16 16:30 ` [PATCH][zeus 1/7] qemu: fix CVE-2019-20382 Anuj Mittal
@ 2020-03-16 16:31 ` Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 3/7] sqlite: fix numerous CVEs Anuj Mittal
` (4 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: 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>
---
.../libpcre/libpcre2/CVE-2019-20454.patch | 19 +++++++++++++++++++
.../recipes-support/libpcre/libpcre2_10.33.bb | 1 +
2 files changed, 20 insertions(+)
create mode 100644 meta/recipes-support/libpcre/libpcre2/CVE-2019-20454.patch
diff --git a/meta/recipes-support/libpcre/libpcre2/CVE-2019-20454.patch b/meta/recipes-support/libpcre/libpcre2/CVE-2019-20454.patch
new file mode 100644
index 0000000000..51f95a7097
--- /dev/null
+++ b/meta/recipes-support/libpcre/libpcre2/CVE-2019-20454.patch
@@ -0,0 +1,19 @@
+Upstream-Status: Backport [https://vcs.pcre.org/pcre2/code/trunk/src/pcre2_jit_compile.c?r1=1092&r2=1091&pathrev=1092]
+CVE: CVE-2020-8002
+Signed-off-by: Lee Chee Yang <chee.yang.lee@intel.com>
+
+--- pcre2-10.30/src/pcre2_jit_compile.c 2019/05/13 16:26:17 1091
++++ pcre2-10.30/src/pcre2_jit_compile.c 2019/05/13 16:38:18 1092
+@@ -8571,7 +8571,10 @@
+ PCRE2_SPTR bptr;
+ uint32_t c;
+
+-GETCHARINC(c, cc);
++/* Patch by PH */
++/* GETCHARINC(c, cc); */
++
++c = *cc++;
+ #if PCRE2_CODE_UNIT_WIDTH == 32
+ if (c >= 0x110000)
+ return NULL;
+
diff --git a/meta/recipes-support/libpcre/libpcre2_10.33.bb b/meta/recipes-support/libpcre/libpcre2_10.33.bb
index 50b26753b4..1020df99b8 100644
--- a/meta/recipes-support/libpcre/libpcre2_10.33.bb
+++ b/meta/recipes-support/libpcre/libpcre2_10.33.bb
@@ -12,6 +12,7 @@ LIC_FILES_CHKSUM = "file://LICENCE;md5=b1588d3bb4cb0e1f5a597d908f8c5b37"
SRC_URI = "https://ftp.pcre.org/pub/pcre/pcre2-${PV}.tar.bz2 \
file://pcre-cross.patch \
+ file://CVE-2019-20454.patch \
"
SRC_URI[md5sum] = "80b355f2dce909a2e2424f5c79eddb44"
--
2.24.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH][zeus 3/7] sqlite: fix numerous CVEs
2020-03-16 16:30 [PATCH][zeus 0/7] zeus review Anuj Mittal
2020-03-16 16:30 ` [PATCH][zeus 1/7] qemu: fix CVE-2019-20382 Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 2/7] libpcre2: fix CVE-2019-20454 Anuj Mittal
@ 2020-03-16 16:31 ` Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 4/7] aspell: CVE-2019-20433 Anuj Mittal
` (3 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: Ross Burton <ross.burton@intel.com>
Fix the following CVEs:
- CVE-2019-19244
- CVE-2019-19923
- CVE-2019-19924
- CVE-2019-19925
- CVE-2019-19926
- CVE-2019-19959
- CVE-2019-20218
Signed-off-by: Ross Burton <ross.burton@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
[ removed the CVE-2019-19880 fix that did not apply cleanly ]
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
---
.../sqlite/sqlite3/CVE-2019-19244.patch | 33 ++++++++++
.../sqlite/sqlite3/CVE-2019-19923.patch | 50 ++++++++++++++
.../sqlite/sqlite3/CVE-2019-19924.patch | 65 +++++++++++++++++++
.../sqlite/sqlite3/CVE-2019-19925.patch | 33 ++++++++++
.../sqlite/sqlite3/CVE-2019-19926.patch | 31 +++++++++
.../sqlite/sqlite3/CVE-2019-19959.patch | 46 +++++++++++++
.../sqlite/sqlite3/CVE-2019-20218.patch | 31 +++++++++
meta/recipes-support/sqlite/sqlite3_3.29.0.bb | 10 ++-
8 files changed, 298 insertions(+), 1 deletion(-)
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-19244.patch
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-19923.patch
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-19924.patch
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-19925.patch
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-19926.patch
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-19959.patch
create mode 100644 meta/recipes-support/sqlite/sqlite3/CVE-2019-20218.patch
diff --git a/meta/recipes-support/sqlite/sqlite3/CVE-2019-19244.patch b/meta/recipes-support/sqlite/sqlite3/CVE-2019-19244.patch
new file mode 100644
index 0000000000..3f70979acc
--- /dev/null
+++ b/meta/recipes-support/sqlite/sqlite3/CVE-2019-19244.patch
@@ -0,0 +1,33 @@
+CVE: CVE-2019-19244
+Upstream-Status: Backport
+Signed-off-by: Ross Burton <ross.burton@intel.com>
+
+From 0f690d4ae5ffe656762fdbb7f36cc4c2dcbb2d9d Mon Sep 17 00:00:00 2001
+From: dan <dan@noemail.net>
+Date: Fri, 22 Nov 2019 10:14:01 +0000
+Subject: [PATCH] Fix a crash that could occur if a sub-select that uses both
+ DISTINCT and window functions also used an ORDER BY that is the same as its
+ select list.
+
+Amalgamation version of the patch:
+FossilOrigin-Name: bcdd66c1691955c697f3d756c2b035acfe98f6aad72e90b0021bab6e9023b3ba
+---
+ sqlite3.c | 5 +++--
+ sqlite3.h | 2 +-
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/sqlite3.c b/sqlite3.c
+index 8fd740b..db1c649 100644
+--- a/sqlite3.c
++++ b/sqlite3.c
+@@ -131679,6 +131679,7 @@ SQLITE_PRIVATE int sqlite3Select(
+ */
+ if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
+ && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0
++ && p->pWin==0
+ ){
+ p->selFlags &= ~SF_Distinct;
+ pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0);
+--
+2.24.1
+
diff --git a/meta/recipes-support/sqlite/sqlite3/CVE-2019-19923.patch b/meta/recipes-support/sqlite/sqlite3/CVE-2019-19923.patch
new file mode 100644
index 0000000000..b1b866b250
--- /dev/null
+++ b/meta/recipes-support/sqlite/sqlite3/CVE-2019-19923.patch
@@ -0,0 +1,50 @@
+CVE: CVE-2019-19923
+Upstream-Status: Backport
+Signed-off-by: Ross Burton <ross.burton@intel.com>
+
+From b64463719dc53bde98b0ce3930b10a32560c3a02 Mon Sep 17 00:00:00 2001
+From: "D. Richard Hipp" <drh@hwaci.com>
+Date: Wed, 18 Dec 2019 20:51:58 +0000
+Subject: [PATCH] Continue to back away from the LEFT JOIN optimization of
+ check-in [41c27bc0ff1d3135] by disallowing query flattening if the outer
+ query is DISTINCT. Without this fix, if an index scan is run on the table
+ within the view on the right-hand side of the LEFT JOIN, stale result
+ registers might be accessed yielding incorrect results, and/or an
+ OP_IfNullRow opcode might be invoked on the un-opened table, resulting in a
+ NULL-pointer dereference. This problem was found by the Yongheng and Rui
+ fuzzer.
+
+FossilOrigin-Name: 862974312edf00e9d1068115d1a39b7235b7db68b6d86b81d38a12f025a4748e
+---
+ sqlite3.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/sqlite3.c b/sqlite3.c
+index d29da07..5bc06c8 100644
+--- a/sqlite3.c
++++ b/sqlite3.c
+@@ -129216,6 +129216,7 @@ static void substSelect(
+ ** (3b) the FROM clause of the subquery may not contain a virtual
+ ** table and
+ ** (3c) the outer query may not be an aggregate.
++** (3d) the outer query may not be DISTINCT.
+ **
+ ** (4) The subquery can not be DISTINCT.
+ **
+@@ -129412,8 +129413,11 @@ static int flattenSubquery(
+ */
+ if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
+ isLeftJoin = 1;
+- if( pSubSrc->nSrc>1 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){
+- /* (3a) (3c) (3b) */
++ if( pSubSrc->nSrc>1 /* (3a) */
++ || isAgg /* (3b) */
++ || IsVirtual(pSubSrc->a[0].pTab) /* (3c) */
++ || (p->selFlags & SF_Distinct)!=0 /* (3d) */
++ ){
+ return 0;
+ }
+ }
+--
+2.24.1
+
diff --git a/meta/recipes-support/sqlite/sqlite3/CVE-2019-19924.patch b/meta/recipes-support/sqlite/sqlite3/CVE-2019-19924.patch
new file mode 100644
index 0000000000..80d5edbb0c
--- /dev/null
+++ b/meta/recipes-support/sqlite/sqlite3/CVE-2019-19924.patch
@@ -0,0 +1,65 @@
+CVE: CVE-2019-19924
+Upstream-Status: Backport
+Signed-off-by: Ross Burton <ross.burton@intel.com>
+
+From 854fe21e8a987f84da81f6bb9e90abc5355c6621 Mon Sep 17 00:00:00 2001
+From: "D. Richard Hipp" <drh@hwaci.com>
+Date: Thu, 19 Dec 2019 20:37:32 +0000
+Subject: [PATCH] When an error occurs while rewriting the parser tree for
+ window functions in the sqlite3WindowRewrite() routine, make sure that
+ pParse->nErr is set, and make sure that this shuts down any subsequent code
+ generation that might depend on the transformations that were implemented.
+ This fixes a problem discovered by the Yongheng and Rui fuzzer.
+
+Amalgamation format of backported patch
+FossilOrigin-Name: e2bddcd4c55ba3cbe0130332679ff4b048630d0ced9a8899982edb5a3569ba7f
+---
+ sqlite3.c | 16 +++++++++++-----
+ sqlite3.h | 2 +-
+ 2 files changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/sqlite3.c b/sqlite3.c
+index 408ec4c..857c28e 100644
+--- a/sqlite3.c
++++ b/sqlite3.c
+@@ -77798,7 +77798,8 @@ SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){
+ */
+ static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){
+ assert( p->nOp>0 || p->aOp==0 );
+- assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed );
++ assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed
++ || p->pParse->nErr>0 );
+ if( p->nOp ){
+ assert( p->aOp );
+ sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment);
+@@ -97872,6 +97873,7 @@ static int codeCompare(
+ int addr;
+ CollSeq *p4;
+
++ if( pParse->nErr ) return 0;
+ p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight);
+ p5 = binaryCompareP5(pLeft, pRight, jumpIfNull);
+ addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1,
+@@ -147627,7 +147629,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
+
+ pTab = sqlite3DbMallocZero(db, sizeof(Table));
+ if( pTab==0 ){
+- return SQLITE_NOMEM;
++ return sqlite3ErrorToParser(db, SQLITE_NOMEM);
+ }
+
+ p->pSrc = 0;
+@@ -147731,6 +147733,10 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
+ sqlite3DbFree(db, pTab);
+ }
+
++ if( rc && pParse->nErr==0 ){
++ assert( pParse->db->mallocFailed );
++ return sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM);
++ }
+ return rc;
+ }
+
+--
+2.24.1
+
diff --git a/meta/recipes-support/sqlite/sqlite3/CVE-2019-19925.patch b/meta/recipes-support/sqlite/sqlite3/CVE-2019-19925.patch
new file mode 100644
index 0000000000..ffc2c6afff
--- /dev/null
+++ b/meta/recipes-support/sqlite/sqlite3/CVE-2019-19925.patch
@@ -0,0 +1,33 @@
+CVE: CVE-2019-19925
+Upstream-Status: Backport
+Signed-off-by: Ross Burton <ross.burton@intel.com>
+
+From e92580434d2cdca228649d32f76167492de4f512 Mon Sep 17 00:00:00 2001
+From: "D. Richard Hipp" <drh@hwaci.com>
+Date: Thu, 19 Dec 2019 15:15:40 +0000
+Subject: [PATCH] Fix the zipfile extension so that INSERT works even if the
+ pathname of the file being inserted is a NULL. Bug discovered by the
+ Yongheng and Rui fuzzer.
+
+FossilOrigin-Name: a80f84b511231204658304226de3e075a55afc2e3f39ac063716f7a57f585c06
+---
+ shell.c | 1 +
+ sqlite3.c | 4 ++--
+ sqlite3.h | 2 +-
+ 3 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/shell.c b/shell.c
+index 053180c..404a8d4 100644
+--- a/shell.c
++++ b/shell.c
+@@ -5827,6 +5827,7 @@ static int zipfileUpdate(
+
+ if( rc==SQLITE_OK ){
+ zPath = (const char*)sqlite3_value_text(apVal[2]);
++ if( zPath==0 ) zPath = "";
+ nPath = (int)strlen(zPath);
+ mTime = zipfileGetTime(apVal[4]);
+ }
+--
+2.24.1
+
diff --git a/meta/recipes-support/sqlite/sqlite3/CVE-2019-19926.patch b/meta/recipes-support/sqlite/sqlite3/CVE-2019-19926.patch
new file mode 100644
index 0000000000..92bc7908bc
--- /dev/null
+++ b/meta/recipes-support/sqlite/sqlite3/CVE-2019-19926.patch
@@ -0,0 +1,31 @@
+CVE: CVE-2019-19926
+Upstream-Status: Backport
+Signed-off-by: Ross Burton <ross.burton@intel.com>
+
+From 4165b1e1e0001165ace9051a70f938099505eadc Mon Sep 17 00:00:00 2001
+From: "D. Richard Hipp" <drh@hwaci.com>
+Date: Thu, 19 Dec 2019 22:08:19 +0000
+Subject: [PATCH] Continuation of [e2bddcd4c55ba3cb]: Add another spot where it
+ is necessary to abort early due to prior errors in sqlite3WindowRewrite().
+
+FossilOrigin-Name: cba2a2a44cdf138a629109bb0ad088ed4ef67fc66bed3e0373554681a39615d2
+---
+ sqlite3.c | 7 ++++---
+ sqlite3.h | 2 +-
+ 2 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/sqlite3.c b/sqlite3.c
+index 857c28e..19a474d 100644
+--- a/sqlite3.c
++++ b/sqlite3.c
+@@ -128427,6 +128427,7 @@ static int multiSelect(
+ }
+ #endif
+ }
++ if( pParse->nErr ) goto multi_select_end;
+
+ /* Compute collating sequences used by
+ ** temporary tables needed to implement the compound select.
+--
+2.24.1
+
diff --git a/meta/recipes-support/sqlite/sqlite3/CVE-2019-19959.patch b/meta/recipes-support/sqlite/sqlite3/CVE-2019-19959.patch
new file mode 100644
index 0000000000..cba8ec9d30
--- /dev/null
+++ b/meta/recipes-support/sqlite/sqlite3/CVE-2019-19959.patch
@@ -0,0 +1,46 @@
+CVE: CVE-2019-19959
+Upstream-Status: Backport
+Signed-off-by: Ross Burton <ross.burton@intel.com>
+
+From f83f7e8141ee7cbbf7f2dc8985279a7372b259b6 Mon Sep 17 00:00:00 2001
+From: "D. Richard Hipp" <drh@hwaci.com>
+Date: Mon, 23 Dec 2019 21:04:33 +0000
+Subject: [PATCH] Fix the zipfile() function in the zipfile extension so that
+ it is able to deal with goofy filenames that contain embedded zeros.
+
+FossilOrigin-Name: cc0fb00a128fd0773db5ff7891f7aa577a3671d570166d2cbb30df922344adcf
+---
+ shell.c | 4 ++--
+ sqlite3.c | 4 ++--
+ sqlite3.h | 2 +-
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/shell.c b/shell.c
+index 404a8d4..48065e9 100644
+--- a/shell.c
++++ b/shell.c
+@@ -5841,7 +5841,7 @@ static int zipfileUpdate(
+ zFree = sqlite3_mprintf("%s/", zPath);
+ if( zFree==0 ){ rc = SQLITE_NOMEM; }
+ zPath = (const char*)zFree;
+- nPath++;
++ nPath = (int)strlen(zPath);
+ }
+ }
+
+@@ -6242,11 +6242,11 @@ void zipfileStep(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){
+ }else{
+ if( zName[nName-1]!='/' ){
+ zName = zFree = sqlite3_mprintf("%s/", zName);
+- nName++;
+ if( zName==0 ){
+ rc = SQLITE_NOMEM;
+ goto zipfile_step_out;
+ }
++ nName = (int)strlen(zName);
+ }else{
+ while( nName>1 && zName[nName-2]=='/' ) nName--;
+ }
+--
+2.24.1
+
diff --git a/meta/recipes-support/sqlite/sqlite3/CVE-2019-20218.patch b/meta/recipes-support/sqlite/sqlite3/CVE-2019-20218.patch
new file mode 100644
index 0000000000..fb6cd6df2d
--- /dev/null
+++ b/meta/recipes-support/sqlite/sqlite3/CVE-2019-20218.patch
@@ -0,0 +1,31 @@
+CVE: CVE-2019-20218
+Upstream-Status: Backport
+Signed-off-by: Ross Burton <ross.burton@intel.com>
+
+From 6bbd76d34f29f61483791231f2ce579dcadab8a5 Mon Sep 17 00:00:00 2001
+From: Dan Kennedy <danielk1977@gmail.com>
+Date: Fri, 27 Dec 2019 20:54:42 +0000
+Subject: [PATCH] Do not attempt to unwind the WITH stack in the Parse object
+ following an error. This fixes a separate case to [de6e6d68].
+
+FossilOrigin-Name: d29edef93451cc67a5d69c1cce1b1832d9ca8fff1f600afdd51338b74d077b92
+---
+ sqlite3.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sqlite3.c b/sqlite3.c
+index 5bc06c8..408ec4c 100644
+--- a/sqlite3.c
++++ b/sqlite3.c
+@@ -130570,7 +130570,7 @@ static int selectExpander(Walker *pWalker, Select *p){
+
+ /* Process NATURAL keywords, and ON and USING clauses of joins.
+ */
+- if( db->mallocFailed || sqliteProcessJoin(pParse, p) ){
++ if( pParse->nErr || db->mallocFailed || sqliteProcessJoin(pParse, p) ){
+ return WRC_Abort;
+ }
+
+--
+2.24.1
+
diff --git a/meta/recipes-support/sqlite/sqlite3_3.29.0.bb b/meta/recipes-support/sqlite/sqlite3_3.29.0.bb
index 34066fbe89..cf3b179845 100644
--- a/meta/recipes-support/sqlite/sqlite3_3.29.0.bb
+++ b/meta/recipes-support/sqlite/sqlite3_3.29.0.bb
@@ -4,6 +4,14 @@ LICENSE = "PD"
LIC_FILES_CHKSUM = "file://sqlite3.h;endline=11;md5=786d3dc581eff03f4fd9e4a77ed00c66"
SRC_URI = "http://www.sqlite.org/2019/sqlite-autoconf-${SQLITE_PV}.tar.gz \
- file://0001-Fix-CVE-2019-16168.patch"
+ file://0001-Fix-CVE-2019-16168.patch \
+ file://CVE-2019-19244.patch \
+ file://CVE-2019-19923.patch \
+ file://CVE-2019-19924.patch \
+ file://CVE-2019-19925.patch \
+ file://CVE-2019-19926.patch \
+ file://CVE-2019-19959.patch \
+ file://CVE-2019-20218.patch \
+"
SRC_URI[md5sum] = "8f3dfe83387e62ecb91c7c5c09c688dc"
SRC_URI[sha256sum] = "8e7c1e2950b5b04c5944a981cb31fffbf9d2ddda939d536838ebc854481afd5b"
--
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
* [PATCH][zeus 5/7] python3: Upgrade 3.7.6 -> 3.7.7
2020-03-16 16:30 [PATCH][zeus 0/7] zeus review Anuj Mittal
` (3 preceding siblings ...)
2020-03-16 16:31 ` [PATCH][zeus 4/7] aspell: CVE-2019-20433 Anuj Mittal
@ 2020-03-16 16:31 ` Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 6/7] libarchive: Fix CVE-2020-9308 Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 7/7] bluez: fix CVE-2020-0556 Anuj Mittal
6 siblings, 0 replies; 8+ messages in thread
From: Anuj Mittal @ 2020-03-16 16:31 UTC (permalink / raw)
To: openembedded-core
From: Adrian Bunk <bunk@stusta.de>
THE LICENSE checksum changed in this update due to copyright notice
added for 2020.
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
---
.../python/{python3_3.7.6.bb => python3_3.7.7.bb} | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
rename meta/recipes-devtools/python/{python3_3.7.6.bb => python3_3.7.7.bb} (98%)
diff --git a/meta/recipes-devtools/python/python3_3.7.6.bb b/meta/recipes-devtools/python/python3_3.7.7.bb
similarity index 98%
rename from meta/recipes-devtools/python/python3_3.7.6.bb
rename to meta/recipes-devtools/python/python3_3.7.7.bb
index b33b7028d4..823eb2f8fd 100644
--- a/meta/recipes-devtools/python/python3_3.7.6.bb
+++ b/meta/recipes-devtools/python/python3_3.7.7.bb
@@ -3,7 +3,7 @@ HOMEPAGE = "http://www.python.org"
LICENSE = "PSFv2"
SECTION = "devel/python"
-LIC_FILES_CHKSUM = "file://LICENSE;md5=e466242989bd33c1bd2b6a526a742498"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=203a6dbc802ee896020a47161e759642"
SRC_URI = "http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.xz \
file://run-ptest \
@@ -38,8 +38,8 @@ SRC_URI_append_class-nativesdk = " \
file://0001-main.c-if-OEPYTHON3HOME-is-set-use-instead-of-PYTHON.patch \
"
-SRC_URI[md5sum] = "c08fbee72ad5c2c95b0f4e44bf6fd72c"
-SRC_URI[sha256sum] = "55a2cce72049f0794e9a11a84862e9039af9183603b78bc60d89539f82cf533f"
+SRC_URI[md5sum] = "172c650156f7bea68ce31b2fd01fa766"
+SRC_URI[sha256sum] = "06a0a9f1bf0d8cd1e4121194d666c4e28ddae4dd54346de6c343206599f02136"
# exclude pre-releases for both python 2.x and 3.x
UPSTREAM_CHECK_REGEX = "[Pp]ython-(?P<pver>\d+(\.\d+)+).tar"
--
2.24.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH][zeus 6/7] libarchive: Fix CVE-2020-9308
2020-03-16 16:30 [PATCH][zeus 0/7] zeus review Anuj Mittal
` (4 preceding siblings ...)
2020-03-16 16:31 ` [PATCH][zeus 5/7] python3: Upgrade 3.7.6 -> 3.7.7 Anuj Mittal
@ 2020-03-16 16:31 ` Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 7/7] bluez: fix CVE-2020-0556 Anuj Mittal
6 siblings, 0 replies; 8+ messages in thread
From: Anuj Mittal @ 2020-03-16 16:31 UTC (permalink / raw)
To: openembedded-core
From: Wenlin Kang <wenlin.kang@windriver.com>
Fix CVE-2020-9308
Signed-off-by: Wenlin Kang <wenlin.kang@windriver.com>
Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
---
| 124 ++++++++++++++++++
.../libarchive/libarchive_3.4.0.bb | 1 +
2 files changed, 125 insertions(+)
create mode 100644 meta/recipes-extended/libarchive/libarchive/0001-RAR5-reader-reject-files-that-declare-invalid-header.patch
--git a/meta/recipes-extended/libarchive/libarchive/0001-RAR5-reader-reject-files-that-declare-invalid-header.patch b/meta/recipes-extended/libarchive/libarchive/0001-RAR5-reader-reject-files-that-declare-invalid-header.patch
new file mode 100644
index 0000000000..a84c1f1f76
--- /dev/null
+++ b/meta/recipes-extended/libarchive/libarchive/0001-RAR5-reader-reject-files-that-declare-invalid-header.patch
@@ -0,0 +1,124 @@
+From c1fe0a8cc8dde8ba3eae3d17e34060d2d6e4eb96 Mon Sep 17 00:00:00 2001
+From: Grzegorz Antoniak <ga@anadoxin.org>
+Date: Sun, 2 Feb 2020 08:04:41 +0100
+Subject: [PATCH] RAR5 reader: reject files that declare invalid header flags
+
+One of the fields in RAR5's base block structure is the size of the
+header. Some invalid files declare a 0 header size setting, which can
+confuse the unpacker. Minimum header size for RAR5 base blocks is 7
+bytes (4 bytes for CRC, and 3 bytes for the rest), so block size of 0
+bytes should be rejected at header parsing stage.
+
+The fix adds an error condition if header size of 0 bytes is detected.
+In this case, the unpacker will not attempt to unpack the file, as the
+header is corrupted.
+
+The commit also adds OSSFuzz #20459 sample to test further regressions
+in this area.
+
+Upstream-Status: Backport[https://github.com/libarchive/libarchive/commit/94821008d6eea81e315c5881cdf739202961040a]
+CVE: CVE-2020-9308
+
+Signed-off-by: Wenlin Kang <wenlin.kang@windriver.com>
+---
+ Makefile.am | 1 +
+ libarchive/archive_read_support_format_rar5.c | 17 +++++++++++++++--
+ libarchive/test/test_read_format_rar5.c | 15 +++++++++++++++
+ ...d_format_rar5_block_size_is_too_small.rar.uu | 8 ++++++++
+ 4 files changed, 39 insertions(+), 2 deletions(-)
+ create mode 100644 libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu
+
+diff --git a/Makefile.am b/Makefile.am
+index da78b24..01abf20 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -863,6 +863,7 @@ libarchive_test_EXTRA_DIST=\
+ libarchive/test/test_read_format_rar5_symlink.rar.uu \
+ libarchive/test/test_read_format_rar5_truncated_huff.rar.uu \
+ libarchive/test/test_read_format_rar5_win32.rar.uu \
++ libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu \
+ libarchive/test/test_read_format_raw.bufr.uu \
+ libarchive/test/test_read_format_raw.data.gz.uu \
+ libarchive/test/test_read_format_raw.data.Z.uu \
+diff --git a/libarchive/archive_read_support_format_rar5.c b/libarchive/archive_read_support_format_rar5.c
+index 7c24627..f73393c 100644
+--- a/libarchive/archive_read_support_format_rar5.c
++++ b/libarchive/archive_read_support_format_rar5.c
+@@ -2034,6 +2034,8 @@ static int scan_for_signature(struct archive_read* a);
+ static int process_base_block(struct archive_read* a,
+ struct archive_entry* entry)
+ {
++ const size_t SMALLEST_RAR5_BLOCK_SIZE = 3;
++
+ struct rar5* rar = get_context(a);
+ uint32_t hdr_crc, computed_crc;
+ size_t raw_hdr_size = 0, hdr_size_len, hdr_size;
+@@ -2057,15 +2059,26 @@ static int process_base_block(struct archive_read* a,
+ return ARCHIVE_EOF;
+ }
+
++ hdr_size = raw_hdr_size + hdr_size_len;
++
+ /* Sanity check, maximum header size for RAR5 is 2MB. */
+- if(raw_hdr_size > (2 * 1024 * 1024)) {
++ if(hdr_size > (2 * 1024 * 1024)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Base block header is too large");
+
+ return ARCHIVE_FATAL;
+ }
+
+- hdr_size = raw_hdr_size + hdr_size_len;
++ /* Additional sanity checks to weed out invalid files. */
++ if(raw_hdr_size == 0 || hdr_size_len == 0 ||
++ hdr_size < SMALLEST_RAR5_BLOCK_SIZE)
++ {
++ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
++ "Too small block encountered (%ld bytes)",
++ raw_hdr_size);
++
++ return ARCHIVE_FATAL;
++ }
+
+ /* Read the whole header data into memory, maximum memory use here is
+ * 2MB. */
+diff --git a/libarchive/test/test_read_format_rar5.c b/libarchive/test/test_read_format_rar5.c
+index 1408f37..32e7ed8 100644
+--- a/libarchive/test/test_read_format_rar5.c
++++ b/libarchive/test/test_read_format_rar5.c
+@@ -1194,3 +1194,18 @@ DEFINE_TEST(test_read_format_rar5_fileattr)
+
+ EPILOGUE();
+ }
++
++DEFINE_TEST(test_read_format_rar5_block_size_is_too_small)
++{
++ char buf[4096];
++ PROLOGUE("test_read_format_rar5_block_size_is_too_small.rar");
++
++ /* This file is damaged, so those functions should return failure.
++ * Additionally, SIGSEGV shouldn't be raised during execution
++ * of those functions. */
++
++ assertA(archive_read_next_header(a, &ae) != ARCHIVE_OK);
++ assertA(archive_read_data(a, buf, sizeof(buf)) <= 0);
++
++ EPILOGUE();
++}
+diff --git a/libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu b/libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu
+new file mode 100644
+index 0000000..5cad219
+--- /dev/null
++++ b/libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu
+@@ -0,0 +1,8 @@
++begin 644 test_read_format_rar5_block_size_is_too_small.rar
++M4F%R(1H'`0"-[P+2``+'(!P,("`@N`,!`B`@("`@("`@("`@("`@("#_("`@
++M("`@("`@("`@((:Q;2!4-'-^4B`!((WO`M(``O\@$/\@-R`@("`@("`@("`@
++M``X@("`@("`@____("`@("`@(/\@("`@("`@("`@("#_(+6U,2"UM;6UM[CU
++M)B`@*(0G(`!.`#D\3R``(/__(,+_````-0#_($&%*/HE=C+N`"```"```"`D
++J`)$#("#_("#__P`@__\@_R#_("`@("`@("#_("#__R`@(/__("#__R`"
++`
++end
+--
+2.23.0
+
diff --git a/meta/recipes-extended/libarchive/libarchive_3.4.0.bb b/meta/recipes-extended/libarchive/libarchive_3.4.0.bb
index c196382b07..db45ccf654 100644
--- a/meta/recipes-extended/libarchive/libarchive_3.4.0.bb
+++ b/meta/recipes-extended/libarchive/libarchive_3.4.0.bb
@@ -33,6 +33,7 @@ EXTRA_OECONF += "--enable-largefile"
SRC_URI = "http://libarchive.org/downloads/libarchive-${PV}.tar.gz \
file://CVE-2019-19221.patch \
+ file://0001-RAR5-reader-reject-files-that-declare-invalid-header.patch \
"
SRC_URI[md5sum] = "6046396255bd7cf6d0f6603a9bda39ac"
--
2.24.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH][zeus 7/7] bluez: fix CVE-2020-0556
2020-03-16 16:30 [PATCH][zeus 0/7] zeus review Anuj Mittal
` (5 preceding siblings ...)
2020-03-16 16:31 ` [PATCH][zeus 6/7] libarchive: Fix CVE-2020-9308 Anuj Mittal
@ 2020-03-16 16:31 ` Anuj Mittal
6 siblings, 0 replies; 8+ messages in thread
From: Anuj Mittal @ 2020-03-16 16:31 UTC (permalink / raw)
To: openembedded-core
It was discovered that BlueZ's HID and HOGP profiles implementations
don't specifically require bonding between the device and the host.
This creates an opportunity for an malicious device to connect to a
target host to either impersonate an existing HID device without
security or to cause an SDP or GATT service discovery to take place
which would allow HID reports to be injected to the input subsystem from
a non-bonded source.
(From OE-Core rev: d598f8eee0741148416e8660e10c716654205cb5)
Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
(cherry picked from commit bed169a07b04a7dc003958fa309e6ff761f85a72)
---
meta/recipes-connectivity/bluez5/bluez5.inc | 2 +
.../bluez5/bluez5/CVE-2020-0556-1.patch | 35 +++++
.../bluez5/bluez5/CVE-2020-0556-2.patch | 143 ++++++++++++++++++
3 files changed, 180 insertions(+)
create mode 100644 meta/recipes-connectivity/bluez5/bluez5/CVE-2020-0556-1.patch
create mode 100644 meta/recipes-connectivity/bluez5/bluez5/CVE-2020-0556-2.patch
diff --git a/meta/recipes-connectivity/bluez5/bluez5.inc b/meta/recipes-connectivity/bluez5/bluez5.inc
index f582a07e22..75fc2dbf4c 100644
--- a/meta/recipes-connectivity/bluez5/bluez5.inc
+++ b/meta/recipes-connectivity/bluez5/bluez5.inc
@@ -58,6 +58,8 @@ SRC_URI = "\
file://CVE-2018-10910.patch \
file://gcc9-fixes.patch \
file://0001-tools-Fix-build-after-y2038-changes-in-glibc.patch \
+ file://CVE-2020-0556-1.patch \
+ file://CVE-2020-0556-2.patch \
"
S = "${WORKDIR}/bluez-${PV}"
diff --git a/meta/recipes-connectivity/bluez5/bluez5/CVE-2020-0556-1.patch b/meta/recipes-connectivity/bluez5/bluez5/CVE-2020-0556-1.patch
new file mode 100644
index 0000000000..a6bf31e14b
--- /dev/null
+++ b/meta/recipes-connectivity/bluez5/bluez5/CVE-2020-0556-1.patch
@@ -0,0 +1,35 @@
+From 8cdbd3b09f29da29374e2f83369df24228da0ad1 Mon Sep 17 00:00:00 2001
+From: Alain Michaud <alainm@chromium.org>
+Date: Tue, 10 Mar 2020 02:35:16 +0000
+Subject: [PATCH 1/2] HOGP must only accept data from bonded devices.
+
+HOGP 1.0 Section 6.1 establishes that the HOGP must require bonding.
+
+Reference:
+https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00352.htm
+
+Upstream-Status: Backport [https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=8cdbd3b09f29da29374e2f83369df24228da0ad1]
+Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
+CVE: CVE-2020-0556
+---
+ profiles/input/hog.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/profiles/input/hog.c b/profiles/input/hog.c
+index 83c017dcb..dfac68921 100644
+--- a/profiles/input/hog.c
++++ b/profiles/input/hog.c
+@@ -186,6 +186,10 @@ static int hog_accept(struct btd_service *service)
+ return -EINVAL;
+ }
+
++ /* HOGP 1.0 Section 6.1 requires bonding */
++ if (!device_is_bonded(device, btd_device_get_bdaddr_type(device)))
++ return -ECONNREFUSED;
++
+ /* TODO: Replace GAttrib with bt_gatt_client */
+ bt_hog_attach(dev->hog, attrib);
+
+--
+2.24.1
+
diff --git a/meta/recipes-connectivity/bluez5/bluez5/CVE-2020-0556-2.patch b/meta/recipes-connectivity/bluez5/bluez5/CVE-2020-0556-2.patch
new file mode 100644
index 0000000000..8acb2f15ec
--- /dev/null
+++ b/meta/recipes-connectivity/bluez5/bluez5/CVE-2020-0556-2.patch
@@ -0,0 +1,143 @@
+From 3cccdbab2324086588df4ccf5f892fb3ce1f1787 Mon Sep 17 00:00:00 2001
+From: Alain Michaud <alainm@chromium.org>
+Date: Tue, 10 Mar 2020 02:35:18 +0000
+Subject: [PATCH 2/2] HID accepts bonded device connections only.
+
+This change adds a configuration for platforms to choose a more secure
+posture for the HID profile. While some older mice are known to not
+support pairing or encryption, some platform may choose a more secure
+posture by requiring the device to be bonded and require the
+connection to be encrypted when bonding is required.
+
+Reference:
+https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00352.html
+
+Upstream-Status: Backport [https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=3cccdbab2324086588df4ccf5f892fb3ce1f1787]
+Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
+CVE: CVE-2020-0556
+
+---
+ profiles/input/device.c | 23 ++++++++++++++++++++++-
+ profiles/input/device.h | 1 +
+ profiles/input/input.conf | 8 ++++++++
+ profiles/input/manager.c | 13 ++++++++++++-
+ 4 files changed, 43 insertions(+), 2 deletions(-)
+
+diff --git a/profiles/input/device.c b/profiles/input/device.c
+index 2cb3811c8..d89da2d7c 100644
+--- a/profiles/input/device.c
++++ b/profiles/input/device.c
+@@ -92,6 +92,7 @@ struct input_device {
+
+ static int idle_timeout = 0;
+ static bool uhid_enabled = false;
++static bool classic_bonded_only = false;
+
+ void input_set_idle_timeout(int timeout)
+ {
+@@ -103,6 +104,11 @@ void input_enable_userspace_hid(bool state)
+ uhid_enabled = state;
+ }
+
++void input_set_classic_bonded_only(bool state)
++{
++ classic_bonded_only = state;
++}
++
+ static void input_device_enter_reconnect_mode(struct input_device *idev);
+ static int connection_disconnect(struct input_device *idev, uint32_t flags);
+
+@@ -970,8 +976,18 @@ static int hidp_add_connection(struct input_device *idev)
+ if (device_name_known(idev->device))
+ device_get_name(idev->device, req->name, sizeof(req->name));
+
++ /* Make sure the device is bonded if required */
++ if (classic_bonded_only && !device_is_bonded(idev->device,
++ btd_device_get_bdaddr_type(idev->device))) {
++ error("Rejected connection from !bonded device %s", dst_addr);
++ goto cleanup;
++ }
++
+ /* Encryption is mandatory for keyboards */
+- if (req->subclass & 0x40) {
++ /* Some platforms may choose to require encryption for all devices */
++ /* Note that this only matters for pre 2.1 devices as otherwise the */
++ /* device is encrypted by default by the lower layers */
++ if (classic_bonded_only || req->subclass & 0x40) {
+ if (!bt_io_set(idev->intr_io, &gerr,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_INVALID)) {
+@@ -1203,6 +1219,11 @@ static void input_device_enter_reconnect_mode(struct input_device *idev)
+ DBG("path=%s reconnect_mode=%s", idev->path,
+ reconnect_mode_to_string(idev->reconnect_mode));
+
++ /* Make sure the device is bonded if required */
++ if (classic_bonded_only && !device_is_bonded(idev->device,
++ btd_device_get_bdaddr_type(idev->device)))
++ return;
++
+ /* Only attempt an auto-reconnect when the device is required to
+ * accept reconnections from the host.
+ */
+diff --git a/profiles/input/device.h b/profiles/input/device.h
+index 51a9aee18..3044db673 100644
+--- a/profiles/input/device.h
++++ b/profiles/input/device.h
+@@ -29,6 +29,7 @@ struct input_conn;
+
+ void input_set_idle_timeout(int timeout);
+ void input_enable_userspace_hid(bool state);
++void input_set_classic_bonded_only(bool state);
+
+ int input_device_register(struct btd_service *service);
+ void input_device_unregister(struct btd_service *service);
+diff --git a/profiles/input/input.conf b/profiles/input/input.conf
+index 3e1d65aae..166aff4a4 100644
+--- a/profiles/input/input.conf
++++ b/profiles/input/input.conf
+@@ -11,3 +11,11 @@
+ # Enable HID protocol handling in userspace input profile
+ # Defaults to false (HIDP handled in HIDP kernel module)
+ #UserspaceHID=true
++
++# Limit HID connections to bonded devices
++# The HID Profile does not specify that devices must be bonded, however some
++# platforms may want to make sure that input connections only come from bonded
++# device connections. Several older mice have been known for not supporting
++# pairing/encryption.
++# Defaults to false to maximize device compatibility.
++#ClassicBondedOnly=true
+diff --git a/profiles/input/manager.c b/profiles/input/manager.c
+index 1d31b0652..5cd27b839 100644
+--- a/profiles/input/manager.c
++++ b/profiles/input/manager.c
+@@ -96,7 +96,7 @@ static int input_init(void)
+ config = load_config_file(CONFIGDIR "/input.conf");
+ if (config) {
+ int idle_timeout;
+- gboolean uhid_enabled;
++ gboolean uhid_enabled, classic_bonded_only;
+
+ idle_timeout = g_key_file_get_integer(config, "General",
+ "IdleTimeout", &err);
+@@ -114,6 +114,17 @@ static int input_init(void)
+ input_enable_userspace_hid(uhid_enabled);
+ } else
+ g_clear_error(&err);
++
++ classic_bonded_only = g_key_file_get_boolean(config, "General",
++ "ClassicBondedOnly", &err);
++
++ if (!err) {
++ DBG("input.conf: ClassicBondedOnly=%s",
++ classic_bonded_only ? "true" : "false");
++ input_set_classic_bonded_only(classic_bonded_only);
++ } else
++ g_clear_error(&err);
++
+ }
+
+ btd_profile_register(&input_profile);
+--
+2.24.1
+
--
2.24.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2020-03-16 16:31 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-03-16 16:30 [PATCH][zeus 0/7] zeus review Anuj Mittal
2020-03-16 16:30 ` [PATCH][zeus 1/7] qemu: fix CVE-2019-20382 Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 2/7] libpcre2: fix CVE-2019-20454 Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 3/7] sqlite: fix numerous CVEs Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 4/7] aspell: CVE-2019-20433 Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 5/7] python3: Upgrade 3.7.6 -> 3.7.7 Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 6/7] libarchive: Fix CVE-2020-9308 Anuj Mittal
2020-03-16 16:31 ` [PATCH][zeus 7/7] bluez: fix CVE-2020-0556 Anuj Mittal
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox