[Python-checkins] CVS: python/dist/src/Objects stringobject.c,2.69,2.70

M.-A. Lemburg python-dev@python.org
Fri, 30 Jun 2000 03:29:19 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory slayer.i.sourceforge.net:/tmp/cvs-serv25322/Objects

Modified Files:
	stringobject.c 
Log Message:
Marc-Andre Lemburg <mal@lemburg.com>:
New buffer overflow checks for formatting strings.

By Trent Mick.

Index: stringobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/stringobject.c,v
retrieving revision 2.69
retrieving revision 2.70
diff -C2 -r2.69 -r2.70
*** stringobject.c	2000/06/20 15:47:54	2.69
--- stringobject.c	2000/06/30 10:29:17	2.70
***************
*** 125,130 ****
  	const char *str;
  {
! 	register unsigned int size = strlen(str);
  	register PyStringObject *op;
  #ifndef DONT_SHARE_SHORT_STRINGS
  	if (size == 0 && (op = nullstring) != NULL) {
--- 125,135 ----
  	const char *str;
  {
! 	register size_t size = strlen(str);
  	register PyStringObject *op;
+ 	if (size > INT_MAX) {
+ 		PyErr_SetString(PyExc_OverflowError,
+ 			"string is too long for a Python string");
+ 		return NULL;
+ 	}
  #ifndef DONT_SHARE_SHORT_STRINGS
  	if (size == 0 && (op = nullstring) != NULL) {
***************
*** 238,244 ****
  	register PyStringObject *op;
  {
! 	/* XXX overflow? */
! 	int newsize = 2 + 4 * op->ob_size * sizeof(char);
! 	PyObject *v = PyString_FromStringAndSize((char *)NULL, newsize);
  	if (v == NULL) {
  		return NULL;
--- 243,253 ----
  	register PyStringObject *op;
  {
! 	size_t newsize = 2 + 4 * op->ob_size * sizeof(char);
! 	PyObject *v;
! 	if (newsize > INT_MAX) {
! 		PyErr_SetString(PyExc_OverflowError,
! 			"string is too large to make repr");
! 	}
! 	v = PyString_FromStringAndSize((char *)NULL, newsize);
  	if (v == NULL) {
  		return NULL;
***************
*** 2336,2341 ****
  
  static int
! formatfloat(buf, flags, prec, type, v)
  	char *buf;
  	int flags;
  	int prec;
--- 2345,2351 ----
  
  static int
! formatfloat(buf, buflen, flags, prec, type, v)
  	char *buf;
+ 	size_t buflen;
  	int flags;
  	int prec;
***************
*** 2343,2346 ****
--- 2353,2358 ----
  	PyObject *v;
  {
+ 	/* fmt = '%#.' + `prec` + `type`
+ 	   worst case length = 3 + 10 (len of INT_MAX) + 1 = 14 (use 20)*/
  	char fmt[20];
  	double x;
***************
*** 2349,2357 ****
  	if (prec < 0)
  		prec = 6;
- 	if (prec > 50)
- 		prec = 50; /* Arbitrary limitation */
  	if (type == 'f' && fabs(x)/1e25 >= 1e25)
  		type = 'g';
  	sprintf(fmt, "%%%s.%d%c", (flags&F_ALT) ? "#" : "", prec, type);
  	sprintf(buf, fmt, x);
  	return strlen(buf);
--- 2361,2379 ----
  	if (prec < 0)
  		prec = 6;
  	if (type == 'f' && fabs(x)/1e25 >= 1e25)
  		type = 'g';
  	sprintf(fmt, "%%%s.%d%c", (flags&F_ALT) ? "#" : "", prec, type);
+ 	/* worst case length calc to ensure no buffer overrun:
+ 	     fmt = %#.<prec>g
+ 	     buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp
+ 	        for any double rep.) 
+ 	     len = 1 + prec + 1 + 2 + 5 = 9 + prec
+ 	   If prec=0 the effective precision is 1 (the leading digit is
+ 	   always given), therefore increase by one to 10+prec. */
+ 	if (buflen <= (size_t)10 + (size_t)prec) {
+ 		PyErr_SetString(PyExc_OverflowError,
+ 			"formatted float is too long (precision too long?)");
+ 		return -1;
+ 	}
  	sprintf(buf, fmt, x);
  	return strlen(buf);
***************
*** 2359,2364 ****
  
  static int
! formatint(buf, flags, prec, type, v)
  	char *buf;
  	int flags;
  	int prec;
--- 2381,2387 ----
  
  static int
! formatint(buf, buflen, flags, prec, type, v)
  	char *buf;
+ 	size_t buflen;
  	int flags;
  	int prec;
***************
*** 2366,2369 ****
--- 2389,2394 ----
  	PyObject *v;
  {
+ 	/* fmt = '%#.' + `prec` + 'l' + `type`
+ 	   worst case length = 3 + 10 (len of INT_MAX) + 1 + 1 = 15 (use 20)*/
  	char fmt[20];
  	long x;
***************
*** 2373,2376 ****
--- 2398,2408 ----
  		prec = 1;
  	sprintf(fmt, "%%%s.%dl%c", (flags&F_ALT) ? "#" : "", prec, type);
+ 	/* buf = '+'/'-'/'0'/'0x' + '[0-9]'*max(prec,len(x in octal))
+ 	   worst case buf = '0x' + [0-9]*prec, where prec >= 11 */
+ 	if (buflen <= 13 || buflen <= (size_t)2+(size_t)prec) {
+ 		PyErr_SetString(PyExc_OverflowError,
+ 			"formatted integer is too long (precision too long?)");
+ 		return -1;
+ 	}
  	sprintf(buf, fmt, x);
  	return strlen(buf);
***************
*** 2378,2385 ****
  
  static int
! formatchar(buf, v)
  	char *buf;
  	PyObject *v;
  {
  	if (PyString_Check(v)) {
  		if (!PyArg_Parse(v, "c;%c requires int or char", &buf[0]))
--- 2410,2419 ----
  
  static int
! formatchar(buf, buflen, v)
  	char *buf;
+ 	size_t buflen;
  	PyObject *v;
  {
+ 	/* presume that the buffer is at least 2 characters long */
  	if (PyString_Check(v)) {
  		if (!PyArg_Parse(v, "c;%c requires int or char", &buf[0]))
***************
*** 2395,2399 ****
  
  
! /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) */
  
  PyObject *
--- 2429,2441 ----
  
  
! /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...)
! 
!    FORMATBUFLEN is the length of the buffer in which the floats, ints, &
!    chars are formatted. XXX This is a magic number. Each formatting
!    routine does bounds checking to ensure no overflow, but a better
!    solution may be to malloc a buffer of appropriate size for each
!    format. For now, the current solution is sufficient.
! */
! #define FORMATBUFLEN (size_t)120
  
  PyObject *
***************
*** 2452,2459 ****
  			PyObject *v = NULL;
  			PyObject *temp = NULL;
! 			char *buf;
  			int sign;
  			int len;
! 			char tmpbuf[120]; /* For format{float,int,char}() */
  			char *fmt_start = fmt;
  			
--- 2494,2501 ----
  			PyObject *v = NULL;
  			PyObject *temp = NULL;
! 			char *pbuf;
  			int sign;
  			int len;
! 			char formatbuf[FORMATBUFLEN]; /* For format{float,int,char}() */
  			char *fmt_start = fmt;
  			
***************
*** 2603,2607 ****
  			switch (c) {
  			case '%':
! 				buf = "%";
  				len = 1;
  				break;
--- 2645,2649 ----
  			switch (c) {
  			case '%':
! 				pbuf = "%";
  				len = 1;
  				break;
***************
*** 2623,2627 ****
  					goto error;
  				}
! 				buf = PyString_AsString(temp);
  				len = PyString_Size(temp);
  				if (prec >= 0 && len > prec)
--- 2665,2669 ----
  					goto error;
  				}
! 				pbuf = PyString_AsString(temp);
  				len = PyString_Size(temp);
  				if (prec >= 0 && len > prec)
***************
*** 2636,2641 ****
  				if (c == 'i')
  					c = 'd';
! 				buf = tmpbuf;
! 				len = formatint(buf, flags, prec, c, v);
  				if (len < 0)
  					goto error;
--- 2678,2683 ----
  				if (c == 'i')
  					c = 'd';
! 				pbuf = formatbuf;
! 				len = formatint(pbuf, sizeof(formatbuf), flags, prec, c, v);
  				if (len < 0)
  					goto error;
***************
*** 2645,2651 ****
  					if ((flags&F_ALT) &&
  					    (c == 'x' || c == 'X') &&
! 					    buf[0] == '0' && buf[1] == c) {
! 						*res++ = *buf++;
! 						*res++ = *buf++;
  						rescnt -= 2;
  						len -= 2;
--- 2687,2693 ----
  					if ((flags&F_ALT) &&
  					    (c == 'x' || c == 'X') &&
! 					    pbuf[0] == '0' && pbuf[1] == c) {
! 						*res++ = *pbuf++;
! 						*res++ = *pbuf++;
  						rescnt -= 2;
  						len -= 2;
***************
*** 2661,2666 ****
  			case 'g':
  			case 'G':
! 				buf = tmpbuf;
! 				len = formatfloat(buf, flags, prec, c, v);
  				if (len < 0)
  					goto error;
--- 2703,2708 ----
  			case 'g':
  			case 'G':
! 				pbuf = formatbuf;
! 				len = formatfloat(pbuf, sizeof(formatbuf), flags, prec, c, v);
  				if (len < 0)
  					goto error;
***************
*** 2670,2675 ****
  				break;
  			case 'c':
! 				buf = tmpbuf;
! 				len = formatchar(buf, v);
  				if (len < 0)
  					goto error;
--- 2712,2717 ----
  				break;
  			case 'c':
! 				pbuf = formatbuf;
! 				len = formatchar(pbuf, sizeof(formatbuf), v);
  				if (len < 0)
  					goto error;
***************
*** 2682,2687 ****
  			}
  			if (sign) {
! 				if (*buf == '-' || *buf == '+') {
! 					sign = *buf++;
  					len--;
  				}
--- 2724,2729 ----
  			}
  			if (sign) {
! 				if (*pbuf == '-' || *pbuf == '+') {
! 					sign = *pbuf++;
  					len--;
  				}
***************
*** 2719,2723 ****
  			if (sign && fill == ' ')
  				*res++ = sign;
! 			memcpy(res, buf, len);
  			res += len;
  			rescnt -= len;
--- 2761,2765 ----
  			if (sign && fill == ' ')
  				*res++ = sign;
! 			memcpy(res, pbuf, len);
  			res += len;
  			rescnt -= len;