Description: Fixes a buffer overflow when reading bogus file headers The header parser was not checking if it had read enough data when trying to parse the header from memory, causing it to accept files with headers smaller than expected. . Fixes CVE-2015-2063. Author: Guillem Jover Origin: vendor Bug-Debian: https://bugs.debian.org/775003 Forwarded: no Last-Update: 2015-02-24 --- unace.c.orig 1998-07-01 08:29:00 UTC +++ unace.c @@ -111,6 +111,7 @@ INT read_header(INT print_err) { USHORT rd, head_size, + need_size, crc_ok; LONG crc; UCHAR *tp=readbuf; @@ -126,6 +127,9 @@ INT read_header(INT print_err) #endif // read size_headrdb bytes into head_size = head.HEAD_SIZE; // header structure + need_size = 3; + if (need_size > head.HEAD_SIZE) + return 0; rd = (head_size > size_headrdb) ? size_headrdb : head_size; if (read(archan, readbuf, rd) < rd) return 0; @@ -145,7 +149,12 @@ INT read_header(INT print_err) head.HEAD_FLAGS=BUFP2WORD(tp); if (head.HEAD_FLAGS & ACE_ADDSIZE) + { + need_size += 4; + if (need_size > head.HEAD_SIZE) + return 0; skipsize = head.ADDSIZE = BUF2LONG(tp); // get ADDSIZE + } else skipsize = 0; @@ -156,6 +165,9 @@ INT read_header(INT print_err) switch (head.HEAD_TYPE) // specific buffer to head conversion { case MAIN_BLK: + need_size += 24; + if (need_size > head.HEAD_SIZE) + return 0; memcpy(mhead.ACESIGN, tp, acesign_len); tp+=acesign_len; mhead.VER_MOD=*tp++; mhead.VER_CR =*tp++; @@ -166,9 +178,15 @@ INT read_header(INT print_err) mhead.RES2 =BUFP2WORD(tp); mhead.RES =BUFP2LONG(tp); mhead.AV_SIZE=*tp++; - memcpy(mhead.AV, tp, rd-(USHORT)(tp-readbuf)); + if (mhead.AV_SIZE > sizeof(mhead.AV) || + mhead.AV_SIZE + need_size > head.HEAD_SIZE) + return 0; + memcpy(mhead.AV, tp, mhead.AV_SIZE); break; case FILE_BLK: + need_size += 28; + if (need_size > head.HEAD_SIZE) + return 0; fhead.PSIZE =BUFP2LONG(tp); fhead.SIZE =BUFP2LONG(tp); fhead.FTIME =BUFP2LONG(tp); @@ -179,7 +197,10 @@ INT read_header(INT print_err) fhead.TECH.PARM =BUFP2WORD(tp); fhead.RESERVED =BUFP2WORD(tp); fhead.FNAME_SIZE=BUFP2WORD(tp); - memcpy(fhead.FNAME, tp, rd-(USHORT)(tp-readbuf)); + if (fhead.FNAME_SIZE > sizeof(fhead.FNAME) || + fhead.FNAME_SIZE + need_size > head.HEAD_SIZE) + return 0; + memcpy(fhead.FNAME, tp, fhead.FNAME_SIZE); break; // default: (REC_BLK and future things): // do nothing 'cause isn't needed for extraction