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

Reply via email to