CVE-2016-9262 (C, published 2017-03-23T18:59Z)
Description: value: Multiple integer overflows in the (1) jas_realloc function in base/jas_malloc.c and (2) mem_resize function in base/jas_stream.c in JasPer before 1.900.22 allow remote attackers to cause a denial of service via a crafted image, which triggers use after free vulnerabilities.
Severity: MEDIUM (CVSS v3 base score: 5.5)
Weakness: CWE-190 \u2014 Integer Overflow or Wraparound
The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
Repository: https://github.com/mdadams/jasper
Files changed:
src/libjasper/base/jas_debug.c
src/libjasper/base/jas_image.c
src/libjasper/base/jas_stream.c
src/libjasper/include/jasper/jas_debug.h
src/libjasper/include/jasper/jas_stream.h
Commit message: Made some changes to the I/O stream library for memory streams.
There were a number of potential problems due to the possibility
of integer overflow.
Changed some integral types to the larger types size_t or ssize_t.
For example, the function mem_resize now takes the buffer size parameter
as a size_t.
Added a new function jas_stream_memopen2, which takes a
buffer size specified as a size_t instead of an int.
This can be used in jas_image_cmpt_create to avoid potential
overflow problems.

Added a new function jas_deprecated to warn about reliance on
deprecated library behavior.


Vulnerable code:
	cmpt->stream_ = (inmem) ? jas_stream_memopen(0, size) :
	int n;
static int mem_resize(jas_stream_memobj_t *m, int bufsize)
	assert(bufsize >= 0);
	JAS_DBGLOG(100, ("mem_resize(%p, %d)\n", m, bufsize));
	int n;
	long newbufsize;
	long newpos;
			newbufsize <<= 1;
			assert(newbufsize >= 0);
		JAS_DBGLOG(100, ("mem_write resizing from %d to %z\n", m->bufsize_,
		JAS_DBGLOG(100, ("mem_write resizing from %d to %ul\n", m->bufsize_,
		  JAS_CAST(unsigned long, newbufsize)));
	long newpos;
	int bufsize_;

Fixed code:

/******************************************************************************\
* Code.
\******************************************************************************/

void jas_deprecated(const char *s)
{
	static char message[] =
	"WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!!\n"
	"WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!!\n"
	"WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!!\n"
	"YOUR CODE IS RELYING ON DEPRECATED FUNCTIONALTIY IN THE JASPER LIBRARY.\n"
	"THIS FUNCTIONALITY WILL BE REMOVED IN THE NEAR FUTURE.\n"
	"PLEASE FIX THIS PROBLEM BEFORE YOUR CODE STOPS WORKING!\n"
	;
	jas_eprintf("%s", message);
	jas_eprintf("The specific problem is as follows:\n%s\n", s);
	//abort();
}
	cmpt->stream_ = (inmem) ? jas_stream_memopen2(0, size) :
#if 0

/* Obsolete code. */

#else

/*
This function will eventually replace jas_stream_memopen.
If buf is 0 and bufsize > 0:
	a buffer is dynamically allocated with size bufsize and this buffer is
	not growable.
If buf is 0 and bufsize is 0:
	a buffer is dynamically allocated whose size will automatically grow to
	accommodate the amount of data written.
If buf is not 0:
	bufsize (which, in this case, is not currently allowed to be zero) is
	the size of the (nongrowable) buffer pointed to by buf.
*/

jas_stream_t *jas_stream_memopen2(char *buf, size_t bufsize)
{
	jas_stream_t *stream;
	jas_stream_memobj_t *obj;

	JAS_DBGLOG(100, ("jas_stream_memopen2(%p, %zu)\n", buf, bufsize));

	assert((buf && bufsize > 0) || (!buf));

	if (!(stream = jas_stream_create())) {
		return 0;
	}

	/* A stream associated with a memory buffer is always opened
	for both reading and writing in binary mode. */
	stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;

	/* Since the stream data is already resident in memory, buffering
	is not necessary. */
	/* But... It still may be faster to use buffering anyways. */
	jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);

	/* Select the operations for a memory stream. */
	stream->ops_ = &jas_stream_memops;

	/* Allocate memory for the underlying memory stream object. */
	if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
		jas_stream_destroy(stream);
		return 0;
	}
	stream->obj_ = (void *) obj;

	/* Initialize a few important members of the memory stream object. */
	obj->myalloc_ = 0;
	obj->buf_ = 0;

	/* If the buffer size specified is nonpositive, then the buffer
	is allocated internally and automatically grown as needed. */
	if (!bufsize) {
		obj->bufsize_ = 1024;
		obj->growable_ = 1;
	} else {
		obj->bufsize_ = bufsize;
		obj->growable_ = 0;
	}
	if (buf) {
		obj->buf_ = JAS_CAST(unsigned char *, buf);
	} else {
		obj->buf_ = jas_malloc(obj->bufsize_);
		obj->myalloc_ = 1;
	}
	if (!obj->buf_) {
		jas_stream_close(stream);
		return 0;
	}
	JAS_DBGLOG(100, ("jas_stream_memopen2 buffer buf=%p myalloc=%d\n",
	  obj->buf_, obj->myalloc_));

	if (bufsize > 0 && buf) {
		/* If a buffer was supplied by the caller and its length is positive,
		  make the associated buffer data appear in the stream initially. */
		obj->len_ = bufsize;
	} else {
		/* The stream is initially empty. */
		obj->len_ = 0;
	}
	obj->pos_ = 0;
	
	return stream;
}

/*
NOTE:
The version of the function jas_stream_memopen only exists for backwards
compatibility.
Eventually, it should be replaced by jas_stream_memopen2.
In retrospect, it was a very poor choice to have specified the buffer
size parameter (bufsize) to have type int.  On some machines, int may only
be a 16-bit integer.  This precludes larger-sized buffer allocations, which
are needed in practice.

If bufsize <= 0, the buffer is growable; otherwise, the buffer has a fixed
size of bufsize.
If buf is 0, the buffer is dynamically allocated with jas_malloc.
If buf is not 0 and bufsize <= 0 (which is not permitted in any
circumstances), bad things will happen (especially if the buf was not
allocated with jas_malloc).
*/
jas_stream_t *jas_stream_memopen(char *buf, int bufsize)
{
	char *new_buf;
	size_t new_bufsize;

	JAS_DBGLOG(100, ("jas_stream_memopen(%p, %d)\n", buf, bufsize));
	if (bufsize < 0) {
		jas_deprecated("negative buffer size for jas_stream_memopen");
	}
	if (buf && bufsize <= 0) {
		// This was never a valid thing to do with the old API.
		jas_eprintf("Invalid use of jas_stream_memopen detected.\n");
		jas_deprecated("A user-provided buffer for "
		  "jas_stream_memopen cannot be growable.\n");
	}
	if (bufsize <= 0) {
		new_bufsize = 0;
		new_buf = 0;
	} else {
		new_bufsize = bufsize;
		new_buf = buf;
	}
	return jas_stream_memopen2(new_buf, new_bufsize);
}

#endif

	if (cnt < 0) {
		jas_deprecated("negative count for jas_stream_read");
	}

	if (cnt < 0) {
		jas_deprecated("negative count for jas_stream_write");
	}

	if (n < 0) {
		jas_deprecated("negative count for jas_stream_gobble");
	}
	if (n < 0) {
		jas_deprecated("negative count for jas_stream_pad");
	}
	ssize_t n;
static int mem_resize(jas_stream_memobj_t *m, size_t bufsize)
	//assert(bufsize >= 0);

	JAS_DBGLOG(100, ("mem_resize(%p, %zu)\n", m, bufsize));
	if (!bufsize) {
		jas_eprintf(
		  "mem_resize was not really designed to handle a buffer of size 0\n"
		  "This may not work.\n"
		);
	}
	size_t n;
	size_t newbufsize;
	size_t newpos;
			//newbufsize <<= 1;
			if (!jas_safe_size_mul(newbufsize, 2, &newbufsize)) {
				JAS_DBGLOG(100, ("new buffer size would cause overflow\n"));
				return -1;
			}
		JAS_DBGLOG(100, ("mem_write resizing from %d to %zu\n", m->bufsize_,
		assert(newbufsize > 0);
	size_t newpos;
/* Warn about use of deprecated functionality. */
void jas_deprecated(const char *s);

	size_t bufsize_;
/* Do not use this function.
It will eventually replace jas_stream_memopen. */
jas_stream_t *jas_stream_memopen2(char *buf, size_t bufsize);