xref: /openbsd-src/regress/sys/kern/realpath/realpathtest.c (revision d1b74578bdab3030aae51cc2652b75a486db8756)
1 /*	$OpenBSD: realpathtest.c,v 1.1 2019/04/19 19:50:48 beck Exp $ */
2 
3 /*
4  * Copyright (c) 2019 Bob Beck <beck@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <stdio.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <err.h>
27 #include <errno.h>
28 
29 /*
30  * Reference copy of userland realpath(3) implementation.
31  * Assumed to be correct.
32  */
33 extern char *realpath3(const char *pathname, char *resolved);
34 
35 struct rp_compare {
36 	char * resolv2;
37 	char * resolv3;
38 	char * r2;
39 	char * r3;
40 	int e2;
41 	int e3;
42 };
43 
44 static struct rp_compare
45 rpcompare(const char *pathname, char *resolv2,
46     char *resolv3) {
47 	struct rp_compare ret = {0};
48 
49 	errno = 0;
50 	ret.r2 = realpath(pathname, resolv2);
51 	ret.e2 = errno;
52 	ret.resolv2 = resolv2;
53 	errno = 0;
54 	ret.r3 = realpath3(pathname, resolv3);
55 	ret.e3 = errno;
56 	ret.resolv3 = resolv3;
57 	errno = 0;
58 	return ret;
59 }
60 
61 #define RP_SHOULD_SUCCEED(A, B, C) do {					\
62 	struct rp_compare rc = rpcompare(A, B, C);			\
63 	if (rc.r2 == NULL)  {						\
64 		errno = rc.e2;						\
65 		err(1, "%s:%d - realpath of '%s' failed", __FILE__, 	\
66 		    __LINE__, (A));					\
67 	} 								\
68 	if (rc.r3 == NULL)  {						\
69 		errno = rc.e3;						\
70 		err(1, "%s:%d - realpath3 of '%s' failed", __FILE__,	\
71 		    __LINE__, (A));					\
72 	}								\
73 	if (strcmp(rc.r2, rc.r3) != 0)					\
74 		errx(1, "%s:%d - realpath of '%s' result '%s',"		\
75 		    "expected '%s", __FILE__, __LINE__, (A), rc.r2,	\
76 		    rc.r3);						\
77 } while(0);
78 
79 #define RP_SHOULD_FAIL(A, B, C) do {					\
80 	struct rp_compare rc = rpcompare(A, B, C); 			\
81 	if (rc.r2 != NULL) 						\
82 		errx(1, "%s:%d - realpath of '%s' should have failed,"	\
83 		    "returned '%s'", __FILE__, __LINE__, (A), rc.r2); 	\
84 	if (rc.r3 != NULL) 						\
85 		errx(1, "%s:%d - realpath3 of '%s' should have failed,"	\
86 		    "returned '%s'", __FILE__, __LINE__, (A), rc.r3); 	\
87 	if (rc.e2 != rc.e3) 						\
88 		errx(1, "%s:%d - realpath of '%s' errno %d does not "	\
89 		    "match realpath3 errno %d", __FILE__, __LINE__, (A),\
90 		    rc.e2, rc.e3 );					\
91 } while(0);
92 
93 int
94 main(int argc, char *argv[])
95 {
96 	int i, j;
97 	char big[PATH_MAX+PATH_MAX];
98 	char r2[PATH_MAX];
99 	char r3[PATH_MAX];
100 
101 	/* some basics */
102 	RP_SHOULD_SUCCEED("/tmp", NULL, NULL);
103 	RP_SHOULD_SUCCEED("/bin", NULL, NULL);
104 	RP_SHOULD_SUCCEED("/bin/herp", NULL, NULL);
105 	RP_SHOULD_SUCCEED("////usr/bin", NULL, NULL);
106 	RP_SHOULD_SUCCEED("////usr/bin/../../herp", r2, r3);
107 	RP_SHOULD_FAIL("////usr/bin/../../herp/derp", r2, r3);
108 	RP_SHOULD_FAIL("/../.../usr/bin", r2, r3);
109 	RP_SHOULD_FAIL("/bsd/herp", r2, r3);
110 
111 	/* total size */
112 	memset(big, '/', PATH_MAX + 1);
113 	RP_SHOULD_FAIL(big, r2, r3);
114 
115 	/* component size */
116 	memset(big, 'a', PATH_MAX + 1);
117 	big[0] = '/';
118 	big[NAME_MAX+1] = '\0';
119 	RP_SHOULD_SUCCEED(big, r2, r3);
120 	memset(big, 'a', PATH_MAX + 1);
121 	big[0] = '/';
122 	big[NAME_MAX+2] = '\0';
123 	RP_SHOULD_FAIL(big, r2, r3);
124 
125 	/* long relatives back to root */
126 	for (i = 0; i < (PATH_MAX - 4); i += 3) {
127 		big[i] = '.';
128 		big[i+1] = '.';
129 		big[i+2] = '/';
130 	}
131 	i-= 3;
132 	strlcpy(big+i, "bsd", 4);
133 	RP_SHOULD_SUCCEED(big, r2, r3);
134 
135 	for (i = 0; i < (PATH_MAX - 5); i += 3) {
136 		big[i] = '.';
137 		big[i+1] = '.';
138 		big[i+2] = '/';
139 	}
140 	i-= 3;
141 	strlcpy(big+i, "bsd/", 5);
142 	RP_SHOULD_SUCCEED(big, r2, r3);	/* XXX is this right? */
143 
144 	for (i = 0; i < (PATH_MAX - 4); i += 3) {
145 		big[i] = '.';
146 		big[i+1] = '.';
147 		big[i+2] = '/';
148 	}
149 	i-= 3;
150 	strlcpy(big+i, "xxx", 4);
151 	RP_SHOULD_SUCCEED(big, r2, r3);
152 
153 	for (i = 0; i < (PATH_MAX - 8); i += 3) {
154 		big[i] = '.';
155 		big[i+1] = '.';
156 		big[i+2] = '/';
157 	}
158 	i-= 3;
159 	strlcpy(big+i, "xxx/../", 8);
160 	RP_SHOULD_FAIL(big, r2, r3);
161 
162 	return (0);
163 }
164