Package: tiger
Version: 1:3.2.4~rc1-3.5
Severity: grave
Tags: security patch
X-Debbugs-Cc: [email protected]

scripts/find_files runs find on each mount point it scans through eval:

eval nice -5 $FIND "$mountpt" $findpruneopt $findopt -print 2>/dev/null

The double quotes go in the first expansion, so eval parses the mount
point's path as shell code. The mount points come from gen_mounts, which
keeps those whose type it counts as local, fuse.encfs and fuse.lxcfs among
them. fusermount3 is setuid root and lets any user mount a FUSE file system
on a directory they own, setting the reported type with -o subtype=, so any
local user can make a "local" mount point whose name holds a command
substitution. find_files runs that command as root the next time it runs:
with the package's cronrc, at 02:00 on the 1st of every month, from the
hourly tigercron job in /etc/cron.d/tiger. The precondition is fuse3 (or
fuse) being installed.

The line is the same in 1:3.2.4~rc1-3.2 (bookworm), -3.4 (trixie) and -3.5
(sid and forky), and in upstream TIGER 3.2.4.

Verified in a privileged debian:sid container with 1:3.2.4~rc1-3.5 and
Tiger_FSScan_WDIR=Y: with a tmpfs mounted on a directory whose name held a
command substitution, find_files ran the command as root. With the attached
patch it did not, and both that mount and one on a directory named with an
apostrophe, which the eval had silently skipped, were scanned. On Ubuntu
24.04 I confirmed in October that an unprivileged user can make such a
mount with fusermount3 -o subtype=encfs, and that mount prints its name
unchanged.

The patch (DEP-3, against 1:3.2.4~rc1-3.5; it applies unchanged to -3.2 and
-3.4) passes the mount points to find as positional parameters, so eval
sees only '$FIND "$mountpt"'. The find options, which come from tiger's own
configuration, still go through eval. It applies with or without the
reworked patch for #610785, in either order.

I reported this privately to [email protected] on 11 October and
followed up on 22 October, saying I would file it here on 29 October unless
asked to wait; there was no reply. Tigris, the fork of TIGER I maintain,
fixed it in 3.9.0, and its advisory is public as GHSA-p8g6-qw5j-8cgc, in
the creativeheadz/tigris repository on GitHub. A CVE was requested through
GitHub for that advisory and has not been assigned yet.

The same report named two lower-impact problems, which need a non-default
setting or an administrator's mistake: with Tiger_Check_PATHALL=Y (the
default is N), check_path sources assignments it extracts from every user's
.profile and .cshrc as root, and config reads ./tigerrc, ./.tigerrc and
./site from the directory tiger is started in, checking only that they are
not group or world writable, not who owns them. I can file those separately.

Andrei Trimbitas
Description: find_files: give find the mount points as arguments, not to eval
 find_files ran find on each mount point with
 eval nice -5 $FIND "$mountpt" $findpruneopt $findopt -print
 The double quotes go in the first expansion, so eval parsed the mount
 point's path as shell code. gen_mounts keeps the mount points whose type
 it counts as local, fuse.encfs and fuse.lxcfs among them, and fusermount3
 lets any user mount a FUSE file system on a directory they own with the
 type they choose (-o subtype=encfs). A command substitution in that
 directory's name ran as root the next time find_files ran: at 02:00 on
 the 1st of the month with the package's cronrc.
 .
 The mount points are now positional parameters, and eval sees only
 '$FIND "$mountpt"', which it expands without parsing the value. The
 find options, which come from tiger's own configuration, still go
 through eval.
Author: Andrei Trimbitas <[email protected]>
Forwarded: no
Last-Update: 2026-10-29
---
diff --git a/scripts/find_files b/scripts/find_files
index a07707f..f6e5a96 100755
--- a/scripts/find_files
+++ b/scripts/find_files
@@ -304,12 +304,18 @@ rw=rw
       otherfile="${outfile}.other.$counter"	
 
 #     echo "$FIND x $findpruneopt $findopt -print" 1>&2
-      for mountpt in $disklist
+      # The mount points are data: whoever mounted a filesystem named its
+      # mount point (any user can, with FUSE), so they reach find as
+      # arguments, never as text for eval to parse.
+      set -f
+      set -- $disklist
+      set +f
+      for mountpt
       do
         # Not sure why we're cd'ing to /, but it breaks all relative paths
 	#     being used in the find options.  Commented out --mlk
         #     cd /
-	eval nice -5 $FIND "$mountpt" $findpruneopt $findopt -print 2>/dev/null
+	eval nice -5 '$FIND "$mountpt"' $findpruneopt $findopt -print 2>/dev/null
       done | nice -6 $output 2>&1 | 
         sed -e '/No such file/s/^.*:[[:space:]]\(.*\):[[:space:]].*$/\1/' |
         while  read symlink ; do 

Reply via email to