SA Bugzilla – Bug 1125
spurious NULL assignment -- segv, string truncation
Last modified: 2002-12-12 10:50:33 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.
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.
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':
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.
Created attachment 418 [details] One-line patch. Bad me!
groovy -- that's now in CVS (HEAD). thanks anomie!
*** Bug 1225 has been marked as a duplicate of this bug. ***
*** Bug 1205 has been marked as a duplicate of this bug. ***