CVE-2014-9050 (C, published 2014-12-01T15:59Z)
Description: value: Heap-based buffer overflow in the cli_scanpe function in libclamav/pe.c in ClamAV before 0.98.5 allows remote attackers to cause a denial of service (crash) via a crafted y0da Crypter PE file.
Severity: MEDIUM (CVSS v3 base score: )
Weakness: CWE-119 \u2014 Improper Restriction of Operations within the Bounds of a Memory Buffer
The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
Repository: https://github.com/vrtadmin/clamav-devel
Files changed:
libclamav/pe.c
Commit message: Merge fix from security/bb11155 branch


Vulnerable code:
	unsigned int i, found, upx_success = 0, min = 0, max = 0, err, overlays = 0;
	uint32_t valign, falign, hdr_size, j;
	strncpy(sname, (char *) section_hdr[i].Name, 8);
	sname[8] = 0;
	exe_sections[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign);
	exe_sections[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign);
	exe_sections[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign);
	exe_sections[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign);
	exe_sections[i].chr = EC32(section_hdr[i].Characteristics);
	exe_sections[i].urva = EC32(section_hdr[i].VirtualAddress); /* Just in case */
	exe_sections[i].uvsz = EC32(section_hdr[i].VirtualSize);
	exe_sections[i].uraw = EC32(section_hdr[i].PointerToRawData);
	exe_sections[i].ursz = EC32(section_hdr[i].SizeOfRawData);
	    if (exe_sections[i].raw >= fsize) { /* really broken */
	      cli_dbgmsg("Broken PE file - Section %d starts beyond the end of file (Offset@ %lu, Total filesize %lu)\n", i, (unsigned long)exe_sections[i].raw, (unsigned long)fsize);
	      cli_dbgmsg("------------------------------------\n");
		free(section_hdr);
		free(exe_sections);
		if(DETECT_BROKEN_PE) {
		    cli_append_virus(ctx, "Heuristics.Broken.Executable");
		    return CL_VIRUS;
		}
		return CL_CLEAN; /* no ninjas to see here! move along! */
	    }


Fixed code:
	unsigned int i, j, found, upx_success = 0, min = 0, max = 0, err, overlays = 0, rescan = 1;
	uint32_t valign, falign, hdr_size;
    while (rescan==1) {
        rescan=0;
        for (i=0; i < nsections; i++) {
            exe_sections[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign);
            exe_sections[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign);
            exe_sections[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign);
            exe_sections[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign);
            exe_sections[i].chr = EC32(section_hdr[i].Characteristics);
            exe_sections[i].urva = EC32(section_hdr[i].VirtualAddress); /* Just in case */
            exe_sections[i].uvsz = EC32(section_hdr[i].VirtualSize);
            exe_sections[i].uraw = EC32(section_hdr[i].PointerToRawData);
            exe_sections[i].ursz = EC32(section_hdr[i].SizeOfRawData);

            if (exe_sections[i].rsz) { /* Don't bother with virtual only sections */
                if (!CLI_ISCONTAINED(0, fsize, exe_sections[i].uraw, exe_sections[i].ursz)
                    || exe_sections[i].raw >= fsize) {
                    cli_dbgmsg("Broken PE file - Section %d starts or exists beyond the end of file (Offset@ %lu, Total filesize %lu)\n", i, (unsigned long)exe_sections[i].raw, (unsigned long)fsize);
                    if (nsections == 1) {
                        free(section_hdr);
                        free(exe_sections);

                        if(DETECT_BROKEN_PE) {
                            cli_append_virus(ctx, "Heuristics.Broken.Executable");
                            return CL_VIRUS;
                        }

                        return CL_CLEAN; /* no ninjas to see here! move along! */
                    }

                    for (j=i; j < nsections-1; j++)
                        memcpy(&exe_sections[j], &exe_sections[j+1], sizeof(struct cli_exe_section));

                    for (j=i; j < nsections-1; j++)
                        memcpy(&section_hdr[j], &section_hdr[j+1], sizeof(struct pe_image_section_hdr));

                    nsections--;
                    rescan=1;
                    break;
                }
            }
        }
    }

        strncpy(sname, (char *) section_hdr[i].Name, 8);
        sname[8] = 0;