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