Commit message: * libtiff/tif_{unix,vms,win32}.c (_TIFFmalloc): ANSI C does not
require malloc() to return NULL pointer if requested allocation
size is zero.  Assure that _TIFFmalloc does.
CVE: CVE-2014-8130
CWE: CWE-369
Vulnerability description: The _TIFFmalloc function in tif_unix.c in LibTIFF 4.0.3 does not reject a zero size, which allows remote attackers to cause a denial of service (divide-by-zero error and application crash) via a crafted TIFF image that is mishandled by the TIFFWriteScanline function in tif_write.c, as demonstrated by tiffdither.

Project: libtiff

TIFFFdOpen(int fd, const char* name, const char* mode)
{
	TIFF* tif;

	tif = TIFFClientOpen(name, mode,
	    (thandle_t) fd,
	    _tiffReadProc, _tiffWriteProc,
	    _tiffSeekProc, _tiffCloseProc, _tiffSizeProc,
	    _tiffMapProc, _tiffUnmapProc);
	if (tif)
		tif->tif_fd = fd;
	return (tif);
}

Project: libtiff

TIFFOpen(const char* name, const char* mode)
{
	static const char module[] = "TIFFOpen";
	int m, fd;
	TIFF* tif;

	m = _TIFFgetMode(mode, module);
	if (m == -1)
		return ((TIFF*)0);

/* for cygwin and mingw */
#ifdef O_BINARY
	m |= O_BINARY;
#endif

	fd = open(name, m, 0666);
	if (fd < 0) {
		if (errno > 0 && strerror(errno) != NULL ) {
			TIFFErrorExt(0, module, "%s: %s", name, strerror(errno) );
		} else {
			TIFFErrorExt(0, module, "%s: Cannot open", name);
		}
		return ((TIFF *)0);
	}

	tif = TIFFFdOpen((int)fd, name, mode);
	if(!tif)
		close(fd);
	return tif;
}

Project: libtiff

TIFFOpenW(const wchar_t* name, const char* mode)
{
	static const char module[] = "TIFFOpenW";
	int m, fd;
	int mbsize;
	char *mbname;
	TIFF* tif;

	m = _TIFFgetMode(mode, module);
	if (m == -1)
		return ((TIFF*)0);

/* for cygwin and mingw */
#ifdef O_BINARY
	m |= O_BINARY;
#endif

	fd = _wopen(name, m, 0666);
	if (fd < 0) {
		TIFFErrorExt(0, module, "%s: Cannot open", name);
		return ((TIFF *)0);
	}

	mbname = NULL;
	mbsize = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL);
	if (mbsize > 0) {
		mbname = _TIFFmalloc(mbsize);
		if (!mbname) {
			TIFFErrorExt(0, module,
			"Can't allocate space for filename conversion buffer");
			return ((TIFF*)0);
		}

		WideCharToMultiByte(CP_ACP, 0, name, -1, mbname, mbsize,
				    NULL, NULL);
	}

	tif = TIFFFdOpen((int)fd, (mbname != NULL) ? mbname : "<unknown>",
			 mode);
	
	_TIFFfree(mbname);
	
	if(!tif)
		close(fd);
	return tif;
}

Project: libtiff

_TIFFmemcmp(const void* p1, const void* p2, tmsize_t c)
{
	return (memcmp(p1, p2, (size_t) c));
}

Project: libtiff

_TIFFrealloc(void* p, tmsize_t s)
{
	return (realloc(p, (size_t) s));
}

Project: libtiff

_tiffMapProc(thandle_t fd, void** pbase, toff_t* psize)
{
	uint64 size64 = _tiffSizeProc(fd);
	tmsize_t sizem = (tmsize_t)size64;
	if ((uint64)sizem==size64) {
		*pbase = (void*)
		    mmap(0, (size_t)sizem, PROT_READ, MAP_SHARED, (int) fd, 0);
		if (*pbase != (void*) -1) {
			*psize = (tmsize_t)sizem;
			return (1);
		}
	}
	return (0);
}

Project: libtiff

_tiffMapProc(thandle_t fd, void** pbase, toff_t* psize)
{
	(void) fd; (void) pbase; (void) psize;
	return (0);
}

Project: libtiff

_tiffReadProc(thandle_t fd, void* buf, tmsize_t size)
{
	size_t size_io = (size_t) size;
	if ((tmsize_t) size_io != size)
	{
		errno=EINVAL;
		return (tmsize_t) -1;
	}
	return ((tmsize_t) read((int) fd, buf, size_io));
}

Project: libtiff

_tiffSeekProc(thandle_t fd, uint64 off, int whence)
{
	off_t off_io = (off_t) off;
	if ((uint64) off_io != off)
	{
		errno=EINVAL;
		return (uint64) -1; /* this is really gross */
	}
	return((uint64)lseek((int)fd,off_io,whence));
}

Project: libtiff

_tiffSizeProc(thandle_t fd)
{
	struct stat sb;
	if (fstat((int)fd,&sb)<0)
		return(0);
	else
		return((uint64)sb.st_size);
}

Project: libtiff

_tiffUnmapProc(thandle_t fd, void* base, toff_t size)
{
	(void) fd;
	(void) munmap(base, (off_t) size);
}

Project: libtiff

_tiffWriteProc(thandle_t fd, void* buf, tmsize_t size)
{
	size_t size_io = (size_t) size;
	if ((tmsize_t) size_io != size)
	{
		errno=EINVAL;
		return (tmsize_t) -1;
	}
	return ((tmsize_t) write((int) fd, buf, size_io));
}

Project: libtiff

unixErrorHandler(const char* module, const char* fmt, va_list ap)
{
	if (module != NULL)
		fprintf(stderr, "%s: ", module);
	vfprintf(stderr, fmt, ap);
	fprintf(stderr, ".\n");
}

Project: libtiff

unixWarningHandler(const char* module, const char* fmt, va_list ap)
{
	if (module != NULL)
		fprintf(stderr, "%s: ", module);
	fprintf(stderr, "Warning, ");
	vfprintf(stderr, fmt, ap);
	fprintf(stderr, ".\n");
}

Project: libtiff

TIFFCvtIEEEFloatToNative(TIFF* tif, u_int n, float* f)
{
	float_t* fp = (float_t*) f;

	while (n-- > 0) {
		IEEEFLOAT2NATIVE(fp);
		fp++;
	}
}

Project: libtiff

TIFFCvtNativeToIEEEDouble(TIFF* tif, u_int n, double* f)
{
	double_t* fp = (double_t*) f;

	while (n-- > 0) {
		NATIVE2IEEEDOUBLE(fp);
		fp++;
	}
}

Project: libtiff

TIFFFdOpen(int fd, const char* name, const char* mode)
{
	TIFF* tif;

	tif = TIFFClientOpen(name, mode,  ddd
	    (thandle_t) fd,
	    _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
	    _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
	if (tif)
		tif->tif_fd = fd;
	return (tif);
}

Project: libtiff

void TIFFModeCCITTFax3(void){}

Project: libtiff

TIFFOpen(const char* name, const char* mode)
{
	static const char module[] = "TIFFOpen";
	int m, fd;

	m = _TIFFgetMode(mode, module);
	if (m == -1)
		return ((TIFF*)0);
        if (m&O_TRUNC){
                /*
		 * There is a bug in open in VAXC. If you use
		 * open w/ m=O_RDWR|O_CREAT|O_TRUNC the
		 * wrong thing happens.  On the other hand
		 * creat does the right thing.
                 */
                fd = creat((char *) /* bug in stdio.h */ name, 0666,
		    "alq = 128", "deq = 64", "mbc = 32",
		    "fop = tef");
	} else if (m&O_RDWR) {
		fd = open(name, m, 0666,
		    "deq = 64", "mbc = 32", "fop = tef", "ctx = stm");
	} else
		fd = open(name, m, 0666, "mbc = 32", "ctx = stm");
	if (fd < 0) {
		TIFFErrorExt(0, module, "%s: Cannot open", name);
		return ((TIFF*)0);
	}
	return (TIFFFdOpen(fd, name, mode));
}

Project: libtiff

_TIFFfree(tdata_t p)
{
	free(p);
}

Project: libtiff

_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c)
{
	memcpy(d, s, (size_t) c);
}

Project: libtiff

_TIFFmemset(tdata_t p, int v, tsize_t c)
{
	memset(p, v, (size_t) c);
}

Project: libtiff

_TIFFrealloc(tdata_t p, tsize_t s)
{
	return (realloc(p, (size_t) s));
}

Project: libtiff

_tiffCloseProc(thandle_t fd)
{
	return (close((int) fd));
}

Project: libtiff

_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
{
	return (0);
}

Project: libtiff

_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
{
	return (read((int) fd, buf, size));
}

Project: libtiff

_tiffSeekProc(thandle_t fd, toff_t off, int whence)
{
	return ((toff_t) lseek((int) fd, (off_t) off, whence));
}

Project: libtiff

_tiffSizeProc(thandle_t fd)
{
	struct stat sb;
	return (toff_t) (fstat((int) fd, &sb) < 0 ? 0 : sb.st_size);
}

Project: libtiff

_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size)
{
	char *inadr[2];
	int i, j;
	
	/* Find the section in the table */
	for (i = 0;i < no_mapped; i++) {
		if (map_table[i].base == (char *) base) {
			/* Unmap the section */
			inadr[0] = (char *) base;
			inadr[1] = map_table[i].top;
			sys$deltva(inadr, 0, 0);
			sys$dassgn(map_table[i].channel);
			/* Remove this section from the list */
			for (j = i+1; j < no_mapped; j++)
				map_table[j-1] = map_table[j];
			no_mapped--;
			return;
		}
	}
}

Project: libtiff

_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size)
{
}

Project: libtiff

_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
{
	return (write((int) fd, buf, size));
}

Project: libtiff

dtoieee(double *dp)
{
	double_t num;
	double x;
	int exp;

	num.d = *dp;
	if (!num.d) {			/* Zero is just binary all zeros */
		num.l[0] = num.l[1] = 0;
		return;
	}

	if (num.d < 0) {		/* Sign is encoded separately */
		num.d = -num.d;
		num.ieee.sign = 1;
	} else {
		num.ieee.sign = 0;
	}

	/* Now separate the absolute value into mantissa and exponent */
	x = frexp(num.d, &exp);

	/*
	 * Handle cases where the value is outside the
	 * range for IEEE floating point numbers. 
	 * (Overflow cannot happen on a VAX, but underflow
	 * can happen for G float.)
	 */
	if (exp < -1022) {		/* Unnormalized number */
		x = ldexp(x, -1023-exp);
		exp = 0;
	} else if (exp > 1023) {	/* +/- infinity */
		x = 0;
		exp = 2047;
	} else {			/* Get rid of most significant bit */
		x *= 2;
		x -= 1;
		exp += 1022; /* fix NDR: 1.0 -> x=0.5, exp=1 -> ieee.exp = 1023 */
	}
	num.ieee.exp = exp;

	x *= (double) (1<<20);
	num.ieee.mant = (long) x;
	x -= (double) num.ieee.mant;
	num.ieee.mant2 = (long) (x*((double) (1<<16)*(double) (1<<16)));

	if (!(num.ieee.mant || num.ieee.exp || num.ieee.mant2)) {
		/* Avoid negative zero */
		num.ieee.sign = 0;
	}
	((double_t*)dp)->ieee = num.ieee;
}

Project: libtiff

ieeetod(double *dp)
{
	double_t source;
	long sign,exp,mant;
	double dmant;

	source.ieee = ((double_t*)dp)->ieee;
	sign = source.ieee.sign;
	exp = source.ieee.exp;
	mant = source.ieee.mant;

	if (exp == 2047) {
		if (mant)			/* Not a Number (NAN) */
			*dp = HUGE_VAL;
		else				/* +/- infinity */
			*dp = (sign ? -HUGE_VAL : HUGE_VAL);
		return;
	}
	if (!exp) {
		if (!(mant || source.ieee.mant2)) {	/* zero */
			*dp=0;
			return;
		} else {			/* Unnormalized number */
			/* NB: not -1023, the 1 bit is not implied */
			exp= -1022;
		}
	} else {
		mant |= 1<<20;
		exp -= 1023;
	}
	dmant = (((double) mant) +
		((double) source.ieee.mant2) / (((double) (1<<16)) *
		((double) (1<<16)))) / (double) (1<<20);
	dmant = ldexp(dmant, exp);
	if (sign)
		dmant= -dmant;
	*dp = dmant;
}

Project: libtiff

vmsErrorHandler(const char* module, const char* fmt, va_list ap)
{
	if (module != NULL)
		fprintf(stderr, "%s: ", module);
	vfprintf(stderr, fmt, ap);
	fprintf(stderr, ".\n");
}

Project: libtiff

vmsWarningHandler(const char* module, const char* fmt, va_list ap)
{
	if (module != NULL)
		fprintf(stderr, "%s: ", module);
	fprintf(stderr, "Warning, ");
	vfprintf(stderr, fmt, ap);
	fprintf(stderr, ".\n");
}

Project: libtiff

TIFFFdOpen(int ifd, const char* name, const char* mode)
{
	TIFF* tif;
	int fSuppressMap;
	int m;
	fSuppressMap=0;
	for (m=0; mode[m]!=0; m++)
	{
		if (mode[m]=='u')
		{
			fSuppressMap=1;
			break;
		}
	}
	tif = TIFFClientOpen(name, mode, (thandle_t)ifd,
			_tiffReadProc, _tiffWriteProc,
			_tiffSeekProc, _tiffCloseProc, _tiffSizeProc,
			fSuppressMap ? _tiffDummyMapProc : _tiffMapProc,
			fSuppressMap ? _tiffDummyUnmapProc : _tiffUnmapProc);
	if (tif)
		tif->tif_fd = ifd;
	return (tif);
}

Project: libtiff

TIFFOpen(const char* name, const char* mode)
{
	static const char module[] = "TIFFOpen";
	thandle_t fd;
	int m;
	DWORD dwMode;
	TIFF* tif;

	m = _TIFFgetMode(mode, module);

	switch(m) {
		case O_RDONLY:			dwMode = OPEN_EXISTING; break;
		case O_RDWR:			dwMode = OPEN_ALWAYS;   break;
		case O_RDWR|O_CREAT:		dwMode = OPEN_ALWAYS;   break;
		case O_RDWR|O_TRUNC:		dwMode = CREATE_ALWAYS; break;
		case O_RDWR|O_CREAT|O_TRUNC:	dwMode = CREATE_ALWAYS; break;
		default:			return ((TIFF*)0);
	}
        
	fd = (thandle_t)CreateFileA(name,
		(m == O_RDONLY)?GENERIC_READ:(GENERIC_READ | GENERIC_WRITE),
		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, dwMode,
		(m == O_RDONLY)?FILE_ATTRIBUTE_READONLY:FILE_ATTRIBUTE_NORMAL,
		NULL);
	if (fd == INVALID_HANDLE_VALUE) {
		TIFFErrorExt(0, module, "%s: Cannot open", name);
		return ((TIFF *)0);
	}

	tif = TIFFFdOpen((int)fd, name, mode);
	if(!tif)
		CloseHandle(fd);
	return tif;
}

Project: libtiff

TIFFOpenW(const wchar_t* name, const char* mode)
{
	static const char module[] = "TIFFOpenW";
	thandle_t fd;
	int m;
	DWORD dwMode;
	int mbsize;
	char *mbname;
	TIFF *tif;

	m = _TIFFgetMode(mode, module);

	switch(m) {
		case O_RDONLY:			dwMode = OPEN_EXISTING; break;
		case O_RDWR:			dwMode = OPEN_ALWAYS;   break;
		case O_RDWR|O_CREAT:		dwMode = OPEN_ALWAYS;   break;
		case O_RDWR|O_TRUNC:		dwMode = CREATE_ALWAYS; break;
		case O_RDWR|O_CREAT|O_TRUNC:	dwMode = CREATE_ALWAYS; break;
		default:			return ((TIFF*)0);
	}

	fd = (thandle_t)CreateFileW(name,
		(m == O_RDONLY)?GENERIC_READ:(GENERIC_READ|GENERIC_WRITE),
		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, dwMode,
		(m == O_RDONLY)?FILE_ATTRIBUTE_READONLY:FILE_ATTRIBUTE_NORMAL,
		NULL);
	if (fd == INVALID_HANDLE_VALUE) {
		TIFFErrorExt(0, module, "%S: Cannot open", name);
		return ((TIFF *)0);
	}

	mbname = NULL;
	mbsize = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL);
	if (mbsize > 0) {
		mbname = (char *)_TIFFmalloc(mbsize);
		if (!mbname) {
			TIFFErrorExt(0, module,
			"Can't allocate space for filename conversion buffer");
			return ((TIFF*)0);
		}

		WideCharToMultiByte(CP_ACP, 0, name, -1, mbname, mbsize,
				    NULL, NULL);
	}

	tif = TIFFFdOpen((int)fd,
			 (mbname != NULL) ? mbname : "<unknown>", mode);
	if(!tif)
		CloseHandle(fd);

	_TIFFfree(mbname);

	return tif;
}

Project: libtiff

Win32ErrorHandler(const char* module, const char* fmt, va_list ap)
{
#ifndef TIF_PLATFORM_CONSOLE
	LPTSTR szTitle;
	LPTSTR szTmp;
	LPCTSTR szTitleText = "%s Error";
	LPCTSTR szDefaultModule = "LIBTIFF";
	LPCTSTR szTmpModule = (module == NULL) ? szDefaultModule : module;
        SIZE_T nBufSize = (strlen(szTmpModule) +
                        strlen(szTitleText) + strlen(fmt) + 256)*sizeof(char);

	if ((szTitle = (LPTSTR)LocalAlloc(LMEM_FIXED, nBufSize)) == NULL)
		return;
	sprintf(szTitle, szTitleText, szTmpModule);
	szTmp = szTitle + (strlen(szTitle)+2)*sizeof(char);
	vsnprintf(szTmp, nBufSize-(strlen(szTitle)+2)*sizeof(char), fmt, ap);
	MessageBoxA(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONEXCLAMATION);
	LocalFree(szTitle);
	return;
#else
	if (module != NULL)
		fprintf(stderr, "%s: ", module);
	vfprintf(stderr, fmt, ap);
	fprintf(stderr, ".\n");
#endif        
}

Project: libtiff

Win32WarningHandler(const char* module, const char* fmt, va_list ap)
{
#ifndef TIF_PLATFORM_CONSOLE
	LPTSTR szTitle;
	LPTSTR szTmp;
	LPCTSTR szTitleText = "%s Warning";
	LPCTSTR szDefaultModule = "LIBTIFF";
	LPCTSTR szTmpModule = (module == NULL) ? szDefaultModule : module;
        SIZE_T nBufSize = (strlen(szTmpModule) +
                        strlen(szTitleText) + strlen(fmt) + 256)*sizeof(char);

	if ((szTitle = (LPTSTR)LocalAlloc(LMEM_FIXED, nBufSize)) == NULL)
		return;
	sprintf(szTitle, szTitleText, szTmpModule);
	szTmp = szTitle + (strlen(szTitle)+2)*sizeof(char);
	vsnprintf(szTmp, nBufSize-(strlen(szTitle)+2)*sizeof(char), fmt, ap);
	MessageBoxA(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONINFORMATION);
	LocalFree(szTitle);

	return;
#else
	if (module != NULL)
		fprintf(stderr, "%s: ", module);
	fprintf(stderr, "Warning, ");
	vfprintf(stderr, fmt, ap);
	fprintf(stderr, ".\n");
#endif        
}

Project: libtiff

_tiffCloseProc(thandle_t fd)
{
	return (CloseHandle(fd) ? 0 : -1);
}

Project: libtiff

_tiffDummyMapProc(thandle_t fd, void** pbase, toff_t* psize)
{
	(void) fd;
	(void) pbase;
	(void) psize;
	return (0);
}

Project: libtiff

_tiffDummyUnmapProc(thandle_t fd, void* base, toff_t size)
{
	(void) fd;
	(void) base;
	(void) size;
}

Project: libtiff

_tiffMapProc(thandle_t fd, void** pbase, toff_t* psize)
{
	uint64 size;
	tmsize_t sizem;
	HANDLE hMapFile;

	size = _tiffSizeProc(fd);
	sizem = (tmsize_t)size;
	if ((uint64)sizem!=size)
		return (0);

	/* By passing in 0 for the maximum file size, it specifies that we
	   create a file mapping object for the full file size. */
	hMapFile = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, 0, NULL);
	if (hMapFile == NULL)
		return (0);
	*pbase = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
	CloseHandle(hMapFile);
	if (*pbase == NULL)
		return (0);
	*psize = size;
	return(1);
}

Project: libtiff

_tiffSizeProc(thandle_t fd)
{
	ULARGE_INTEGER m;
	m.LowPart=GetFileSize(fd,&m.HighPart);
	return(m.QuadPart);
}

Project: libtiff

_tiffUnmapProc(thandle_t fd, void* base, toff_t size)
{
	(void) fd;
	(void) size;
	UnmapViewOfFile(base);
}

Project: libtiff

_tiffWriteProc(thandle_t fd, void* buf, tmsize_t size)
{
	/* tmsize_t is 64bit on 64bit systems, but the WinAPI WriteFile takes
	 * 32bit sizes, so we loop through the data in suitable 32bit sized
	 * chunks */
	uint8* ma;
	uint64 mb;
	DWORD n;
	DWORD o;
	tmsize_t p;
	ma=(uint8*)buf;
	mb=size;
	p=0;
	while (mb>0)
	{
		n=0x80000000UL;
		if ((uint64)n>mb)
			n=(DWORD)mb;
		if (!WriteFile(fd,(LPVOID)ma,n,&o,NULL))
			return(0);
		ma+=o;
		mb-=o;
		p+=o;
		if (o!=n)
			break;
	}
	return(p);
}