xref: /openbsd-src/regress/lib/libc/mkstemp/mkstemp_test.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*
2  * Copyright (c) 2010  Philip Guenther <guenther@openbsd.org>
3  *
4  * Public domain.
5  *
6  * Verify that mkstemp() and mkstemps() doesn't overrun or underrun
7  * the template buffer and that it can generate names that don't
8  * contain any X's
9  */
10 
11 #include <sys/param.h>
12 #include <sys/mman.h>
13 #include <sys/stat.h>
14 
15 #include <err.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 
22 #define MAX_TEMPLATE_LEN	10
23 #define MAX_TRIES		100
24 #define MIN_Xs			6
25 
26 #define SUFFIX	".suff"
27 #define SLEN	(sizeof SUFFIX - 1)
28 
29 long pg;
30 
31 /*
32  * verify that a path generated by mkstemp() or mkstemp() looks like a
33  * reasonable expansion of the template and matches the fd.  Returns true
34  * if all the X's were replaced with non-X's
35  */
36 int
37 check(int fd, char const *path, char const *prefix, size_t plen,
38     char const *suffix, size_t slen, int tlen)
39 {
40 	struct stat sb, fsb;
41 	char const *p;
42 
43 	if (tlen < MIN_Xs) {
44 		if (fd >= 0)
45 			errx(1, "mkstemp(%s) succeed with too few Xs", path);
46 		if (errno != EINVAL)
47 			err(1, "mkstemp(%s) failed with wrong errno", path);
48 		return 1;
49 	}
50 	if (fd < 0)
51 		err(1, "mkstemp(%s)", path);
52 	if (stat(path, &sb))
53 		err(1, "stat(%s)", path);
54 	if (fstat(fd, &fsb))
55 		err(1, "fstat(%d==%s)", fd, path);
56 	if (sb.st_dev != fsb.st_dev || sb.st_ino != fsb.st_ino)
57 		errx(1, "stat mismatch");
58 	close(fd);
59 	if (memcmp(path, prefix, plen) != 0)
60 		errx(1, "prefix changed!  %s vs %s", prefix, path);
61 	if (memcmp(path + plen + tlen, suffix, slen + 1) != 0)
62 		errx(1, "suffix changed!  %s vs %s", suffix, path);
63 	for (p = path + plen; p < path + plen + tlen; p++)
64 		if (*p == '\0')
65 			errx(1, "unexpected truncation");
66 		else if (*p == 'X')
67 			return 0;
68 	return 1;
69 }
70 
71 
72 void
73 try_mkstemp(char *p, char const *prefix, int len)
74 {
75 	char *q;
76 	size_t plen = strlen(prefix);
77 	int tries, fd;
78 
79 	for (tries = 0; tries < MAX_TRIES; tries++) {
80 		memcpy(p, prefix, plen);
81 		memset(p + plen, 'X', len);
82 		p[plen + len] = '\0';
83 		fd = mkstemp(p);
84 		if (check(fd, p, prefix, plen, "", 0, len))
85 			return;
86 	}
87 	errx(1, "exceeded MAX_TRIES");
88 }
89 
90 void
91 try_mkstemps(char *p, char const *prefix, int len, char const *suffix)
92 {
93 	char *q;
94 	size_t plen = strlen(prefix);
95 	size_t slen = strlen(suffix);
96 	int tries, fd;
97 
98 	for (tries = 0; tries < MAX_TRIES; tries++) {
99 		memcpy(p, prefix, plen);
100 		memset(p + plen, 'X', len);
101 		memcpy(p + plen + len, suffix, slen + 1);
102 		fd = mkstemps(p, slen);
103 		if (check(fd, p, prefix, plen, suffix, slen, len))
104 			return;
105 	}
106 	errx(1, "exceeded MAX_TRIES");
107 }
108 
109 int
110 main(void)
111 {
112 	struct stat sb, fsb;
113 	char cwd[MAXPATHLEN + 1];
114 	char *p;
115 	size_t clen;
116 	int i;
117 
118 	pg = sysconf(_SC_PAGESIZE);
119 	if (getcwd(cwd, sizeof cwd - 1) == NULL)
120 		err(1, "getcwd");
121 	clen = strlen(cwd);
122 	cwd[clen++] = '/';
123 	cwd[clen] = '\0';
124 	p = mmap(NULL, pg * 3, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
125 	if (p == NULL)
126 		err(1, "mmap");
127 	if (mprotect(p, pg, PROT_NONE) || mprotect(p + pg * 2, pg, PROT_NONE))
128 		err(1, "mprotect");
129 	p += pg;
130 
131 	i = MAX_TEMPLATE_LEN + 1;
132 	while (i-- > 0) {
133 		/* try first at the start of a page, no prefix */
134 		try_mkstemp(p, "", i);
135 		/* now at the end of the page, no prefix */
136 		try_mkstemp(p + pg - i - 1, "", i);
137 		/* start of the page, prefixed with the cwd */
138 		try_mkstemp(p, cwd, i);
139 		/* how about at the end of the page, prefixed with cwd? */
140 		try_mkstemp(p + pg - clen - i - 1, cwd, i);
141 
142 		/* again, with mkstemps() and an empty suffix */
143 		/* try first at the start of a page, no prefix */
144 		try_mkstemps(p, "", i, "");
145 		/* now at the end of the page, no prefix */
146 		try_mkstemps(p + pg - i - 1, "", i, "");
147 		/* start of the page, prefixed with the cwd */
148 		try_mkstemps(p, cwd, i, "");
149 		/* how about at the end of the page, prefixed with cwd? */
150 		try_mkstemps(p + pg - clen - i - 1, cwd, i, "");
151 
152 		/* mkstemps() and a non-empty suffix */
153 		/* try first at the start of a page, no prefix */
154 		try_mkstemps(p, "", i, SUFFIX);
155 		/* now at the end of the page, no prefix */
156 		try_mkstemps(p + pg - i - SLEN - 1, "", i, SUFFIX);
157 		/* start of the page, prefixed with the cwd */
158 		try_mkstemps(p, cwd, i, SUFFIX);
159 		/* how about at the end of the page, prefixed with cwd? */
160 		try_mkstemps(p + pg - clen - i - SLEN - 1, cwd, i, SUFFIX);
161 
162 	}
163 
164 	return 0;
165 }
166