]> granicus.if.org Git - sudo/commitdiff
Add regress for mkdtemp and mkstemps from OpenBSD
authorTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 20 Feb 2015 21:37:02 +0000 (14:37 -0700)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 20 Feb 2015 21:37:02 +0000 (14:37 -0700)
MANIFEST
configure
configure.ac
lib/util/Makefile.in
lib/util/mktemp.c
lib/util/regress/mktemp/mktemp_test.c [new file with mode: 0644]
mkdep.pl

index f58ea9ce0da9d20844acd2da42bde204bdf9939d..5e1d2095bd20e9dda795f03254c1a7d14483a9ad 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -119,6 +119,7 @@ lib/util/regress/fnmatch/fnm_test.in
 lib/util/regress/glob/files
 lib/util/regress/glob/globtest.c
 lib/util/regress/glob/globtest.in
+lib/util/regress/mktemp/mktemp_test.c
 lib/util/regress/progname/progname_test.c
 lib/util/regress/sudo_conf/conf_test.c
 lib/util/regress/sudo_conf/test1.in
index 575586e298d857043a8cd099a7a2663b3391a3df..f9b9c34d816676b86a6e2b2360fff904e5a33e1c 100755 (executable)
--- a/configure
+++ b/configure
@@ -19651,6 +19651,7 @@ esac
 "
     done
 
+    COMPAT_TEST_PROGS="${COMPAT_TEST_PROGS}${COMPAT_TEST_PROGS+ }mktemp_test"
 fi
 for ac_func in snprintf vsnprintf
 do :
index 7dc24f3c3505f76ae3d13f2d60f21f9561a36c3d..10b7a20497be6b2a4e537a89783a1c43e763de1e 100644 (file)
@@ -2571,6 +2571,7 @@ if test X"$ac_cv_func_mkstemps$ac_cv_func_mkdtemp" != X"yesyes"; then
     AC_LIBOBJ(mktemp)
     # If either mkdtemp() or mkstemps() is missing, replace both.
     SUDO_APPEND_COMPAT_EXP(sudo_mkdtemp sudo_mkstemps)
+    COMPAT_TEST_PROGS="${COMPAT_TEST_PROGS}${COMPAT_TEST_PROGS+ }mktemp_test"
 fi
 AX_FUNC_SNPRINTF
 if test X"$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf" = X"yesyes"; then
index c6649cfd58afb458e3aa4bc7f5ae76be07f3a411..fb71b8861417163cd7ba83e041b1e74a6cbdddf8 100644 (file)
@@ -103,6 +103,8 @@ LTOBJS = alloc.lo event.lo fatal.lo key_val.lo gethostname.lo gidlist.lo \
 
 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
@@ -176,6 +178,9 @@ globtest: $(GLOBTEST_OBJS) libsudo_util.la
 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)
 
@@ -225,6 +230,9 @@ check: $(TEST_PROGS)
                ./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 + $$?`; \
@@ -347,7 +355,6 @@ fatal.lo: $(srcdir)/fatal.c $(incdir)/compat/stdbool.h $(incdir)/sudo_alloc.h \
 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
@@ -383,12 +390,14 @@ glob.lo: $(srcdir)/glob.c $(incdir)/compat/charclass.h $(incdir)/compat/glob.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 \
@@ -426,6 +435,11 @@ mksigname.lo: $(srcdir)/mksigname.c $(incdir)/sudo_compat.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 \
index fa86d123e8d636c34f78af99c9fdbabc4e5306d9..2a64cc9ca2df43de1154169d46622c349f0d6730 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2003, 2004, 2008-2011, 2013, 2014
+ * Copyright (c) 2001, 2003, 2004, 2008-2011, 2013, 2015
  *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
 #ifdef HAVE_STDLIB_H
 # include <stdlib.h>
 #endif /* HAVE_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 <ctype.h>
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
@@ -45,6 +51,7 @@
 
 #define TEMPCHARS      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
 #define NUM_CHARS      (sizeof(TEMPCHARS) - 1)
+#define MIN_X          6
 
 #ifndef INT_MAX
 #define INT_MAX        0x7fffffff
@@ -122,15 +129,15 @@ mktemp_internal(char *path, int slen, int mode)
        char *start, *cp, *ep;
        const char tempchars[] = TEMPCHARS;
        unsigned int r, tries;
+       size_t len;
        int fd;
 
-       for (ep = path; *ep; ep++)
-               ;
-       if (path + slen >= ep) {
+       len = strlen(path);
+       if (len < MIN_X || slen < 0 || (size_t)slen > len - MIN_X) {
                errno = EINVAL;
                return -1;
        }
-       ep -= slen;
+       ep = path + len - slen;
 
        tries = 1;
        for (start = ep; start > path && start[-1] == 'X'; start--) {
@@ -138,6 +145,10 @@ mktemp_internal(char *path, int slen, int mode)
                        tries *= NUM_CHARS;
        }
        tries *= 2;
+       if (ep - start < MIN_X) {
+               errno = EINVAL;
+               return -1;
+       }
 
        do {
                for (cp = start; cp != ep; cp++) {
diff --git a/lib/util/regress/mktemp/mktemp_test.c b/lib/util/regress/mktemp/mktemp_test.c
new file mode 100644 (file)
index 0000000..b6b6d76
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * 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;
+}
index b3326f0ab87cdffb837633e66e78e075a3feed92..d6774a9c842c3880fc087a504b05d47b291c517b 100755 (executable)
--- a/mkdep.pl
+++ b/mkdep.pl
@@ -70,7 +70,7 @@ sub mkdep {
     $makefile =~ s:\@SUDOERS_OBJS\@:bsm_audit.lo linux_audit.lo ldap.lo solaris_audit.lo sssd.lo:;
     # XXX - fill in AUTH_OBJS from contents of the auth dir instead
     $makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:;
-    $makefile =~ s:\@LTLIBOBJS\@:clock_gettime.lo closefrom.lo fnmatch.lo getaddrinfo.lo getcwd.lo getgrouplist.lo getline.lo getopt_long.lo glob.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo pw_dup.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo strlcat.lo strlcpy.lo strsignal.lo strtonum.lo utimes.lo globtest.o fnm_test.o inet_pton:;
+    $makefile =~ s:\@LTLIBOBJS\@:clock_gettime.lo closefrom.lo fnmatch.lo getaddrinfo.lo getcwd.lo getgrouplist.lo getline.lo getopt_long.lo glob.lo inet_ntop_lo inet_pton.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo pw_dup.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo strlcat.lo strlcpy.lo strsignal.lo strtonum.lo utimes.lo:;
 
     # Parse OBJS lines
     my %objs;