COMMAND
libc
SYSTEMS AFFECTED
NetBSD, OpenBSD, FreeBSD
PROBLEM
Charles M. Hannum posted following. The OpenBSD version of fts.c
is still susceptible to at least two bugs that can cause a core
dump when FTS_NOCHDIR is used (e.g. by pax(1)). Beware if you do
backups with pax(1)!
The fts library functions had a buffer overflow in them where
which would lead to a core dump when periodic ran the security
checking scripts (or other scripts which traverse trees that can
be controlled by users). periodic(3) should limit core size to
zero to disable core dumps while it is executing commands, but
does not do so. In addition, the kernel should not follow
symbolic links. All three of these problems caused a situation
where it was possible for an attacker could create or overwrite
an arbitrary file on the system with a moderate degree of controll
of its contents to cause a problem (FreeBSD). Local users could
gain root access.
SOLUTION
These problems, and others, are fixed in the current NetBSD
version:
revision 1.20
date: 1999/08/27 18:01:35; author: mycroft; state: Exp; lines: +16 -10
Fix multiple problems in the FTS_NOCHDIR case:
* There was an off-by-one error that caused the addition of a
NUL or slash in fts_build() to overwrite other memory.
* After fts_palloc(), we need to reset `cp' so that it points
to the new path name buffer; otherwise the addition of the
file name before calling fts_stat() could lose.
One can workaround this problem by preventing core dumps for
periodic (FreeBSD). This solution is less than completely
satisfying, since it only plugs the known exploit hole. None the
less, this may provide a short term stopgap solution until a new
kernel and userland can be installed.
# mv /usr/sbin/periodic /usr/sbin/periodic.bin
# cat > /usr/sbin/periodic
#!/bin/sh
ulimit -c 0
/usr/sbin/periodic.bin $*
^D
# chmod 555 /usr/sbin/periodic
Apply the following patches to libc and do a make world. Please
also see the companion advisory FreeBSD-SA-99:04.core.asc in the
BSD section:
http://oliver.efri.hr/crv/security/bugs/BSD/kernel91.html
for details on the kernel portions of this fix.
Index: lib/libc/gen/fts.c
RCS file: /home/imp/FreeBSD/CVS/src/lib/libc/gen/fts.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- fts.c 1999/08/15 19:21:29 1.10
+++ fts.c 1999/09/02 07:45:07 1.11
@@ -963,6 +963,24 @@
return (sp->fts_path == NULL);
}
+static void
+ADJUST(p, addr)
+ FTSENT *p;
+ void *addr;
+{
+ if ((p)->fts_accpath >= (p)->fts_path &&
+ (p)->fts_accpath < (p)->fts_path + (p)->fts_pathlen) {
+ if (p->fts_accpath != p->fts_path)
+ errx(1, "fts ADJUST: accpath %p path %p",
+ p->fts_accpath, p->fts_path);
+ if (p->fts_level != 0)
+ errx(1, "fts ADJUST: level %d not 0", p->fts_level);
+ (p)->fts_accpath =
+ (char *)addr + ((p)->fts_accpath - (p)->fts_path);
+ }
+ (p)->fts_path = addr;
+}
+
/*
* When the path is realloc'd, have to fix all of the pointers in structures
* already returned.
@@ -974,18 +992,18 @@
{
FTSENT *p;
-#define ADJUST(p) { \
- (p)->fts_accpath = \
- (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
+#define ADJUST1(p) { \
+ if ((p)->fts_accpath == (p)->fts_path) \
+ (p)->fts_accpath = (addr); \
(p)->fts_path = addr; \
}
/* Adjust the current set of children. */
for (p = sp->fts_child; p; p = p->fts_link)
- ADJUST(p);
+ ADJUST(p, addr);
/* Adjust the rest of the tree. */
for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
- ADJUST(p);
+ ADJUST(p, addr);
p = p->fts_link ? p->fts_link : p->fts_parent;
}
}