Bug 4705 - SpamAssassin uses eval() too often
Summary: SpamAssassin uses eval() too often
Status: RESOLVED INVALID
Alias: None
Product: Spamassassin
Classification: Unclassified
Component: Security (show other bugs)
Version: 3.1.0
Hardware: All All
: P5 critical
Target Milestone: Undefined
Assignee: SpamAssassin Security List
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-11-24 00:29 UTC by Roland Illig
Modified: 2005-11-23 16:04 UTC (History)
0 users



Attachment Type Modified Status Actions Submitter/CLA Status

Note You need to log in before you can comment on or make changes to this bug.
Description Roland Illig 2005-11-24 00:29:16 UTC
It seems to me that you (the authors of SpamAssassin) don't know how to use
Perl's eval() correctly. The following is a list that grep(1) found, and in
which all lines I considered irrelevant are removed. I'll discuss some of the
lines below.

Please verify for each of these lines that the eval() is not exploitable. And
when you have done this it would be really nice if you could add a comment to
every "eval" line that indicates that this particular instance of eval() has
been checked thoroughly. This makes checking with grep(1) more effective. :)

But best of all, avoid eval($string) whenever possible.

===> Please check if the following can be transformed to eval { ... }.
./t/meta.t:26:use constant HAS_DATADUMPER => eval 'use Data::Dumper; 1;';
./masses/mass-check:99:eval "use bytes";
./lib/Mail/SpamAssassin/DnsResolver.pm:166:    eval '$family = AF_INET6; $ipv6 =
1;';
./lib/Mail/SpamAssassin/Util/DependencyInfo.pm:189:  eval '
./lib/Mail/SpamAssassin/Util.pm:165:    $AM_TAINTED = eval q(no warnings
q(syntax); ${^TAINT});

./lib/Mail/SpamAssassin/Util.pm:584:    eval ' sub _getpwuid_wrapper {
getpwuid($_[0]); } ';
./lib/Mail/SpamAssassin/Util.pm:587:    eval ' sub _getpwuid_wrapper {
_fake_getpwuid($_[0]); } ';
=> (Perl 5.8 allows to nest subroutines syntactically)

===> The following seem safe to me.
./lib/Mail/SpamAssassin/AutoWhitelist.pm:77:      eval '
./lib/Mail/SpamAssassin/Plugin/MIMEHeader.pm:132:      eval $evalcode;
./lib/Mail/SpamAssassin/Util/DependencyInfo.pm:196:    if (eval ' require
'.$module.'; $modver = $'.$module.'::VERSION; 1;')
./lib/Mail/SpamAssassin/Util/DependencyInfo.pm:232:  eval "use $moddef->{module}
$moddef->{version};";
./lib/Mail/SpamAssassin/Util/DependencyInfo.pm:238:  eval "use $moddef->{module};";
./lib/Mail/SpamAssassin/BayesStore/DBM.pm:1479:    eval 'use ' . $dbm . ';


===> I wasn't motivated enough to check the following, not even basically:
./masses/corpora/remove-tests-from-logs:30:eval $sub;
./masses/hit-frequencies:434:    eval $evalstr;
./lib/Mail/SpamAssassin/PerMsgStatus.pm:1693:  eval $evalstr;
./lib/Mail/SpamAssassin/PerMsgStatus.pm:1784:  eval $evalstr;
./lib/Mail/SpamAssassin/PerMsgStatus.pm:2195:  eval $evalstr;
./lib/Mail/SpamAssassin/PerMsgStatus.pm:2284:  eval $evalstr;
./lib/Mail/SpamAssassin/PerMsgStatus.pm:2354:  eval $evalstr;
./lib/Mail/SpamAssassin/PerMsgStatus.pm:2520:  eval $evalstr;
./lib/Mail/SpamAssassin/PerMsgStatus.pm:2617:  eval $evalstr;
=> Please don't make the eval() code that complicated.

===> Maybe they are exploitable, at least they look promising:
./lib/Mail/SpamAssassin/Conf/Parser.pm:484:  if (eval $eval) {
./lib/Mail/SpamAssassin/Conf/Parser.pm:848:  if (eval $evalstr) {
./lib/Mail/SpamAssassin/PerMsgStatus.pm:1049:    eval $fmt;

===> Obviously exploitable:
./lib/Mail/SpamAssassin/Conf/Parser.pm:913:    if (eval $evalstr) {


===> Needs more error checking:
./lib/Mail/SpamAssassin/EvalTests.pm:2751:  return eval "\$val $expr";
./lib/Mail/SpamAssassin/EvalTests.pm:2815:  return eval "\$val $expr";
./lib/Mail/SpamAssassin/Dns.pm:264:      $self->got_hit($rule, "SenderBase: ")
if !$undef && eval $subtest;

===> Called from external sources, so I haven't checked:
./lib/Mail/SpamAssassin/PluginHandler.pm:91:    $ret = eval qq{ require $package; };
./lib/Mail/SpamAssassin/PluginHandler.pm:100:  my $plugin = eval
$package.q{->new ($self->{main}); };
./lib/Mail/SpamAssassin/Logger.pm:228:  eval 'use
Mail::SpamAssassin::Logger::'.$class.';';
./lib/Mail/SpamAssassin/Logger.pm:232:    my $object = eval
'Mail::SpamAssassin::Logger::'.$class.'->new(%params);';
./lib/Mail/SpamAssassin/PerMsgStatus.pm:1798:  return 0 if (eval 'defined
&Mail::SpamAssassin::PerMsgStatus::'.$subname);

===> Operates on data from external sources:
./lib/Mail/SpamAssassin/Bayes.pm:242:    eval '
./lib/Mail/SpamAssassin/Util.pm:832:    if (eval 'require '.$mod.'; 1; ') {


===> I don't understand that at all. If you die if an error occurs, what is the
purpose of eval()?
./lib/Mail/SpamAssassin.pm:328:  eval '...'; ($@) and die $@;

Roland
Comment 1 Justin Mason 2005-11-24 00:59:25 UTC
as I said in bug 4700:

It's core to SpamAssassin's architecture that we evaluate chunks of perl
code derived from rules read from the configuration directories;
SpamAssassin's core ruleset is compiled into perl bytecode internally. If
this is undesirable in your security configuration, you should not use
SpamAssassin.
Comment 2 Justin Mason 2005-11-24 01:04:43 UTC
I hit Commit too early -- this is pissing me off.

In addition to that comment, perhaps some investigation on *YOUR* part might be
in order.

Please check if the following can be transformed to eval { ... }.

./t/meta.t:26:use constant HAS_DATADUMPER => eval 'use Data::Dumper; 1;';

why don't YOU check?  the answer is, in a word, "no" -- it cannot.


The use of "eval STRING" is *core* to much software development in perl
(similarly to similar constructs in Lisp, among other languages).  If you wish
to eradicate its use, good luck.