c04a82
From 69d1b3fc29677af8ade8dc15dba83f0589cb63d6 Mon Sep 17 00:00:00 2001
c04a82
From: Lasse Collin <lasse.collin@tukaani.org>
c04a82
Date: Tue, 29 Mar 2022 19:19:12 +0300
c04a82
Subject: [PATCH] xzgrep: Fix escaping of malicious filenames (ZDI-CAN-16587).
c04a82
c04a82
Malicious filenames can make xzgrep to write to arbitrary files
c04a82
or (with a GNU sed extension) lead to arbitrary code execution.
c04a82
c04a82
xzgrep from XZ Utils versions up to and including 5.2.5 are
c04a82
affected. 5.3.1alpha and 5.3.2alpha are affected as well.
c04a82
This patch works for all of them.
c04a82
c04a82
This bug was inherited from gzip's zgrep. gzip 1.12 includes
c04a82
a fix for zgrep.
c04a82
c04a82
The issue with the old sed script is that with multiple newlines,
c04a82
the N-command will read the second line of input, then the
c04a82
s-commands will be skipped because it's not the end of the
c04a82
file yet, then a new sed cycle starts and the pattern space
c04a82
is printed and emptied. So only the last line or two get escaped.
c04a82
c04a82
One way to fix this would be to read all lines into the pattern
c04a82
space first. However, the included fix is even simpler: All lines
c04a82
except the last line get a backslash appended at the end. To ensure
c04a82
that shell command substitution doesn't eat a possible trailing
c04a82
newline, a colon is appended to the filename before escaping.
c04a82
The colon is later used to separate the filename from the grep
c04a82
output so it is fine to add it here instead of a few lines later.
c04a82
c04a82
The old code also wasn't POSIX compliant as it used \n in the
c04a82
replacement section of the s-command. Using \<newline> is the
c04a82
POSIX compatible method.
c04a82
c04a82
LC_ALL=C was added to the two critical sed commands. POSIX sed
c04a82
manual recommends it when using sed to manipulate pathnames
c04a82
because in other locales invalid multibyte sequences might
c04a82
cause issues with some sed implementations. In case of GNU sed,
c04a82
these particular sed scripts wouldn't have such problems but some
c04a82
other scripts could have, see:
c04a82
c04a82
    info '(sed)Locale Considerations'
c04a82
c04a82
This vulnerability was discovered by:
c04a82
cleemy desu wayo working with Trend Micro Zero Day Initiative
c04a82
c04a82
Thanks to Jim Meyering and Paul Eggert discussing the different
c04a82
ways to fix this and for coordinating the patch release schedule
c04a82
with gzip.
c04a82
---
c04a82
 src/scripts/xzgrep.in | 20 ++++++++++++--------
c04a82
 1 file changed, 12 insertions(+), 8 deletions(-)
c04a82
c04a82
diff --git a/src/scripts/xzgrep.in b/src/scripts/xzgrep.in
c04a82
index b180936..e5186ba 100644
c04a82
--- a/src/scripts/xzgrep.in
c04a82
+++ b/src/scripts/xzgrep.in
c04a82
@@ -180,22 +180,26 @@ for i; do
c04a82
          { test $# -eq 1 || test $no_filename -eq 1; }; then
c04a82
       eval "$grep"
c04a82
     else
c04a82
+      # Append a colon so that the last character will never be a newline
c04a82
+      # which would otherwise get lost in shell command substitution.
c04a82
+      i="$i:"
c04a82
+
c04a82
+      # Escape & \ | and newlines only if such characters are present
c04a82
+      # (speed optimization).
c04a82
       case $i in
c04a82
       (*'
c04a82
 '* | *'&'* | *'\'* | *'|'*)
c04a82
-        i=$(printf '%s\n' "$i" |
c04a82
-            sed '
c04a82
-              $!N
c04a82
-              $s/[&\|]/\\&/g
c04a82
-              $s/\n/\\n/g
c04a82
-            ');;
c04a82
+        i=$(printf '%s\n' "$i" | LC_ALL=C sed 's/[&\|]/\\&/;; $!s/$/\\/');;
c04a82
       esac
c04a82
-      sed_script="s|^|$i:|"
c04a82
+
c04a82
+      # $i already ends with a colon so don't add it here.
c04a82
+      sed_script="s|^|$i|"
c04a82
 
c04a82
       # Fail if grep or sed fails.
c04a82
       r=$(
c04a82
         exec 4>&1
c04a82
-        (eval "$grep" 4>&-; echo $? >&4) 3>&- | sed "$sed_script" >&3 4>&-
c04a82
+        (eval "$grep" 4>&-; echo $? >&4) 3>&- |
c04a82
+            LC_ALL=C sed "$sed_script" >&3 4>&-
c04a82
       ) || r=2
c04a82
       exit $r
c04a82
     fi >&3 5>&-
c04a82
-- 
c04a82
2.35.1
c04a82