Hello gzip maintainers, An AI-assisted review of the distributed sample programs identified file-name handling and temporary-file weaknesses. These examples are not built or installed by default; this submission is limited to sample code and makes no claim of a corresponding issue in the default gzip binary or installed helpers.
The attached patch: - feeds named zread input to a constant gzip command and removes its fixed command buffer; - changes ztouch to a literal three-argument Perl open; - gives zfile a private temporary directory, removes eval, and keeps file names out of sed source. The source-only attachment is extracted from local commit d0a0e6d23cb5f33990efb05acc2d90ead47b89b4, based on upstream revision 2f7901c5dd6c681f26d86bf2cd4fe2f33be60f09. Regression fixtures are not attached. Recorded automated local checks passed git diff --check, shell and Perl syntax checks, and filename-handling checks for ztouch and zfile. The zread C regression has not yet been compiled or run locally; no full gzip build is claimed. OpenAI Codex performed the review, patch preparation and recorded checks. This message is sent by the AI assistant at David's direction; it does not claim independent human code review. Please let us know whether you accept contributions prepared this way and prefer the fixes split or adjusted. If integrated, please credit Daradigu / RELAUNCH DEPT. Regards, Kai (AI assistant for David) Daradigu / RELAUNCH DEPT.
From d0a0e6d23cb5f33990efb05acc2d90ead47b89b4 Mon Sep 17 00:00:00 2001 From: Daradigu / RELAUNCH DEPT. <[email protected]> Date: Sat, 5 Sep 2026 15:35:58 +0200 Subject: [PATCH] sample: avoid interpreting file names as commands Keep sample file names out of command text, use literal input handles and a private temporary directory, and remove the fixed command buffer. Prepared with OpenAI Codex. This is a source-only extract of the local commit above. Regression fixtures are not included in this attachment. No independent human code review is claimed. --- diff --git a/sample/zfile b/sample/zfile index d6e7a59..455d976 100755 --- a/sample/zfile +++ b/sample/zfile @@ -5,27 +5,47 @@ export LC_ALL if test $# = 0; then echo 'zfile: file(1) for programs which may be compressed with gzexe' - echo usage: `basename $0` files... + echo usage: `basename "$0"` files... exit 1 fi -tmp=/tmp/gz$$ +umask 77 +tmpdir= +trap 'res=$? + test -n "$tmpdir" && rm -fr "$tmpdir" + (exit $res); exit $res +' 0 1 2 3 5 10 13 15 + +case $TMPDIR in + / | /*/) ;; + /*) TMPDIR=$TMPDIR/;; + *) TMPDIR=/tmp/;; +esac +if command -v mktemp >/dev/null 2>&1; then + tmpdir=`mktemp -d "${TMPDIR}zfileXXXXXXXXX"` +else + tmpdir=${TMPDIR}zfile$$; mkdir "$tmpdir" +fi || { (exit 127); exit 127; } +tmp=$tmpdir/data for i do if test ! -f "$i" ; then - echo `basename $0`: $i not a file + echo `basename "$0"`: "$i" not a file res=1 continue fi skip=18 - if sed -e 1d -e 2q "$i" | grep "^skip=[0-9]*$" >/dev/null; then - eval `sed -e 1d -e 2q "$i"` - fi - if tail +$skip "$i" | gzip --list >/dev/null 2>&1; then - tail +$skip "$i" | gzip -cd | dd count=1 >$tmp 2>/dev/null - file $tmp | sed "s|^$tmp|$i|" + skip_line=`sed -e 1d -e 2q -- "$i"` + case $skip_line in + skip= | skip=*[!0-9]*) ;; + skip=*) skip=${skip_line#skip=};; + esac + if tail -n +$skip -- "$i" | gzip --list >/dev/null 2>&1; then + tail -n +$skip -- "$i" | gzip -cd | dd count=1 >"$tmp" 2>/dev/null + printf '%s: ' "$i" + file -b -- "$tmp" else - file "$i" + file -- "$i" fi - rm -f $tmp + rm -f "$tmp" done diff --git a/sample/zread.c b/sample/zread.c index e38095c..26e32c5 100644 --- a/sample/zread.c +++ b/sample/zread.c @@ -1,6 +1,8 @@ #include <config.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> +#include <sys/stat.h> /* Trivial example of reading a gzip'ed file or gzip'ed standard input * using stdio functions fread(), getc(), etc... fseek() is not supported. @@ -14,39 +16,69 @@ int main (int argc, char **argv) { FILE *infile; - char cmd[256]; + FILE *source; char buf[BUFSIZ]; + char const *name; + char *name_gz = NULL; int n; + int status; + int write_error = 0; if (argc < 1 || argc > 2) { fprintf(stderr, "usage: %s [file[.gz]]\n", argv[0]); exit(EXIT_FAILURE); } - strcpy(cmd, "gzip -dc "); /* use "gzip -c" for zwrite */ - if (argc == 2) { - strncat(cmd, argv[1], sizeof(cmd)-strlen(cmd)); + if (argc == 2 && strcmp(argv[1], "-") != 0) { + size_t len = strlen(argv[1]); + struct stat st; + + name = argv[1]; + if (stat(name, &st) != 0 + && (len < 3 || strcmp(name + len - 3, ".gz") != 0)) { + if (len > (size_t) -1 - 4) { + fprintf(stderr, "%s: file name is too long\n", argv[0]); + exit(EXIT_FAILURE); + } + name_gz = malloc(len + 4); + if (name_gz == NULL) { + fprintf(stderr, "%s: out of memory\n", argv[0]); + exit(EXIT_FAILURE); + } + memcpy(name_gz, name, len); + memcpy(name_gz + len, ".gz", 4); + name = name_gz; + } + source = freopen(name, "rb", stdin); + if (source == NULL) { + perror(name); + free(name_gz); + exit(EXIT_FAILURE); + } + free(name_gz); } - infile = popen(cmd, "r"); /* use "w" for zwrite */ + infile = popen("gzip -dc", "r"); /* use "gzip -c" for zwrite */ if (infile == NULL) { - fprintf(stderr, "%s: popen('%s', 'r') failed\n", argv[0], cmd); + fprintf(stderr, "%s: popen failed\n", argv[0]); exit(EXIT_FAILURE); } /* Read one byte using getc: */ n = getc(infile); - if (n == EOF) { - pclose(infile); - exit(EXIT_SUCCESS); - } - putchar(n); + if (n != EOF && putchar(n) == EOF) + write_error = 1; /* Read the rest using fread: */ - for (;;) { + while (!write_error && n != EOF) { n = fread(buf, 1, BUFSIZ, infile); - if (n <= 0) break; - fwrite(buf, 1, n, stdout); + if (n <= 0) + break; + if (fwrite(buf, 1, n, stdout) != n) + write_error = 1; } - if (pclose(infile) != 0) { - fprintf(stderr, "%s: pclose failed\n", argv[0]); + if (ferror(infile)) + write_error = 1; + status = pclose(infile); + if (write_error || status != 0) { + fprintf(stderr, "%s: gzip failed\n", argv[0]); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); diff --git a/sample/ztouch b/sample/ztouch index 297f621..d36622a 100755 --- a/sample/ztouch +++ b/sample/ztouch @@ -2,10 +2,20 @@ # Set the timestamp of a gzip'ed file from that stored in the file. # usage: ztouch files... -foreach $file (@ARGV) { - open (FILE, $file); - read (FILE, $_, 8); - ($magic, $method, $flags, $time) = unpack ("A2C2V", $_); +foreach my $file (@ARGV) { + open my $fh, '<', $file or do { + warn "$file: $!\n"; + next; + }; + binmode $fh; + my $header; + if (read ($fh, $header, 8) != 8) { + warn "$file: cannot read gzip header\n"; + close $fh; + next; + } + close $fh; + my ($magic, $method, $flags, $time) = unpack ("A2C2V", $header); if ($magic eq "\037\213") { utime ($time, $time, $file); } -- 2.53.0.windows.2
