$OpenBSD: patch-unace_c,v 1.3 2015/04/03 11:26:27 naddy Exp $

read_header: CVE-2015-2063

--- unace.c.orig	Wed Jul  1 10:29:00 1998
+++ unace.c	Fri Apr  3 13:20:59 2015
@@ -111,6 +111,7 @@ INT  read_header(INT print_err)         // reads any h
 {
    USHORT rd,
         head_size,
+        need_size,
         crc_ok;
    LONG crc;
    UCHAR *tp=readbuf;
@@ -120,12 +121,15 @@ INT  read_header(INT print_err)         // reads any h
    if (read(archan, &head, 4)<4)
       return 0;                         // read CRC and header size
 
-#ifdef HI_LO_BYTE_ORDER
+#if BYTE_ORDER == BIG_ENDIAN
    WORDswap(&head.HEAD_CRC);
    WORDswap(&head.HEAD_SIZE);
 #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)         // reads any h
    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)         // reads any h
    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)         // reads any h
          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)         // reads any h
          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
@@ -240,6 +261,7 @@ INT read_arc_head(void)         // searches for the ar
 INT  open_archive(INT print_err)        // opens archive (or volume)
 {
    CHAR av_str[80];
+   unsigned int copylen;
 
    archan = open(aname, O_RDONLY | O_BINARY);   // open file
 
@@ -263,8 +285,11 @@ INT  open_archive(INT print_err)        // opens archi
       sprintf(av_str, "\ncreated on %d.%d.%d by ",
               ts_day(adat.time_cr), ts_month(adat.time_cr), ts_year(adat.time_cr));
       printf(av_str);
-      strncpy(av_str, mhead.AV, mhead.AV_SIZE);
-      av_str[mhead.AV_SIZE] = 0;
+      copylen = mhead.AV_SIZE;
+      if (copylen > 79)
+        copylen = 79;
+      strncpy(av_str, mhead.AV, copylen);
+      av_str[copylen] = 0;
       printf("%s\n\n", av_str);
    }
    comment_out("Main comment:");        // print main comment
@@ -300,7 +325,7 @@ void get_next_volname(void)             // get file na
 INT  proc_vol(void)                     // opens volume
 {
    INT  i;
-   CHAR s[80];
+   CHAR s[PATH_MAX + 80];
 
    // if f_allvol_pr is 2 we have -y and should never ask
    if ((!fileexists_insense(aname) && f_allvol_pr != 2) || !f_allvol_pr)
@@ -428,7 +453,7 @@ void extract_files(int nopath, int test)
       if (head.HEAD_TYPE == FILE_BLK)
       {
          comment_out("File comment:");   // show file comment
-         ace_fname(file, &head, nopath); // get file name
+         ace_fname(file, &head, nopath, sizeof(file)); // get file name
          printf("\n%s", file);
          flush;
          dcpr_init_file();               // initialize decompression of file
@@ -496,7 +521,7 @@ void list_files(int verbose)
       if (head.HEAD_TYPE == FILE_BLK)
       {
          ULONG ti=fhead.FTIME;
-         ace_fname(file, &head, verbose ? 0 : 1); // get file name
+         ace_fname(file, &head, verbose ? 0 : 1, sizeof(file)); // get file name
 
          size  += fhead.SIZE;
          psize +=
@@ -588,7 +613,8 @@ int main(INT argc, CHAR * argv[])              // proc
 
       init_unace();                              // initialize unace
 
-      strcpy(aname, argv[arg_cnt]);              // get archive name
+      strncpy(aname, argv[arg_cnt], sizeof(aname) - 4);  // get archive name
+      aname[sizeof(aname) - 5] = '\0';
       if (!(s = (CHAR *) strrchr(aname, DIRSEP)))
          s = aname;
       if (!strrchr(s, '.'))
