[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Off by one buffer overflow in getcwd(3)
- To: bugs_(_at_)_openbsd_(_dot_)_org
- Subject: Off by one buffer overflow in getcwd(3)
- From: Peter Philipp <philipp_(_at_)_scan-plus_(_dot_)_de>
- Date: Tue, 04 Jan 2005 09:18:54 +0100
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
This is a demonstration of a "off-by-one" buffer overflow on the heap in
getcwd(3). Told in a script output, so get your popcorn and watch
closely. Tested on OpenBSD 3.2/macppc. Found with help of "jafari" on
efnet.
Script started on Mon Jan 3 21:22:53 2005
triton# more mklargedir.c
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int
main(void)
{
~ char buf[512];
~ char lbuf[512];
~ int i;
~ for (i = 0; i < 255; i++) {
~ buf[i] = 'A';
~ }
~ buf[i] = '\0';
~ sprintf(lbuf, "/tmp/%s", buf);
~ mkdir(lbuf, 0755);
~ sprintf(buf, "/tmp/test");
~ mkdir(buf, 0755);
~ sprintf(buf, "/tmp/test2");
~ mkdir(buf, 0755);
~ return 0;
}
triton# ./mklargedir
triton# ls /tmp
.ICE-unix
.X11-unix
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
test
test2
triton# more opendirtest.c
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
int
main(void)
{
~ DIR *d;
~ struct dirent *de;
~ d = opendir("/tmp");
~ if (d == NULL) {
~ perror("opendir");
~ exit(1);
~ }
~ while ((de = readdir(d)) != NULL) {
~ printf("%s\n", de->d_name);
~ }
~ closedir(d);
~ return 0;
}
triton# ./opendirtest
.
..
.X11-unix
.ICE-unix
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
test
test2
triton# more mkdir.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int
main(void)
{
~ int i;
~ chdir("/tmp/test");
~ for (i = 0; i < 254; i++) {
~ mkdir("A", 0755);
~ chdir("A");
~ }
}
triton# ./mkdir
triton# more prog.c
#include <stdio.h>
char * getcwd(char *pt, size_t size);
int
main(void)
{
~ if (getcwd(NULL, -1) == NULL) {
~ perror("getcwd");
~ }
}
triton# diff -u /usr/src/lib/libc/gen/getcwd.c getcwd.c
- --- /usr/src/lib/libc/gen/getcwd.c Mon May 19 20:14:37 2003
+++ getcwd.c Wed Dec 29 20:17:52 2004
@@ -175,6 +175,7 @@
~ continue;
~ bcopy(dp->d_name, bup, dp->d_namlen + 1);
+ printf("%d\n", strlen(up));
~ /* Save the first error for later. */
~ if (lstat(up, &s)) {
~ if (!save_errno)
triton# cc -o /tmp/prog prog.c getcwd.c
triton# cd /tmp
triton# ls
.ICE-unix
.X11-unix
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
prog
test
test2
triton# mount_null test test2
triton# df
Filesystem 1K-blocks Used Avail Capacity Mounted on
10.0.0.1:/usr/triton/root 18549738 15211447 2410805 86% /
192.168.0.1:/usr/triton/usr 18549738 15211447 2410805 86% /usr
192.168.0.1:/usr/triton/var 18549738 15211447 2410805 86% /var
192.168.0.1:/usr/triton/etc 18549738 15211447 2410805 86% /etc
192.168.0.1:/usr/triton/tmp 18549738 15211447 2410805 86% /tmp
/tmp/test 18549738 15211447 2410805 86% test2
triton# cd test2
triton# ls
A
triton# repeat 254 cd A
triton# ls
triton# cp /tmp/prog .
triton# ./prog
774
774
1020
769
770
4
getcwd: No such file or directory
triton# grep 1024 /usr/src/lib/libc/gen/getcwd.c
~ if ((pt = malloc(ptsize = 1024 - 4)) == NULL)
~ * Allocate bytes (1024 - malloc space) for the string of "../"'s.
~ if ((up = malloc(upsize = 1024 - 4)) == NULL)
triton# exit
triton# exit
Script done on Mon Jan 3 21:35:24 2005
The 1020 is the strlen() of array up which means that the buffer to hold
this is 1021 bytes in length which includes the trailing NUL byte. What
the grep shows is that the array up is malloc'ed to just 1020 bytes.
off-by-one.
Here a simple untested patch, comments would probably need rewriting as
well. This also deals with the eup pointer which would otherwise have
resided outside of the up array as well.
- --- /usr/src/lib/libc/gen/getcwd.c Mon May 19 20:14:37 2003
+++ getcwd.c Mon Jan 3 22:14:31 2005
@@ -92,7 +92,7 @@
~ * Should always be enough (it's 340 levels). If it's not,
allocate
~ * as necessary. Special * case the first stat, it's ".", not
"..".
~ */
- - if ((up = malloc(upsize = 1024 - 4)) == NULL)
+ if ((up = malloc(upsize = MAXPATHLEN)) == NULL)
~ goto err;
~ eup = up + MAXPATHLEN;
~ bup = up;
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFB2lFt3j5xRv0RIEURAolPAJ0VK4c27ES37myHfFEEnoCJYI9D9ACfVxj/
17ZOLVXE456nBIauGQkEFoU=
=tMC2
-----END PGP SIGNATURE-----
Visit your host, monkey.org