Thu Mar 26 22:29:47 2020 UTC ()
archivers/unzoo: fix out-of-bounds read when matching non-ASCII

Found by GCC's -Wchar-subscripts.


(rillig)
diff -r1.14 -r1.15 pkgsrc/archivers/unzoo/Makefile
diff -r1.3 -r1.4 pkgsrc/archivers/unzoo/distinfo
diff -r0 -r1.1 pkgsrc/archivers/unzoo/patches/patch-unzoo.c

cvs diff -r1.14 -r1.15 pkgsrc/archivers/unzoo/Makefile (expand / switch to unified diff)

--- pkgsrc/archivers/unzoo/Makefile 2014/10/09 14:05:54 1.14
+++ pkgsrc/archivers/unzoo/Makefile 2020/03/26 22:29:47 1.15
@@ -1,18 +1,19 @@ @@ -1,18 +1,19 @@
1# $NetBSD: Makefile,v 1.14 2014/10/09 14:05:54 wiz Exp $ 1# $NetBSD: Makefile,v 1.15 2020/03/26 22:29:47 rillig Exp $
2# 2#
3 3
4DISTNAME= unzoo.c 4DISTNAME= unzoo.c
5PKGNAME= unzoo-4.4 5PKGNAME= unzoo-4.4
 6PKGREVISION= 1
6CATEGORIES= archivers 7CATEGORIES= archivers
7MASTER_SITES= # no dist site available 8MASTER_SITES= # no dist site available
8EXTRACT_SUFX= # empty 9EXTRACT_SUFX= # empty
9 10
10MAINTAINER= pkgsrc-users@NetBSD.org 11MAINTAINER= pkgsrc-users@NetBSD.org
11COMMENT= Extract zoo archives 12COMMENT= Extract zoo archives
12 13
13WRKSRC= ${WRKDIR} 14WRKSRC= ${WRKDIR}
14NO_CONFIGURE= YES 15NO_CONFIGURE= YES
15 16
16INSTALLATION_DIRS= bin 17INSTALLATION_DIRS= bin
17 18
18do-extract: 19do-extract:

cvs diff -r1.3 -r1.4 pkgsrc/archivers/unzoo/distinfo (expand / switch to unified diff)

--- pkgsrc/archivers/unzoo/distinfo 2015/11/03 00:56:26 1.3
+++ pkgsrc/archivers/unzoo/distinfo 2020/03/26 22:29:47 1.4
@@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
1$NetBSD: distinfo,v 1.3 2015/11/03 00:56:26 agc Exp $ 1$NetBSD: distinfo,v 1.4 2020/03/26 22:29:47 rillig Exp $
2 2
3SHA1 (unzoo.c) = 99a6e9922ccdf5d454c78d3a514d5e33ae17562d 3SHA1 (unzoo.c) = 99a6e9922ccdf5d454c78d3a514d5e33ae17562d
4RMD160 (unzoo.c) = f7cf751dc865e73d3c51e4476dd2472e409b20ff 4RMD160 (unzoo.c) = f7cf751dc865e73d3c51e4476dd2472e409b20ff
5SHA512 (unzoo.c) = d293e244e44af131702550ddefdd035e32de3e7228f6c1c805139d448ba96357931405d313405572c30fc7c8d2ff005cc0ffc4d0ad209f47ee9ec1217ccaed21 5SHA512 (unzoo.c) = d293e244e44af131702550ddefdd035e32de3e7228f6c1c805139d448ba96357931405d313405572c30fc7c8d2ff005cc0ffc4d0ad209f47ee9ec1217ccaed21
6Size (unzoo.c) = 115328 bytes 6Size (unzoo.c) = 115328 bytes
 7SHA1 (patch-unzoo.c) = 5b652586c919a8a5a5498c00ae2330620af39ea4

File Added: pkgsrc/archivers/unzoo/patches/patch-unzoo.c
$NetBSD: patch-unzoo.c,v 1.1 2020/03/26 22:29:47 rillig Exp $

unzoo.c: In function 'IsMatchName':
unzoo.c:1268:40: error: array subscript has type 'char' [-Werror=char-subscripts]
         else if ( *pat=='?' && ! IsSpec[*str] ) { pat++;       str++;       }
                                        ^
unzoo.c:1271:40: error: array subscript has type 'char' [-Werror=char-subscripts]
         else if ( tmp != 0  && ! IsSpec[*tmp] ) { pat =   pos; str = ++tmp; }
                                        ^

This looks indeed like undefined behavior since the function IsMatchName
accepts arbitrary filenames, and filenames containing non-ASCII
characters would access the array outside of its bounds.

On NetBSD-8.0-x86_64 using GCC 5.5.0 the memory below IsSpec is BufArch,
which means that pattern matching depended on the contents of the archive
before.

--- unzoo.c.orig	2020-03-26 22:01:16.074248902 +0000
+++ unzoo.c
@@ -244,6 +244,7 @@
 *H
 */
 #include        <stdio.h>
+#include	<string.h>
 
 
 /****************************************************************************
@@ -1265,10 +1266,10 @@ int             IsMatchName ( pat, str )
     /* try to match the name part                                          */
     while ( *pat != '\0' || *str != '\0' ) {
         if      ( *pat==*str                  ) { pat++;       str++;       }
-        else if ( *pat=='?' && ! IsSpec[*str] ) { pat++;       str++;       }
+        else if ( *pat=='?' && ! IsSpec[(unsigned char) *str] ) { pat++;       str++;       }
         else if ( *pat=='?' && *str != '\0'   ) { pat++;       str++;       }
         else if ( *pat=='*'                   ) { pos = ++pat; tmp =   str; }
-        else if ( tmp != 0  && ! IsSpec[*tmp] ) { pat =   pos; str = ++tmp; }
+        else if ( tmp != 0  && ! IsSpec[(unsigned char) *tmp] ) { pat =   pos; str = ++tmp; }
         else                                    break;
     }
     return *pat == '\0' && *str == '\0';