Package: procmail
Version: 3.22-20+deb7u1
Severity: important
Tags: security
We ran into a procmail segfault when dealing with a ridiculous (but
legit) procmailrc, and I tracked it down to an off-by-one error in the
overflow handling of getlline() in the presence of an overly long and
suitably aligned set of line continuations.
Please find a (very crudely tested) patch below that appears to handle
this specific example. I have only tested this patch against this
specific test case, and NOT against normal use of procmail.
The latter change (target>=end-2) should fix the root cause of this bug.
The first change (q>=end) is just to be extra sure, in case any other
bug exposes getbl() to similarly confusing parameters.
--- procmail-3.22.orig/src/cstdio.c
+++ procmail-3.22/src/cstdio.c
@@ -144,7 +144,7 @@ int getbl(p,end)char*p,*end;
/* my
{ case '\n':case EOF:*q='\0';
return overflow?-1:p!=q; /* did we read anything at all? */
}
- if(q==end) /* check here so that a trailing backslash won't be
lost */
+ if(q>=end) /* check here so that a trailing backslash won't be
lost */
q=p,overflow=1;
*q++=i;
}
@@ -199,7 +199,7 @@ int getlline(target,end)char*target,*end
if(*(target=strchr(target,'\0')-1)=='\\')
{ if(chp2!=target) /* non-empty line? */
target++; /* then preserve the backslash */
- if(target>end-2) /* space enough for getbl? */
+ if(target>=end-2) /* space enough for getbl? */
target=end-linebuf,overflow=1; /* toss what we have */
continue;
}
Detailed analysis of the crash follows below. Thanks to Antti Jaakkola
for providing the input file used to debug this, and Henri Salo for
advice on reporting it.
-- Tero Marttila
Hardware watchpoint 5: buf2[linebuf+1]
Old value = 0 '\000'
New value = 65 'A'
0x0000000000404abc in getbl (p=p@entry=0x88f64f "AAA", end=0x88f64f "AAA",
end@entry=0x88f650 "AA") at cstdio.c:149
149 *q++=i;
(gdb) bt
#0 0x0000000000404abc in getbl (p=p@entry=0x88f64f "AAA", end=0x88f64f "AAA",
end@entry=0x88f650 "AA") at cstdio.c:149
#1 0x0000000000404c2f in getlline (target=0x88f64f "AAA", end=0x88f650 "AA")
at cstdio.c:196
#2 0x0000000000409dc3 in conditions (flags=flags@entry=0x615528 "",
prevcond=prevcond@entry=0, lastsucc=lastsucc@entry=0, lastcond=lastcond@entry=0,
skipping=skipping@entry=0, nrcond=-1, nrcond@entry=0) at misc.c:439
#3 0x00000000004026a9 in mainloop () at procmail.c:678
#4 0x0000000000403eb1 in main (argc=<optimized out>, argv=<optimized out>) at
procmail.c:461
(gdb) p p
$155 = 0x88f64f "AAA"
(gdb) p end
$156 = 0x88f64f "AAA"
(gdb) p q
$157 = 0x88f651 "A"
IOW, getlline() is overflowing the buffer it is being passed:
(gdb) p buf2
$153 = 0x88ee50 "\nFrom:", 'a' <repeats 84 times>, "|\\\nFrom:", 'a' <repeats 84 times>,
"|\\\nFrom:aaaaaaaaaa"...
(gdb) p buf2 + linebuf
$154 = 0x88f650 "AA"
I assume this is due to an off-by-one bug in getbl():
(gdb) l 140,151
140 int getbl(p,end)char*p,*end; /* my
gets */
141 { int i,overflow=0;char*q;
142 for(q=p,end--;;)
143 { switch(i=getb())
144 { case '\n':case EOF:*q='\0';
145 return overflow?-1:p!=q; /* did we read anything at
all? */
146 }
147 if(q==end) /* check here so that a trailing backslash won't be
lost */
148 q=p,overflow=1;
149 *q++=i;
150 }
151 }
When passed p = 0x88f64f, end = 0x88f650 (i.e. the last char in the
buffer), after the first read, we have q == end and the if evaluates to
true, overflow is set, but q = p is a no-op, and the unconditional *q++
then ensures that we escape into q > end territory, and getbl() just
continues copying input bytes into the heap.
In the build I was testing with, then shows up as a SIGSEGV when the
global myenv linked list gets corrupted:
(gdb) c
Continuing.
procmail: Exceeded LINEBUF
Program received signal SIGSEGV, Segmentation fault.
__strncmp_sse42 () at ../sysdeps/x86_64/multiarch/strcmp.S:260
260 ../sysdeps/x86_64/multiarch/strcmp.S: No such file or directory.
(gdb) up
#1 0x000000000040dd62 in sputenv (a=a@entry=0x412070 "PROCMAIL_OVERFLOW=yes")
at variables.c:62
62 if(!strncmp(a,curr->ename,eq)&&((char*)curr->ename)[eq]=='=')
(gdb) bt
#0 __strncmp_sse42 () at ../sysdeps/x86_64/multiarch/strcmp.S:260
#1 0x000000000040dd62 in sputenv (a=a@entry=0x412070 "PROCMAIL_OVERFLOW=yes")
at variables.c:62
#2 0x000000000040e0ea in setoverflow () at variables.c:148
#3 0x0000000000404c46 in getlline (target=<optimized out>, end=0x88f650 'A'
<repeats 87 times>) at cstdio.c:208
#4 0x0000000000409dc3 in conditions (flags=flags@entry=0x615528 "",
prevcond=prevcond@entry=0, lastsucc=lastsucc@entry=0, lastcond=lastcond@entry=0,
skipping=skipping@entry=0, nrcond=-1, nrcond@entry=0) at misc.c:439
#5 0x00000000004026a9 in mainloop () at procmail.c:678
#6 0x0000000000403eb1 in main (argc=<optimized out>, argv=<optimized out>) at
procmail.c:461
(gdb) p curr
$160 = (struct dynstring *) 0x4141414141414141
This is due to the `struct dynstring *` (part of myenv) situated after
buf2 getting corrupted:
(gdb) p *(struct dynstring*) 0x88f650
$163 = {enext = 0x4141414141414141,
ename = 'A' <repeats 79 times>, '\000' <repeats 17 times>, "<censored>", '\000' <repeats
37 times>, "n\000\000\000\000\000"}
The input file used to reproduce this issue is below. The trailing part
of arbitrary AAAAA's is where the heap overflow begins. This is tied to
the LINEBUF used (default 2048), and could thus probably be shorter; the
final "\\\n" just needs to suitably fall on the second-to-last position
(?) in the buf2. I assume that the code which is supposed to guard
against this also has an off-by-one bug:
(gdb) l 199,205
199 if(*(target=strchr(target,'\0')-1)=='\\')
200 { if(chp2!=target) /* non-empty
line? */
201 target++; /* then preserve the
backslash */
202 if(target>end-2) /* space enough for
getbl? */
203 target=end-linebuf,overflow=1; /* toss what we
have */
204 continue;
205 }
--- cut here ---
DEFAULT=mailbox
:0:
*
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
From:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
--
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]