This is the mail archive of the
newlib@sources.redhat.com
mailing list for the newlib project.
Security Problem ( Buffer Overflow) in newlib
- To: <newlib at sources dot redhat dot com>
- Subject: Security Problem ( Buffer Overflow) in newlib
- From: Bjoern Voigt <bjoern at cs dot tu-berlin dot de>
- Date: Sun, 16 Sep 2001 13:32:31 +0200 (CEST)
Hello Cygwin-Friends,
I made some C/C++ experiments with Cygwin and found an Buffer Overflow
problem in the newlib library. I have a CVS snapshot
"cygwin-src-20010907.tar.bz2" of Cygwin/Newlib, but the problem isn't
new.
Let us take a look at newlib/libc/unix/getpwent.c:
Line 13-19:
-------------------------------------------------------------------
static char logname[8];
static char password[1024];
static char gecos[1024];
static char dir[1024];
static char shell[1024];
-------------------------------------------------------------------
Line 33-37:
-------------------------------------------------------------------
sscanf (buf, "%[^:]:%[^:]:%d:%d:%[^:]:%[^:]:%s\n",
logname, password, &pw_passwd.pw_uid,
&pw_passwd.pw_gid, gecos,
dir, shell);
-------------------------------------------------------------------
We see, that there is no length checking.
One example for a buffer overflow:
1) Cygwin is installed as "administrator", so /etc/passwd contains:
administator:x:1111:2222:Administrator:/home/administrator:/bin/bash
2) The word "Administrator" has 13 characters, but logname[8] has only
7 characters plus '\0'.
I suggest to dynamically resize logname, password, dir and shell. As
an (not so nice) alternative we can check the length and cut for
instance logname after xy characters.
For testing I uses the following entry in /etc/passwd:
-------------------------------------------------------------------
administator:x:3333:100:Administrator:/home/administrator:/bin/bash
-------------------------------------------------------------------
and the following C program (runs on Cygwin and Linux):
-------------------------------------------------------------------
#include <pwd.h>
int main(int argc, char *argv[])
{
struct passwd *pw;
if(argc!=2) {
printf("usage: %s loginname\n",argv[0]);
return 1;
}
pw=getpwnam(argv[1]);
if(pw) {
printf("char *pw_name: %s\n",pw->pw_name);
printf("char *pw_passwd: %s\n",pw->pw_passwd);
printf("int pw_uid: %d\n",pw->pw_uid);
printf("int pw_gid: %d\n",pw->pw_gid);
/* on Linux there is no pw_comment */
/*printf("char *pw_comment: %s\n",pw->pw_comment);*/
printf("char *pw_gecos: %s\n",pw->pw_gecos);
printf("char *pw_dir: %s\n",pw->pw_dir);
printf("char *pw_shell: %s\n",pw->pw_shell);
}
else {
printf("Could not find %s !\n",argv[1]);
return 2;
}
return 0;
}
-------------------------------------------------------------------
Bye, Björn
--
Björn Voigt <bjoern@cs.tu-berlin.de>
WWW: http://user.cs.tu-berlin.de/~bjoern/