Patchwork encoding: check overflow while calculating size of JSON escape buffer

login
register
mail settings
Submitter Yuya Nishihara
Date Aug. 31, 2017, 2:46 p.m.
Message ID <aac5ba5f39be117d89c1.1504190771@mimosa>
Download mbox | patch
Permalink /patch/23539/
State Accepted
Headers show

Comments

Yuya Nishihara - Aug. 31, 2017, 2:46 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1504184200 -32400
#      Thu Aug 31 21:56:40 2017 +0900
# Node ID aac5ba5f39be117d89c196252b52db501809e3c1
# Parent  167fea06d67ff144461c38799ba8cecaaddd0228
encoding: check overflow while calculating size of JSON escape buffer

The minimum input size to exploit is ~682MB (= INT_MAX / len('\\u0000') * 2)
on 32bit system, which isn't easy to achieve using Python str in 2GB process
address space, but probably doable.
Augie Fackler - Aug. 31, 2017, 7:22 p.m.
On Thu, Aug 31, 2017 at 11:46:11PM +0900, Yuya Nishihara wrote:
> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1504184200 -32400
> #      Thu Aug 31 21:56:40 2017 +0900
> # Node ID aac5ba5f39be117d89c196252b52db501809e3c1
> # Parent  167fea06d67ff144461c38799ba8cecaaddd0228
> encoding: check overflow while calculating size of JSON escape buffer

queued, thanks

Patch

diff --git a/mercurial/cext/charencode.c b/mercurial/cext/charencode.c
--- a/mercurial/cext/charencode.c
+++ b/mercurial/cext/charencode.c
@@ -294,11 +294,21 @@  static Py_ssize_t jsonescapelen(const ch
 				return -1;
 			}
 			esclen += jsonparanoidlentable[(unsigned char)c];
+			if (esclen < 0) {
+				PyErr_SetString(PyExc_MemoryError,
+						"overflow in jsonescapelen");
+				return -1;
+			}
 		}
 	} else {
 		for (i = 0; i < len; i++) {
 			char c = buf[i];
 			esclen += jsonlentable[(unsigned char)c];
+			if (esclen < 0) {
+				PyErr_SetString(PyExc_MemoryError,
+						"overflow in jsonescapelen");
+				return -1;
+			}
 		}
 	}
 
@@ -366,7 +376,7 @@  PyObject *jsonescapeu8fast(PyObject *sel
 	origlen = PyBytes_GET_SIZE(origstr);
 	esclen = jsonescapelen(origbuf, origlen, paranoid);
 	if (esclen < 0)
-		return NULL;  /* unsupported char found */
+		return NULL;  /* unsupported char found or overflow */
 	if (origlen == esclen) {
 		Py_INCREF(origstr);
 		return origstr;