Fix problem reported by Kris Kennaway <kris@obsecurity.org>; In

the default case fts(3) uses chdir("..") to ascend the tree. The
sequence of chdir's can be intercepted by a malicious user who
moves a subtree that fts is currently traversing to a higher level,
thus making fts operate outside it's original starting directory.
This commit is contained in:
christos 2001-06-05 17:05:11 +00:00
parent 8f12cb2799
commit 4a37917f04
1 changed files with 29 additions and 4 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: __fts13.c,v 1.32 2000/11/05 20:05:29 christos Exp $ */
/* $NetBSD: __fts13.c,v 1.33 2001/06/05 17:05:11 christos Exp $ */
/*-
* Copyright (c) 1990, 1993, 1994
@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
#else
__RCSID("$NetBSD: __fts13.c,v 1.32 2000/11/05 20:05:29 christos Exp $");
__RCSID("$NetBSD: __fts13.c,v 1.33 2001/06/05 17:05:11 christos Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
@ -494,8 +494,33 @@ name: t = sp->fts_path + NAPPEND(p->fts_parent);
return (NULL);
}
(void)close(p->fts_symfd);
} else if (!(p->fts_flags & FTS_DONTCHDIR)) {
if (CHDIR(sp, "..")) {
} else if (!(p->fts_flags & FTS_DONTCHDIR) &&
!ISSET(FTS_NOCHDIR)) {
int fd;
struct STAT sb;
if ((fd = open("..", O_RDONLY)) == -1) {
SET(FTS_STOP);
return (NULL);
}
if (fstat(fd, &sb) == -1) {
saved_errno = errno;
(void)close(fd);
errno = saved_errno;
SET(FTS_STOP);
return (NULL);
}
if (sb.st_ino != p->fts_parent->fts_ino ||
sb.st_dev != p->fts_parent->fts_dev) {
(void)close(fd);
errno = ENOENT;
SET(FTS_STOP);
return (NULL);
}
if (fchdir(fd) == -1) {
saved_errno = errno;
(void)close(fd);
errno = saved_errno;
SET(FTS_STOP);
return (NULL);
}