Commit message: Use asserts on lengths to prevent invalid reads/writes.
CVE: CVE-2017-6307
CWE: CWE-125
Vulnerability description: An issue was discovered in tnef before 1.4.13. Two OOB Writes have been identified in src/mapi_attr.c:mapi_attr_read(). These might lead to invalid read and write operations, controlled by an attacker.

Project: tnef

alloc_mapi_values (MAPI_Attr* a)
{
    if (a && a->num_values)
    {
	a->values = CHECKED_XCALLOC (MAPI_Value, a->num_values);
	return a->values;
    }
    return NULL;
}

Project: tnef

copy_guid_from_buf (GUID* guid, unsigned char *buf, size_t len)
{
    int i;
    int idx = 0;
    assert (guid);
    assert (buf);

    CHECKINT32(idx, len); guid->data1 = GETINT32(buf + idx); idx += sizeof (uint32);
    CHECKINT16(idx, len); guid->data2 = GETINT16(buf + idx); idx += sizeof (uint16);
    CHECKINT16(idx, len); guid->data3 = GETINT16(buf + idx); idx += sizeof (uint16);
    for (i = 0; i < 8; i++, idx += sizeof (uint8))
	guid->data4[i] = (uint8)(buf[idx]);
}

Project: tnef

mapi_attr_dump (MAPI_Attr* attr)
{
    char *name = get_mapi_name_str (attr->name);
    char *type = get_mapi_type_str (attr->type);
    size_t i;

    fprintf (stdout, "(MAPI) %s [type: %s] [num_values = %lu] = \n",
	     name, type, (unsigned long)attr->num_values);
    if (attr->guid)
    {
	fprintf (stdout, "\tGUID: ");
	write_guid (stdout, attr->guid);
	fputc ('\n', stdout);
    }
	
    for (i = 0; i < attr->num_names; i++)
      fprintf (stdout, "\tname #%d: '%s'\n", (int)i, attr->names[i].data);

    for (i = 0; i < attr->num_values; i++)
    {
	fprintf (stdout, "\t#%lu [len: %lu] = ",
		 (unsigned long)i,
		 (unsigned long)attr->values[i].len);

	switch (attr->type)
	{
	case szMAPI_NULL:
	    fprintf (stdout, "NULL");
	    break;

	case szMAPI_SHORT:
	    write_int16 (stdout, (int16)attr->values[i].data.bytes2);
	    break;

	case szMAPI_INT:
	    write_int32 (stdout, (int32)attr->values[i].data.bytes4);
	    break;

	case szMAPI_FLOAT:
	case szMAPI_DOUBLE:
	    write_float (stdout, (float)attr->values[i].data.bytes4);
	    break;

	case szMAPI_BOOLEAN:
	    write_boolean (stdout, attr->values[i].data.bytes4);
	    break;

	case szMAPI_STRING:
	case szMAPI_UNICODE_STRING:
	    write_string (stdout, (char*)attr->values[i].data.buf);
	    break;

	case szMAPI_SYSTIME:
	case szMAPI_CURRENCY:
	case szMAPI_INT8BYTE:
	case szMAPI_APPTIME:
	    write_uint64 (stdout, attr->values[i].data.bytes8);
	    break;

	case szMAPI_ERROR:
	    write_uint32 (stdout, attr->values[i].data.bytes4);
	    break;

	case szMAPI_CLSID:
	    write_guid (stdout, &attr->values[i].data.guid);
	    break;

	case szMAPI_OBJECT:
	case szMAPI_BINARY:
	{
	    size_t x;

	    for (x = 0; x < attr->values[i].len; x++)
	    {
		write_byte (stdout, (uint8)attr->values[i].data.buf[x]);
		fputc (' ', stdout);
	    }
	}
	break;

	default:
	    fprintf (stdout, "<unknown type>");
	    break;
	}
	fprintf (stdout, "\n");
    }

    fflush( NULL );
}

Project: tnef

mapi_attr_free (MAPI_Attr* attr)
{
    if (attr)
    {
	size_t i;
	for (i = 0; i < attr->num_values; i++)
	{
	    if ((attr->type == szMAPI_STRING)
		|| (attr->type == szMAPI_UNICODE_STRING)
		|| (attr->type == szMAPI_BINARY))
	    {
		XFREE (attr->values[i].data.buf);
	    }
	}
        if (attr->num_names > 0) {
            for (i = 0; i < attr->num_names; i++)
            {
                XFREE(attr->names[i].data);
            }
            XFREE(attr->names);
        }
	XFREE (attr->values);
	XFREE (attr->guid);
	memset (attr, '\0', sizeof (MAPI_Attr));
    }
}

Project: tnef

mapi_attr_free_list (MAPI_Attr** attrs)
{
    int i;
    for (i = 0; attrs && attrs[i]; i++)
    {
	mapi_attr_free (attrs[i]);
	XFREE (attrs[i]);
    }
}