* libtiff/tif_jpeg.c: validate BitsPerSample in JPEGSetupEncode() to avoid
undefined behaviour caused by invalid shift exponent.
Fixes http://bugzilla.maptools.org/show_bug.cgi?id=2648

JPEGSetupEncode(TIFF* tif)
{
	JPEGState* sp = JState(tif);
	TIFFDirectory *td = &tif->tif_dir;
	static const char module[] = "JPEGSetupEncode";

#if defined(JPEG_DUAL_MODE_8_12) && !defined(TIFFInitJPEG)
        if( tif->tif_dir.td_bitspersample == 12 )
            return TIFFReInitJPEG_12( tif, COMPRESSION_JPEG, 1 );
#endif

        JPEGInitializeLibJPEG( tif, FALSE );

	assert(sp != NULL);
	assert(!sp->cinfo.comm.is_decompressor);

	sp->photometric = td->td_photometric;

	/*
	 * Initialize all JPEG parameters to default values.
	 * Note that jpeg_set_defaults needs legal values for
	 * in_color_space and input_components.
	 */
	if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
		sp->cinfo.c.input_components = td->td_samplesperpixel;
		if (sp->photometric == PHOTOMETRIC_YCBCR) {
			if (sp->jpegcolormode == JPEGCOLORMODE_RGB) {
				sp->cinfo.c.in_color_space = JCS_RGB;
			} else {
				sp->cinfo.c.in_color_space = JCS_YCbCr;
			}
		} else {
			if ((td->td_photometric == PHOTOMETRIC_MINISWHITE || td->td_photometric == PHOTOMETRIC_MINISBLACK) && td->td_samplesperpixel == 1)
				sp->cinfo.c.in_color_space = JCS_GRAYSCALE;
			else if (td->td_photometric == PHOTOMETRIC_RGB && td->td_samplesperpixel == 3)
				sp->cinfo.c.in_color_space = JCS_RGB;
			else if (td->td_photometric == PHOTOMETRIC_SEPARATED && td->td_samplesperpixel == 4)
				sp->cinfo.c.in_color_space = JCS_CMYK;
			else
				sp->cinfo.c.in_color_space = JCS_UNKNOWN;
		}
	} else {
		sp->cinfo.c.input_components = 1;
		sp->cinfo.c.in_color_space = JCS_UNKNOWN;
	}
	if (!TIFFjpeg_set_defaults(sp))
		return (0);
	/* Set per-file parameters */
	switch (sp->photometric) {
	case PHOTOMETRIC_YCBCR:
		sp->h_sampling = td->td_ycbcrsubsampling[0];
		sp->v_sampling = td->td_ycbcrsubsampling[1];
                if( sp->h_sampling == 0 || sp->v_sampling == 0 )
                {
                    TIFFErrorExt(tif->tif_clientdata, module,
                            "Invalig horizontal/vertical sampling value");
                    return (0);
                }

		/*
		 * A ReferenceBlackWhite field *must* be present since the
		 * default value is inappropriate for YCbCr.  Fill in the
		 * proper value if application didn't set it.
		 */
		{
			float *ref;
			if (!TIFFGetField(tif, TIFFTAG_REFERENCEBLACKWHITE,
					  &ref)) {
				float refbw[6];
				long top = 1L << td->td_bitspersample;
				refbw[0] = 0;
				refbw[1] = (float)(top-1L);
				refbw[2] = (float)(top>>1);
				refbw[3] = refbw[1];
				refbw[4] = refbw[2];
				refbw[5] = refbw[1];
				TIFFSetField(tif, TIFFTAG_REFERENCEBLACKWHITE,
					     refbw);
			}
		}
		break;
	case PHOTOMETRIC_PALETTE:		/* disallowed by Tech Note */
	case PHOTOMETRIC_MASK:
		TIFFErrorExt(tif->tif_clientdata, module,
			  "PhotometricInterpretation %d not allowed for JPEG",
			  (int) sp->photometric);
		return (0);
	default:
		/* TIFF 6.0 forbids subsampling of all other color spaces */
		sp->h_sampling = 1;
		sp->v_sampling = 1;
		break;
	}

	/* Verify miscellaneous parameters */

	/*
	 * This would need work if libtiff ever supports different
	 * depths for different components, or if libjpeg ever supports
	 * run-time selection of depth.  Neither is imminent.
	 */
#ifdef JPEG_LIB_MK1
        /* BITS_IN_JSAMPLE now permits 8 and 12 --- dgilbert */
	if (td->td_bitspersample != 8 && td->td_bitspersample != 12)
#else
	if (td->td_bitspersample != BITS_IN_JSAMPLE )
#endif
	{
		TIFFErrorExt(tif->tif_clientdata, module, "BitsPerSample %d not allowed for JPEG",
			  (int) td->td_bitspersample);
		return (0);
	}
	sp->cinfo.c.data_precision = td->td_bitspersample;
#ifdef JPEG_LIB_MK1
        sp->cinfo.c.bits_in_jsample = td->td_bitspersample;
#endif
	if (isTiled(tif)) {
		if ((td->td_tilelength % (sp->v_sampling * DCTSIZE)) != 0) {
			TIFFErrorExt(tif->tif_clientdata, module,
				  "JPEG tile height must be multiple of %d",
				  sp->v_sampling * DCTSIZE);
			return (0);
		}
		if ((td->td_tilewidth % (sp->h_sampling * DCTSIZE)) != 0) {
			TIFFErrorExt(tif->tif_clientdata, module,
				  "JPEG tile width must be multiple of %d",
				  sp->h_sampling * DCTSIZE);
			return (0);
		}
	} else {
		if (td->td_rowsperstrip < td->td_imagelength &&
		    (td->td_rowsperstrip % (sp->v_sampling * DCTSIZE)) != 0) {
			TIFFErrorExt(tif->tif_clientdata, module,
				  "RowsPerStrip must be multiple of %d for JPEG",
				  sp->v_sampling * DCTSIZE);
			return (0);
		}
	}

	/* Create a JPEGTables field if appropriate */
	if (sp->jpegtablesmode & (JPEGTABLESMODE_QUANT|JPEGTABLESMODE_HUFF)) {
                if( sp->jpegtables == NULL
                    || memcmp(sp->jpegtables,"\0\0\0\0\0\0\0\0\0",8) == 0 )
                {
                        if (!prepare_JPEGTables(tif))
                                return (0);
                        /* Mark the field present */
                        /* Can't use TIFFSetField since BEENWRITING is already set! */
                        tif->tif_flags |= TIFF_DIRTYDIRECT;
                        TIFFSetFieldBit(tif, FIELD_JPEGTABLES);
                }
	} else {
		/* We do not support application-supplied JPEGTables, */
		/* so mark the field not present */
		TIFFClrFieldBit(tif, FIELD_JPEGTABLES);
	}

	/* Direct libjpeg output to libtiff's output buffer */
	TIFFjpeg_data_dest(sp, tif);

	return (1);
}

LibTIFF 4.0.7 has a "shift exponent too large for 64-bit type long" undefined behavior issue, which might allow remote attackers to cause a denial of service (application crash) or possibly have unspecified other impact via a crafted image.


JPEGSetupEncode(TIFF* tif)
{
	JPEGState* sp = JState(tif);
	TIFFDirectory *td = &tif->tif_dir;
	static const char module[] = "JPEGSetupEncode";

#if defined(JPEG_DUAL_MODE_8_12) && !defined(TIFFInitJPEG)
        if( tif->tif_dir.td_bitspersample == 12 )
            return TIFFReInitJPEG_12( tif, COMPRESSION_JPEG, 1 );
#endif

        JPEGInitializeLibJPEG( tif, FALSE );

	assert(sp != NULL);
	assert(!sp->cinfo.comm.is_decompressor);

	sp->photometric = td->td_photometric;

	/*
	 * Initialize all JPEG parameters to default values.
	 * Note that jpeg_set_defaults needs legal values for
	 * in_color_space and input_components.
	 */
	if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
		sp->cinfo.c.input_components = td->td_samplesperpixel;
		if (sp->photometric == PHOTOMETRIC_YCBCR) {
			if (sp->jpegcolormode == JPEGCOLORMODE_RGB) {
				sp->cinfo.c.in_color_space = JCS_RGB;
			} else {
				sp->cinfo.c.in_color_space = JCS_YCbCr;
			}
		} else {
			if ((td->td_photometric == PHOTOMETRIC_MINISWHITE || td->td_photometric == PHOTOMETRIC_MINISBLACK) && td->td_samplesperpixel == 1)
				sp->cinfo.c.in_color_space = JCS_GRAYSCALE;
			else if (td->td_photometric == PHOTOMETRIC_RGB && td->td_samplesperpixel == 3)
				sp->cinfo.c.in_color_space = JCS_RGB;
			else if (td->td_photometric == PHOTOMETRIC_SEPARATED && td->td_samplesperpixel == 4)
				sp->cinfo.c.in_color_space = JCS_CMYK;
			else
				sp->cinfo.c.in_color_space = JCS_UNKNOWN;
		}
	} else {
		sp->cinfo.c.input_components = 1;
		sp->cinfo.c.in_color_space = JCS_UNKNOWN;
	}
	if (!TIFFjpeg_set_defaults(sp))
		return (0);
	/* Set per-file parameters */
	switch (sp->photometric) {
	case PHOTOMETRIC_YCBCR:
		sp->h_sampling = td->td_ycbcrsubsampling[0];
		sp->v_sampling = td->td_ycbcrsubsampling[1];
                if( sp->h_sampling == 0 || sp->v_sampling == 0 )
                {
                    TIFFErrorExt(tif->tif_clientdata, module,
                            "Invalig horizontal/vertical sampling value");
                    return (0);
                }
                if( td->td_bitspersample > 16 )
                {
                    TIFFErrorExt(tif->tif_clientdata, module,
                                 "BitsPerSample %d not allowed for JPEG",
                                 td->td_bitspersample);
                    return (0);
                }

		/*
		 * A ReferenceBlackWhite field *must* be present since the
		 * default value is inappropriate for YCbCr.  Fill in the
		 * proper value if application didn't set it.
		 */
		{
			float *ref;
			if (!TIFFGetField(tif, TIFFTAG_REFERENCEBLACKWHITE,
					  &ref)) {
				float refbw[6];
				long top = 1L << td->td_bitspersample;
				refbw[0] = 0;
				refbw[1] = (float)(top-1L);
				refbw[2] = (float)(top>>1);
				refbw[3] = refbw[1];
				refbw[4] = refbw[2];
				refbw[5] = refbw[1];
				TIFFSetField(tif, TIFFTAG_REFERENCEBLACKWHITE,
					     refbw);
			}
		}
		break;
	case PHOTOMETRIC_PALETTE:		/* disallowed by Tech Note */
	case PHOTOMETRIC_MASK:
		TIFFErrorExt(tif->tif_clientdata, module,
			  "PhotometricInterpretation %d not allowed for JPEG",
			  (int) sp->photometric);
		return (0);
	default:
		/* TIFF 6.0 forbids subsampling of all other color spaces */
		sp->h_sampling = 1;
		sp->v_sampling = 1;
		break;
	}

	/* Verify miscellaneous parameters */

	/*
	 * This would need work if libtiff ever supports different
	 * depths for different components, or if libjpeg ever supports
	 * run-time selection of depth.  Neither is imminent.
	 */
#ifdef JPEG_LIB_MK1
        /* BITS_IN_JSAMPLE now permits 8 and 12 --- dgilbert */
	if (td->td_bitspersample != 8 && td->td_bitspersample != 12)
#else
	if (td->td_bitspersample != BITS_IN_JSAMPLE )
#endif
	{
		TIFFErrorExt(tif->tif_clientdata, module, "BitsPerSample %d not allowed for JPEG",
			  (int) td->td_bitspersample);
		return (0);
	}
	sp->cinfo.c.data_precision = td->td_bitspersample;
#ifdef JPEG_LIB_MK1
        sp->cinfo.c.bits_in_jsample = td->td_bitspersample;
#endif
	if (isTiled(tif)) {
		if ((td->td_tilelength % (sp->v_sampling * DCTSIZE)) != 0) {
			TIFFErrorExt(tif->tif_clientdata, module,
				  "JPEG tile height must be multiple of %d",
				  sp->v_sampling * DCTSIZE);
			return (0);
		}
		if ((td->td_tilewidth % (sp->h_sampling * DCTSIZE)) != 0) {
			TIFFErrorExt(tif->tif_clientdata, module,
				  "JPEG tile width must be multiple of %d",
				  sp->h_sampling * DCTSIZE);
			return (0);
		}
	} else {
		if (td->td_rowsperstrip < td->td_imagelength &&
		    (td->td_rowsperstrip % (sp->v_sampling * DCTSIZE)) != 0) {
			TIFFErrorExt(tif->tif_clientdata, module,
				  "RowsPerStrip must be multiple of %d for JPEG",
				  sp->v_sampling * DCTSIZE);
			return (0);
		}
	}

	/* Create a JPEGTables field if appropriate */
	if (sp->jpegtablesmode & (JPEGTABLESMODE_QUANT|JPEGTABLESMODE_HUFF)) {
                if( sp->jpegtables == NULL
                    || memcmp(sp->jpegtables,"\0\0\0\0\0\0\0\0\0",8) == 0 )
                {
                        if (!prepare_JPEGTables(tif))
                                return (0);
                        /* Mark the field present */
                        /* Can't use TIFFSetField since BEENWRITING is already set! */
                        tif->tif_flags |= TIFF_DIRTYDIRECT;
                        TIFFSetFieldBit(tif, FIELD_JPEGTABLES);
                }
	} else {
		/* We do not support application-supplied JPEGTables, */
		/* so mark the field not present */
		TIFFClrFieldBit(tif, FIELD_JPEGTABLES);
	}

	/* Direct libjpeg output to libtiff's output buffer */
	TIFFjpeg_data_dest(sp, tif);

	return (1);
}


* tools/tiff2pdf.c: prevent heap buffer overflow write in "Raw"
mode on PlanarConfig=Contig input images.
Fixes http://bugzilla.maptools.org/show_bug.cgi?id=2715
Reported by team OWL337

void t2p_read_tiff_data(T2P* t2p, TIFF* input){

	int i=0;
	uint16* r;
	uint16* g;
	uint16* b;
	uint16* a;
	uint16 xuint16;
	uint16* xuint16p;
	float* xfloatp;

	t2p->pdf_transcode = T2P_TRANSCODE_ENCODE;
	t2p->pdf_sample = T2P_SAMPLE_NOTHING;
        t2p->pdf_switchdecode = t2p->pdf_colorspace_invert;

	TIFFSetDirectory(input, t2p->tiff_pages[t2p->pdf_page].page_directory);

	TIFFGetField(input, TIFFTAG_IMAGEWIDTH, &(t2p->tiff_width));
	if(t2p->tiff_width == 0){
		TIFFError(
			TIFF2PDF_MODULE,
			"No support for %s with zero width",
			TIFFFileName(input)	);
		t2p->t2p_error = T2P_ERR_ERROR;
		return;
	}

	TIFFGetField(input, TIFFTAG_IMAGELENGTH, &(t2p->tiff_length));
	if(t2p->tiff_length == 0){
		TIFFError(
			TIFF2PDF_MODULE,
			"No support for %s with zero length",
			TIFFFileName(input)	);
		t2p->t2p_error = T2P_ERR_ERROR;
		return;
	}

        if(TIFFGetField(input, TIFFTAG_COMPRESSION, &(t2p->tiff_compression)) == 0){
                TIFFError(
                        TIFF2PDF_MODULE,
                        "No support for %s with no compression tag",
                        TIFFFileName(input)     );
                t2p->t2p_error = T2P_ERR_ERROR;
                return;

        }
        if( TIFFIsCODECConfigured(t2p->tiff_compression) == 0){
		TIFFError(
			TIFF2PDF_MODULE,
			"No support for %s with compression type %u:  not configured",
			TIFFFileName(input),
			t2p->tiff_compression
			);
		t2p->t2p_error = T2P_ERR_ERROR;
		return;

	}

	TIFFGetFieldDefaulted(input, TIFFTAG_BITSPERSAMPLE, &(t2p->tiff_bitspersample));
	switch(t2p->tiff_bitspersample){
		case 1:
		case 2:
		case 4:
		case 8:
			break;
		case 0:
			TIFFWarning(
				TIFF2PDF_MODULE,
				"Image %s has 0 bits per sample, assuming 1",
				TIFFFileName(input));
			t2p->tiff_bitspersample=1;
			break;
		default:
			TIFFError(
				TIFF2PDF_MODULE,
				"No support for %s with %u bits per sample",
				TIFFFileName(input),
				t2p->tiff_bitspersample);
			t2p->t2p_error = T2P_ERR_ERROR;
			return;
	}

	TIFFGetFieldDefaulted(input, TIFFTAG_SAMPLESPERPIXEL, &(t2p->tiff_samplesperpixel));
	if(t2p->tiff_samplesperpixel>4){
		TIFFError(
			TIFF2PDF_MODULE,
			"No support for %s with %u samples per pixel",
			TIFFFileName(input),
			t2p->tiff_samplesperpixel);
		t2p->t2p_error = T2P_ERR_ERROR;
		return;
	}
	if(t2p->tiff_samplesperpixel==0){
		TIFFWarning(
			TIFF2PDF_MODULE,
			"Image %s has 0 samples per pixel, assuming 1",
			TIFFFileName(input));
		t2p->tiff_samplesperpixel=1;
	}

	if(TIFFGetField(input, TIFFTAG_SAMPLEFORMAT, &xuint16) != 0 ){
		switch(xuint16){
			case 0:
			case 1:
			case 4:
				break;
			default:
				TIFFError(
					TIFF2PDF_MODULE,
					"No support for %s with sample format %u",
					TIFFFileName(input),
					xuint16);
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
				break;
		}
	}

	TIFFGetFieldDefaulted(input, TIFFTAG_FILLORDER, &(t2p->tiff_fillorder));

        if(TIFFGetField(input, TIFFTAG_PHOTOMETRIC, &(t2p->tiff_photometric)) == 0){
                TIFFError(
                        TIFF2PDF_MODULE,
                        "No support for %s with no photometric interpretation tag",
                        TIFFFileName(input)     );
                t2p->t2p_error = T2P_ERR_ERROR;
                return;

        }

	switch(t2p->tiff_photometric){
		case PHOTOMETRIC_MINISWHITE:
		case PHOTOMETRIC_MINISBLACK:
			if (t2p->tiff_bitspersample==1){
				t2p->pdf_colorspace=T2P_CS_BILEVEL;
				if(t2p->tiff_photometric==PHOTOMETRIC_MINISWHITE){
					t2p->pdf_switchdecode ^= 1;
				}
			} else {
				t2p->pdf_colorspace=T2P_CS_GRAY;
				if(t2p->tiff_photometric==PHOTOMETRIC_MINISWHITE){
					t2p->pdf_switchdecode ^= 1;
				}
			}
			break;
		case PHOTOMETRIC_RGB:
			t2p->pdf_colorspace=T2P_CS_RGB;
			if(t2p->tiff_samplesperpixel == 3){
				break;
			}
			if(TIFFGetField(input, TIFFTAG_INDEXED, &xuint16)){
				if(xuint16==1)
					goto photometric_palette;
			}
			if(t2p->tiff_samplesperpixel > 3) {
				if(t2p->tiff_samplesperpixel == 4) {
					t2p->pdf_colorspace = T2P_CS_RGB;
					if(TIFFGetField(input,
							TIFFTAG_EXTRASAMPLES,
							&xuint16, &xuint16p)
					   && xuint16 == 1) {
						if(xuint16p[0] == EXTRASAMPLE_ASSOCALPHA){
							if( t2p->tiff_bitspersample != 8 )
							{
							    TIFFError(
								    TIFF2PDF_MODULE,
								    "No support for BitsPerSample=%d for RGBA",
								    t2p->tiff_bitspersample);
							    t2p->t2p_error = T2P_ERR_ERROR;
							    return;
							}
							t2p->pdf_sample=T2P_SAMPLE_RGBAA_TO_RGB;
							break;
						}
						if(xuint16p[0] == EXTRASAMPLE_UNASSALPHA){
							if( t2p->tiff_bitspersample != 8 )
							{
							    TIFFError(
								    TIFF2PDF_MODULE,
								    "No support for BitsPerSample=%d for RGBA",
								    t2p->tiff_bitspersample);
							    t2p->t2p_error = T2P_ERR_ERROR;
							    return;
							}
							t2p->pdf_sample=T2P_SAMPLE_RGBA_TO_RGB;
							break;
						}
						TIFFWarning(
							TIFF2PDF_MODULE,
							"RGB image %s has 4 samples per pixel, assuming RGBA",
							TIFFFileName(input));
							break;
					}
					t2p->pdf_colorspace=T2P_CS_CMYK;
					t2p->pdf_switchdecode ^= 1;
					TIFFWarning(
						TIFF2PDF_MODULE,
						"RGB image %s has 4 samples per pixel, assuming inverse CMYK",
					TIFFFileName(input));
					break;
				} else {
					TIFFError(
						TIFF2PDF_MODULE,
						"No support for RGB image %s with %u samples per pixel",
						TIFFFileName(input),
						t2p->tiff_samplesperpixel);
					t2p->t2p_error = T2P_ERR_ERROR;
					break;
				}
			} else {
				TIFFError(
					TIFF2PDF_MODULE,
					"No support for RGB image %s with %u samples per pixel",
					TIFFFileName(input),
					t2p->tiff_samplesperpixel);
				t2p->t2p_error = T2P_ERR_ERROR;
				break;
			}
		case PHOTOMETRIC_PALETTE:
			photometric_palette:
			if(t2p->tiff_samplesperpixel!=1){
				TIFFError(
					TIFF2PDF_MODULE,
					"No support for palettized image %s with not one sample per pixel",
					TIFFFileName(input));
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			t2p->pdf_colorspace=T2P_CS_RGB | T2P_CS_PALETTE;
			t2p->pdf_palettesize=0x0001<<t2p->tiff_bitspersample;
			if(!TIFFGetField(input, TIFFTAG_COLORMAP, &r, &g, &b)){
				TIFFError(
					TIFF2PDF_MODULE,
					"Palettized image %s has no color map",
					TIFFFileName(input));
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			if(t2p->pdf_palette != NULL){
				_TIFFfree(t2p->pdf_palette);
				t2p->pdf_palette=NULL;
			}
			t2p->pdf_palette = (unsigned char*)
				_TIFFmalloc(TIFFSafeMultiply(tmsize_t,t2p->pdf_palettesize,3));
			if(t2p->pdf_palette==NULL){
				TIFFError(
					TIFF2PDF_MODULE,
					"Can't allocate %u bytes of memory for t2p_read_tiff_image, %s",
					t2p->pdf_palettesize,
					TIFFFileName(input));
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			for(i=0;i<t2p->pdf_palettesize;i++){
				t2p->pdf_palette[(i*3)]  = (unsigned char) (r[i]>>8);
				t2p->pdf_palette[(i*3)+1]= (unsigned char) (g[i]>>8);
				t2p->pdf_palette[(i*3)+2]= (unsigned char) (b[i]>>8);
			}
			t2p->pdf_palettesize *= 3;
			break;
		case PHOTOMETRIC_SEPARATED:
			if(TIFFGetField(input, TIFFTAG_INDEXED, &xuint16)){
				if(xuint16==1){
						goto photometric_palette_cmyk;
				}
			}
			if( TIFFGetField(input, TIFFTAG_INKSET, &xuint16) ){
				if(xuint16 != INKSET_CMYK){
					TIFFError(
						TIFF2PDF_MODULE,
						"No support for %s because its inkset is not CMYK",
						TIFFFileName(input) );
					t2p->t2p_error = T2P_ERR_ERROR;
					return;
				}
			}
			if(t2p->tiff_samplesperpixel==4){
				t2p->pdf_colorspace=T2P_CS_CMYK;
			} else {
				TIFFError(
					TIFF2PDF_MODULE,
					"No support for %s because it has %u samples per pixel",
					TIFFFileName(input),
					t2p->tiff_samplesperpixel);
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			break;
			photometric_palette_cmyk:
			if(t2p->tiff_samplesperpixel!=1){
				TIFFError(
					TIFF2PDF_MODULE,
					"No support for palettized CMYK image %s with not one sample per pixel",
					TIFFFileName(input));
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			t2p->pdf_colorspace=T2P_CS_CMYK | T2P_CS_PALETTE;
			t2p->pdf_palettesize=0x0001<<t2p->tiff_bitspersample;
			if(!TIFFGetField(input, TIFFTAG_COLORMAP, &r, &g, &b, &a)){
				TIFFError(
					TIFF2PDF_MODULE,
					"Palettized image %s has no color map",
					TIFFFileName(input));
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			if(t2p->pdf_palette != NULL){
				_TIFFfree(t2p->pdf_palette);
				t2p->pdf_palette=NULL;
			}
			t2p->pdf_palette = (unsigned char*)
				_TIFFmalloc(TIFFSafeMultiply(tmsize_t,t2p->pdf_palettesize,4));
			if(t2p->pdf_palette==NULL){
				TIFFError(
					TIFF2PDF_MODULE,
					"Can't allocate %u bytes of memory for t2p_read_tiff_image, %s",
					t2p->pdf_palettesize,
					TIFFFileName(input));
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			for(i=0;i<t2p->pdf_palettesize;i++){
				t2p->pdf_palette[(i*4)]  = (unsigned char) (r[i]>>8);
				t2p->pdf_palette[(i*4)+1]= (unsigned char) (g[i]>>8);
				t2p->pdf_palette[(i*4)+2]= (unsigned char) (b[i]>>8);
				t2p->pdf_palette[(i*4)+3]= (unsigned char) (a[i]>>8);
			}
			t2p->pdf_palettesize *= 4;
			break;
		case PHOTOMETRIC_YCBCR:
			t2p->pdf_colorspace=T2P_CS_RGB;
			if(t2p->tiff_samplesperpixel==1){
				t2p->pdf_colorspace=T2P_CS_GRAY;
				t2p->tiff_photometric=PHOTOMETRIC_MINISBLACK;
				break;
			}
			t2p->pdf_sample=T2P_SAMPLE_YCBCR_TO_RGB;
#ifdef JPEG_SUPPORT
			if(t2p->pdf_defaultcompression==T2P_COMPRESS_JPEG){
				t2p->pdf_sample=T2P_SAMPLE_NOTHING;
			}
#endif
			break;
		case PHOTOMETRIC_CIELAB:
            if( t2p->tiff_samplesperpixel != 3){
                TIFFError(
                    TIFF2PDF_MODULE,
                    "Unsupported samplesperpixel = %d for CIELAB",
                    t2p->tiff_samplesperpixel);
                t2p->t2p_error = T2P_ERR_ERROR;
                return;
            }
            if( t2p->tiff_bitspersample != 8){
                TIFFError(
                    TIFF2PDF_MODULE,
                    "Invalid bitspersample = %d for CIELAB",
                    t2p->tiff_bitspersample);
                t2p->t2p_error = T2P_ERR_ERROR;
                return;
            }
			t2p->pdf_labrange[0]= -127;
			t2p->pdf_labrange[1]= 127;
			t2p->pdf_labrange[2]= -127;
			t2p->pdf_labrange[3]= 127;
			t2p->pdf_sample=T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED;
			t2p->pdf_colorspace=T2P_CS_LAB;
			break;
		case PHOTOMETRIC_ICCLAB:
			t2p->pdf_labrange[0]= 0;
			t2p->pdf_labrange[1]= 255;
			t2p->pdf_labrange[2]= 0;
			t2p->pdf_labrange[3]= 255;
			t2p->pdf_colorspace=T2P_CS_LAB;
			break;
		case PHOTOMETRIC_ITULAB:
            if( t2p->tiff_samplesperpixel != 3){
                TIFFError(
                    TIFF2PDF_MODULE,
                    "Unsupported samplesperpixel = %d for ITULAB",
                    t2p->tiff_samplesperpixel);
                t2p->t2p_error = T2P_ERR_ERROR;
                return;
            }
            if( t2p->tiff_bitspersample != 8){
                TIFFError(
                    TIFF2PDF_MODULE,
                    "Invalid bitspersample = %d for ITULAB",
                    t2p->tiff_bitspersample);
                t2p->t2p_error = T2P_ERR_ERROR;
                return;
            }
			t2p->pdf_labrange[0]=-85;
			t2p->pdf_labrange[1]=85;
			t2p->pdf_labrange[2]=-75;
			t2p->pdf_labrange[3]=124;
			t2p->pdf_sample=T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED;
			t2p->pdf_colorspace=T2P_CS_LAB;
			break;
		case PHOTOMETRIC_LOGL:
		case PHOTOMETRIC_LOGLUV:
			TIFFError(
				TIFF2PDF_MODULE,
				"No support for %s with photometric interpretation LogL/LogLuv",
				TIFFFileName(input));
			t2p->t2p_error = T2P_ERR_ERROR;
			return;
		default:
			TIFFError(
				TIFF2PDF_MODULE,
				"No support for %s with photometric interpretation %u",
				TIFFFileName(input),
				t2p->tiff_photometric);
			t2p->t2p_error = T2P_ERR_ERROR;
			return;
	}

	if(TIFFGetField(input, TIFFTAG_PLANARCONFIG, &(t2p->tiff_planar))){
		switch(t2p->tiff_planar){
			case 0:
				TIFFWarning(
					TIFF2PDF_MODULE,
					"Image %s has planar configuration 0, assuming 1",
					TIFFFileName(input));
				t2p->tiff_planar=PLANARCONFIG_CONTIG;
			case PLANARCONFIG_CONTIG:
				break;
			case PLANARCONFIG_SEPARATE:
				t2p->pdf_sample=T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG;
				if(t2p->tiff_bitspersample!=8){
					TIFFError(
						TIFF2PDF_MODULE,
						"No support for %s with separated planar configuration and %u bits per sample",
						TIFFFileName(input),
						t2p->tiff_bitspersample);
					t2p->t2p_error = T2P_ERR_ERROR;
					return;
				}
				break;
			default:
				TIFFError(
					TIFF2PDF_MODULE,
					"No support for %s with planar configuration %u",
					TIFFFileName(input),
					t2p->tiff_planar);
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
		}
	}

        TIFFGetFieldDefaulted(input, TIFFTAG_ORIENTATION,
                              &(t2p->tiff_orientation));
        if(t2p->tiff_orientation>8){
                TIFFWarning(TIFF2PDF_MODULE,
                            "Image %s has orientation %u, assuming 0",
                            TIFFFileName(input), t2p->tiff_orientation);
                t2p->tiff_orientation=0;
        }

        if(TIFFGetField(input, TIFFTAG_XRESOLUTION, &(t2p->tiff_xres) ) == 0){
                t2p->tiff_xres=0.0;
        }
        if(TIFFGetField(input, TIFFTAG_YRESOLUTION, &(t2p->tiff_yres) ) == 0){
                t2p->tiff_yres=0.0;
        }
	TIFFGetFieldDefaulted(input, TIFFTAG_RESOLUTIONUNIT,
			      &(t2p->tiff_resunit));
	if(t2p->tiff_resunit == RESUNIT_CENTIMETER) {
		t2p->tiff_xres *= 2.54F;
		t2p->tiff_yres *= 2.54F;
	} else if (t2p->tiff_resunit != RESUNIT_INCH
		   && t2p->pdf_centimeters != 0) {
		t2p->tiff_xres *= 2.54F;
		t2p->tiff_yres *= 2.54F;
	}

	t2p_compose_pdf_page(t2p);
        if( t2p->t2p_error == T2P_ERR_ERROR )
	    return;

	t2p->pdf_transcode = T2P_TRANSCODE_ENCODE;
	if(t2p->pdf_nopassthrough==0){
#ifdef CCITT_SUPPORT
		if(t2p->tiff_compression==COMPRESSION_CCITTFAX4
			){
			if(TIFFIsTiled(input) || (TIFFNumberOfStrips(input)==1) ){
				t2p->pdf_transcode = T2P_TRANSCODE_RAW;
				t2p->pdf_compression=T2P_COMPRESS_G4;
			}
		}
#endif
#ifdef ZIP_SUPPORT
		if(t2p->tiff_compression== COMPRESSION_ADOBE_DEFLATE
			|| t2p->tiff_compression==COMPRESSION_DEFLATE){
			if(TIFFIsTiled(input) || (TIFFNumberOfStrips(input)==1) ){
				t2p->pdf_transcode = T2P_TRANSCODE_RAW;
				t2p->pdf_compression=T2P_COMPRESS_ZIP;
			}
		}
#endif
#ifdef OJPEG_SUPPORT
		if(t2p->tiff_compression==COMPRESSION_OJPEG){
			t2p->pdf_transcode = T2P_TRANSCODE_RAW;
			t2p->pdf_compression=T2P_COMPRESS_JPEG;
			t2p_process_ojpeg_tables(t2p, input);
		}
#endif
#ifdef JPEG_SUPPORT
		if(t2p->tiff_compression==COMPRESSION_JPEG){
			t2p->pdf_transcode = T2P_TRANSCODE_RAW;
			t2p->pdf_compression=T2P_COMPRESS_JPEG;
		}
#endif
		(void)0;
	}

	if(t2p->pdf_transcode!=T2P_TRANSCODE_RAW){
		t2p->pdf_compression = t2p->pdf_defaultcompression;
	}

#ifdef JPEG_SUPPORT
	if(t2p->pdf_defaultcompression==T2P_COMPRESS_JPEG){
		if(t2p->pdf_colorspace & T2P_CS_PALETTE){
			t2p->pdf_sample|=T2P_SAMPLE_REALIZE_PALETTE;
			t2p->pdf_colorspace ^= T2P_CS_PALETTE;
			t2p->tiff_pages[t2p->pdf_page].page_extra--;
		}
	}
	if(t2p->tiff_compression==COMPRESSION_JPEG){
		if(t2p->tiff_planar==PLANARCONFIG_SEPARATE){
			TIFFError(
				TIFF2PDF_MODULE,
				"No support for %s with JPEG compression and separated planar configuration",
				TIFFFileName(input));
				t2p->t2p_error=T2P_ERR_ERROR;
			return;
		}
	}
#endif
#ifdef OJPEG_SUPPORT
	if(t2p->tiff_compression==COMPRESSION_OJPEG){
		if(t2p->tiff_planar==PLANARCONFIG_SEPARATE){
			TIFFError(
				TIFF2PDF_MODULE,
				"No support for %s with OJPEG compression and separated planar configuration",
				TIFFFileName(input));
				t2p->t2p_error=T2P_ERR_ERROR;
			return;
		}
	}
#endif

	if(t2p->pdf_sample & T2P_SAMPLE_REALIZE_PALETTE){
		if(t2p->pdf_colorspace & T2P_CS_CMYK){
			t2p->tiff_samplesperpixel=4;
			t2p->tiff_photometric=PHOTOMETRIC_SEPARATED;
		} else {
			t2p->tiff_samplesperpixel=3;
			t2p->tiff_photometric=PHOTOMETRIC_RGB;
		}
	}

	if (TIFFGetField(input, TIFFTAG_TRANSFERFUNCTION,
			 &(t2p->tiff_transferfunction[0]),
			 &(t2p->tiff_transferfunction[1]),
			 &(t2p->tiff_transferfunction[2]))) {
		if((t2p->tiff_transferfunction[1] != (float*) NULL) &&
                   (t2p->tiff_transferfunction[2] != (float*) NULL) &&
                   (t2p->tiff_transferfunction[1] !=
                    t2p->tiff_transferfunction[0])) {
			t2p->tiff_transferfunctioncount=3;
		} else {
			t2p->tiff_transferfunctioncount=1;
		}
	} else {
		t2p->tiff_transferfunctioncount=0;
	}
	if(TIFFGetField(input, TIFFTAG_WHITEPOINT, &xfloatp)!=0){
		t2p->tiff_whitechromaticities[0]=xfloatp[0];
		t2p->tiff_whitechromaticities[1]=xfloatp[1];
		if(t2p->pdf_colorspace & T2P_CS_GRAY){
			t2p->pdf_colorspace |= T2P_CS_CALGRAY;
		}
		if(t2p->pdf_colorspace & T2P_CS_RGB){
			t2p->pdf_colorspace |= T2P_CS_CALRGB;
		}
	}
	if(TIFFGetField(input, TIFFTAG_PRIMARYCHROMATICITIES, &xfloatp)!=0){
		t2p->tiff_primarychromaticities[0]=xfloatp[0];
		t2p->tiff_primarychromaticities[1]=xfloatp[1];
		t2p->tiff_primarychromaticities[2]=xfloatp[2];
		t2p->tiff_primarychromaticities[3]=xfloatp[3];
		t2p->tiff_primarychromaticities[4]=xfloatp[4];
		t2p->tiff_primarychromaticities[5]=xfloatp[5];
		if(t2p->pdf_colorspace & T2P_CS_RGB){
			t2p->pdf_colorspace |= T2P_CS_CALRGB;
		}
	}
	if(t2p->pdf_colorspace & T2P_CS_LAB){
		if(TIFFGetField(input, TIFFTAG_WHITEPOINT, &xfloatp) != 0){
			t2p->tiff_whitechromaticities[0]=xfloatp[0];
			t2p->tiff_whitechromaticities[1]=xfloatp[1];
		} else {
			t2p->tiff_whitechromaticities[0]=0.3457F; /* 0.3127F; */
			t2p->tiff_whitechromaticities[1]=0.3585F; /* 0.3290F; */
		}
	}
	if(TIFFGetField(input,
		TIFFTAG_ICCPROFILE,
		&(t2p->tiff_iccprofilelength),
		&(t2p->tiff_iccprofile))!=0){
		t2p->pdf_colorspace |= T2P_CS_ICCBASED;
	} else {
		t2p->tiff_iccprofilelength=0;
		t2p->tiff_iccprofile=NULL;
	}

#ifdef CCITT_SUPPORT
	if( t2p->tiff_bitspersample==1 &&
		t2p->tiff_samplesperpixel==1){
		t2p->pdf_compression = T2P_COMPRESS_G4;
	}
#endif

	return;
}

There is a heap based buffer overflow in tools/tiff2pdf.c of LibTIFF 4.0.8 via a PlanarConfig=Contig image, which causes a more than one hundred bytes out-of-bounds write (related to the ZIPDecode function in tif_zip.c). A crafted input may lead to a remote denial of service attack or an arbitrary code execution attack.


void t2p_read_tiff_data(T2P* t2p, TIFF* input){

	int i=0;
	uint16* r;
	uint16* g;
	uint16* b;
	uint16* a;
	uint16 xuint16;
	uint16* xuint16p;
	float* xfloatp;

	t2p->pdf_transcode = T2P_TRANSCODE_ENCODE;
	t2p->pdf_sample = T2P_SAMPLE_NOTHING;
        t2p->pdf_switchdecode = t2p->pdf_colorspace_invert;

	TIFFSetDirectory(input, t2p->tiff_pages[t2p->pdf_page].page_directory);

	TIFFGetField(input, TIFFTAG_IMAGEWIDTH, &(t2p->tiff_width));
	if(t2p->tiff_width == 0){
		TIFFError(
			TIFF2PDF_MODULE,
			"No support for %s with zero width",
			TIFFFileName(input)	);
		t2p->t2p_error = T2P_ERR_ERROR;
		return;
	}

	TIFFGetField(input, TIFFTAG_IMAGELENGTH, &(t2p->tiff_length));
	if(t2p->tiff_length == 0){
		TIFFError(
			TIFF2PDF_MODULE,
			"No support for %s with zero length",
			TIFFFileName(input)	);
		t2p->t2p_error = T2P_ERR_ERROR;
		return;
	}

        if(TIFFGetField(input, TIFFTAG_COMPRESSION, &(t2p->tiff_compression)) == 0){
                TIFFError(
                        TIFF2PDF_MODULE,
                        "No support for %s with no compression tag",
                        TIFFFileName(input)     );
                t2p->t2p_error = T2P_ERR_ERROR;
                return;

        }
        if( TIFFIsCODECConfigured(t2p->tiff_compression) == 0){
		TIFFError(
			TIFF2PDF_MODULE,
			"No support for %s with compression type %u:  not configured",
			TIFFFileName(input),
			t2p->tiff_compression
			);
		t2p->t2p_error = T2P_ERR_ERROR;
		return;

	}

	TIFFGetFieldDefaulted(input, TIFFTAG_BITSPERSAMPLE, &(t2p->tiff_bitspersample));
	switch(t2p->tiff_bitspersample){
		case 1:
		case 2:
		case 4:
		case 8:
			break;
		case 0:
			TIFFWarning(
				TIFF2PDF_MODULE,
				"Image %s has 0 bits per sample, assuming 1",
				TIFFFileName(input));
			t2p->tiff_bitspersample=1;
			break;
		default:
			TIFFError(
				TIFF2PDF_MODULE,
				"No support for %s with %u bits per sample",
				TIFFFileName(input),
				t2p->tiff_bitspersample);
			t2p->t2p_error = T2P_ERR_ERROR;
			return;
	}

	TIFFGetFieldDefaulted(input, TIFFTAG_SAMPLESPERPIXEL, &(t2p->tiff_samplesperpixel));
	if(t2p->tiff_samplesperpixel>4){
		TIFFError(
			TIFF2PDF_MODULE,
			"No support for %s with %u samples per pixel",
			TIFFFileName(input),
			t2p->tiff_samplesperpixel);
		t2p->t2p_error = T2P_ERR_ERROR;
		return;
	}
	if(t2p->tiff_samplesperpixel==0){
		TIFFWarning(
			TIFF2PDF_MODULE,
			"Image %s has 0 samples per pixel, assuming 1",
			TIFFFileName(input));
		t2p->tiff_samplesperpixel=1;
	}

	if(TIFFGetField(input, TIFFTAG_SAMPLEFORMAT, &xuint16) != 0 ){
		switch(xuint16){
			case 0:
			case 1:
			case 4:
				break;
			default:
				TIFFError(
					TIFF2PDF_MODULE,
					"No support for %s with sample format %u",
					TIFFFileName(input),
					xuint16);
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
				break;
		}
	}

	TIFFGetFieldDefaulted(input, TIFFTAG_FILLORDER, &(t2p->tiff_fillorder));

        if(TIFFGetField(input, TIFFTAG_PHOTOMETRIC, &(t2p->tiff_photometric)) == 0){
                TIFFError(
                        TIFF2PDF_MODULE,
                        "No support for %s with no photometric interpretation tag",
                        TIFFFileName(input)     );
                t2p->t2p_error = T2P_ERR_ERROR;
                return;

        }

	switch(t2p->tiff_photometric){
		case PHOTOMETRIC_MINISWHITE:
		case PHOTOMETRIC_MINISBLACK:
			if (t2p->tiff_bitspersample==1){
				t2p->pdf_colorspace=T2P_CS_BILEVEL;
				if(t2p->tiff_photometric==PHOTOMETRIC_MINISWHITE){
					t2p->pdf_switchdecode ^= 1;
				}
			} else {
				t2p->pdf_colorspace=T2P_CS_GRAY;
				if(t2p->tiff_photometric==PHOTOMETRIC_MINISWHITE){
					t2p->pdf_switchdecode ^= 1;
				}
			}
			break;
		case PHOTOMETRIC_RGB:
			t2p->pdf_colorspace=T2P_CS_RGB;
			if(t2p->tiff_samplesperpixel == 3){
				break;
			}
			if(TIFFGetField(input, TIFFTAG_INDEXED, &xuint16)){
				if(xuint16==1)
					goto photometric_palette;
			}
			if(t2p->tiff_samplesperpixel > 3) {
				if(t2p->tiff_samplesperpixel == 4) {
					t2p->pdf_colorspace = T2P_CS_RGB;
					if(TIFFGetField(input,
							TIFFTAG_EXTRASAMPLES,
							&xuint16, &xuint16p)
					   && xuint16 == 1) {
						if(xuint16p[0] == EXTRASAMPLE_ASSOCALPHA){
							if( t2p->tiff_bitspersample != 8 )
							{
							    TIFFError(
								    TIFF2PDF_MODULE,
								    "No support for BitsPerSample=%d for RGBA",
								    t2p->tiff_bitspersample);
							    t2p->t2p_error = T2P_ERR_ERROR;
							    return;
							}
							t2p->pdf_sample=T2P_SAMPLE_RGBAA_TO_RGB;
							break;
						}
						if(xuint16p[0] == EXTRASAMPLE_UNASSALPHA){
							if( t2p->tiff_bitspersample != 8 )
							{
							    TIFFError(
								    TIFF2PDF_MODULE,
								    "No support for BitsPerSample=%d for RGBA",
								    t2p->tiff_bitspersample);
							    t2p->t2p_error = T2P_ERR_ERROR;
							    return;
							}
							t2p->pdf_sample=T2P_SAMPLE_RGBA_TO_RGB;
							break;
						}
						TIFFWarning(
							TIFF2PDF_MODULE,
							"RGB image %s has 4 samples per pixel, assuming RGBA",
							TIFFFileName(input));
							break;
					}
					t2p->pdf_colorspace=T2P_CS_CMYK;
					t2p->pdf_switchdecode ^= 1;
					TIFFWarning(
						TIFF2PDF_MODULE,
						"RGB image %s has 4 samples per pixel, assuming inverse CMYK",
					TIFFFileName(input));
					break;
				} else {
					TIFFError(
						TIFF2PDF_MODULE,
						"No support for RGB image %s with %u samples per pixel",
						TIFFFileName(input),
						t2p->tiff_samplesperpixel);
					t2p->t2p_error = T2P_ERR_ERROR;
					break;
				}
			} else {
				TIFFError(
					TIFF2PDF_MODULE,
					"No support for RGB image %s with %u samples per pixel",
					TIFFFileName(input),
					t2p->tiff_samplesperpixel);
				t2p->t2p_error = T2P_ERR_ERROR;
				break;
			}
		case PHOTOMETRIC_PALETTE:
			photometric_palette:
			if(t2p->tiff_samplesperpixel!=1){
				TIFFError(
					TIFF2PDF_MODULE,
					"No support for palettized image %s with not one sample per pixel",
					TIFFFileName(input));
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			t2p->pdf_colorspace=T2P_CS_RGB | T2P_CS_PALETTE;
			t2p->pdf_palettesize=0x0001<<t2p->tiff_bitspersample;
			if(!TIFFGetField(input, TIFFTAG_COLORMAP, &r, &g, &b)){
				TIFFError(
					TIFF2PDF_MODULE,
					"Palettized image %s has no color map",
					TIFFFileName(input));
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			if(t2p->pdf_palette != NULL){
				_TIFFfree(t2p->pdf_palette);
				t2p->pdf_palette=NULL;
			}
			t2p->pdf_palette = (unsigned char*)
				_TIFFmalloc(TIFFSafeMultiply(tmsize_t,t2p->pdf_palettesize,3));
			if(t2p->pdf_palette==NULL){
				TIFFError(
					TIFF2PDF_MODULE,
					"Can't allocate %u bytes of memory for t2p_read_tiff_image, %s",
					t2p->pdf_palettesize,
					TIFFFileName(input));
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			for(i=0;i<t2p->pdf_palettesize;i++){
				t2p->pdf_palette[(i*3)]  = (unsigned char) (r[i]>>8);
				t2p->pdf_palette[(i*3)+1]= (unsigned char) (g[i]>>8);
				t2p->pdf_palette[(i*3)+2]= (unsigned char) (b[i]>>8);
			}
			t2p->pdf_palettesize *= 3;
			break;
		case PHOTOMETRIC_SEPARATED:
			if(TIFFGetField(input, TIFFTAG_INDEXED, &xuint16)){
				if(xuint16==1){
						goto photometric_palette_cmyk;
				}
			}
			if( TIFFGetField(input, TIFFTAG_INKSET, &xuint16) ){
				if(xuint16 != INKSET_CMYK){
					TIFFError(
						TIFF2PDF_MODULE,
						"No support for %s because its inkset is not CMYK",
						TIFFFileName(input) );
					t2p->t2p_error = T2P_ERR_ERROR;
					return;
				}
			}
			if(t2p->tiff_samplesperpixel==4){
				t2p->pdf_colorspace=T2P_CS_CMYK;
			} else {
				TIFFError(
					TIFF2PDF_MODULE,
					"No support for %s because it has %u samples per pixel",
					TIFFFileName(input),
					t2p->tiff_samplesperpixel);
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			break;
			photometric_palette_cmyk:
			if(t2p->tiff_samplesperpixel!=1){
				TIFFError(
					TIFF2PDF_MODULE,
					"No support for palettized CMYK image %s with not one sample per pixel",
					TIFFFileName(input));
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			t2p->pdf_colorspace=T2P_CS_CMYK | T2P_CS_PALETTE;
			t2p->pdf_palettesize=0x0001<<t2p->tiff_bitspersample;
			if(!TIFFGetField(input, TIFFTAG_COLORMAP, &r, &g, &b, &a)){
				TIFFError(
					TIFF2PDF_MODULE,
					"Palettized image %s has no color map",
					TIFFFileName(input));
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			if(t2p->pdf_palette != NULL){
				_TIFFfree(t2p->pdf_palette);
				t2p->pdf_palette=NULL;
			}
			t2p->pdf_palette = (unsigned char*)
				_TIFFmalloc(TIFFSafeMultiply(tmsize_t,t2p->pdf_palettesize,4));
			if(t2p->pdf_palette==NULL){
				TIFFError(
					TIFF2PDF_MODULE,
					"Can't allocate %u bytes of memory for t2p_read_tiff_image, %s",
					t2p->pdf_palettesize,
					TIFFFileName(input));
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
			}
			for(i=0;i<t2p->pdf_palettesize;i++){
				t2p->pdf_palette[(i*4)]  = (unsigned char) (r[i]>>8);
				t2p->pdf_palette[(i*4)+1]= (unsigned char) (g[i]>>8);
				t2p->pdf_palette[(i*4)+2]= (unsigned char) (b[i]>>8);
				t2p->pdf_palette[(i*4)+3]= (unsigned char) (a[i]>>8);
			}
			t2p->pdf_palettesize *= 4;
			break;
		case PHOTOMETRIC_YCBCR:
			t2p->pdf_colorspace=T2P_CS_RGB;
			if(t2p->tiff_samplesperpixel==1){
				t2p->pdf_colorspace=T2P_CS_GRAY;
				t2p->tiff_photometric=PHOTOMETRIC_MINISBLACK;
				break;
			}
			t2p->pdf_sample=T2P_SAMPLE_YCBCR_TO_RGB;
#ifdef JPEG_SUPPORT
			if(t2p->pdf_defaultcompression==T2P_COMPRESS_JPEG){
				t2p->pdf_sample=T2P_SAMPLE_NOTHING;
			}
#endif
			break;
		case PHOTOMETRIC_CIELAB:
            if( t2p->tiff_samplesperpixel != 3){
                TIFFError(
                    TIFF2PDF_MODULE,
                    "Unsupported samplesperpixel = %d for CIELAB",
                    t2p->tiff_samplesperpixel);
                t2p->t2p_error = T2P_ERR_ERROR;
                return;
            }
            if( t2p->tiff_bitspersample != 8){
                TIFFError(
                    TIFF2PDF_MODULE,
                    "Invalid bitspersample = %d for CIELAB",
                    t2p->tiff_bitspersample);
                t2p->t2p_error = T2P_ERR_ERROR;
                return;
            }
			t2p->pdf_labrange[0]= -127;
			t2p->pdf_labrange[1]= 127;
			t2p->pdf_labrange[2]= -127;
			t2p->pdf_labrange[3]= 127;
			t2p->pdf_sample=T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED;
			t2p->pdf_colorspace=T2P_CS_LAB;
			break;
		case PHOTOMETRIC_ICCLAB:
			t2p->pdf_labrange[0]= 0;
			t2p->pdf_labrange[1]= 255;
			t2p->pdf_labrange[2]= 0;
			t2p->pdf_labrange[3]= 255;
			t2p->pdf_colorspace=T2P_CS_LAB;
			break;
		case PHOTOMETRIC_ITULAB:
            if( t2p->tiff_samplesperpixel != 3){
                TIFFError(
                    TIFF2PDF_MODULE,
                    "Unsupported samplesperpixel = %d for ITULAB",
                    t2p->tiff_samplesperpixel);
                t2p->t2p_error = T2P_ERR_ERROR;
                return;
            }
            if( t2p->tiff_bitspersample != 8){
                TIFFError(
                    TIFF2PDF_MODULE,
                    "Invalid bitspersample = %d for ITULAB",
                    t2p->tiff_bitspersample);
                t2p->t2p_error = T2P_ERR_ERROR;
                return;
            }
			t2p->pdf_labrange[0]=-85;
			t2p->pdf_labrange[1]=85;
			t2p->pdf_labrange[2]=-75;
			t2p->pdf_labrange[3]=124;
			t2p->pdf_sample=T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED;
			t2p->pdf_colorspace=T2P_CS_LAB;
			break;
		case PHOTOMETRIC_LOGL:
		case PHOTOMETRIC_LOGLUV:
			TIFFError(
				TIFF2PDF_MODULE,
				"No support for %s with photometric interpretation LogL/LogLuv",
				TIFFFileName(input));
			t2p->t2p_error = T2P_ERR_ERROR;
			return;
		default:
			TIFFError(
				TIFF2PDF_MODULE,
				"No support for %s with photometric interpretation %u",
				TIFFFileName(input),
				t2p->tiff_photometric);
			t2p->t2p_error = T2P_ERR_ERROR;
			return;
	}

	if(TIFFGetField(input, TIFFTAG_PLANARCONFIG, &(t2p->tiff_planar))){
		switch(t2p->tiff_planar){
			case 0:
				TIFFWarning(
					TIFF2PDF_MODULE,
					"Image %s has planar configuration 0, assuming 1",
					TIFFFileName(input));
				t2p->tiff_planar=PLANARCONFIG_CONTIG;
			case PLANARCONFIG_CONTIG:
				break;
			case PLANARCONFIG_SEPARATE:
				t2p->pdf_sample=T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG;
				if(t2p->tiff_bitspersample!=8){
					TIFFError(
						TIFF2PDF_MODULE,
						"No support for %s with separated planar configuration and %u bits per sample",
						TIFFFileName(input),
						t2p->tiff_bitspersample);
					t2p->t2p_error = T2P_ERR_ERROR;
					return;
				}
				break;
			default:
				TIFFError(
					TIFF2PDF_MODULE,
					"No support for %s with planar configuration %u",
					TIFFFileName(input),
					t2p->tiff_planar);
				t2p->t2p_error = T2P_ERR_ERROR;
				return;
		}
	}

        TIFFGetFieldDefaulted(input, TIFFTAG_ORIENTATION,
                              &(t2p->tiff_orientation));
        if(t2p->tiff_orientation>8){
                TIFFWarning(TIFF2PDF_MODULE,
                            "Image %s has orientation %u, assuming 0",
                            TIFFFileName(input), t2p->tiff_orientation);
                t2p->tiff_orientation=0;
        }

        if(TIFFGetField(input, TIFFTAG_XRESOLUTION, &(t2p->tiff_xres) ) == 0){
                t2p->tiff_xres=0.0;
        }
        if(TIFFGetField(input, TIFFTAG_YRESOLUTION, &(t2p->tiff_yres) ) == 0){
                t2p->tiff_yres=0.0;
        }
	TIFFGetFieldDefaulted(input, TIFFTAG_RESOLUTIONUNIT,
			      &(t2p->tiff_resunit));
	if(t2p->tiff_resunit == RESUNIT_CENTIMETER) {
		t2p->tiff_xres *= 2.54F;
		t2p->tiff_yres *= 2.54F;
	} else if (t2p->tiff_resunit != RESUNIT_INCH
		   && t2p->pdf_centimeters != 0) {
		t2p->tiff_xres *= 2.54F;
		t2p->tiff_yres *= 2.54F;
	}

	t2p_compose_pdf_page(t2p);
        if( t2p->t2p_error == T2P_ERR_ERROR )
	    return;

	t2p->pdf_transcode = T2P_TRANSCODE_ENCODE;
        /* It seems that T2P_TRANSCODE_RAW mode doesn't support separate->contig */
        /* conversion. At least t2p_read_tiff_size and t2p_read_tiff_size_tile */
        /* do not take into account the number of samples, and thus */
        /* that can cause heap buffer overflows such as in */
        /* http://bugzilla.maptools.org/show_bug.cgi?id=2715 */
	if(t2p->pdf_nopassthrough==0 && t2p->tiff_planar!=PLANARCONFIG_SEPARATE){
#ifdef CCITT_SUPPORT
		if(t2p->tiff_compression==COMPRESSION_CCITTFAX4
			){
			if(TIFFIsTiled(input) || (TIFFNumberOfStrips(input)==1) ){
				t2p->pdf_transcode = T2P_TRANSCODE_RAW;
				t2p->pdf_compression=T2P_COMPRESS_G4;
			}
		}
#endif
#ifdef ZIP_SUPPORT
		if(t2p->tiff_compression== COMPRESSION_ADOBE_DEFLATE
			|| t2p->tiff_compression==COMPRESSION_DEFLATE){
			if(TIFFIsTiled(input) || (TIFFNumberOfStrips(input)==1) ){
				t2p->pdf_transcode = T2P_TRANSCODE_RAW;
				t2p->pdf_compression=T2P_COMPRESS_ZIP;
			}
		}
#endif
#ifdef OJPEG_SUPPORT
		if(t2p->tiff_compression==COMPRESSION_OJPEG){
			t2p->pdf_transcode = T2P_TRANSCODE_RAW;
			t2p->pdf_compression=T2P_COMPRESS_JPEG;
			t2p_process_ojpeg_tables(t2p, input);
		}
#endif
#ifdef JPEG_SUPPORT
		if(t2p->tiff_compression==COMPRESSION_JPEG){
			t2p->pdf_transcode = T2P_TRANSCODE_RAW;
			t2p->pdf_compression=T2P_COMPRESS_JPEG;
		}
#endif
		(void)0;
	}

	if(t2p->pdf_transcode!=T2P_TRANSCODE_RAW){
		t2p->pdf_compression = t2p->pdf_defaultcompression;
	}

#ifdef JPEG_SUPPORT
	if(t2p->pdf_defaultcompression==T2P_COMPRESS_JPEG){
		if(t2p->pdf_colorspace & T2P_CS_PALETTE){
			t2p->pdf_sample|=T2P_SAMPLE_REALIZE_PALETTE;
			t2p->pdf_colorspace ^= T2P_CS_PALETTE;
			t2p->tiff_pages[t2p->pdf_page].page_extra--;
		}
	}
	if(t2p->tiff_compression==COMPRESSION_JPEG){
		if(t2p->tiff_planar==PLANARCONFIG_SEPARATE){
			TIFFError(
				TIFF2PDF_MODULE,
				"No support for %s with JPEG compression and separated planar configuration",
				TIFFFileName(input));
				t2p->t2p_error=T2P_ERR_ERROR;
			return;
		}
	}
#endif
#ifdef OJPEG_SUPPORT
	if(t2p->tiff_compression==COMPRESSION_OJPEG){
		if(t2p->tiff_planar==PLANARCONFIG_SEPARATE){
			TIFFError(
				TIFF2PDF_MODULE,
				"No support for %s with OJPEG compression and separated planar configuration",
				TIFFFileName(input));
				t2p->t2p_error=T2P_ERR_ERROR;
			return;
		}
	}
#endif

	if(t2p->pdf_sample & T2P_SAMPLE_REALIZE_PALETTE){
		if(t2p->pdf_colorspace & T2P_CS_CMYK){
			t2p->tiff_samplesperpixel=4;
			t2p->tiff_photometric=PHOTOMETRIC_SEPARATED;
		} else {
			t2p->tiff_samplesperpixel=3;
			t2p->tiff_photometric=PHOTOMETRIC_RGB;
		}
	}

	if (TIFFGetField(input, TIFFTAG_TRANSFERFUNCTION,
			 &(t2p->tiff_transferfunction[0]),
			 &(t2p->tiff_transferfunction[1]),
			 &(t2p->tiff_transferfunction[2]))) {
		if((t2p->tiff_transferfunction[1] != (float*) NULL) &&
                   (t2p->tiff_transferfunction[2] != (float*) NULL) &&
                   (t2p->tiff_transferfunction[1] !=
                    t2p->tiff_transferfunction[0])) {
			t2p->tiff_transferfunctioncount=3;
		} else {
			t2p->tiff_transferfunctioncount=1;
		}
	} else {
		t2p->tiff_transferfunctioncount=0;
	}
	if(TIFFGetField(input, TIFFTAG_WHITEPOINT, &xfloatp)!=0){
		t2p->tiff_whitechromaticities[0]=xfloatp[0];
		t2p->tiff_whitechromaticities[1]=xfloatp[1];
		if(t2p->pdf_colorspace & T2P_CS_GRAY){
			t2p->pdf_colorspace |= T2P_CS_CALGRAY;
		}
		if(t2p->pdf_colorspace & T2P_CS_RGB){
			t2p->pdf_colorspace |= T2P_CS_CALRGB;
		}
	}
	if(TIFFGetField(input, TIFFTAG_PRIMARYCHROMATICITIES, &xfloatp)!=0){
		t2p->tiff_primarychromaticities[0]=xfloatp[0];
		t2p->tiff_primarychromaticities[1]=xfloatp[1];
		t2p->tiff_primarychromaticities[2]=xfloatp[2];
		t2p->tiff_primarychromaticities[3]=xfloatp[3];
		t2p->tiff_primarychromaticities[4]=xfloatp[4];
		t2p->tiff_primarychromaticities[5]=xfloatp[5];
		if(t2p->pdf_colorspace & T2P_CS_RGB){
			t2p->pdf_colorspace |= T2P_CS_CALRGB;
		}
	}
	if(t2p->pdf_colorspace & T2P_CS_LAB){
		if(TIFFGetField(input, TIFFTAG_WHITEPOINT, &xfloatp) != 0){
			t2p->tiff_whitechromaticities[0]=xfloatp[0];
			t2p->tiff_whitechromaticities[1]=xfloatp[1];
		} else {
			t2p->tiff_whitechromaticities[0]=0.3457F; /* 0.3127F; */
			t2p->tiff_whitechromaticities[1]=0.3585F; /* 0.3290F; */
		}
	}
	if(TIFFGetField(input,
		TIFFTAG_ICCPROFILE,
		&(t2p->tiff_iccprofilelength),
		&(t2p->tiff_iccprofile))!=0){
		t2p->pdf_colorspace |= T2P_CS_ICCBASED;
	} else {
		t2p->tiff_iccprofilelength=0;
		t2p->tiff_iccprofile=NULL;
	}

#ifdef CCITT_SUPPORT
	if( t2p->tiff_bitspersample==1 &&
		t2p->tiff_samplesperpixel==1){
		t2p->pdf_compression = T2P_COMPRESS_G4;
	}
#endif

	return;
}


bgo#783835 - Don't divide by zero in box_blur_line() for gaussian blurs

We were making the decision to use box blurs, instead of a true
Gaussian kernel, based on the size of *both* x and y dimensions.  Do
them individually instead.

box_blur_line (gint box_width, gint even_offset,
               guchar *src, guchar *dest,
               gint len, gint bpp)
{
    gint  i;
    gint  lead;    /* This marks the leading edge of the kernel              */
    gint  output;  /* This marks the center of the kernel                    */
    gint  trail;   /* This marks the pixel BEHIND the last 1 in the
                      kernel; it's the pixel to remove from the accumulator. */
    gint  *ac;     /* Accumulator for each channel                           */

    ac = g_new0 (gint, bpp);

    /* The algorithm differs for even and odd-sized kernels.
     * With the output at the center,
     * If odd, the kernel might look like this: 0011100
     * If even, the kernel will either be centered on the boundary between
     * the output and its left neighbor, or on the boundary between the
     * output and its right neighbor, depending on even_lr.
     * So it might be 0111100 or 0011110, where output is on the center
     * of these arrays.
     */
    lead = 0;

    if (box_width % 2 != 0) {
        /* Odd-width kernel */
        output = lead - (box_width - 1) / 2;
        trail  = lead - box_width;
    } else {
        /* Even-width kernel. */
        if (even_offset == 1) {
            /* Right offset */
            output = lead + 1 - box_width / 2;
            trail  = lead - box_width;
        } else if (even_offset == -1) {
            /* Left offset */
            output = lead - box_width / 2;
            trail  = lead - box_width;
        } else {
            /* If even_offset isn't 1 or -1, there's some error. */
            g_assert_not_reached ();
        }
    }

    /* Initialize accumulator */
    for (i = 0; i < bpp; i++)
        ac[i] = 0;

    /* As the kernel moves across the image, it has a leading edge and a
     * trailing edge, and the output is in the middle. */
    while (output < len) {
        /* The number of pixels that are both in the image and
         * currently covered by the kernel. This is necessary to
         * handle edge cases. */
        guint coverage = (lead < len ? lead : len - 1) - (trail >= 0 ? trail : -1);

#ifdef READABLE_BOXBLUR_CODE
/* The code here does the same as the code below, but the code below
 * has been optimized by moving the if statements out of the tight for
 * loop, and is harder to understand.
 * Don't use both this code and the code below. */
        for (i = 0; i < bpp; i++) {
            /* If the leading edge of the kernel is still on the image,
             * add the value there to the accumulator. */
            if (lead < len)
                ac[i] += src[bpp * lead + i];

            /* If the trailing edge of the kernel is on the image,
             * subtract the value there from the accumulator. */
            if (trail >= 0)
                ac[i] -= src[bpp * trail + i];

            /* Take the averaged value in the accumulator and store
             * that value in the output. The number of pixels currently
             * stored in the accumulator can be less than the nominal
             * width of the kernel because the kernel can go "over the edge"
             * of the image. */
            if (output >= 0)
                dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
        }
#endif

        /* If the leading edge of the kernel is still on the image... */
        if (lead < len) {
            if (trail >= 0) {
                /* If the trailing edge of the kernel is on the image. (Since
                 * the output is in between the lead and trail, it must be on
                 * the image. */
                for (i = 0; i < bpp; i++) {
                    ac[i] += src[bpp * lead + i];
                    ac[i] -= src[bpp * trail + i];
                    dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
                }
            } else if (output >= 0) {
                /* If the output is on the image, but the trailing edge isn't yet
                 * on the image. */

                for (i = 0; i < bpp; i++) {
                    ac[i] += src[bpp * lead + i];
                    dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
                }
            } else {
                /* If leading edge is on the image, but the output and trailing
                 * edge aren't yet on the image. */
                for (i = 0; i < bpp; i++)
                    ac[i] += src[bpp * lead + i];
            }
        } else if (trail >= 0) {
            /* If the leading edge has gone off the image, but the output and
             * trailing edge are on the image. (The big loop exits when the
             * output goes off the image. */
            for (i = 0; i < bpp; i++) {
                ac[i] -= src[bpp * trail + i];
                dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
            }
        } else if (output >= 0) {
            /* Leading has gone off the image and trailing isn't yet in it
             * (small image) */
            for (i = 0; i < bpp; i++)
                dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
        }

        lead++;
        output++;
        trail++;
    }

    g_free (ac);
}

A SIGFPE is raised in the function box_blur_line of rsvg-filter.c in GNOME librsvg 2.40.17 during an attempted parse of a crafted SVG file, because of incorrect protection against division by zero.


box_blur_line (gint box_width, gint even_offset,
               guchar *src, guchar *dest,
               gint len, gint bpp)
{
    gint  i;
    gint  lead;    /* This marks the leading edge of the kernel              */
    gint  output;  /* This marks the center of the kernel                    */
    gint  trail;   /* This marks the pixel BEHIND the last 1 in the
                      kernel; it's the pixel to remove from the accumulator. */
    gint  *ac;     /* Accumulator for each channel                           */

    g_assert (box_width > 0);

    ac = g_new0 (gint, bpp);

    /* The algorithm differs for even and odd-sized kernels.
     * With the output at the center,
     * If odd, the kernel might look like this: 0011100
     * If even, the kernel will either be centered on the boundary between
     * the output and its left neighbor, or on the boundary between the
     * output and its right neighbor, depending on even_lr.
     * So it might be 0111100 or 0011110, where output is on the center
     * of these arrays.
     */
    lead = 0;

    if (box_width % 2 != 0) {
        /* Odd-width kernel */
        output = lead - (box_width - 1) / 2;
        trail  = lead - box_width;
    } else {
        /* Even-width kernel. */
        if (even_offset == 1) {
            /* Right offset */
            output = lead + 1 - box_width / 2;
            trail  = lead - box_width;
        } else if (even_offset == -1) {
            /* Left offset */
            output = lead - box_width / 2;
            trail  = lead - box_width;
        } else {
            /* If even_offset isn't 1 or -1, there's some error. */
            g_assert_not_reached ();
        }
    }

    /* Initialize accumulator */
    for (i = 0; i < bpp; i++)
        ac[i] = 0;

    /* As the kernel moves across the image, it has a leading edge and a
     * trailing edge, and the output is in the middle. */
    while (output < len) {
        /* The number of pixels that are both in the image and
         * currently covered by the kernel. This is necessary to
         * handle edge cases. */
        guint coverage = (lead < len ? lead : len - 1) - (trail >= 0 ? trail : -1);

#ifdef READABLE_BOXBLUR_CODE
/* The code here does the same as the code below, but the code below
 * has been optimized by moving the if statements out of the tight for
 * loop, and is harder to understand.
 * Don't use both this code and the code below. */
        for (i = 0; i < bpp; i++) {
            /* If the leading edge of the kernel is still on the image,
             * add the value there to the accumulator. */
            if (lead < len)
                ac[i] += src[bpp * lead + i];

            /* If the trailing edge of the kernel is on the image,
             * subtract the value there from the accumulator. */
            if (trail >= 0)
                ac[i] -= src[bpp * trail + i];

            /* Take the averaged value in the accumulator and store
             * that value in the output. The number of pixels currently
             * stored in the accumulator can be less than the nominal
             * width of the kernel because the kernel can go "over the edge"
             * of the image. */
            if (output >= 0)
                dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
        }
#endif

        /* If the leading edge of the kernel is still on the image... */
        if (lead < len) {
            if (trail >= 0) {
                /* If the trailing edge of the kernel is on the image. (Since
                 * the output is in between the lead and trail, it must be on
                 * the image. */
                for (i = 0; i < bpp; i++) {
                    ac[i] += src[bpp * lead + i];
                    ac[i] -= src[bpp * trail + i];
                    dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
                }
            } else if (output >= 0) {
                /* If the output is on the image, but the trailing edge isn't yet
                 * on the image. */

                for (i = 0; i < bpp; i++) {
                    ac[i] += src[bpp * lead + i];
                    dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
                }
            } else {
                /* If leading edge is on the image, but the output and trailing
                 * edge aren't yet on the image. */
                for (i = 0; i < bpp; i++)
                    ac[i] += src[bpp * lead + i];
            }
        } else if (trail >= 0) {
            /* If the leading edge has gone off the image, but the output and
             * trailing edge are on the image. (The big loop exits when the
             * output goes off the image. */
            for (i = 0; i < bpp; i++) {
                ac[i] -= src[bpp * trail + i];
                dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
            }
        } else if (output >= 0) {
            /* Leading has gone off the image and trailing isn't yet in it
             * (small image) */
            for (i = 0; i < bpp; i++)
                dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
        }

        lead++;
        output++;
        trail++;
    }

    g_free (ac);
}


MW-416 DDL replication moved after acl checking

galera_events test shows a regression with the original fix for MW-416
Reason was that Events::drop_event() can be called also from inside event
execution, and there we have a speacial treatment for event, which executes
"DROP EVENT" statement, and runs TOI replication inside the event processing body.
This resulted in executing WSREP_TO_ISOLATION two times for such DROP EVENT statement.
Fix is to call WSREP_TO_ISOLATION_BEGIN only in Events::drop_event()

Event_job_data::execute(THD *thd, bool drop)
{
  String sp_sql;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  Security_context event_sctx, *save_sctx= NULL;
#endif
  List<Item> empty_item_list;
  bool ret= TRUE;

  DBUG_ENTER("Event_job_data::execute");

  thd->reset_for_next_command();

  /*
    MySQL parser currently assumes that current database is either
    present in THD or all names in all statements are fully specified.
    And yet not fully specified names inside stored programs must be
    be supported, even if the current database is not set:
    CREATE PROCEDURE db1.p1() BEGIN CREATE TABLE t1; END//
    -- in this example t1 should be always created in db1 and the statement
    must parse even if there is no current database.

    To support this feature and still address the parser limitation,
    we need to set the current database here.
    We don't have to call mysql_change_db, since the checks performed
    in it are unnecessary for the purpose of parsing, and
    mysql_change_db will be invoked anyway later, to activate the
    procedure database before it's executed.
  */
  thd->set_db(dbname.str, dbname.length);

  lex_start(thd);

#ifndef NO_EMBEDDED_ACCESS_CHECKS
  if (event_sctx.change_security_context(thd,
                                         &definer_user, &definer_host,
                                         &dbname, &save_sctx))
  {
    sql_print_error("Event Scheduler: "
                    "[%s].[%s.%s] execution failed, "
                    "failed to authenticate the user.",
                    definer.str, dbname.str, name.str);
    goto end;
  }
#endif

  if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
  {
    /*
      This aspect of behavior is defined in the worklog,
      and this is how triggers work too: if TRIGGER
      privilege is revoked from trigger definer,
      triggers are not executed.
    */
    sql_print_error("Event Scheduler: "
                    "[%s].[%s.%s] execution failed, "
                    "user no longer has EVENT privilege.",
                    definer.str, dbname.str, name.str);
    goto end;
  }

  if (construct_sp_sql(thd, &sp_sql))
    goto end;

  /*
    Set up global thread attributes to reflect the properties of
    this Event. We can simply reset these instead of usual
    backup/restore employed in stored programs since we know that
    this is a top level statement and the worker thread is
    allocated exclusively to execute this event.
  */

  thd->variables.sql_mode= sql_mode;
  thd->variables.time_zone= time_zone;

  thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());

  {
    Parser_state parser_state;
    if (parser_state.init(thd, thd->query(), thd->query_length()))
      goto end;

    if (parse_sql(thd, & parser_state, creation_ctx))
    {
      sql_print_error("Event Scheduler: "
                      "%serror during compilation of %s.%s",
                      thd->is_fatal_error ? "fatal " : "",
                      (const char *) dbname.str, (const char *) name.str);
      goto end;
    }
  }

  {
    sp_head *sphead= thd->lex->sphead;

    DBUG_ASSERT(sphead);

    sphead->m_flags|= sp_head::LOG_SLOW_STATEMENTS;
    sphead->m_flags|= sp_head::LOG_GENERAL_LOG;

    sphead->set_info(0, 0, &thd->lex->sp_chistics, sql_mode);
    sphead->set_creation_ctx(creation_ctx);
    sphead->optimize();

    ret= sphead->execute_procedure(thd, &empty_item_list);
    /*
      There is no pre-locking and therefore there should be no
      tables open and locked left after execute_procedure.
    */
  }

end:
  if (drop && !thd->is_fatal_error)
  {
    /*
      We must do it here since here we're under the right authentication
      ID of the event definer.
    */
    sql_print_information("Event Scheduler: Dropping %s.%s",
                          (const char *) dbname.str, (const char *) name.str);
    /*
      Construct a query for the binary log, to ensure the event is dropped
      on the slave
    */
    if (construct_drop_event_sql(thd, &sp_sql))
      ret= 1;
    else
    {
      ulong saved_master_access;

      thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());

      /*
        NOTE: even if we run in read-only mode, we should be able to lock
        the mysql.event table for writing. In order to achieve this, we
        should call mysql_lock_tables() under the super-user.

        Same goes for transaction access mode.
        Temporarily reset it to read-write.
      */

      saved_master_access= thd->security_ctx->master_access;
      thd->security_ctx->master_access |= SUPER_ACL;
      bool save_tx_read_only= thd->tx_read_only;
      thd->tx_read_only= false;

      if (WSREP(thd))
      {
        thd->lex->sql_command = SQLCOM_DROP_EVENT;
        WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
      }

      ret= Events::drop_event(thd, dbname, name, FALSE);

      WSREP_TO_ISOLATION_END;

#ifdef WITH_WSREP
  error:
#endif
      thd->tx_read_only= save_tx_read_only;
      thd->security_ctx->master_access= saved_master_access;
    }
  }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  if (save_sctx)
    event_sctx.restore_security_context(thd, save_sctx);
#endif
  thd->lex->unit.cleanup();
  thd->end_statement();
  thd->cleanup_after_query();
  /* Avoid races with SHOW PROCESSLIST */
  thd->reset_query();

  DBUG_PRINT("info", ("EXECUTED %s.%s  ret: %d", dbname.str, name.str, ret));

  DBUG_RETURN(ret);
}

sql/event_data_objects.cc in MariaDB before 10.1.30 and 10.2.x before 10.2.10 and Percona XtraDB Cluster before 5.6.37-26.21-3 and 5.7.x before 5.7.19-29.22-3 allows remote authenticated users with SQL access to bypass intended access restrictions and replicate data definition language (DDL) statements to cluster nodes by leveraging incorrect ordering of DDL replication and ACL checking.


Event_job_data::execute(THD *thd, bool drop)
{
  String sp_sql;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  Security_context event_sctx, *save_sctx= NULL;
#endif
  List<Item> empty_item_list;
  bool ret= TRUE;

  DBUG_ENTER("Event_job_data::execute");

  thd->reset_for_next_command();

  /*
    MySQL parser currently assumes that current database is either
    present in THD or all names in all statements are fully specified.
    And yet not fully specified names inside stored programs must be
    be supported, even if the current database is not set:
    CREATE PROCEDURE db1.p1() BEGIN CREATE TABLE t1; END//
    -- in this example t1 should be always created in db1 and the statement
    must parse even if there is no current database.

    To support this feature and still address the parser limitation,
    we need to set the current database here.
    We don't have to call mysql_change_db, since the checks performed
    in it are unnecessary for the purpose of parsing, and
    mysql_change_db will be invoked anyway later, to activate the
    procedure database before it's executed.
  */
  thd->set_db(dbname.str, dbname.length);

  lex_start(thd);

#ifndef NO_EMBEDDED_ACCESS_CHECKS
  if (event_sctx.change_security_context(thd,
                                         &definer_user, &definer_host,
                                         &dbname, &save_sctx))
  {
    sql_print_error("Event Scheduler: "
                    "[%s].[%s.%s] execution failed, "
                    "failed to authenticate the user.",
                    definer.str, dbname.str, name.str);
    goto end;
  }
#endif

  if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
  {
    /*
      This aspect of behavior is defined in the worklog,
      and this is how triggers work too: if TRIGGER
      privilege is revoked from trigger definer,
      triggers are not executed.
    */
    sql_print_error("Event Scheduler: "
                    "[%s].[%s.%s] execution failed, "
                    "user no longer has EVENT privilege.",
                    definer.str, dbname.str, name.str);
    goto end;
  }

  if (construct_sp_sql(thd, &sp_sql))
    goto end;

  /*
    Set up global thread attributes to reflect the properties of
    this Event. We can simply reset these instead of usual
    backup/restore employed in stored programs since we know that
    this is a top level statement and the worker thread is
    allocated exclusively to execute this event.
  */

  thd->variables.sql_mode= sql_mode;
  thd->variables.time_zone= time_zone;

  thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());

  {
    Parser_state parser_state;
    if (parser_state.init(thd, thd->query(), thd->query_length()))
      goto end;

    if (parse_sql(thd, & parser_state, creation_ctx))
    {
      sql_print_error("Event Scheduler: "
                      "%serror during compilation of %s.%s",
                      thd->is_fatal_error ? "fatal " : "",
                      (const char *) dbname.str, (const char *) name.str);
      goto end;
    }
  }

  {
    sp_head *sphead= thd->lex->sphead;

    DBUG_ASSERT(sphead);

    sphead->m_flags|= sp_head::LOG_SLOW_STATEMENTS;
    sphead->m_flags|= sp_head::LOG_GENERAL_LOG;

    sphead->set_info(0, 0, &thd->lex->sp_chistics, sql_mode);
    sphead->set_creation_ctx(creation_ctx);
    sphead->optimize();

    ret= sphead->execute_procedure(thd, &empty_item_list);
    /*
      There is no pre-locking and therefore there should be no
      tables open and locked left after execute_procedure.
    */
  }

end:
  if (drop && !thd->is_fatal_error)
  {
    /*
      We must do it here since here we're under the right authentication
      ID of the event definer.
    */
    sql_print_information("Event Scheduler: Dropping %s.%s",
                          (const char *) dbname.str, (const char *) name.str);
    /*
      Construct a query for the binary log, to ensure the event is dropped
      on the slave
    */
    if (construct_drop_event_sql(thd, &sp_sql))
      ret= 1;
    else
    {
      ulong saved_master_access;

      thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());

      /*
        NOTE: even if we run in read-only mode, we should be able to lock
        the mysql.event table for writing. In order to achieve this, we
        should call mysql_lock_tables() under the super-user.

        Same goes for transaction access mode.
        Temporarily reset it to read-write.
      */

      saved_master_access= thd->security_ctx->master_access;
      thd->security_ctx->master_access |= SUPER_ACL;
      bool save_tx_read_only= thd->tx_read_only;
      thd->tx_read_only= false;

      /*
         This code is processing event execution and does not have client
         connection. Here, event execution will now execute a prepared
         DROP EVENT statement, but thd->lex->sql_command is set to
         SQLCOM_CREATE_PROCEDURE
         DROP EVENT will be logged in binlog, and we have to
         replicate it to make all nodes have consistent event definitions
         Wsrep DDL replication is triggered inside Events::drop_event(),
         and here we need to prepare the THD so that DDL replication is
         possible, essentially it requires setting sql_command to
         SQLCOMM_DROP_EVENT, we will switch sql_command for the duration
         of DDL replication only.
      */
      const enum_sql_command sql_command_save= thd->lex->sql_command;
      const bool sql_command_set= WSREP(thd);

      if (sql_command_set)
        thd->lex->sql_command = SQLCOM_DROP_EVENT;

      ret= Events::drop_event(thd, dbname, name, FALSE);

      if (sql_command_set)
      {
        WSREP_TO_ISOLATION_END;
        thd->lex->sql_command = sql_command_save;
      }

      thd->tx_read_only= save_tx_read_only;
      thd->security_ctx->master_access= saved_master_access;
    }
  }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  if (save_sctx)
    event_sctx.restore_security_context(thd, save_sctx);
#endif
  thd->lex->unit.cleanup();
  thd->end_statement();
  thd->cleanup_after_query();
  /* Avoid races with SHOW PROCESSLIST */
  thd->reset_query();

  DBUG_PRINT("info", ("EXECUTED %s.%s  ret: %d", dbname.str, name.str, ret));

  DBUG_RETURN(ret);
}


SimpleModule: set output chunk framecount after pull

After pulling the data, set the output chunk to the amount of
frames we pulled so that the next module in the chain has the correct
frame count.

Fixes #50 and #51

void SimpleModule::runPull()
{
	pull(m_outChunk->frameCount);
	run(*m_inChunk, *m_outChunk);
}

An issue has been discovered in mpruett Audio File Library (aka audiofile) 0.3.6, 0.3.5, 0.3.4, 0.3.3, 0.3.2, 0.3.1, 0.3.0. A heap-based buffer overflow in Expand3To4Module::run has occurred when running sfconvert.


void SimpleModule::runPull()
{
	pull(m_outChunk->frameCount);
	m_outChunk->frameCount = m_inChunk->frameCount;
	run(*m_inChunk, *m_outChunk);
}


lib-imap: Don't accept strings with NULs

IMAP doesn't allow NULs except in binary literals. We'll still allow them
in regular literals as well, but just not in strings.

This fixes a bug with unescaping a string with NULs: str_unescape() could
have been called for memory that points outside the allocated string,
causing heap corruption. This could cause crashes or theoretically even
result in remote code execution exploit.

Found by Nick Roessler and Rafi Rubin

static bool imap_parser_read_string(struct imap_parser *parser,
				    const unsigned char *data, size_t data_size)
{
	size_t i;

	/* read until we've found non-escaped ", CR or LF */
	for (i = parser->cur_pos; i < data_size; i++) {
		if (data[i] == '"') {
			imap_parser_save_arg(parser, data, i);

			i++; /* skip the trailing '"' too */
			break;
		}

		if (data[i] == '\\') {
			if (i+1 == data_size) {
				/* known data ends with '\' - leave it to
				   next time as well if it happens to be \" */
				break;
			}

			/* save the first escaped char */
			if (parser->str_first_escape < 0)
				parser->str_first_escape = i;

			/* skip the escaped char */
			i++;
		}

		/* check linebreaks here, so escaping CR/LF isn't possible.
		   string always ends with '"', so it's an error if we found
		   a linebreak.. */
		if (is_linebreak(data[i]) &&
		    (parser->flags & IMAP_PARSE_FLAG_MULTILINE_STR) == 0) {
			parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
			parser->error_msg = "Missing '\"'";
			return FALSE;
		}
	}

	parser->cur_pos = i;
	return parser->cur_type == ARG_PARSE_NONE;
}

In Dovecot before 2.2.36.4 and 2.3.x before 2.3.7.2 (and Pigeonhole before 0.5.7.2), protocol processing can fail for quoted strings. This occurs because '\0' characters are mishandled, and can lead to out-of-bounds writes and remote code execution.


static bool imap_parser_read_string(struct imap_parser *parser,
				    const unsigned char *data, size_t data_size)
{
	size_t i;

	/* read until we've found non-escaped ", CR or LF */
	for (i = parser->cur_pos; i < data_size; i++) {
		if (data[i] == '"') {
			imap_parser_save_arg(parser, data, i);

			i++; /* skip the trailing '"' too */
			break;
		}

		if (data[i] == '\0') {
			parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
			parser->error_msg = "NULs not allowed in strings";
			return FALSE;
		}

		if (data[i] == '\\') {
			if (i+1 == data_size) {
				/* known data ends with '\' - leave it to
				   next time as well if it happens to be \" */
				break;
			}

			/* save the first escaped char */
			if (parser->str_first_escape < 0)
				parser->str_first_escape = i;

			/* skip the escaped char */
			i++;
		}

		/* check linebreaks here, so escaping CR/LF isn't possible.
		   string always ends with '"', so it's an error if we found
		   a linebreak.. */
		if (is_linebreak(data[i]) &&
		    (parser->flags & IMAP_PARSE_FLAG_MULTILINE_STR) == 0) {
			parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
			parser->error_msg = "Missing '\"'";
			return FALSE;
		}
	}

	parser->cur_pos = i;
	return parser->cur_type == ARG_PARSE_NONE;
}


lib-imap: Make sure str_unescape() won't be writing past allocated memory

The previous commit should already prevent this, but this makes sure it
can't become broken in the future either. It makes the performance a tiny
bit worse, but that's not practically noticeable.

static void imap_parser_save_arg(struct imap_parser *parser,
				 const unsigned char *data, size_t size)
{
	struct imap_arg *arg;
	char *str;

	arg = imap_arg_create(parser);

	switch (parser->cur_type) {
	case ARG_PARSE_ATOM:
	case ARG_PARSE_TEXT:
		if (size == 3 && i_memcasecmp(data, "NIL", 3) == 0) {
			/* NIL argument. it might be an actual NIL, but if
			   we're reading astring, it's an atom and we can't
			   lose its case. */
			arg->type = IMAP_ARG_NIL;
		} else {
			/* simply save the string */
			arg->type = IMAP_ARG_ATOM;
		}
		arg->_data.str = imap_parser_strdup(parser, data, size);
		arg->str_len = size;
		break;
	case ARG_PARSE_STRING:
		/* data is quoted and may contain escapes. */
		i_assert(size > 0);

		arg->type = IMAP_ARG_STRING;
		str = p_strndup(parser->pool, data+1, size-1);

		/* remove the escapes */
		if (parser->str_first_escape >= 0 &&
		    (parser->flags & IMAP_PARSE_FLAG_NO_UNESCAPE) == 0) {
			/* -1 because we skipped the '"' prefix */
			(void)str_unescape(str + parser->str_first_escape-1);
		}
		arg->_data.str = str;
		arg->str_len = strlen(str);
		break;
	case ARG_PARSE_LITERAL_DATA:
		if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_SIZE) != 0) {
			/* save literal size */
			arg->type = parser->literal_nonsync ?
				IMAP_ARG_LITERAL_SIZE_NONSYNC :
				IMAP_ARG_LITERAL_SIZE;
			arg->_data.literal_size = parser->literal_size;
			arg->literal8 = parser->literal8;
			break;
		}
		/* fall through */
	case ARG_PARSE_LITERAL_DATA_FORCED:
		if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_TYPE) != 0)
			arg->type = IMAP_ARG_LITERAL;
		else
			arg->type = IMAP_ARG_STRING;
		arg->_data.str = imap_parser_strdup(parser, data, size);
		arg->literal8 = parser->literal8;
		arg->str_len = size;
		break;
	default:
                i_unreached();
	}

	parser->cur_type = ARG_PARSE_NONE;
}


static void imap_parser_save_arg(struct imap_parser *parser,
				 const unsigned char *data, size_t size)
{
	struct imap_arg *arg;
	char *str;

	arg = imap_arg_create(parser);

	switch (parser->cur_type) {
	case ARG_PARSE_ATOM:
	case ARG_PARSE_TEXT:
		if (size == 3 && i_memcasecmp(data, "NIL", 3) == 0) {
			/* NIL argument. it might be an actual NIL, but if
			   we're reading astring, it's an atom and we can't
			   lose its case. */
			arg->type = IMAP_ARG_NIL;
		} else {
			/* simply save the string */
			arg->type = IMAP_ARG_ATOM;
		}
		arg->_data.str = imap_parser_strdup(parser, data, size);
		arg->str_len = size;
		break;
	case ARG_PARSE_STRING:
		/* data is quoted and may contain escapes. */
		i_assert(size > 0);

		arg->type = IMAP_ARG_STRING;
		str = p_strndup(parser->pool, data+1, size-1);

		/* remove the escapes */
		if (parser->str_first_escape >= 0 &&
		    (parser->flags & IMAP_PARSE_FLAG_NO_UNESCAPE) == 0)
			(void)str_unescape(str);
		arg->_data.str = str;
		arg->str_len = strlen(str);
		break;
	case ARG_PARSE_LITERAL_DATA:
		if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_SIZE) != 0) {
			/* save literal size */
			arg->type = parser->literal_nonsync ?
				IMAP_ARG_LITERAL_SIZE_NONSYNC :
				IMAP_ARG_LITERAL_SIZE;
			arg->_data.literal_size = parser->literal_size;
			arg->literal8 = parser->literal8;
			break;
		}
		/* fall through */
	case ARG_PARSE_LITERAL_DATA_FORCED:
		if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_TYPE) != 0)
			arg->type = IMAP_ARG_LITERAL;
		else
			arg->type = IMAP_ARG_STRING;
		arg->_data.str = imap_parser_strdup(parser, data, size);
		arg->literal8 = parser->literal8;
		arg->str_len = size;
		break;
	default:
                i_unreached();
	}

	parser->cur_type = ARG_PARSE_NONE;
}


CVE-2019-14889: scp: Don't allow file path longer than 32kb

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 0b5ee397260b6e08dffa2c1ce515a153aaeda765)

ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location)
{
    ssh_scp scp = NULL;

    if (session == NULL) {
        goto error;
    }

    scp = (ssh_scp)calloc(1, sizeof(struct ssh_scp_struct));
    if (scp == NULL) {
        ssh_set_error(session, SSH_FATAL,
                      "Error allocating memory for ssh_scp");
        goto error;
    }

    if ((mode & ~SSH_SCP_RECURSIVE) != SSH_SCP_WRITE &&
        (mode & ~SSH_SCP_RECURSIVE) != SSH_SCP_READ)
    {
        ssh_set_error(session, SSH_FATAL,
                      "Invalid mode %d for ssh_scp_new()", mode);
        goto error;
    }

    scp->location = strdup(location);
    if (scp->location == NULL) {
        ssh_set_error(session, SSH_FATAL,
                      "Error allocating memory for ssh_scp");
        goto error;
    }

    scp->session = session;
    scp->mode = mode & ~SSH_SCP_RECURSIVE;
    scp->recursive = (mode & SSH_SCP_RECURSIVE) != 0;
    scp->channel = NULL;
    scp->state = SSH_SCP_NEW;

    return scp;

error:
    ssh_scp_free(scp);
    return NULL;
}

A flaw was found with the libssh API function ssh_scp_new() in versions before 0.9.3 and before 0.8.8. When the libssh SCP client connects to a server, the scp command, which includes a user-provided path, is executed on the server-side. In case the library is used in a way where users can influence the third parameter of the function, it would become possible for an attacker to inject arbitrary commands, leading to a compromise of the remote target.


ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location)
{
    ssh_scp scp = NULL;

    if (session == NULL) {
        goto error;
    }

    scp = (ssh_scp)calloc(1, sizeof(struct ssh_scp_struct));
    if (scp == NULL) {
        ssh_set_error(session, SSH_FATAL,
                      "Error allocating memory for ssh_scp");
        goto error;
    }

    if ((mode & ~SSH_SCP_RECURSIVE) != SSH_SCP_WRITE &&
        (mode & ~SSH_SCP_RECURSIVE) != SSH_SCP_READ)
    {
        ssh_set_error(session, SSH_FATAL,
                      "Invalid mode %d for ssh_scp_new()", mode);
        goto error;
    }

    if (strlen(location) > 32 * 1024) {
        ssh_set_error(session, SSH_FATAL,
                      "Location path is too long");
        goto error;
    }

    scp->location = strdup(location);
    if (scp->location == NULL) {
        ssh_set_error(session, SSH_FATAL,
                      "Error allocating memory for ssh_scp");
        goto error;
    }

    scp->session = session;
    scp->mode = mode & ~SSH_SCP_RECURSIVE;
    scp->recursive = (mode & SSH_SCP_RECURSIVE) != 0;
    scp->channel = NULL;
    scp->state = SSH_SCP_NEW;

    return scp;

error:
    ssh_scp_free(scp);
    return NULL;
}


CVE-2019-14889: scp: Quote location to be used on shell

Single quote file paths to be used on commands to be executed on remote
shell.

Fixes T181

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 3830c7ae6eec751b7618d3fc159cb5bb3c8806a6)

int ssh_scp_init(ssh_scp scp)
{
    int rc;
    char execbuffer[1024] = {0};

    if (scp == NULL) {
        return SSH_ERROR;
    }

    if (scp->state != SSH_SCP_NEW) {
        ssh_set_error(scp->session, SSH_FATAL,
                      "ssh_scp_init called under invalid state");
        return SSH_ERROR;
    }

    SSH_LOG(SSH_LOG_PROTOCOL,
            "Initializing scp session %s %son location '%s'",
            scp->mode == SSH_SCP_WRITE?"write":"read",
            scp->recursive?"recursive ":"",
            scp->location);

    scp->channel = ssh_channel_new(scp->session);
    if (scp->channel == NULL) {
        scp->state = SSH_SCP_ERROR;
        return SSH_ERROR;
    }

    rc = ssh_channel_open_session(scp->channel);
    if (rc == SSH_ERROR) {
        scp->state = SSH_SCP_ERROR;
        return SSH_ERROR;
    }

    if (scp->mode == SSH_SCP_WRITE) {
        snprintf(execbuffer, sizeof(execbuffer), "scp -t %s %s",
                scp->recursive ? "-r":"", scp->location);
    } else {
        snprintf(execbuffer, sizeof(execbuffer), "scp -f %s %s",
                scp->recursive ? "-r":"", scp->location);
    }

    if (ssh_channel_request_exec(scp->channel, execbuffer) == SSH_ERROR) {
        scp->state = SSH_SCP_ERROR;
        return SSH_ERROR;
    }

    if (scp->mode == SSH_SCP_WRITE) {
        rc = ssh_scp_response(scp, NULL);
        if (rc != 0) {
            return SSH_ERROR;
        }
    } else {
        ssh_channel_write(scp->channel, "", 1);
    }

    if (scp->mode == SSH_SCP_WRITE) {
        scp->state = SSH_SCP_WRITE_INITED;
    } else {
        scp->state = SSH_SCP_READ_INITED;
    }

    return SSH_OK;
}


int ssh_scp_init(ssh_scp scp)
{
    int rc;
    char execbuffer[1024] = {0};
    char *quoted_location = NULL;
    size_t quoted_location_len = 0;
    size_t scp_location_len;

    if (scp == NULL) {
        return SSH_ERROR;
    }

    if (scp->state != SSH_SCP_NEW) {
        ssh_set_error(scp->session, SSH_FATAL,
                      "ssh_scp_init called under invalid state");
        return SSH_ERROR;
    }

    if (scp->location == NULL) {
        ssh_set_error(scp->session, SSH_FATAL,
                      "Invalid scp context: location is NULL");
        return SSH_ERROR;
    }

    SSH_LOG(SSH_LOG_PROTOCOL, "Initializing scp session %s %son location '%s'",
            scp->mode == SSH_SCP_WRITE?"write":"read",
            scp->recursive ? "recursive " : "",
            scp->location);

    scp->channel = ssh_channel_new(scp->session);
    if (scp->channel == NULL) {
        ssh_set_error(scp->session, SSH_FATAL,
                      "Channel creation failed for scp");
        scp->state = SSH_SCP_ERROR;
        return SSH_ERROR;
    }

    rc = ssh_channel_open_session(scp->channel);
    if (rc == SSH_ERROR) {
        ssh_set_error(scp->session, SSH_FATAL,
                      "Failed to open channel for scp");
        scp->state = SSH_SCP_ERROR;
        return SSH_ERROR;
    }

    /* In the worst case, each character would be replaced by 3 plus the string
     * terminator '\0' */
    scp_location_len = strlen(scp->location);
    quoted_location_len = ((size_t)3 * scp_location_len) + 1;
    /* Paranoia check */
    if (quoted_location_len < scp_location_len) {
        ssh_set_error(scp->session, SSH_FATAL,
                      "Buffer overflow detected");
        scp->state = SSH_SCP_ERROR;
        return SSH_ERROR;
    }

    quoted_location = (char *)calloc(1, quoted_location_len);
    if (quoted_location == NULL) {
        ssh_set_error(scp->session, SSH_FATAL,
                      "Failed to allocate memory for quoted location");
        scp->state = SSH_SCP_ERROR;
        return SSH_ERROR;
    }

    rc = ssh_quote_file_name(scp->location, quoted_location,
                             quoted_location_len);
    if (rc <= 0) {
        ssh_set_error(scp->session, SSH_FATAL,
                      "Failed to single quote command location");
        SAFE_FREE(quoted_location);
        scp->state = SSH_SCP_ERROR;
        return SSH_ERROR;
    }

    if (scp->mode == SSH_SCP_WRITE) {
        snprintf(execbuffer, sizeof(execbuffer), "scp -t %s %s",
                scp->recursive ? "-r" : "", quoted_location);
    } else {
        snprintf(execbuffer, sizeof(execbuffer), "scp -f %s %s",
                scp->recursive ? "-r" : "", quoted_location);
    }

    SAFE_FREE(quoted_location);

    SSH_LOG(SSH_LOG_DEBUG, "Executing command: %s", execbuffer);

    rc = ssh_channel_request_exec(scp->channel, execbuffer);
    if (rc == SSH_ERROR){
        ssh_set_error(scp->session, SSH_FATAL,
                      "Failed executing command: %s", execbuffer);
        scp->state = SSH_SCP_ERROR;
        return SSH_ERROR;
    }

    if (scp->mode == SSH_SCP_WRITE) {
        rc = ssh_scp_response(scp, NULL);
        if (rc != 0) {
            return SSH_ERROR;
        }
    } else {
        ssh_channel_write(scp->channel, "", 1);
    }

    if (scp->mode == SSH_SCP_WRITE) {
        scp->state = SSH_SCP_WRITE_INITED;
    } else {
        scp->state = SSH_SCP_READ_INITED;
    }

    return SSH_OK;
}


lib-mail: message_snippet_generate() - Fix potential crash when input ends with '>'

This happens only when the mail was large enough and full enough with
whitespace that message-parser returned multiple blocks before the snippet
was finished.

Broken by 74063ed8219d055489d5233b0c02a59886d2078c

static void snippet_add_content(struct snippet_context *ctx,
				struct snippet_data *target,
				const unsigned char *data, size_t size,
				size_t *count_r)
{
	i_assert(target != NULL);
	if (size >= 3 &&
	     ((data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF) ||
	      (data[0] == 0xBF && data[1] == 0xBB && data[2] == 0xEF))) {
		*count_r = 3;
		return;
	}
	if (data[0] == '\0') {
		/* skip NULs without increasing snippet size */
		return;
	}
	if (i_isspace(*data)) {
		/* skip any leading whitespace */
		if (str_len(target->snippet) > 1)
			ctx->add_whitespace = TRUE;
		if (data[0] == '\n')
			ctx->state = SNIPPET_STATE_NEWLINE;
		return;
	}
	if (ctx->add_whitespace) {
		str_append_c(target->snippet, ' ');
		ctx->add_whitespace = FALSE;
		if (target->chars_left-- == 0)
			return;
	}
	if (target->chars_left == 0)
		return;
	target->chars_left--;
	*count_r = uni_utf8_char_bytes(data[0]);
	i_assert(*count_r <= size);
	str_append_data(target->snippet, data, *count_r);
}

The IMAP and LMTP components in Dovecot 2.3.9 before 2.3.9.3 mishandle snippet generation when many characters must be read to compute the snippet and a trailing > character exists. This causes a denial of service in which the recipient cannot read all of their messages.


static void snippet_add_content(struct snippet_context *ctx,
				struct snippet_data *target,
				const unsigned char *data, size_t size,
				size_t *count_r)
{
	i_assert(target != NULL);
	if (size == 0)
		return;
	if (size >= 3 &&
	     ((data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF) ||
	      (data[0] == 0xBF && data[1] == 0xBB && data[2] == 0xEF))) {
		*count_r = 3;
		return;
	}
	if (data[0] == '\0') {
		/* skip NULs without increasing snippet size */
		return;
	}
	if (i_isspace(*data)) {
		/* skip any leading whitespace */
		if (str_len(target->snippet) > 1)
			ctx->add_whitespace = TRUE;
		if (data[0] == '\n')
			ctx->state = SNIPPET_STATE_NEWLINE;
		return;
	}
	if (ctx->add_whitespace) {
		str_append_c(target->snippet, ' ');
		ctx->add_whitespace = FALSE;
		if (target->chars_left-- == 0)
			return;
	}
	if (target->chars_left == 0)
		return;
	target->chars_left--;
	*count_r = uni_utf8_char_bytes(data[0]);
	i_assert(*count_r <= size);
	str_append_data(target->snippet, data, *count_r);
}


Fix NULL dereference in SSL_check_chain() for TLS 1.3

In the tls1_check_sig_alg() helper function, we loop through the list of
"signature_algorithms_cert" values received from the client and attempt
to look up each one in turn in our internal table that maps wire
codepoint to string-form name, digest and/or signature NID, etc., in
order to compare the signature scheme from the peer's list against what
is used to sign the certificates in the certificate chain we're
checking.  Unfortunately, when the peer sends a value that we don't
support, the lookup returns NULL, but we unconditionally dereference the
lookup result for the comparison, leading to an application crash
triggerable by an unauthenticated client.

Since we will not be able to say anything about algorithms we don't
recognize, treat NULL return from lookup as "does not match".

We currently only apply the "signature_algorithm_cert" checks on TLS 1.3
connections, so previous TLS versions are unaffected.  SSL_check_chain()
is not called directly from libssl, but may be used by the application
inside a callback (e.g., client_hello or cert callback) to verify that a
candidate certificate chain will be acceptable to the client.

CVE-2020-1967

Reviewed-by: Matt Caswell <matt@openssl.org>

static int tls1_check_sig_alg(SSL *s, X509 *x, int default_nid)
{
    int sig_nid, use_pc_sigalgs = 0;
    size_t i;
    const SIGALG_LOOKUP *sigalg;
    size_t sigalgslen;
    if (default_nid == -1)
        return 1;
    sig_nid = X509_get_signature_nid(x);
    if (default_nid)
        return sig_nid == default_nid ? 1 : 0;

    if (SSL_IS_TLS13(s) && s->s3.tmp.peer_cert_sigalgs != NULL) {
        /*
         * If we're in TLSv1.3 then we only get here if we're checking the
         * chain. If the peer has specified peer_cert_sigalgs then we use them
         * otherwise we default to normal sigalgs.
         */
        sigalgslen = s->s3.tmp.peer_cert_sigalgslen;
        use_pc_sigalgs = 1;
    } else {
        sigalgslen = s->shared_sigalgslen;
    }
    for (i = 0; i < sigalgslen; i++) {
        sigalg = use_pc_sigalgs
                 ? tls1_lookup_sigalg(s->s3.tmp.peer_cert_sigalgs[i])
                 : s->shared_sigalgs[i];
        if (sig_nid == sigalg->sigandhash)
            return 1;
    }
    return 0;
}

Server or client applications that call the SSL_check_chain() function during or after a TLS 1.3 handshake may crash due to a NULL pointer dereference as a result of incorrect handling of the "signature_algorithms_cert" TLS extension. The crash occurs if an invalid or unrecognised signature algorithm is received from the peer. This could be exploited by a malicious peer in a Denial of Service attack. OpenSSL version 1.1.1d, 1.1.1e, and 1.1.1f are affected by this issue. This issue did not affect OpenSSL versions prior to 1.1.1d. Fixed in OpenSSL 1.1.1g (Affected 1.1.1d-1.1.1f).


static int tls1_check_sig_alg(SSL *s, X509 *x, int default_nid)
{
    int sig_nid, use_pc_sigalgs = 0;
    size_t i;
    const SIGALG_LOOKUP *sigalg;
    size_t sigalgslen;
    if (default_nid == -1)
        return 1;
    sig_nid = X509_get_signature_nid(x);
    if (default_nid)
        return sig_nid == default_nid ? 1 : 0;

    if (SSL_IS_TLS13(s) && s->s3.tmp.peer_cert_sigalgs != NULL) {
        /*
         * If we're in TLSv1.3 then we only get here if we're checking the
         * chain. If the peer has specified peer_cert_sigalgs then we use them
         * otherwise we default to normal sigalgs.
         */
        sigalgslen = s->s3.tmp.peer_cert_sigalgslen;
        use_pc_sigalgs = 1;
    } else {
        sigalgslen = s->shared_sigalgslen;
    }
    for (i = 0; i < sigalgslen; i++) {
        sigalg = use_pc_sigalgs
                 ? tls1_lookup_sigalg(s->s3.tmp.peer_cert_sigalgs[i])
                 : s->shared_sigalgs[i];
        if (sigalg != NULL && sig_nid == sigalg->sigandhash)
            return 1;
    }
    return 0;
}