https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=297394
--- Comment #18 from Jeremy Chadwick <[email protected]> ---
(In reply to Benjamin Jacobs from comment #17)
Contents are below, including full deep dive. But again, /root/.shrc and
/root/.profile are whatever FreeBSD 15.1 put in place. No modifications.
These files have never been modified by me and 15.1 upgrade overwrote them
anyway. It takes a few minutes to launch an EC2 or GCP VM running 15.1 to
reproduce this problem, and that doesn't need to involve me.
$ cat /root/.shrc
#
# .shrc - bourne shell startup file
#
# This file will be used if the shell is invoked for interactive use and
# the environment variable ENV is set to this file.
#
# see also sh(1), environ(7).
#
# file permissions: rwxr-xr-x
#
# umask 022
# Uncomment this to enable the builtin vi(1) command line editor in sh(1),
# e.g. ESC to go into visual mode.
# set -o vi
# # some useful aliases
# alias h='fc -l'
# alias j=jobs
# alias m="$PAGER"
# alias ll='ls -laFo'
# alias l='ls -l'
# alias g='egrep -i'
# # be paranoid
# alias cp='cp -ip'
# alias mv='mv -i'
# alias rm='rm -i'
# # csh like history on arrow up and down
bind ^[[A ed-search-prev-history
bind ^[[B ed-search-next-history
# # Ctrl+right arrow: go to the next word
# # Ctrl+left arrow: go to the previous word
bind "\\e[1;5C" em-next-word
bind "\\e[1;5D" ed-prev-word
alias history='fc -l'
# Fix home/del for mobaxterm
bind ^[[5~ ed-move-to-beg
bind ^[[6~ ed-move-to-end
# read(2) of directories may not be desirable by default, as this will provoke
# EISDIR errors from each directory encountered.
# alias grep='grep -d skip'
# set prompt: ``username@hostname:directory $ ''
PS1="\u@\h:\w \\$ "
# search path for cd(1)
# CDPATH=:$HOME
Next: Linux distros do not all use bash for /bin/sh. If you think that, you
need to use more Linux :-) Debian/Ubuntu for example use dash, which is
identical to FreeBSD sh, as their /bin/sh. dash also honours $ENV in whatever
way it does (man page is the same!). But this problem does not happen on those
distros, because they do not set $ENV anywhere. Only FreeBSD does this. I
cover Linux later on though, where their stuff works fine for multiple reasons
(albeit poor Linux mindsets/habits, sigh).
Next: please read the below slowly, as in this PR I've already seen people
"gloss over" info because I'm verbose. If you aren't familiar with \command
then I'm doing it here to ensure there are no aliases/etc. used, just to rule
out someone barking up *that* tree.
$ sudo chsh -s /bin/sh
chsh: user information updated
$ \sudo su -
root@mambo:~ # rm -f junk
root@mambo:~ # truss -e -f -o junk sa-compile
Can't exec "re2c": No such file or directory at /usr/local/bin/sa-compile line
114.
root@mambo:~ # egrep 're2c|env' junk
43742: read(4," environment variable will be se"...,8192) = 8192 (0x2000)
43743: execve("/bin/re2c",0x25868f2b7ee0,[ "PAGER=less", "LANG=C.UTF-8",
"MAIL=/var/mail/root", "PATH=/bin:/usr/bin", "PWD=/root", "TERM=xterm",
"USER=root", "HOME=/root", "SHELL=/bin/sh", "MM_CHARSET=UTF-8", "BLOCKSIZE=K"
]) ERR#2 'No such file or directory'
43743: execve("/usr/bin/re2c",0x25868f2b7ee0,[ "PAGER=less", "LANG=C.UTF-8",
"MAIL=/var/mail/root", "PATH=/bin:/usr/bin", "PWD=/root", "TERM=xterm",
"USER=root", "HOME=/root", "SHELL=/bin/sh", "MM_CHARSET=UTF-8", "BLOCKSIZE=K"
]) ERR#2 'No such file or directory'
43743: write(2,"Can't exec "re2c": No such file "...,84) = 84 (0x54)
Look closely at what $PATH is in execve() calls. This isn't doing /bin/sh -c
"re2c" either, as my grep would have caught that.
Now let's unset ENV (like with csh environment) and see what happens:
root@mambo:~ # unset ENV
root@mambo:~ # rm -f junk
root@mambo:~ # truss -e -f -o junk sa-compile
Aug 11 10:51:15.933 [43766] info: generic: base extraction starting. this can
take a while...
Aug 11 10:51:15.934 [43766] info: generic: extracting from rules of type
body_neg2000
100%
[=========================================================================================================================================================================]
29.02 rules/sec 0m 0s DONE
0% [
^C
root@mambo:~ # egrep 're2c|env' junk
43766: read(4," environment variable will be se"...,8192) = 8192 (0x2000)
43768: execve("/sbin/re2c",0x2d956c9ce740,[ "PAGER=less", "LANG=C.UTF-8",
"MAIL=/var/mail/root",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
"PWD=/root", "TERM=xterm", "USER=root", "HOME=/root", "SHELL=/bin/sh",
"MM_CHARSET=UTF-8", "BLOCKSIZE=K" ]) ERR#2 'No such file or directory'
43768: execve("/bin/re2c",0x2d956c9ce740,[ "PAGER=less", "LANG=C.UTF-8",
"MAIL=/var/mail/root",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
"PWD=/root", "TERM=xterm", "USER=root", "HOME=/root", "SHELL=/bin/sh",
"MM_CHARSET=UTF-8", "BLOCKSIZE=K" ]) ERR#2 'No such file or directory'
43768: execve("/usr/sbin/re2c",0x2d956c9ce740,[ "PAGER=less", "LANG=C.UTF-8",
"MAIL=/var/mail/root",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
"PWD=/root", "TERM=xterm", "USER=root", "HOME=/root", "SHELL=/bin/sh",
"MM_CHARSET=UTF-8", "BLOCKSIZE=K" ]) ERR#2 'No such file or directory'
43768: execve("/usr/bin/re2c",0x2d956c9ce740,[ "PAGER=less", "LANG=C.UTF-8",
"MAIL=/var/mail/root",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
"PWD=/root", "TERM=xterm", "USER=root", "HOME=/root", "SHELL=/bin/sh",
"MM_CHARSET=UTF-8", "BLOCKSIZE=K" ]) ERR#2 'No such file or directory'
43768: execve("/usr/local/sbin/re2c",0x2d956c9ce740,[ "PAGER=less",
"LANG=C.UTF-8", "MAIL=/var/mail/root",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
"PWD=/root", "TERM=xterm", "USER=root", "HOME=/root", "SHELL=/bin/sh",
"MM_CHARSET=UTF-8", "BLOCKSIZE=K" ]) ERR#2 'No such file or directory'
43768: execve("/usr/local/bin/re2c",0x2d956c9ce740,[ "PAGER=less",
"LANG=C.UTF-8", "MAIL=/var/mail/root",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
"PWD=/root", "TERM=xterm", "USER=root", "HOME=/root", "SHELL=/bin/sh",
"MM_CHARSET=UTF-8", "BLOCKSIZE=K" ]) EJUSTRETURN
So we can tell within sa-compile, $PATH changes conditionally. With $ENV set,
$PATH gets set to /bin:/usr/bin. But is this Perl's taint mode or
SpamAssassin?
Let's test Perl's taint mode for behaviour using -T. Again, this is Perl
itself, not sa-compile. We should get taint warnings by default:
root@mambo:~ # exit
$ \sudo su -
root@mambo:~ # truss -e -f -o junk perl -Te 'print qx("re2c");'
Insecure $ENV{PATH} while running with -T switch at -e line 1.
Expected. Let's untaint PATH (dirty way but we're just testing Perl):
root@mambo:~ # truss -e -f -o junk perl -Te 'delete @ENV{"PATH"}; print
qx("re2c");'
Insecure $ENV{ENV} while running with -T switch at -e line 1.
This is a new one to me, but is documented in Perl's perlsec man page:
https://perldoc.perl.org/perlsec#Cleaning-Up-Your-Path . So let's untaint ENV:
root@mambo:~ # truss -e -f -o junk perl -Te 'delete @ENV{"PATH"}; delete
@ENV{"ENV"}; print qx("re2c");'
re2c: error: no source file
OK, we see /usr/local/bin being honoured here, so Perl itself seems to be
honouring what's in the shell $PATH (/usr/local/bin being present).
Now let's unset ENV and see what happens.
root@mambo:~ # unset ENV
root@mambo:~ # truss -e -f -o junk perl -Te 'print qx("re2c");'
Insecure $ENV{PATH} while running with -T switch at -e line 1.
Again, expected. Let's untaint PATH:
root@mambo:~ # truss -e -f -o junk perl -Te 'delete @ENV{"PATH"}; print
qx("re2c");'
re2c: error: no source file
So yes, SpamAssassin is doing something with $PATH when $ENV is set, prior to
any execve() calls.
What about Linux? All I have on hand is Ubuntu/Debian right now.
Rather than do the same analysis, we can tell one difference right off the bat:
Linux chooses to install sa-compile in /usr/bin, therefore whatever
SpamAssassin's hard-coded $PATH defaults would likely still work -- even if
$ENV was set. It also hard-links to /bin/sa-compile, for whatever god-awful
reason:
root@linux:~# dpkg-query -L sa-compile
...
/usr/bin
/usr/bin/sa-compile
...
root@linux:~# ls -li /usr/bin/sa-compile /bin/sa-compile
15102207 -rwxr-xr-x 1 root root 22375 Mar 23 2023 /bin/sa-compile
15102207 -rwxr-xr-x 1 root root 22375 Mar 23 2023 /usr/bin/sa-compile
Before we get to "What have we learned?", I will remind readers: there are TWO
PROBLEMS to solve: one with sa-update and one with sa-compile. The problems
manifest differently, but both stem from $ENV being set.
So what have we learned?
1. sa-update does not like $ENV being set: period. It does not untaint $ENV.
Probably a bug/quirk in SpamAssassin.
2. sa-compile, when $ENV is set, causes $PATH to change to /bin:/usr/bin. We
can tell that Perl taint mode IS NOT doing this because qx() (and probably
system()) with a binary in /usr/local/bin actually is found, rather than
ENOENT. We can additionally tell because execve() $PATH is seen to change.
Untainting these variables is of course required, and which approach you take
for untainting is your choice. SpamAssassin has apparently chosen a poor
choice, probably because I doubt anyone on the SA team runs FreeBSD. Ports, as
we all know, defaults to /usr/local base. So this has been a problem lurking
on FreeBSD for a very long time (whenever SA started doing this).
3. This problem doesn't happen on Linux (Debian/Ubuntu) because 1) dash doesn't
set $ENV like FreeBSD, but even if it did, 2) the sa-compile binary gets
installed in /usr/bin and a hardlink in /bin, so it's going to work with
whatever SpamAssassin's code is. Further proof SA team probably only uses
Linux.
Workarounds:
WA1) Patch FreeBSD spamassassin port. Needs two changes:
a. sa-update modification: fix $ENV tainting -- consider upstream patch to SA
as well
b. sa-compile modification: find where $PATH is changed to hard-coded value and
add $PORTSBASE (or whatever it's called)
One could also hand-modify the software on a system to fix this. Be sure to
pkg lock spamassassin after though, otherwise next change will wipe out your
hacks.
WA2) Modify /root/.profile and comment/delete line that sets ENV. Prompt etc.
will change as a result, as /root/.shrc will no longer be read. You could also
"just remember to unset ENV" every time, which is ridiculous IMO. FreeBSD felt
29 years ago setting this env var and pointing it to /root/.shrc was "the right
thing" due to this /bin/sh feature.
WA3) Change root's shell to /bin/csh. csh dotfiles do not set $ENV, and csh
does not care about $ENV, thus immune all of the above. Quickest/easiest
solution and guarantees no further surprises with other software (I suspect
SpamAssassin probably isn't the only one).
No AI was used in the course of this analysis, just human time -- 2 hours -- of
a guy who isn't responsible for any of this software.
I've done as much as I'm willing to do on this PR/bug. Move it to ports
category, close it for CoC violations, whatever.
--
You are receiving this mail because:
You are the assignee for the bug.
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.