Subject: [stas@SONET.CRIMEA.UA: fts, du, find]
To: None <tech-userlevel@NetBSD.org>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: tech-userlevel
Date: 05/14/1999 22:25:46
From bugtraq ... Someone with free time should probably check if this applies
to us ...

-----Forwarded message from Stas Kisel <stas@SONET.CRIMEA.UA>-----

	by antioche.lip6.fr (8.8.8/8.8.5) with ESMTP id AAA06015
	for <bouyer@ANTIOCHE.lip6.fr>; Fri, 14 May 1999 00:42:52 +0200 (MEST)
          by isis.lip6.fr (8.8.8/jtpda-5.2.9.1+lip6) with ESMTP id AAA24953
          for <bouyer@ANTIOCHE.LIP6.FR>; Fri, 14 May 1999 00:42:50 +0200 (MET DST)
          spool id 862259 for BUGTRAQ@NETSPACE.ORG; Thu, 13 May 1999 21:21:54
          +0000
Approved-By: aleph1@UNDERGROUND.ORG
          netspace.org (8.8.7/8.8.7) with ESMTP id HAA17097 for
          <bugtraq@netspace.org>; Wed, 12 May 1999 07:30:27 -0400
          Wed, 12 May 1999 14:32:42 +0400 (MSD)
Message-ID: <199905121032.OAA12043@sonet.crimea.ua>
Date: 	Wed, 12 May 1999 14:32:42 +0400
Reply-To: Stas Kisel <stas@SONET.CRIMEA.UA>
Sender: Bugtraq List <BUGTRAQ@netspace.org>
From: Stas Kisel <stas@SONET.CRIMEA.UA>
Subject:      fts, du, find
To: BUGTRAQ@netspace.org

Hi.

I use FreeBSD-2.2.8 and FreeBSD-2.2.7 and I know that these versions are
no longer supported, but:
1. There are many people still using 2.2
2. This bug probably applies to FreeBSD-3.1 and ever to OpenBSD and other.

Approximately a month ago I've found a very strange behaviour of 'du'
with long direstory structures. I left this alone due to lack of time,
but some days ago I saw an article on bugtraq concerning similar
behaviour of 'find'.

There is a one bug in libc causing this behaviour. I have a patch, but
I did not tested it much ;)

Both 'find' and 'du' use 'fts' (fts_read,...) functions to traverse
directory structure.
fts uses realloc() to reallocate memory in quite complex lists.
There is a bug in adjusting pointers after realloc().
So when dealing with large directory structures (when realloc() needed),
some pointers can point to free()-ed memory.

I have no exploit and probably will no have a free time (I think
3 days is more than enough) for doing it, but I beleive it is
possible to exploit this bug using carefully designed directory
tree to execute arbitrary commands as root during
/etc/daily->/etc/security->find.
REMOTE ROOT EXPLOIT (POSSIBLE).
At least it is possible to hide setuid binary this way in home dir or in /tmp.

The following patch is designed for FreeBSD-2.2.8-RELEASE libc.
There was the following ID in the beginning of the source file.
/*      $OpenBSD: fts.c,v 1.9 1997/08/02 00:13:49 millert Exp $ */
I've only tested this patch on one machine during one day, so
it is probably buggy.
If you'll apply this patch, please drop me a line if there was any side effect
and I'll do a followup in the bugtraq, say, on the Friday.

------------------ patch ----------------------------------------
--- /usr/src/lib/libc/gen/fts.c.orig	Tue May 11 13:37:49 1999
+++ /usr/src/lib/libc/gen/fts.c	Wed May 12 13:16:08 1999
@@ -740,8 +740,26 @@
 	 * If had to realloc the path, adjust the addresses for the rest
 	 * of the tree.
 	 */
-	if (adjaddr)
+	if (adjaddr){
 		fts_padjust(sp, adjaddr);
+		/* Adjust the list, because we want to return it robust. */
+/* fix p->fts_path and p->fts_accpath
+   p->fts_accpath can be:
+	either cur->fts_path	(adjust, because cur is already adjusted)
+	either p->fts_path	(adjust)
+	either p->fts_name	(do not adjust)
+   I'm also almost sure that in first case cur->fts_path=p->fts_path...
+*/
+#define	ADJUST1(p) if((p)->fts_path != adjaddr){	\
+	if((p)->fts_accpath != (p)->fts_name){		\
+		(p)->fts_accpath =			\
+			(char *)adjaddr + ((p)->fts_accpath - (p)->fts_path);\
+	}						\
+	(p)->fts_path = adjaddr;			\
+}
+		for (p = head; p; p = p->fts_link)
+			ADJUST1(p);
+	}

 	/*
 	 * If not changing directories, reset the path back to original
@@ -974,18 +992,18 @@
 {
 	FTSENT *p;

-#define	ADJUST(p) {							\
+#define	ADJUST2(p) {							\
 	(p)->fts_accpath =						\
 	    (char *)addr + ((p)->fts_accpath - (p)->fts_path);		\
 	(p)->fts_path = addr;						\
 }
 	/* Adjust the current set of children. */
 	for (p = sp->fts_child; p; p = p->fts_link)
-		ADJUST(p);
+		ADJUST2(p);

 	/* Adjust the rest of the tree. */
 	for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
-		ADJUST(p);
+		ADJUST2(p);
 		p = p->fts_link ? p->fts_link : p->fts_parent;
 	}
 }
------------------ endpatch ----------------------------------------

--
Stas Kisel
Open Tavrical College		Sysadmin	stas@sonet.crimea.ua
Simferopol State University	Web-designer	stas@ccssu.crimea.ua

-----End of forwarded message-----

-- 
--
Manuel Bouyer, LIP6, Universite Paris VI.           Manuel.Bouyer@lip6.fr
     {Net,Free}BSD: 22 ans d'experience feront toujours la difference
--