Bug 1125 - spurious NULL assignment -- segv, string truncation
Summary: spurious NULL assignment -- segv, string truncation
Status: RESOLVED FIXED
Alias: None
Product: Spamassassin
Classification: Unclassified
Component: spamc/spamd (show other bugs)
Version: 2.43
Hardware: PC Linux
: P2 normal
Target Milestone: ---
Assignee: SpamAssassin Developer Mailing List
URL:
Whiteboard:
Keywords:
: 1205 1225 (view as bug list)
Depends on:
Blocks:
 
Reported: 2002-10-19 12:45 UTC by David Kewley
Modified: 2002-12-12 10:50 UTC (History)
2 users (show)



Attachment Type Modified Status Actions Submitter/CLA Status
One-line patch. Bad me! patch None Brad "anomie" Jorsch [HasCLA]

Note You need to log in before you can comment on or make changes to this bug.
Description David Kewley 2002-10-19 12:45:24 UTC
Hi Craig,

First off, thanks for spamd/spamc.  I've just been implementing a SpamAssassin
setup in the clusters I admin at Caltech, and I'm glad I can use spamc/spamd.

I believe I found a critical bug in spamc.c.  I'm not a highly experienced C
hacker, but this one seems pretty obvious.  I tracked it down because in my
hands, about 10% of my mails were causing spamc to segfault.  I have not verified
that this bug was causing my specific segfaults, but it seems apparent that it
could.  It can also cause various other errors (including truncating strings,
another bug I've seen occur in read_args()).

In the latest SpamAssassion version (2.43), here's how you're handling the -e
option to spamc:

    79    while(-1 != (opt = getopt(argc,argv,"-Bcd:e:fhp:t:s:u:")))
    80    {
    81      switch(opt)
...
    98      case 'e':
    99        {
   100          if((exec_argv=malloc(sizeof(*exec_argv)*(argc-optind+2)))==NULL)
   101              return EX_OSERR;
   102          for(i=0, j=optind-1; j<argc; i++, j++){
   103              exec_argv[i]=argv[j];
   104          }
   105          argv[opt]=NULL;
   106          return EX_OK;
   107        }

What is line 105 doing there?  opt has the value 'e'==101!  I don't think line 105
should be there at all.  Also, I think to null-terminate exec_argv properly, you
need to use j<=argc instead of j<argc as the terminal test in the for statement.

I'm curious: Do you know how line 105 came into existence in the first place? :)

David

P.S. I wrote the foregoing to Craig personally and he asked me to submit this
bug report (which I probably should have figured out myself...).

Craig commented to me that "I'm guessing, but the line was 
probably intended to mark that argument as "processed" or something.  
Why, I don't know.  But I bet it is meant to say argv[optind] rather 
than argv[opt].  I agree that this code is likely to cause segvs.  
Could cause string truncation if memory is aligned wrong."

Indeed it does cause string truncation, irrespctive (I think) of memory
alignment -- it turns out that the strings pointed to by *argv[x] are placed
in memory after argv on my machine, and I'm using some long argv
strings.  So  for me *argv[101] happens sometimes to be in the middle of
one of my argv strings, and that string gets truncated.  Other times it 
apparently points beyond allocated memory, causing a segv (I'm getting
segv's but haven't been able to track the exact cause of those segv's.)

This is clearly a bug, so platform doesn't really matter, but in case it's
useful for correlating with others' experiences, I've seen these spamc
segv's and string truncations on on a nearly-fully-patched Red Hat Linux
6.2 x86 machine.  Yes, I want to upgrade to 7.3 or 8.0...

Last night I implemented the two fixes I suggested above (removing line
105 and adjusting the terminal condition in the for loop), and ~100 emails
later have not experienced any segvs or string truncations (earlier, about
10% were getting segv's).

One last note.  I am running SpamAssassin 2.42, but this bug also appears
in the 2.43 source code.  I chose to assign this as a 2.43 bug.
Comment 1 Brad "anomie" Jorsch 2002-10-19 13:42:20 UTC
Subject: Re: [SAdev]  New: spurious NULL assignment -- segv, string truncation

On Sat, Oct 19, 2002 at 12:45:24PM -0700, kewley@cns.caltech.edu
reported:
> 
> What is line 105 doing there?  opt has the value 'e'==101!  I don't
> think line 105 should be there at all.  Also, I think to
> null-terminate exec_argv properly, you need to use j<=argc instead of
> j<argc as the terminal test in the for statement.
> 
> I'm curious: Do you know how line 105 came into existence in the first
> place? :)

My fault probably, i wrote that code...

Probably, the opt came from using 'opt' instead of 'j' in the for loop
(during development), and wasn't changed to j when the for loop was.
Line 105 was probably intended to be something along the lines of:
  exec_argv[j]=NULL;

So yeah, i'm dumb.

Comment 2 David Kewley 2002-10-22 22:47:35 UTC
I've described the fix in words, but here's a patch for good measure.

David

diff -burBN Mail-SpamAssassin-2.43-orig/spamd/spamc.c Mail-SpamAssassin-2.43/spamd/spamc.c
--- Mail-SpamAssassin-2.43-orig/spamd/spamc.c   Tue Oct 15 08:22:49 2002
+++ Mail-SpamAssassin-2.43/spamd/spamc.c        Tue Oct 22 15:41:10 2002
@@ -99,10 +99,9 @@
       {
         if((exec_argv=malloc(sizeof(*exec_argv)*(argc-optind+2)))==NULL)
             return EX_OSERR;
-        for(i=0, j=optind-1; j<argc; i++, j++){
+        for(i=0, j=optind-1; j<=argc; i++, j++){
             exec_argv[i]=argv[j];
         }
-        argv[opt]=NULL;
         return EX_OK;
       }
     case 'p':

Comment 3 Brad "anomie" Jorsch 2002-10-23 12:12:15 UTC
On Tue, Oct 22, 2002 at 10:47:35PM -0700, kewley@cns.caltech.edu commented:
> 
> diff -burBN Mail-SpamAssassin-2.43-orig/spamd/spamc.c
Mail-SpamAssassin-2.43/spamd/spamc.c
> --- Mail-SpamAssassin-2.43-orig/spamd/spamc.c   Tue Oct 15 08:22:49 2002
> +++ Mail-SpamAssassin-2.43/spamd/spamc.c        Tue Oct 22 15:41:10 2002
> @@ -99,10 +99,9 @@
>        {
>          if((exec_argv=malloc(sizeof(*exec_argv)*(argc-optind+2)))==NULL)
>              return EX_OSERR;
> -        for(i=0, j=optind-1; j<argc; i++, j++){
> +        for(i=0, j=optind-1; j<=argc; i++, j++){

Can we actually count on argv[argc] being valid and NULL, even on odd platforms?
That's probably why that troublesome line was there in the first place.

Unless it says somewhere that argv[argc] will always be accessable and NULL, i'd
rather leave the for loop and explicitly set that last exec_argv to NULL.

I'll attach my suggested patch shortly.
Comment 4 Brad "anomie" Jorsch 2002-10-23 12:13:17 UTC
Created attachment 418 [details]
One-line patch. Bad me!
Comment 5 Justin Mason 2002-10-23 15:00:59 UTC
groovy -- that's now in CVS (HEAD). thanks anomie!
Comment 6 Per Jessen 2002-12-01 11:39:52 UTC
*** Bug 1225 has been marked as a duplicate of this bug. ***
Comment 7 Duncan Findlay 2002-12-12 19:50:33 UTC
*** Bug 1205 has been marked as a duplicate of this bug. ***