Module Name:    othersrc
Committed By:   lukem
Date:           Thu Jan 24 02:52:48 UTC 2019

Modified Files:
        othersrc/libexec/tnftpd/libnetbsd: ftpfts.h fts_open.c

Log Message:
sync to fts.c 1.49, fts.h 1.19

Update from NetBSD src/lib/libc/gen/fts.c 1.38 to 1.49.
Update from NetBSD src/include/fts.h 1.18 to 1.19.

Notable changes:
- Minimize changes from upstream NetBSD methods.
- Bump fts_level from short to int to avoid a potential DoS.
- Make sure fts_statp is NULL when FTS_NOSTAT is set.
- Use [non-standard] O_CLOEXEC instead of fcntl(FD_CLOEXEC).
- Avoid potential integer overflow.
- Fix double free in fts_read()/fts_close().
- Use calloc(1, ...) instead of malloc(...) & memset.


To generate a diff of this commit:
cvs rdiff -u -r1.8 -r1.9 othersrc/libexec/tnftpd/libnetbsd/ftpfts.h
cvs rdiff -u -r1.12 -r1.13 othersrc/libexec/tnftpd/libnetbsd/fts_open.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: othersrc/libexec/tnftpd/libnetbsd/ftpfts.h
diff -u othersrc/libexec/tnftpd/libnetbsd/ftpfts.h:1.8 othersrc/libexec/tnftpd/libnetbsd/ftpfts.h:1.9
--- othersrc/libexec/tnftpd/libnetbsd/ftpfts.h:1.8	Sun Mar  1 02:50:11 2009
+++ othersrc/libexec/tnftpd/libnetbsd/ftpfts.h	Thu Jan 24 02:52:48 2019
@@ -1,5 +1,5 @@
-/* $NetBSD: ftpfts.h,v 1.8 2009/03/01 02:50:11 lukem Exp $ */
-/*	from NetBSD: fts.h,v 1.18 2009/01/11 03:04:12 christos Exp */
+/* $NetBSD: ftpfts.h,v 1.9 2019/01/24 02:52:48 lukem Exp $ */
+/* from NetBSD: fts.h,v 1.19 2009/08/16 19:33:38 christos Exp */
 
 /*
  * Copyright (c) 1989, 1993
@@ -53,6 +53,9 @@
 #ifndef	__fts_dev_t
 #define	__fts_dev_t	dev_t
 #endif
+#ifndef	__fts_level_t
+#define	__fts_level_t	int
+#endif
 
 typedef struct {
 	struct _ftsent *fts_cur;	/* current node */
@@ -64,7 +67,7 @@ typedef struct {
 	unsigned int fts_pathlen;	/* sizeof(path) */
 	unsigned int fts_nitems;	/* elements in the sort array */
 	int (*fts_compar)		/* compare function */
-	    (const struct _ftsent **, const struct _ftsent **);
+		(const struct _ftsent **, const struct _ftsent **);
 
 #define	FTS_COMFOLLOW	0x001		/* follow command line symlinks */
 #define	FTS_LOGICAL	0x002		/* logical walk */
@@ -100,7 +103,7 @@ typedef struct _ftsent {
 
 #define	FTS_ROOTPARENTLEVEL	-1
 #define	FTS_ROOTLEVEL		 0
-	short fts_level;		/* depth (-1 to N) */
+	__fts_level_t fts_level;		/* depth (-1 to N) */
 
 #define	FTS_D		 1		/* preorder directory */
 #define	FTS_DC		 2		/* directory that causes cycles */

Index: othersrc/libexec/tnftpd/libnetbsd/fts_open.c
diff -u othersrc/libexec/tnftpd/libnetbsd/fts_open.c:1.12 othersrc/libexec/tnftpd/libnetbsd/fts_open.c:1.13
--- othersrc/libexec/tnftpd/libnetbsd/fts_open.c:1.12	Sun Mar  1 03:23:00 2009
+++ othersrc/libexec/tnftpd/libnetbsd/fts_open.c	Thu Jan 24 02:52:48 2019
@@ -1,5 +1,5 @@
-/* $NetBSD: fts_open.c,v 1.12 2009/03/01 03:23:00 lukem Exp $ */
-/*	from NetBSD: fts.c,v 1.38 2009/02/28 14:34:18 pgoyette Exp */
+/* $NetBSD: fts_open.c,v 1.13 2019/01/24 02:52:48 lukem Exp $ */
+/* from NetBSD: fts.c,v 1.49 2016/05/31 07:49:09 pgoyette Exp */
 
 /*-
  * Copyright (c) 1990, 1993, 1994
@@ -32,6 +32,40 @@
 
 #include "tnftpd.h"
 
+#if 0
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)fts.c	8.6 (Berkeley) 8/14/94";
+#else
+__RCSID("$NetBSD: fts_open.c,v 1.13 2019/01/24 02:52:48 lukem Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if ! HAVE_NBTOOL_CONFIG_H
+#define	HAVE_STRUCT_DIRENT_D_NAMLEN
+#endif
+
+#endif
+
 static FTSENT	*fts_alloc(FTS *, const char *, size_t);
 static FTSENT	*fts_build(FTS *, int);
 static void	 fts_free(FTSENT *);
@@ -42,9 +76,9 @@ static size_t	 fts_pow2(size_t);
 static int	 fts_palloc(FTS *, size_t);
 static void	 fts_padjust(FTS *, FTSENT *);
 static FTSENT	*fts_sort(FTS *, FTSENT *, size_t);
-static unsigned short	 fts_stat(FTS *, FTSENT *, int);
+static unsigned short fts_stat(FTS *, FTSENT *, int);
 static int	 fts_safe_changedir(const FTS *, const FTSENT *, int,
-		    const char *);
+    const char *);
 
 #if defined(ALIGNBYTES) && defined(ALIGN)
 #define	FTS_ALLOC_ALIGNED	1
@@ -52,6 +86,23 @@ static int	 fts_safe_changedir(const FTS
 #undef	FTS_ALLOC_ALIGNED
 #endif
 
+#ifndef ftsent_namelen_truncate
+#define ftsent_namelen_truncate(a)	\
+    ((a) > UINT_MAX ? UINT_MAX : (unsigned int)(a))
+#endif
+#ifndef ftsent_pathlen_truncate
+#define ftsent_pathlen_truncate(a) \
+    ((a) > UINT_MAX ? UINT_MAX : (unsigned int)(a))
+#endif
+#ifndef fts_pathlen_truncate
+#define fts_pathlen_truncate(a)	\
+    ((a) > UINT_MAX ? UINT_MAX : (unsigned int)(a))
+#endif
+#ifndef fts_nitems_truncate
+#define fts_nitems_truncate(a) \
+    ((a) > UINT_MAX ? UINT_MAX : (unsigned int)(a))
+#endif
+
 #define	ISDOT(a)	(a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
 
 #define	CLR(opt)	(sp->fts_options &= ~(opt))
@@ -80,6 +131,8 @@ fts_open(char * const *argv, int options
 	FTSENT *parent, *tmp = NULL;	/* pacify gcc */
 	size_t len;
 
+	_DIAGASSERT(argv != NULL);
+
 	/* Options check. */
 	if (options & ~FTS_OPTIONMASK) {
 		errno = EINVAL;
@@ -87,9 +140,8 @@ fts_open(char * const *argv, int options
 	}
 
 	/* Allocate/initialize the stream */
-	if ((sp = malloc((unsigned int)sizeof(FTS))) == NULL)
+	if ((sp = calloc(1, sizeof(FTS))) == NULL)
 		return (NULL);
-	memset(sp, 0, sizeof(FTS));
 	sp->fts_compar = compar;
 	sp->fts_options = options;
 
@@ -159,19 +211,18 @@ fts_open(char * const *argv, int options
 	sp->fts_cur->fts_info = FTS_INIT;
 
 	/*
-	 * If using chdir(2), grab a file descriptor pointing to dot to insure
+	 * If using chdir(2), grab a file descriptor pointing to dot to ensure
 	 * that we can get back here; this could be avoided for some paths,
 	 * but almost certainly not worth the effort.  Slashes, symbolic links,
 	 * and ".." are all fairly nasty problems.  Note, if we can't get the
 	 * descriptor we run anyway, just more slowly.
 	 */
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
 	if (!ISSET(FTS_NOCHDIR)) {
-		if ((sp->fts_rfd = open(".", O_RDONLY, 0)) == -1)
-			SET(FTS_NOCHDIR);
-		else if (fcntl(sp->fts_rfd, F_SETFD, FD_CLOEXEC) == -1) {
-			close(sp->fts_rfd);
+		if ((sp->fts_rfd = open(".", O_RDONLY | O_CLOEXEC, 0)) == -1)
 			SET(FTS_NOCHDIR);
-		}
 	}
 
 	if (nitems == 0)
@@ -192,6 +243,9 @@ fts_load(FTS *sp, FTSENT *p)
 	size_t len;
 	char *cp;
 
+	_DIAGASSERT(sp != NULL);
+	_DIAGASSERT(p != NULL);
+
 	/*
 	 * Load the stream structure for the next traversal.  Since we don't
 	 * actually enter the directory until after the preorder visit, set
@@ -204,7 +258,7 @@ fts_load(FTS *sp, FTSENT *p)
 	if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
 		len = strlen(++cp);
 		memmove(p->fts_name, cp, len + 1);
-		p->fts_namelen = len;
+		p->fts_namelen = ftsent_namelen_truncate(len);
 	}
 	p->fts_accpath = p->fts_path = sp->fts_path;
 	sp->fts_dev = p->fts_dev;
@@ -216,6 +270,8 @@ fts_close(FTS *sp)
 	FTSENT *freep, *p;
 	int saved_errno = 0;
 
+	_DIAGASSERT(sp != NULL);
+
 	/*
 	 * This still works if we haven't read anything -- the dummy structure
 	 * points to the root list, so we step through to the end of the root
@@ -289,6 +345,8 @@ fts_read(FTS *sp)
 	char *t;
 	int saved_errno;
 
+	_DIAGASSERT(sp != NULL);
+
 	/* If finished or unrecoverable error, return NULL. */
 	if (sp->fts_cur == NULL || ISSET(FTS_STOP))
 		return (NULL);
@@ -316,13 +374,10 @@ fts_read(FTS *sp)
 	    (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
 		p->fts_info = fts_stat(sp, p, 1);
 		if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
-			if ((p->fts_symfd = open(".", O_RDONLY, 0)) == -1) {
-				p->fts_errno = errno;
-				p->fts_info = FTS_ERR;
-			} else if (fcntl(p->fts_symfd, F_SETFD, FD_CLOEXEC) == -1) {
+			if ((p->fts_symfd = open(".", O_RDONLY | O_CLOEXEC, 0))
+			    == -1) {
 				p->fts_errno = errno;
 				p->fts_info = FTS_ERR;
-				close(p->fts_symfd);
 			} else
 				p->fts_flags |= FTS_SYMFOLLOW;
 		}
@@ -381,8 +436,21 @@ fts_read(FTS *sp)
 		goto name;
 	}
 
+next:	
 	/* Move to the next node on this level. */
-next:	tmp = p;
+	tmp = p;
+
+	/* 
+	 * We are going to free sp->fts_cur, set it to NULL so 
+	 * that fts_close() does not attempt to free it again 
+	 * if we exit without setting it to a new value because
+	 * FCHDIR() failed below.
+	 */
+#if 0
+	assert(tmp == sp->fts_cur);
+#endif
+	sp->fts_cur = NULL;
+	
 	if ((p = p->fts_link) != NULL) {
 		fts_free(tmp);
 
@@ -410,13 +478,9 @@ next:	tmp = p;
 			p->fts_info = fts_stat(sp, p, 1);
 			if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
 				if ((p->fts_symfd =
-				    open(".", O_RDONLY, 0)) == -1) {
-					p->fts_errno = errno;
-					p->fts_info = FTS_ERR;
-				} else if (fcntl(p->fts_symfd, F_SETFD, FD_CLOEXEC) == -1) {
+				    open(".", O_RDONLY | O_CLOEXEC, 0)) == -1) {
 					p->fts_errno = errno;
 					p->fts_info = FTS_ERR;
-					close(p->fts_symfd);
 				} else
 					p->fts_flags |= FTS_SYMFOLLOW;
 			}
@@ -443,7 +507,7 @@ name:		t = sp->fts_path + NAPPEND(p->fts
 		return (sp->fts_cur = NULL);
 	}
 
-	/* Nul terminate the pathname. */
+	/* NUL terminate the pathname. */
 	sp->fts_path[p->fts_pathlen] = '\0';
 
 	/*
@@ -485,6 +549,9 @@ int
 fts_set(FTS *sp, FTSENT *p, int instr)
 {
 
+	_DIAGASSERT(sp != NULL);
+	_DIAGASSERT(p != NULL);
+
 	if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
 	    instr != FTS_NOINSTR && instr != FTS_SKIP) {
 		errno = EINVAL;
@@ -500,6 +567,8 @@ fts_children(FTS *sp, int instr)
 	FTSENT *p;
 	int fd;
 
+	_DIAGASSERT(sp != NULL);
+
 	if (instr && instr != FTS_NAMEONLY) {
 		errno = EINVAL;
 		return (NULL);
@@ -551,7 +620,7 @@ fts_children(FTS *sp, int instr)
 	    ISSET(FTS_NOCHDIR))
 		return (sp->fts_child = fts_build(sp, instr));
 
-	if ((fd = open(".", O_RDONLY, 0)) == -1)
+	if ((fd = open(".", O_RDONLY | O_CLOEXEC, 0)) == -1)
 		return (sp->fts_child = NULL);
 	sp->fts_child = fts_build(sp, instr);
 	if (fchdir(fd)) {
@@ -593,6 +662,8 @@ fts_build(FTS *sp, int type)
 #endif
 	char *cp = NULL;	/* pacify gcc */
 
+	_DIAGASSERT(sp != NULL);
+
 	/* Set current node pointer. */
 	cur = sp->fts_cur;
 
@@ -606,7 +677,7 @@ fts_build(FTS *sp, int type)
 	else
 		oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
 #else
-#define __opendir2(path, flag) opendir(path)
+#define	__opendir2(path, flag) opendir(path)
 #endif
 	if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
 		if (type == BREAD) {
@@ -683,6 +754,8 @@ fts_build(FTS *sp, int type)
 	len++;
 	maxlen = sp->fts_pathlen - len;
 
+#if  0
+#if defined(__FTS_COMPAT_LEVEL)
 	if (cur->fts_level == SHRT_MAX) {
 		(void)closedir(dirp);
 		cur->fts_info = FTS_ERR;
@@ -690,6 +763,8 @@ fts_build(FTS *sp, int type)
 		errno = ENAMETOOLONG;
 		return (NULL);
 	}
+#endif
+#endif
 
 	level = cur->fts_level + 1;
 
@@ -753,7 +828,7 @@ mem1:				saved_errno = errno;
 		}
 #endif
 		p->fts_level = level;
-		p->fts_pathlen = len + dnamlen;
+		p->fts_pathlen = ftsent_pathlen_truncate(len + dnamlen);
 		p->fts_parent = sp->fts_cur;
 
 #ifdef FTS_WHITEOUT
@@ -861,6 +936,9 @@ fts_stat(FTS *sp, FTSENT *p, int follow)
 	__fts_stat_t *sbp, sb;
 	int saved_errno;
 
+	_DIAGASSERT(sp != NULL);
+	_DIAGASSERT(p != NULL);
+
 	/* If user needs stat info, stat buffer already allocated. */
 	sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
 
@@ -937,6 +1015,9 @@ fts_sort(FTS *sp, FTSENT *head, size_t n
 {
 	FTSENT **ap, *p;
 
+	_DIAGASSERT(sp != NULL);
+	_DIAGASSERT(head != NULL);
+
 	/*
 	 * Construct an array of pointers to the structures and call qsort(3).
 	 * Reassemble the array in the order returned by qsort.  If unable to
@@ -951,7 +1032,7 @@ fts_sort(FTS *sp, FTSENT *head, size_t n
 		if (new == 0)
 			return (head);
 		sp->fts_array = new;
-		sp->fts_nitems = nitems + 40;
+		sp->fts_nitems = fts_nitems_truncate(nitems + 40);
 	}
 	for (ap = sp->fts_array, p = head; p; p = p->fts_link)
 		*ap++ = p;
@@ -971,6 +1052,9 @@ fts_alloc(FTS *sp, const char *name, siz
 	size_t len;
 #endif
 
+	_DIAGASSERT(sp != NULL);
+	_DIAGASSERT(name != NULL);
+
 #if defined(FTS_ALLOC_ALIGNED)
 	/*
 	 * The file name is a variable length array and no stat structure is
@@ -1000,10 +1084,13 @@ fts_alloc(FTS *sp, const char *name, siz
 		}
 #endif
 
+        if (ISSET(FTS_NOSTAT))
+                p->fts_statp = NULL;
+
 	/* Copy the name plus the trailing NULL. */
 	memmove(p->fts_name, name, namelen + 1);
 
-	p->fts_namelen = namelen;
+	p->fts_namelen = ftsent_namelen_truncate(namelen);
 	p->fts_path = sp->fts_path;
 	p->fts_errno = 0;
 	p->fts_flags = 0;
@@ -1068,6 +1155,8 @@ fts_palloc(FTS *sp, size_t size)
 {
 	char *new;
 
+	_DIAGASSERT(sp != NULL);
+
 #ifdef __FTS_COMPAT_LENGTH
 	/* Protect against fts_pathlen overflow. */
 	if (size > USHRT_MAX + 1) {
@@ -1080,7 +1169,7 @@ fts_palloc(FTS *sp, size_t size)
 	if (new == 0)
 		return (1);
 	sp->fts_path = new;
-	sp->fts_pathlen = size;
+	sp->fts_pathlen = fts_pathlen_truncate(size);
 	return (0);
 }
 
@@ -1094,6 +1183,8 @@ fts_padjust(FTS *sp, FTSENT *head)
 	FTSENT *p;
 	char *addr;
 
+	_DIAGASSERT(sp != NULL);
+
 #define	ADJUST(p) do {							\
 	if ((p)->fts_accpath != (p)->fts_name)				\
 		(p)->fts_accpath =					\
@@ -1119,6 +1210,8 @@ fts_maxarglen(char * const *argv)
 {
 	size_t len, max;
 
+	_DIAGASSERT(argv != NULL);
+
 	for (max = 0; *argv; ++argv)
 		if ((len = strlen(*argv)) > max)
 			max = len;
@@ -1139,7 +1232,7 @@ fts_safe_changedir(const FTS *sp, const 
 	if (ISSET(FTS_NOCHDIR))
 		return 0;
 
-	if (oldfd < 0 && (fd = open(path, O_RDONLY)) == -1)
+	if (oldfd < 0 && (fd = open(path, O_RDONLY | O_CLOEXEC)) == -1)
 		return -1;
 
 	if (fstat(fd, &sb) == -1)

Reply via email to