xref: /openbsd-src/regress/sys/kern/realpath/realpathtest.c (revision 794d35a423b05aeaef47f566d6188008969ec5e6)
1 /*	$OpenBSD: realpathtest.c,v 1.3 2019/04/26 06:47:43 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_SUCCEED("/usr/include/machine/setjmp.h", r2, r3);
108 	RP_SHOULD_FAIL("//.//usr/bin/.././../herp/derp", r2, r3);
109 	RP_SHOULD_FAIL("/../.../usr/bin", r2, r3);
110 	RP_SHOULD_FAIL("/bsd/herp", r2, r3);
111 
112 	/* total size */
113 	memset(big, '/', PATH_MAX + 1);
114 	RP_SHOULD_FAIL(big, r2, r3);
115 
116 	/* component size */
117 	memset(big, 'a', PATH_MAX + 1);
118 	big[0] = '/';
119 	big[NAME_MAX+1] = '\0';
120 	RP_SHOULD_SUCCEED(big, r2, r3);
121 	memset(big, 'a', PATH_MAX + 1);
122 	big[0] = '/';
123 	big[NAME_MAX+2] = '\0';
124 	RP_SHOULD_FAIL(big, r2, r3);
125 
126 	/* long relatives back to root */
127 	for (i = 0; i < (PATH_MAX - 4); i += 3) {
128 		big[i] = '.';
129 		big[i+1] = '.';
130 		big[i+2] = '/';
131 	}
132 	i-= 3;
133 	strlcpy(big+i, "bsd", 4);
134 	RP_SHOULD_SUCCEED(big, r2, r3);
135 
136 	for (i = 0; i < (PATH_MAX - 5); i += 3) {
137 		big[i] = '.';
138 		big[i+1] = '.';
139 		big[i+2] = '/';
140 	}
141 	i-= 3;
142 	strlcpy(big+i, "bsd/", 5);
143 	RP_SHOULD_SUCCEED(big, r2, r3);	/* XXX is this right? */
144 
145 	for (i = 0; i < (PATH_MAX - 4); i += 3) {
146 		big[i] = '.';
147 		big[i+1] = '.';
148 		big[i+2] = '/';
149 	}
150 	i-= 3;
151 	strlcpy(big+i, "xxx", 4);
152 	RP_SHOULD_SUCCEED(big, r2, r3);
153 
154 	for (i = 0; i < (PATH_MAX - 8); i += 3) {
155 		big[i] = '.';
156 		big[i+1] = '.';
157 		big[i+2] = '/';
158 	}
159 	i-= 3;
160 	strlcpy(big+i, "xxx/../", 8);
161 	RP_SHOULD_FAIL(big, r2, r3);
162 
163 	return (0);
164 }
165