Hi
I have installed the cfengine 2.1.20 package from Fedora Core 5 Extras,
and when I run it with my previous configuration, cfagent fails with the
message:
*** stack smashing detected ***: cfagent terminated
Aborted
Apparently a problem found by the "Buffer Overflow detection ..."
mentioned at http://fedora.redhat.com/docs/release-notes/fc5/#id2934140
I installed debuginfo and gdb, and run this with gdb cfagent, run
--no-splay -v, and after the abort, see the stack trace below.
Note the "out of bounds" at #5, this was actually the first arg to
HandleIPRange in #6.
Looking closer, I see that arg 2 to FuzzySetMatch is that of an IPv6
interface being matched against a definition in my cfagent.conf:
ikr = ( IPRange(129.132.166.67-98) ) #HostRange(ikr,1-32)
This causes trouble at lines 833 and 845 of item.c, which sscanf the
entire arg 2 of FuzzySetMatch ("fe80::240:63ff:fee2:1ecc") into a buffer
of length 8, killing the canary on the stack.
I see similar behaviour at line 840 of item.c by crafting a special arg
in the configuration file (IPRange(123456789....), more than 7 chars
before the dot) - this writes beyond buffer1.
I don't have an easy patch at hand. First, I think that the address
family of both args should be checked (false if ipv4 and ipv6 are
mixed). Second I was thinking of using stuff like "if (2==sscanf(sp1,
"%d-%d", &min, &max)) ... else if (1==sscanf(sp1, "%d", &min)) {
max=min; } ...", but it is not satisfactory either.
I also attach a small test prog isolating the problem.
Kind regards, Martin
(gdb) where
#0 0x0050a402 in __kernel_vsyscall ()
#1 0x00550159 in raise () from /lib/libc.so.6
#2 0x005516e3 in abort () from /lib/libc.so.6
#3 0x00584a1b in __libc_message () from /lib/libc.so.6
#4 0x00604e45 in __stack_chk_fail () from /lib/libc.so.6
#5 0x08069753 in FuzzySetMatch (s1=0x3 <Address 0x3 out of bounds>,
s2=0x8cf3528 "fe80::240:63ff:fee2:1ecc") at item.c:968
#6 0x0807a1b1 in HandleIPRange (args=0xbfc6fce8 "129.132.166.67-98",
value=0xbfc72128 "XX_CF_opposite_any_XX") at functions.c:422
#7 0x0807a7d7 in EvaluateFunction (f=0x8d18dcd
"IPRange(129.132.166.67-98)",
value=0xbfc72128 "XX_CF_opposite_any_XX") at functions.c:147
#8 0x08074e44 in HandleFunctionObject (
fn=0x8d18dcd "IPRange(129.132.166.67-98)") at parse.c:648
#9 0x080a6b0e in yylex () at cflex.l:431
#10 0x0809f4ce in yyparse () at y.tab.c:1189
#11 0x08073cbc in ParseFile (
filename=0xbfc73738 "/var/cfengine/inputs/cfagent.conf",
env=0xbfc73738 "/var/cfengine/inputs/cfagent.conf") at parse.c:1051
#12 0x080749e9 in ParseInputFile (file=0x8136200 "cfagent.conf") at
parse.c:82
#13 0x0804f466 in main (argc=3, argv=0xbfc74804) at cfagent.c:140
#14 0x0053d7e4 in __libc_start_main () from /lib/libc.so.6
#15 0x0804b231 in _start ()
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#define CF_ADDRSIZE 128
#define false 0
#define CF_BUFSIZE 4096
#define true 1
#define Debug if (DEBUG || D1 || D2) printf
char OUTPUT[CF_BUFSIZE*2];
enum cfoutputlevel
{
cfsilent,
cfinform,
cfverbose,
cfeditverbose,
cferror,
cflogonly,
cfloginform
};
void CfLog (enum cfoutputlevel level, char *string, char *errstr)
{
}
int DEBUG=0, D1=0, D2=0;
void FatalError(s)
char *s;
{
//fprintf (stderr,"%s:%s:%s\n",VPREFIX,VCURRENTFILE,s);
//SILENT = true;
//ReleaseCurrentLock();
//closelog();
exit(1);
}
char *sockaddr_ntop(struct sockaddr *sa) {
static char addrbuf[20];
struct in_addr addr;
switch (sa->sa_family)
{
case AF_INET:
Debug("IPV4 address\n");
snprintf(addrbuf,20,"%.19s",inet_ntoa(((struct sockaddr_in
*)sa)->sin_addr));
break;
#ifdef AF_LOCAL
case AF_LOCAL:
Debug("Local socket\n") ;
strcpy(addrbuf, "127.0.0.1") ;
break;
#endif
default:
Debug("Address family was %d\n",sa->sa_family);
FatalError("Software failure in sockaddr_ntop\n");
}
Debug("sockaddr_ntop(%s)\n",addrbuf);
return addrbuf;
}
void *sockaddr_pton(int af,void *src) { int err;
static struct sockaddr_in adr;
switch (af)
{
case AF_INET:
memset(&adr,0,sizeof(adr));
adr.sin_family = AF_INET;
adr.sin_addr.s_addr = inet_addr(src);
Debug("Coded ipv4 %s\n",sockaddr_ntop((struct sockaddr *)&adr));
return (void *)&adr;
default:
Debug("Address family was %d\n",af);
FatalError("Software failure in sockaddr_pton\n");
}
return NULL;
}
int FuzzySetMatch(char *s1,char *s2)
/* Match two IP strings - with : or . in hex or decimal
s1 is the test string, and s2 is the reference e.g.
FuzzySetMatch("128.39.74.10/23","128.39.75.56") == 0 */
{ short isCIDR = false, isrange = false, isv6 = false, isv4 = false;
char address[CF_ADDRSIZE];
int mask;
unsigned long a1,a2;
if (strstr(s1,"/") != 0)
{
isCIDR = true;
}
if (strstr(s1,"-") != 0)
{
isrange = true;
}
if (strstr(s1,".") != 0)
{
isv4 = true;
}
if (strstr(s1,":") != 0)
{
isv6 = true;
}
if (isv4 && isv6)
{
snprintf(OUTPUT,CF_BUFSIZE,"Mixture of IPv6 and IPv4 addresses: %s",s1);
CfLog(cferror,OUTPUT,"");
return -1;
}
if (isCIDR && isrange)
{
snprintf(OUTPUT,CF_BUFSIZE,"Cannot mix CIDR notation with xxx-yyy range
notation: %s",s1);
CfLog(cferror,OUTPUT,"");
return -1;
}
if (!(isv6 || isv4))
{
snprintf(OUTPUT,CF_BUFSIZE,"Not a valid address range - or not a fully
qualified name: %s",s1);
CfLog(cferror,OUTPUT,"");
return -1;
}
if (!(isrange||isCIDR))
{
return strncmp(s1,s2,strlen(s1)); /* do partial string match */
}
if (isv4)
{
struct sockaddr_in addr1,addr2;
int shift;
memset(&addr1,0,sizeof(struct sockaddr_in));
memset(&addr2,0,sizeof(struct sockaddr_in));
if (isCIDR)
{
address[0] = '\0';
mask = 0;
sscanf(s1,"%16[^/]/%d",address,&mask);
shift = 32 - mask;
memcpy(&addr1,(struct sockaddr_in *)
sockaddr_pton(AF_INET,address),sizeof(struct sockaddr_in));
memcpy(&addr2,(struct sockaddr_in *)
sockaddr_pton(AF_INET,s2),sizeof(struct sockaddr_in));
a1 = htonl(addr1.sin_addr.s_addr);
a2 = htonl(addr2.sin_addr.s_addr);
a1 = a1 >> shift;
a2 = a2 >> shift;
if (a1 == a2)
{
return 0;
}
else
{
return -1;
}
}
else
{
long i, from = -1, to = -1, cmp = -1;
char *sp1,*sp2,buffer1[8],buffer2[8];
sp1 = s1;
sp2 = s2;
for (i = 0; i < 4; i++)
{
if (sscanf(sp1,"%[^.]",buffer1) <= 0)
{
break;
}
sp1 += strlen(buffer1)+1;
sscanf(sp2,"%[^.]",buffer2);
sp2 += strlen(buffer2)+1;
if (strstr(buffer1,"-"))
{
sscanf(buffer1,"%ld-%ld",&from,&to);
sscanf(buffer2,"%ld",&cmp);
if (from < 0 || to < 0)
{
Debug("Couldn't read range\n");
return -1;
}
if ((from > cmp) || (cmp > to))
{
Debug("Out of range %d > %d > %d (range
%s)\n",from,cmp,to,buffer2);
return -1;
}
}
else
{
sscanf(buffer1,"%ld",&from);
sscanf(buffer2,"%ld",&cmp);
if (from != cmp)
{
Debug("Unequal\n");
return -1;
}
}
Debug("Matched octet %s with %s\n",buffer1,buffer2);
}
Debug("Matched IP range\n");
return 0;
}
}
#if defined(HAVE_GETADDRINFO) && !defined(DARWIN)
if (isv6)
{
struct sockaddr_in6 addr1,addr2;
int blocks, i;
memset(&addr1,0,sizeof(struct sockaddr_in6));
memset(&addr2,0,sizeof(struct sockaddr_in6));
if (isCIDR)
{
address[0] = '\0';
mask = 0;
sscanf(s1,"%40[^/]/%d",address,&mask);
blocks = mask/8;
if (mask % 8 != 0)
{
CfLog(cferror,"Cannot handle ipv6 masks which are not 8 bit multiples
(fix me)","");
return -1;
}
memcpy(&addr1,(struct sockaddr_in6 *)
sockaddr_pton(AF_INET6,address),sizeof(struct sockaddr_in6));
memcpy(&addr2,(struct sockaddr_in6 *)
sockaddr_pton(AF_INET6,s2),sizeof(struct sockaddr_in6));
for (i = 0; i < blocks; i++) /* blocks < 16 */
{
if (addr1.sin6_addr.s6_addr[i] != addr2.sin6_addr.s6_addr[i])
{
return -1;
}
}
return 0;
}
else
{
long i, from = -1, to = -1, cmp = -1;
char *sp1,*sp2,buffer1[16],buffer2[16];
sp1 = s1;
sp2 = s2;
for (i = 0; i < 8; i++)
{
sscanf(sp1,"%[^:]",buffer1);
sp1 += strlen(buffer1)+1;
sscanf(sp2,"%[^:]",buffer2);
sp2 += strlen(buffer2)+1;
if (strstr(buffer1,"-"))
{
sscanf(buffer1,"%lx-%lx",&from,&to);
sscanf(buffer2,"%lx",&cmp);
if (from < 0 || to < 0)
{
return -1;
}
if ((from >= cmp) || (cmp > to))
{
printf("%x < %x < %x\n",from,cmp,to);
return -1;
}
}
else
{
sscanf(buffer1,"%ld",&from);
sscanf(buffer2,"%ld",&cmp);
if (from != cmp)
{
return -1;
}
}
}
return 0;
}
}
#endif
return -1;
}
int main(int argc, char *argv[]) {
FuzzySetMatch("129.132.166.67-98", "fe80::240:63ff:fee2:1ecc");
}
_______________________________________________
Bug-cfengine mailing list
[email protected]
http://cfengine.org/mailman/listinfo/bug-cfengine