From eb80c90221cdfeac03a7a7a77108c6949b5cbc3a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 1 Jun 2023 14:00:28 +0530 Subject: [PATCH] Ensure palmdoc decompress does nto write out of bounds. Fixes #2022035 [Private bug](https://bugs.launchpad.net/calibre/+bug/2022035) --- src/calibre/ebooks/compression/palmdoc.c | 43 ++++++++++++++---------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/calibre/ebooks/compression/palmdoc.c b/src/calibre/ebooks/compression/palmdoc.c index 45eac58fd2..81e3d16f0a 100644 --- a/src/calibre/ebooks/compression/palmdoc.c +++ b/src/calibre/ebooks/compression/palmdoc.c @@ -42,10 +42,19 @@ typedef struct { #define CHAR(x) (( (x) > 127 ) ? (x)-256 : (x)) +static bool +write_to_bytes_object(PyObject **output, Py_ssize_t pos, char ch) { + if (pos >= PyBytes_GET_SIZE(*output)) { + if (_PyBytes_Resize(output, 2 * pos) != 0) return false; + } + PyBytes_AS_STRING(*output)[pos] = ch; + return true; +} + static PyObject * cpalmdoc_decompress(PyObject *self, PyObject *args) { const char *_input = NULL; Py_ssize_t input_len = 0; - Byte *input; char *output; Byte c; PyObject *ans; + Byte *input; Byte c; PyObject *ans; Py_ssize_t i = 0, o = 0, j = 0, di, n; if (!PyArg_ParseTuple(args, "y#", &_input, &input_len)) return NULL; @@ -54,31 +63,29 @@ cpalmdoc_decompress(PyObject *self, PyObject *args) { // Map chars to bytes for (j = 0; j < input_len; j++) input[j] = (_input[j] < 0) ? _input[j]+256 : _input[j]; - output = (char *)PyMem_Malloc(sizeof(char)*(MAX(BUFFER, 8*input_len))); - if (output == NULL) return PyErr_NoMemory(); + ans = PyBytes_FromStringAndSize(NULL, 8*input_len); + if (ans == NULL) { PyMem_Free(input); return NULL; } +#define write(ch) if (!write_to_bytes_object(&ans, o++, ch)) { PyMem_Free(input); return NULL; } while (i < input_len) { c = input[i++]; - if (c >= 1 && c <= 8) // copy 'c' bytes - while (c--) output[o++] = (char)input[i++]; - - else if (c <= 0x7F) // 0, 09-7F = self - output[o++] = (char)c; - - else if (c >= 0xC0) { // space + ASCII char - output[o++] = ' '; - output[o++] = c ^ 0x80; - } - else { // 80-BF repeat sequences + if (c >= 1 && c <= 8) { // copy 'c' bytes + while (c--) { write(input[i++]); } + } else if (c <= 0x7F) { // 0, 09-7F = self + write((char)c); + } else if (c >= 0xC0) { // space + ASCII char + write(' '); write(c ^ 0x80); + } else { // 80-BF repeat sequences c = (c << 8) + input[i++]; di = (c & 0x3FFF) >> 3; - for ( n = (c & 7) + 3; n--; ++o ) - output[o] = output[o - di]; + for ( n = (c & 7) + 3; n--; ++o ) { + if (!write_to_bytes_object(&ans, o, PyBytes_AS_STRING(ans)[o-di])) { PyMem_Free(input); return NULL; } + } } } - ans = Py_BuildValue("y#", output, o); - if (output != NULL) PyMem_Free(output); +#undef write if (input != NULL) PyMem_Free(input); + if (_PyBytes_Resize(&ans, o) != 0) return NULL; return ans; }