diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index d1253916d..b89f37467 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,11 @@ +2014-05-20 Corinna Vinschen + + * libc/bsdlib.cc (forkpty): Close master and slave if fork fails to + avoid resource leak (CID 59997). + * libc/fts.c: Update to FreeBSD version 1.39 (CID 59947). + * libc/minires.c (minires_get_search): Fix out-of-bounds read from + words array (CID 59937). + 2014-05-20 Corinna Vinschen * flock.cc (delete_lock_in_parent): Use LIST_FOREACH_SAFE to avoid diff --git a/winsup/cygwin/libc/bsdlib.cc b/winsup/cygwin/libc/bsdlib.cc index 66cffc7d3..696a9f856 100644 --- a/winsup/cygwin/libc/bsdlib.cc +++ b/winsup/cygwin/libc/bsdlib.cc @@ -150,6 +150,8 @@ forkpty (int *amaster, char *name, const struct termios *termp, switch (pid = fork ()) { case -1: + close (master); + close (slave); return -1; case 0: close (master); diff --git a/winsup/cygwin/libc/fts.c b/winsup/cygwin/libc/fts.c index e82ec3fd7..003f85146 100644 --- a/winsup/cygwin/libc/fts.c +++ b/winsup/cygwin/libc/fts.c @@ -34,14 +34,9 @@ static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; #endif /* LIBC_SCCS and not lint */ #endif -#ifdef __CYGWIN__ -#include "winsup.h" -#include -#define _open open -#define _close close -#endif + #include -__FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/gen/fts.c,v 1.27 2004/06/08 06:23:23 das Exp $"); +__FBSDID("$FreeBSD: src/lib/libc/gen/fts.c,v 1.39 2013/02/11 02:00:16 svnexp Exp $"); #ifndef __CYGWIN__ #include "namespace.h" @@ -57,19 +52,37 @@ __FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/gen/fts.c,v 1.27 2004/06/08 06: #include #include #include -#ifndef __CYGWIN__ +#ifdef __CYGWIN__ +#include "winsup.h" +#include +#define _open open +#define _close close +#define _dirfd dirfd +#ifdef __x86_64__ +#define _fstat fstat +#else +extern int stat64 (const char *path, struct stat *buf); +extern int fstat64 (int fd, struct stat *buf); +extern int lstat64 (const char *path, struct stat *buf); +#define stat(a,b) stat64((a),(b)) +#define _fstat(a,b) fstat64((a),(b)) +#define lstat(a,b) lstat64((a),(b)) +#endif +#else #include "un-namespace.h" + +#include "gen-private.h" #endif -static FTSENT *fts_alloc(FTS *, const char *, int); +static FTSENT *fts_alloc(FTS *, const char *, size_t); static FTSENT *fts_build(FTS *, int); static void fts_lfree(FTSENT *); static void fts_load(FTS *, FTSENT *); static size_t fts_maxarglen(char * const *); static void fts_padjust(FTS *, FTSENT *); static int fts_palloc(FTS *, size_t); -static FTSENT *fts_sort(FTS *, FTSENT *, int); -static u_short fts_stat(FTS *, FTSENT *, int); +static FTSENT *fts_sort(FTS *, FTSENT *, size_t); +static int fts_stat(FTS *, FTSENT *, int); static int fts_safe_changedir(FTS *, FTSENT *, int, const char *); static int fts_ufslinks(FTS *, const FTSENT *); @@ -110,6 +123,7 @@ struct _fts_private { #ifndef __CYGWIN__ static const char *ufslike_filesystems[] = { "ufs", + "zfs", "nfs", "nfs4", "ext2fs", @@ -126,9 +140,8 @@ fts_open(argv, options, compar) struct _fts_private *priv; FTS *sp; FTSENT *p, *root; - int nitems; FTSENT *parent, *tmp; - int len; + size_t len, nitems; /* Options check. */ if (options & ~FTS_OPTIONMASK) { @@ -136,10 +149,15 @@ fts_open(argv, options, compar) return (NULL); } - /* Allocate/initialize the stream. */ - if ((priv = malloc(sizeof(*priv))) == NULL) + /* fts_open() requires at least one path */ + if (*argv == NULL) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream. */ + if ((priv = calloc(1, sizeof(*priv))) == NULL) return (NULL); - memset(priv, 0, sizeof(*priv)); sp = &priv->ftsp_fts; sp->fts_compar = compar; sp->fts_options = options; @@ -218,7 +236,8 @@ fts_open(argv, options, compar) * and ".." are all fairly nasty problems. Note, if we can't get the * descriptor we run anyway, just more slowly. */ - if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = _open(".", O_RDONLY, 0)) < 0) + if (!ISSET(FTS_NOCHDIR) && + (sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) SET(FTS_NOCHDIR); return (sp); @@ -231,11 +250,9 @@ mem1: free(sp); } static void -fts_load(sp, p) - FTS *sp; - FTSENT *p; +fts_load(FTS *sp, FTSENT *p) { - int len; + size_t len; char *cp; /* @@ -257,8 +274,7 @@ fts_load(sp, p) } int -fts_close(sp) - FTS *sp; +fts_close(FTS *sp) { FTSENT *freep, *p; int saved_errno; @@ -312,8 +328,7 @@ fts_close(sp) ? p->fts_pathlen - 1 : p->fts_pathlen) FTSENT * -fts_read(sp) - FTS *sp; +fts_read(FTS *sp) { FTSENT *p, *tmp; int instr; @@ -347,7 +362,8 @@ fts_read(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)) < 0) { + if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC, + 0)) < 0) { p->fts_errno = errno; p->fts_info = FTS_ERR; } else @@ -438,7 +454,7 @@ 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)) < 0) { + _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) { p->fts_errno = errno; p->fts_info = FTS_ERR; } else @@ -506,10 +522,7 @@ name: t = sp->fts_path + NAPPEND(p->fts_parent); */ /* ARGSUSED */ int -fts_set(sp, p, instr) - FTS *sp __attribute__ ((unused)); - FTSENT *p; - int instr; +fts_set(FTS *sp, FTSENT *p, int instr) { if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW && instr != FTS_NOINSTR && instr != FTS_SKIP) { @@ -521,9 +534,7 @@ fts_set(sp, p, instr) } FTSENT * -fts_children(sp, instr) - FTS *sp; - int instr; +fts_children(FTS *sp, int instr) { FTSENT *p; int fd; @@ -579,11 +590,13 @@ fts_children(sp, instr) ISSET(FTS_NOCHDIR)) return (sp->fts_child = fts_build(sp, instr)); - if ((fd = _open(".", O_RDONLY, 0)) < 0) + if ((fd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) return (NULL); sp->fts_child = fts_build(sp, instr); - if (fchdir(fd)) + if (fchdir(fd)) { + (void)_close(fd); return (NULL); + } (void)_close(fd); return (sp->fts_child); } @@ -631,20 +644,18 @@ fts_set_clientptr(FTS *sp, void *clientptr) * been found, cutting the stat calls by about 2/3. */ static FTSENT * -fts_build(sp, type) - FTS *sp; - int type; +fts_build(FTS *sp, int type) { struct dirent *dp; FTSENT *p, *head; - int nitems; FTSENT *cur, *tail; DIR *dirp; void *oldaddr; - size_t dnamlen; - int cderrno, descend, len, level, maxlen, nlinks, /*oflag,*/ saved_errno, - nostat, doadjust; char *cp; + int cderrno, descend, /* oflag, */ saved_errno, nostat, doadjust; + long level; + long nlinks; /* has to be signed because -1 is a magic value */ + size_t dnamlen, len, maxlen, nitems; /* Set current node pointer. */ cur = sp->fts_cur; @@ -711,7 +722,7 @@ fts_build(sp, type) */ cderrno = 0; if (nlinks || type == BREAD) { - if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { + if (fts_safe_changedir(sp, cur, _dirfd(dirp), NULL)) { if (nlinks && type == BREAD) cur->fts_errno = errno; cur->fts_flags |= FTS_DONTCHDIR; @@ -756,9 +767,9 @@ fts_build(sp, type) if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) continue; - if ((p = fts_alloc(sp, dp->d_name, (int)dnamlen)) == NULL) + if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL) goto mem1; - if ((int) dnamlen >= maxlen) { /* include space for NUL */ + if (dnamlen >= maxlen) { /* include space for NUL */ oldaddr = sp->fts_path; if (fts_palloc(sp, dnamlen + len + 1)) { /* @@ -785,21 +796,6 @@ mem1: saved_errno = errno; maxlen = sp->fts_pathlen - len; } - if (len + dnamlen >= USHRT_MAX) { - /* - * In an FTSENT, fts_pathlen is a u_short so it is - * possible to wraparound here. If we do, free up - * the current structure and the structures already - * allocated, then error out with ENAMETOOLONG. - */ - free(p); - fts_lfree(head); - (void)closedir(dirp); - cur->fts_info = FTS_ERR; - SET(FTS_STOP); - errno = ENAMETOOLONG; - return (NULL); - } p->fts_level = level; p->fts_parent = sp->fts_cur; p->fts_pathlen = len + dnamlen; @@ -817,7 +813,7 @@ mem1: saved_errno = errno; p->fts_info = FTS_NSOK; p->fts_accpath = cur->fts_accpath; } else if (nlinks == 0 -#if defined(DT_DIR) +#ifdef DT_DIR || (nostat && dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) #endif @@ -865,11 +861,8 @@ mem1: saved_errno = errno; * If not changing directories, reset the path back to original * state. */ - if (ISSET(FTS_NOCHDIR)) { - if (len == sp->fts_pathlen || nitems == 0) - --cp; - *cp = '\0'; - } + if (ISSET(FTS_NOCHDIR)) + sp->fts_path[cur->fts_pathlen] = '\0'; /* * If descended after called from fts_children or after called from @@ -900,11 +893,8 @@ mem1: saved_errno = errno; return (head); } -static u_short -fts_stat(sp, p, follow) - FTS *sp; - FTSENT *p; - int follow; +static int +fts_stat(FTS *sp, FTSENT *p, int follow) { FTSENT *t; dev_t dev; @@ -932,16 +922,16 @@ fts_stat(sp, p, follow) * fail, set the errno from the stat call. */ if (ISSET(FTS_LOGICAL) || follow) { - if (stat64(p->fts_accpath, sbp)) { + if (stat(p->fts_accpath, sbp)) { saved_errno = errno; - if (!lstat64(p->fts_accpath, sbp)) { + if (!lstat(p->fts_accpath, sbp)) { errno = 0; return (FTS_SLNONE); } p->fts_errno = saved_errno; goto err; } - } else if (lstat64(p->fts_accpath, sbp)) { + } else if (lstat(p->fts_accpath, sbp)) { p->fts_errno = errno; err: memset(sbp, 0, sizeof(struct stat)); return (FTS_NS); @@ -999,10 +989,7 @@ fts_compar(const void *a, const void *b) } static FTSENT * -fts_sort(sp, head, nitems) - FTS *sp; - FTSENT *head; - int nitems; +fts_sort(FTS *sp, FTSENT *head, size_t nitems) { FTSENT **ap, *p; @@ -1031,10 +1018,7 @@ fts_sort(sp, head, nitems) } static FTSENT * -fts_alloc(sp, name, namelen) - FTS *sp; - const char *name; - int namelen; +fts_alloc(FTS *sp, const char *name, size_t namelen) { FTSENT *p; size_t len; @@ -1081,8 +1065,7 @@ fts_alloc(sp, name, namelen) } static void -fts_lfree(head) - FTSENT *head; +fts_lfree(FTSENT *head) { FTSENT *p; @@ -1100,24 +1083,10 @@ fts_lfree(head) * plus 256 bytes so don't realloc the path 2 bytes at a time. */ static int -fts_palloc(sp, more) - FTS *sp; - size_t more; +fts_palloc(FTS *sp, size_t more) { sp->fts_pathlen += more + 256; - /* - * Check for possible wraparound. In an FTS, fts_pathlen is - * a signed int but in an FTSENT it is an unsigned short. - * We limit fts_pathlen to USHRT_MAX to be safe in both cases. - */ - if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) { - if (sp->fts_path) - free(sp->fts_path); - sp->fts_path = NULL; - errno = ENAMETOOLONG; - return (1); - } sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen); return (sp->fts_path == NULL); } @@ -1127,9 +1096,7 @@ fts_palloc(sp, more) * already returned. */ static void -fts_padjust(sp, head) - FTS *sp; - FTSENT *head; +fts_padjust(FTS *sp, FTSENT *head) { FTSENT *p; char *addr = sp->fts_path; @@ -1170,11 +1137,7 @@ fts_maxarglen(argv) * Assumes p->fts_dev and p->fts_ino are filled in. */ static int -fts_safe_changedir(sp, p, fd, path) - FTS *sp; - FTSENT *p; - int fd; - const char *path; +fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const char *path) { int ret, oerrno, newfd; struct stat sb; @@ -1182,9 +1145,10 @@ fts_safe_changedir(sp, p, fd, path) newfd = fd; if (ISSET(FTS_NOCHDIR)) return (0); - if (fd < 0 && (newfd = _open(path, O_RDONLY, 0)) < 0) + if (fd < 0 && (newfd = _open(path, O_RDONLY | O_DIRECTORY | + O_CLOEXEC, 0)) < 0) return (-1); - if (fstat64(newfd, &sb)) { + if (_fstat(newfd, &sb)) { ret = -1; goto bail; } diff --git a/winsup/cygwin/libc/minires.c b/winsup/cygwin/libc/minires.c index c73ad3c58..b25c927c9 100644 --- a/winsup/cygwin/libc/minires.c +++ b/winsup/cygwin/libc/minires.c @@ -77,7 +77,7 @@ void minires_get_search(char * string, res_state statp) ptr += sizes[j]; DPRINTF(debug, "search \"%s\"\n", words[j]); } - else + else if (j < MAXDNSRCH + 1) DPRINTF(debug, "no space for \"%s\"\n", words[j]); } }