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)