Commit message: double64_init: Check psf->sf.channels against upper bound

This prevents division by zero later in the code.

While the trivial case to catch this (i.e. sf.channels < 1) has already
been covered, a crafted file may report a number of channels that is
so high (i.e. > INT_MAX/sizeof(double)) that it "somehow" gets
miscalculated to zero (if this makes sense) in the determination of the
blockwidth. Since we only support a limited number of channels anyway,
make sure to check here as well.

CVE-2017-14634

Closes: https://github.com/erikd/libsndfile/issues/318
Signed-off-by: Erik de Castro Lopo <erikd@mega-nerd.com>
CVE: CVE-2017-14634
CWE: CWE-369
Vulnerability description: In libsndfile 1.0.28, a divide-by-zero error exists in the function double64_init() in double64.c, which may lead to DoS when playing a crafted audio file.

Project: libsndfile

double64_init	(SF_PRIVATE *psf)
{	static int double64_caps ;

	if (psf->sf.channels < 1)
	{	psf_log_printf (psf, "double64_init : internal error : channels = %d\n", psf->sf.channels) ;
		return SFE_INTERNAL ;
		} ;

	double64_caps = double64_get_capability (psf) ;

	psf->blockwidth = sizeof (double) * psf->sf.channels ;

	if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR)
	{	switch (psf->endian + double64_caps)
		{	case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_BE) :
					psf->data_endswap = SF_FALSE ;
					psf->read_short		= host_read_d2s ;
					psf->read_int		= host_read_d2i ;
					psf->read_float		= host_read_d2f ;
					psf->read_double	= host_read_d ;
					break ;

			case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_LE) :
					psf->data_endswap = SF_FALSE ;
					psf->read_short		= host_read_d2s ;
					psf->read_int		= host_read_d2i ;
					psf->read_float		= host_read_d2f ;
					psf->read_double	= host_read_d ;
					break ;

			case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_LE) :
					psf->data_endswap = SF_TRUE ;
					psf->read_short		= host_read_d2s ;
					psf->read_int		= host_read_d2i ;
					psf->read_float		= host_read_d2f ;
					psf->read_double	= host_read_d ;
					break ;

			case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_BE) :
					psf->data_endswap = SF_TRUE ;
					psf->read_short		= host_read_d2s ;
					psf->read_int		= host_read_d2i ;
					psf->read_float		= host_read_d2f ;
					psf->read_double	= host_read_d ;
					break ;

			/* When the CPU is not IEEE compatible. */
			case (SF_ENDIAN_BIG + DOUBLE_BROKEN_BE) :
					psf->data_endswap = SF_FALSE ;
					psf->read_short		= replace_read_d2s ;
					psf->read_int		= replace_read_d2i ;
					psf->read_float		= replace_read_d2f ;
					psf->read_double	= replace_read_d ;
					break ;

			case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_LE) :
					psf->data_endswap = SF_FALSE ;
					psf->read_short		= replace_read_d2s ;
					psf->read_int		= replace_read_d2i ;
					psf->read_float		= replace_read_d2f ;
					psf->read_double	= replace_read_d ;
					break ;

			case (SF_ENDIAN_BIG + DOUBLE_BROKEN_LE) :
					psf->data_endswap = SF_TRUE ;
					psf->read_short		= replace_read_d2s ;
					psf->read_int		= replace_read_d2i ;
					psf->read_float		= replace_read_d2f ;
					psf->read_double	= replace_read_d ;
					break ;

			case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_BE) :
					psf->data_endswap = SF_TRUE ;
					psf->read_short		= replace_read_d2s ;
					psf->read_int		= replace_read_d2i ;
					psf->read_float		= replace_read_d2f ;
					psf->read_double	= replace_read_d ;
					break ;

			default : break ;
			} ;
		} ;

	if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
	{	switch (psf->endian + double64_caps)
		{	case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_LE) :
					psf->data_endswap = SF_FALSE ;
					psf->write_short	= host_write_s2d ;
					psf->write_int		= host_write_i2d ;
					psf->write_float	= host_write_f2d ;
					psf->write_double	= host_write_d ;
					break ;

			case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_BE) :
					psf->data_endswap = SF_FALSE ;
					psf->write_short	= host_write_s2d ;
					psf->write_int		= host_write_i2d ;
					psf->write_float	= host_write_f2d ;
					psf->write_double	= host_write_d ;
					break ;

			case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_LE) :
					psf->data_endswap = SF_TRUE ;
					psf->write_short	= host_write_s2d ;
					psf->write_int		= host_write_i2d ;
					psf->write_float	= host_write_f2d ;
					psf->write_double	= host_write_d ;
					break ;

			case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_BE) :
					psf->data_endswap = SF_TRUE ;
					psf->write_short	= host_write_s2d ;
					psf->write_int		= host_write_i2d ;
					psf->write_float	= host_write_f2d ;
					psf->write_double	= host_write_d ;
					break ;

			/* When the CPU is not IEEE compatible. */
			case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_LE) :
					psf->data_endswap = SF_FALSE ;
					psf->write_short	= replace_write_s2d ;
					psf->write_int		= replace_write_i2d ;
					psf->write_float	= replace_write_f2d ;
					psf->write_double	= replace_write_d ;
					break ;

			case (SF_ENDIAN_BIG + DOUBLE_BROKEN_BE) :
					psf->data_endswap = SF_FALSE ;
					psf->write_short	= replace_write_s2d ;
					psf->write_int		= replace_write_i2d ;
					psf->write_float	= replace_write_f2d ;
					psf->write_double	= replace_write_d ;
					break ;

			case (SF_ENDIAN_BIG + DOUBLE_BROKEN_LE) :
					psf->data_endswap = SF_TRUE ;
					psf->write_short	= replace_write_s2d ;
					psf->write_int		= replace_write_i2d ;
					psf->write_float	= replace_write_f2d ;
					psf->write_double	= replace_write_d ;
					break ;

			case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_BE) :
					psf->data_endswap = SF_TRUE ;
					psf->write_short	= replace_write_s2d ;
					psf->write_int		= replace_write_i2d ;
					psf->write_float	= replace_write_f2d ;
					psf->write_double	= replace_write_d ;
					break ;

			default : break ;
			} ;
		} ;

	if (psf->filelength > psf->dataoffset)
	{	psf->datalength = (psf->dataend > 0) ? psf->dataend - psf->dataoffset :
							psf->filelength - psf->dataoffset ;
		}
	else
		psf->datalength = 0 ;

	psf->sf.frames = psf->datalength / psf->blockwidth ;

	return 0 ;
} /* double64_init */