CVE-2020-13112 (C, published 2020-05-21T16:15Z)
Description: value: An issue was discovered in libexif before 0.6.22. Several buffer over-reads in EXIF MakerNote handling could lead to information disclosure and crashes. This is different from CVE-2020-0093.
Severity: MEDIUM (CVSS v3 base score: 9.1)
Weakness: CWE-125 \u2014 Out-of-bounds Read
The product reads data past the end, or before the beginning, of the intended buffer.
Repository: https://github.com/libexif/libexif
Files changed:
libexif/canon/exif-mnote-data-canon.c
libexif/fuji/exif-mnote-data-fuji.c
libexif/olympus/exif-mnote-data-olympus.c
libexif/pentax/exif-mnote-data-pentax.c
Commit message: Fix MakerNote tag size overflow issues at read time.

Check for a size overflow while reading tags, which ensures that the
size is always consistent for the given components and type of the
entry, making checking further down superfluous.

This provides an alternate fix for
https://sourceforge.net/p/libexif/bugs/125/ CVE-2016-6328 and for all
the MakerNote types. Likely, this makes both commits 41bd0423 and
89e5b1c1 redundant as it ensures that MakerNote entries are well-formed
when they're populated.

Some improvements on top by Marcus Meissner <marcus@jet.franken.de>

CVE-2020-13112


Vulnerable code:
	if ((datao + 2 < datao) || (datao + 2 < 2) || (datao + 2 > buf_size)) {
		if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) {
	        }
			if ((dataofs + s < s) || (dataofs + s < dataofs) || (dataofs + s > buf_size)) {
	if ((datao + 12 < datao) || (datao + 12 < 12) || (datao + 12 > buf_size)) {
	if ((datao + 2 < datao) || (datao + 2 < 2) ||
	    (datao + 2 > buf_size)) {
		if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) {
			if ((dataofs + s < dataofs) || (dataofs + s < s) ||
				(dataofs + s >= buf_size)) {
	if ((o2 + 10 < o2) || (o2 + 10 < 10) || (o2 + 10 > buf_size)) {
		if ((o2 + 4 < o2) || (o2 + 4 < 4) || (o2 + 4 > buf_size)) return;
		if ((o2 + 12 < o2) || (o2 + 12 < 12) || (o2 + 12 > buf_size)) return;
	if ((o2 + 2 < o2) || (o2 + 2 < 2) || (o2 + 2 > buf_size)) {
		if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) {
			    if (dataofs + s > buf_size && n->version == sanyoV1) {
			if ((dataofs + s < dataofs) || (dataofs + s < s) || 
			    (dataofs + s > buf_size)) {
	if ((datao + 8 < datao) || (datao + 8 < 8) || (datao + 8 > buf_size)) {
		if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) {
			if ((dataofs + s < dataofs) || (dataofs + s < s) ||
				(dataofs + s > buf_size)) {

Fixed code:
#define CHECKOVERFLOW(offset,datasize,structsize) (( offset >= datasize) || (structsize > datasize) || (offset > datasize - structsize ))

	if (CHECKOVERFLOW(datao, buf_size, 2)) {

		if (CHECKOVERFLOW(o,buf_size,12)) {
		}
		/* Check if we overflow the multiplication. Use buf_size as the max size for integer overflow detection,
		 * we will check the buffer sizes closer later. */
		if (	exif_format_get_size (n->entries[tcount].format) &&
			buf_size / exif_format_get_size (n->entries[tcount].format) < n->entries[tcount].components
		) {
			exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
				  "ExifMnoteCanon", "Tag size overflow detected (%u * %lu)", exif_format_get_size (n->entries[tcount].format), n->entries[tcount].components);
			continue;
		}


			if (CHECKOVERFLOW(dataofs, buf_size, s)) {
#define CHECKOVERFLOW(offset,datasize,structsize) (( offset >= datasize) || (structsize > datasize) || (offset > datasize - structsize ))

	if (CHECKOVERFLOW(datao, buf_size, 12)) {

	if (CHECKOVERFLOW(datao, buf_size, 2)) {

		if (CHECKOVERFLOW(o, buf_size, 12)) {
		/* Check if we overflow the multiplication. Use buf_size as the max size for integer overflow detection,
		 * we will check the buffer sizes closer later. */
		if (	exif_format_get_size (n->entries[tcount].format) &&
			buf_size / exif_format_get_size (n->entries[tcount].format) < n->entries[tcount].components
		) {
			exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
					  "ExifMnoteDataFuji", "Tag size overflow detected (%u * %lu)", exif_format_get_size (n->entries[tcount].format), n->entries[tcount].components);
			continue;
		}

			if (CHECKOVERFLOW(dataofs, buf_size, s)) {
#define CHECKOVERFLOW(offset,datasize,structsize) (( offset >= datasize) || (structsize > datasize) || (offset > datasize - structsize ))

	if (CHECKOVERFLOW(o2,buf_size,10)) {
		if (CHECKOVERFLOW(o2,buf_size,4)) return;
		if (CHECKOVERFLOW(o2,buf_size,12)) return;
	if (CHECKOVERFLOW(o2,buf_size,2)) {
		if (CHECKOVERFLOW(o, buf_size, 12)) {
	    /* Check if we overflow the multiplication. Use buf_size as the max size for integer overflow detection,
	     * we will check the buffer sizes closer later. */
	    if (exif_format_get_size (n->entries[tcount].format) &&
		buf_size / exif_format_get_size (n->entries[tcount].format) < n->entries[tcount].components
	    ) {
		exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteOlympus", "Tag size overflow detected (%u * %lu)", exif_format_get_size (n->entries[tcount].format), n->entries[tcount].components);
		continue;
	    }
			    if (dataofs > (buf_size - s) && n->version == sanyoV1) {
			if (CHECKOVERFLOW(dataofs, buf_size, s)) {
#define CHECKOVERFLOW(offset,datasize,structsize) (( offset >= datasize) || (structsize > datasize) || (offset > datasize - structsize ))

	if (CHECKOVERFLOW(datao, buf_size, 8)) {

		if (CHECKOVERFLOW(o,buf_size,12)) {
		/* Check if we overflow the multiplication. Use buf_size as the max size for integer overflow detection,
		 * we will check the buffer sizes closer later. */
		if (	exif_format_get_size (n->entries[tcount].format) &&
			buf_size / exif_format_get_size (n->entries[tcount].format) < n->entries[tcount].components
		) {
			exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
				  "ExifMnoteDataPentax", "Tag size overflow detected (%u * %lu)", exif_format_get_size (n->entries[tcount].format), n->entries[tcount].components);
			break;
		}

			if (CHECKOVERFLOW(dataofs, buf_size, s)) {