ATOFOO_TEST_OBJS = atofoo_test.lo locale_stub.lo
+MKTEMP_TEST_OBJS = mktemp_test.lo locale_stub.lo
+
PARSELN_TEST_OBJS = parseln_test.lo locale_stub.lo
PROGNAME_TEST_OBJS = progname_test.lo progname.lo
hltq_test: $(HLTQ_TEST_OBJS) libsudo_util.la
$(LIBTOOL) --mode=link $(CC) -o $@ $(HLTQ_TEST_OBJS) libsudo_util.la $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS)
+mktemp_test: $(MKTEMP_TEST_OBJS) libsudo_util.la
+ $(LIBTOOL) --mode=link $(CC) -o $@ $(MKTEMP_TEST_OBJS) libsudo_util.la $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS)
+
parseln_test: $(PARSELN_TEST_OBJS) libsudo_util.la
$(LIBTOOL) --mode=link $(CC) -o $@ $(PARSELN_TEST_OBJS) libsudo_util.la $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS)
./globtest $(srcdir)/regress/glob/globtest.in || rval=`expr $$rval + $$?`; \
rm -rf fake; \
fi; \
+ if test -f mktemp_test; then \
+ ./mktemp_test || rval=`expr $$rval + $$?`; \
+ fi; \
./atofoo_test || rval=`expr $$rval + $$?`; \
./hltq_test || rval=`expr $$rval + $$?`; \
./progname_test || rval=`expr $$rval + $$?`; \
fnm_test.lo: $(srcdir)/regress/fnmatch/fnm_test.c $(incdir)/compat/fnmatch.h \
$(incdir)/sudo_compat.h $(top_builddir)/config.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/fnmatch/fnm_test.c
-fnm_test.o: fnm_test.lo
fnmatch.lo: $(srcdir)/fnmatch.c $(incdir)/compat/charclass.h \
$(incdir)/compat/fnmatch.h $(incdir)/sudo_compat.h \
$(top_builddir)/config.h
globtest.lo: $(srcdir)/regress/glob/globtest.c $(incdir)/compat/glob.h \
$(incdir)/sudo_compat.h $(top_builddir)/config.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/glob/globtest.c
-globtest.o: globtest.lo
hltq_test.lo: $(srcdir)/regress/tailq/hltq_test.c $(incdir)/compat/stdbool.h \
$(incdir)/sudo_compat.h $(incdir)/sudo_fatal.h \
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
$(top_builddir)/config.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/tailq/hltq_test.c
+inet_pton.lo: $(srcdir)/inet_pton.c $(incdir)/sudo_compat.h \
+ $(top_builddir)/config.h
+ $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/inet_pton.c
isblank.lo: $(srcdir)/isblank.c $(incdir)/sudo_compat.h $(top_builddir)/config.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/isblank.c
key_val.lo: $(srcdir)/key_val.c $(incdir)/compat/stdbool.h \
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/mksigname.c
mktemp.lo: $(srcdir)/mktemp.c $(incdir)/sudo_compat.h $(top_builddir)/config.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/mktemp.c
+mktemp_test.lo: $(srcdir)/regress/mktemp/mktemp_test.c \
+ $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
+ $(incdir)/sudo_fatal.h $(incdir)/sudo_util.h \
+ $(top_builddir)/config.h
+ $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/regress/mktemp/mktemp_test.c
parseln.lo: $(srcdir)/parseln.c $(incdir)/compat/stdbool.h \
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
--- /dev/null
+/*
+ * Copyright (c) 2010 Philip Guenther <guenther@openbsd.org>
+ *
+ * Public domain.
+ *
+ * Verify that mkdtemp() and mkstemps() doesn't overrun or underrun
+ * the template buffer and that it can generate names that don't
+ * contain any X's
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <unistd.h>
+
+#define SUDO_ERROR_WRAP 0
+
+#include "sudo_compat.h"
+#include "sudo_util.h"
+#include "sudo_fatal.h"
+
+#ifndef MAP_ANON
+# if defined(MAP_ANONYMOUS)
+# define MAP_ANON MAP_ANONYMOUS
+# endif
+#endif
+
+#define MAX_TEMPLATE_LEN 10
+#define MAX_TRIES 100
+#define MIN_Xs 6
+
+#define SUFFIX ".suff"
+#define SLEN (sizeof SUFFIX - 1)
+
+__dso_public int main(int argc, char *argv[]);
+
+/*
+ * verify that a path generated by mkdtemp() or mkstemp() looks like a
+ * reasonable expansion of the template and matches the fd. Returns true
+ * if all the X's were replaced with non-X's
+ */
+int
+check(int fd, char const *kind, char const *path, char const *prefix,
+ size_t plen, char const *suffix, size_t slen, int tlen)
+{
+ struct stat sb, fsb;
+ char const *p;
+
+ if (tlen < MIN_Xs) {
+ if (fd != -1)
+ sudo_fatalx("%s(%s) succeed with too few Xs", kind, path);
+ if (errno != EINVAL)
+ sudo_fatal("%s(%s) failed with wrong errno: %d", kind, path, errno);
+ return 1;
+ }
+ if (fd == -1)
+ sudo_fatal("%s(%s)", kind, path);
+ if (stat(path, &sb))
+ sudo_fatal("%s: stat(%s)", kind, path);
+ if (fd >= 0) {
+ if (fstat(fd, &fsb))
+ sudo_fatal("%s: fstat(%d==%s)", kind, fd, path);
+ if (sb.st_dev != fsb.st_dev || sb.st_ino != fsb.st_ino)
+ sudo_fatalx("%s: stat mismatch", kind);
+ }
+ if (memcmp(path, prefix, plen) != 0)
+ sudo_fatalx("%s: prefix changed! %s vs %s", kind, prefix, path);
+ if (memcmp(path + plen + tlen, suffix, slen + 1) != 0)
+ sudo_fatalx("%s: suffix changed! %s vs %s", kind, suffix, path);
+ for (p = path + plen; p < path + plen + tlen; p++)
+ if (*p == '\0')
+ sudo_fatalx("%s: unexpected truncation", kind);
+ else if (*p == 'X')
+ return 0;
+ return 1;
+}
+
+void
+try_mkdtemp(char *p, char const *prefix, int len)
+{
+ size_t plen = strlen(prefix);
+ int fd, tries, ok;
+
+ for (tries = 0; tries < MAX_TRIES; tries++) {
+ memcpy(p, prefix, plen);
+ memset(p + plen, 'X', len);
+ p[plen + len] = '\0';
+ fd = mkdtemp(p) ? -2 : -1;
+ ok = check(fd, "mkdtemp", p, prefix, plen, "", 0, len);
+ rmdir(p);
+ if (ok)
+ return;
+ }
+ sudo_fatalx("mkdtemp: exceeded MAX_TRIES");
+}
+
+void
+try_mkstemps(char *p, char const *prefix, int len, char const *suffix)
+{
+ size_t plen = strlen(prefix);
+ size_t slen = strlen(suffix);
+ int tries, fd, ok;
+
+ for (tries = 0; tries < MAX_TRIES; tries++) {
+ memcpy(p, prefix, plen);
+ memset(p + plen, 'X', len);
+ memcpy(p + plen + len, suffix, slen + 1);
+ fd = mkstemps(p, slen);
+ ok = check(fd, "mkstemp", p, prefix, plen, suffix, slen, len);
+ close(fd);
+ unlink(p);
+ if (ok)
+ return;
+ }
+ sudo_fatalx("mkstemps: exceeded MAX_TRIES");
+}
+
+int
+main(int argc, char *argv[])
+{
+ char cwd[PATH_MAX + 1];
+ char *p;
+ size_t clen;
+ long pg;
+ int i;
+
+ initprogname(argc > 0 ? argv[0] : "mktemp_test");
+
+ pg = sysconf(_SC_PAGESIZE);
+ if (getcwd(cwd, sizeof cwd - 1) == NULL)
+ sudo_fatal("getcwd");
+ clen = strlen(cwd);
+ cwd[clen++] = '/';
+ cwd[clen] = '\0';
+#ifdef MAP_ANON
+ p = mmap(NULL, pg * 3, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
+#else
+ i = open("/dev/zero", O_RDWR);
+ if (i == -1)
+ sudo_fatal("/dev/zero");
+ p = mmap(NULL, pg * 3, PROT_READ | PROT_WRITE, MAP_PRIVATE, i, 0);
+#endif
+ if (p == MAP_FAILED)
+ sudo_fatal("mmap");
+ if (mprotect(p, pg, PROT_NONE) || mprotect(p + pg * 2, pg, PROT_NONE))
+ sudo_fatal("mprotect");
+ p += pg;
+
+ i = MAX_TEMPLATE_LEN + 1;
+ while (i-- > 0) {
+ /* try first at the start of a page, no prefix */
+ try_mkdtemp(p, "", i);
+ /* now at the end of the page, no prefix */
+ try_mkdtemp(p + pg - i - 1, "", i);
+ /* start of the page, prefixed with the cwd */
+ try_mkdtemp(p, cwd, i);
+ /* how about at the end of the page, prefixed with cwd? */
+ try_mkdtemp(p + pg - clen - i - 1, cwd, i);
+
+ /* again, with mkstemps() and an empty suffix */
+ /* try first at the start of a page, no prefix */
+ try_mkstemps(p, "", i, "");
+ /* now at the end of the page, no prefix */
+ try_mkstemps(p + pg - i - 1, "", i, "");
+ /* start of the page, prefixed with the cwd */
+ try_mkstemps(p, cwd, i, "");
+ /* how about at the end of the page, prefixed with cwd? */
+ try_mkstemps(p + pg - clen - i - 1, cwd, i, "");
+
+ /* mkstemps() and a non-empty suffix */
+ /* try first at the start of a page, no prefix */
+ try_mkstemps(p, "", i, SUFFIX);
+ /* now at the end of the page, no prefix */
+ try_mkstemps(p + pg - i - SLEN - 1, "", i, SUFFIX);
+ /* start of the page, prefixed with the cwd */
+ try_mkstemps(p, cwd, i, SUFFIX);
+ /* how about at the end of the page, prefixed with cwd? */
+ try_mkstemps(p + pg - clen - i - SLEN - 1, cwd, i, SUFFIX);
+ }
+
+ return 0;
+}