1*860a6011Sbluhm /* $OpenBSD: realpathtest.c,v 1.13 2019/08/06 11:38:16 bluhm Exp $ */
2d1b74578Sbeck
3d1b74578Sbeck /*
4d1b74578Sbeck * Copyright (c) 2019 Bob Beck <beck@openbsd.org>
5d1b74578Sbeck *
6d1b74578Sbeck * Permission to use, copy, modify, and distribute this software for any
7d1b74578Sbeck * purpose with or without fee is hereby granted, provided that the above
8d1b74578Sbeck * copyright notice and this permission notice appear in all copies.
9d1b74578Sbeck *
10d1b74578Sbeck * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11d1b74578Sbeck * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12d1b74578Sbeck * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13d1b74578Sbeck * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14d1b74578Sbeck * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15d1b74578Sbeck * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16d1b74578Sbeck * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17d1b74578Sbeck */
18d1b74578Sbeck
19d1b74578Sbeck #include <sys/types.h>
20083f3669Sbeck #include <sys/stat.h>
21d1b74578Sbeck
22d1b74578Sbeck #include <stdio.h>
23d1b74578Sbeck #include <limits.h>
24d1b74578Sbeck #include <stdlib.h>
25d1b74578Sbeck #include <string.h>
26d1b74578Sbeck #include <unistd.h>
27d1b74578Sbeck #include <err.h>
28d1b74578Sbeck #include <errno.h>
29d1b74578Sbeck
30d1b74578Sbeck /*
31d1b74578Sbeck * Reference copy of userland realpath(3) implementation.
32d1b74578Sbeck * Assumed to be correct.
33d1b74578Sbeck */
34d1b74578Sbeck extern char *realpath3(const char *pathname, char *resolved);
35d1b74578Sbeck
36d1b74578Sbeck struct rp_compare {
37d1b74578Sbeck char * resolv2;
38d1b74578Sbeck char * resolv3;
39d1b74578Sbeck char * r2;
40d1b74578Sbeck char * r3;
41d1b74578Sbeck int e2;
42d1b74578Sbeck int e3;
43d1b74578Sbeck };
44d1b74578Sbeck
45d1b74578Sbeck static struct rp_compare
rpcompare(const char * pathname,char * resolv2,char * resolv3)46d1b74578Sbeck rpcompare(const char *pathname, char *resolv2,
47d1b74578Sbeck char *resolv3) {
48d1b74578Sbeck struct rp_compare ret = {0};
49d1b74578Sbeck
50d1b74578Sbeck errno = 0;
51d1b74578Sbeck ret.r2 = realpath(pathname, resolv2);
52d1b74578Sbeck ret.e2 = errno;
53d1b74578Sbeck ret.resolv2 = resolv2;
54d1b74578Sbeck errno = 0;
55d1b74578Sbeck ret.r3 = realpath3(pathname, resolv3);
56d1b74578Sbeck ret.e3 = errno;
57d1b74578Sbeck ret.resolv3 = resolv3;
58d1b74578Sbeck errno = 0;
59d1b74578Sbeck return ret;
60d1b74578Sbeck }
61d1b74578Sbeck
62d1b74578Sbeck #define RP_SHOULD_SUCCEED(A, B, C) do { \
63d1b74578Sbeck struct rp_compare rc = rpcompare(A, B, C); \
64d1b74578Sbeck if (rc.r2 == NULL) { \
65d1b74578Sbeck errno = rc.e2; \
66d1b74578Sbeck err(1, "%s:%d - realpath of '%s' failed", __FILE__, \
67d1b74578Sbeck __LINE__, (A)); \
68d1b74578Sbeck } \
69d1b74578Sbeck if (rc.r3 == NULL) { \
70d1b74578Sbeck errno = rc.e3; \
71d1b74578Sbeck err(1, "%s:%d - realpath3 of '%s' failed", __FILE__, \
72d1b74578Sbeck __LINE__, (A)); \
73d1b74578Sbeck } \
74d1b74578Sbeck if (strcmp(rc.r2, rc.r3) != 0) \
75d1b74578Sbeck errx(1, "%s:%d - realpath of '%s' result '%s', " \
76d1b74578Sbeck "expected '%s", __FILE__, __LINE__, (A), rc.r2, \
77d1b74578Sbeck rc.r3); \
78d1b74578Sbeck } while(0);
79d1b74578Sbeck
80d1b74578Sbeck #define RP_SHOULD_FAIL(A, B, C) do { \
81d1b74578Sbeck struct rp_compare rc = rpcompare(A, B, C); \
82d1b74578Sbeck if (rc.r2 != NULL) \
83d1b74578Sbeck errx(1, "%s:%d - realpath of '%s' should have failed, " \
84d1b74578Sbeck "returned '%s'", __FILE__, __LINE__, (A), rc.r2); \
85d1b74578Sbeck if (rc.r3 != NULL) \
86d1b74578Sbeck errx(1, "%s:%d - realpath3 of '%s' should have failed, "\
87d1b74578Sbeck "returned '%s'", __FILE__, __LINE__, (A), rc.r3); \
88d1b74578Sbeck if (rc.e2 != rc.e3) \
89d1b74578Sbeck errx(1, "%s:%d - realpath of '%s' errno %d does not " \
90d1b74578Sbeck "match realpath3 errno %d", __FILE__, __LINE__, (A),\
91d1b74578Sbeck rc.e2, rc.e3 ); \
92d1b74578Sbeck } while(0);
93d1b74578Sbeck
94d1b74578Sbeck int
main(int argc,char * argv[])95d1b74578Sbeck main(int argc, char *argv[])
96d1b74578Sbeck {
97d1b74578Sbeck int i, j;
98d1b74578Sbeck char big[PATH_MAX+PATH_MAX];
99d1b74578Sbeck char r2[PATH_MAX];
100d1b74578Sbeck char r3[PATH_MAX];
101d1b74578Sbeck
102d1b74578Sbeck /* some basics */
1038430be28Sbluhm RP_SHOULD_FAIL(NULL, NULL, NULL);
104bd83cd64Sstsp RP_SHOULD_FAIL("", NULL, NULL);
1058430be28Sbluhm RP_SHOULD_SUCCEED("/", NULL, NULL);
1068f5cd82fSbluhm RP_SHOULD_SUCCEED("//", NULL, NULL);
107*860a6011Sbluhm RP_SHOULD_SUCCEED("/./", NULL, NULL);
108*860a6011Sbluhm RP_SHOULD_SUCCEED("/./.", NULL, NULL);
109*860a6011Sbluhm RP_SHOULD_SUCCEED("/./..", NULL, NULL);
110*860a6011Sbluhm RP_SHOULD_SUCCEED("/../../", NULL, NULL);
111d1b74578Sbeck RP_SHOULD_SUCCEED("/tmp", NULL, NULL);
1128430be28Sbluhm RP_SHOULD_FAIL("/tmp/noreallydoesntexist", NULL, NULL);
113ef641529Sbeck RP_SHOULD_FAIL("/tmp/noreallydoesntexist/stillnope", NULL, NULL);
114d1b74578Sbeck RP_SHOULD_SUCCEED("/bin", NULL, NULL);
1158430be28Sbluhm RP_SHOULD_FAIL("/bin/herp", NULL, NULL);
116d1b74578Sbeck RP_SHOULD_SUCCEED("////usr/bin", NULL, NULL);
1178430be28Sbluhm RP_SHOULD_FAIL("//.//usr/bin/.././../herp", r2, r3);
1185af7ca97Sbeck RP_SHOULD_SUCCEED("/usr/include/machine/setjmp.h", r2, r3);
119794d35a4Sbeck RP_SHOULD_FAIL("//.//usr/bin/.././../herp/derp", r2, r3);
120d1b74578Sbeck RP_SHOULD_FAIL("/../.../usr/bin", r2, r3);
121d1b74578Sbeck RP_SHOULD_FAIL("/bsd/herp", r2, r3);
122d1b74578Sbeck
123083f3669Sbeck /* relative paths */
124083f3669Sbeck if (mkdir("hoobla", 0755) == -1) {
125083f3669Sbeck if (errno != EEXIST)
126083f3669Sbeck err(1, "mkdir");
127083f3669Sbeck }
128083f3669Sbeck RP_SHOULD_SUCCEED("hoobla", r2, r3);
1298430be28Sbluhm RP_SHOULD_FAIL("hoobla/porkrind", r2, r3);
130083f3669Sbeck RP_SHOULD_FAIL("hoobla/porkrind/peepee", r2, r3);
131083f3669Sbeck
132d1b74578Sbeck /* total size */
133d1b74578Sbeck memset(big, '/', PATH_MAX + 1);
134d1b74578Sbeck RP_SHOULD_FAIL(big, r2, r3);
135d1b74578Sbeck
136d1b74578Sbeck /* component size */
137d1b74578Sbeck memset(big, 'a', PATH_MAX + 1);
138d1b74578Sbeck big[0] = '/';
139d1b74578Sbeck big[NAME_MAX+1] = '\0';
1408430be28Sbluhm RP_SHOULD_FAIL(big, r2, r3);
141d1b74578Sbeck memset(big, 'a', PATH_MAX + 1);
142d1b74578Sbeck big[0] = '/';
143d1b74578Sbeck big[NAME_MAX+2] = '\0';
144d1b74578Sbeck RP_SHOULD_FAIL(big, r2, r3);
145d1b74578Sbeck
146d1b74578Sbeck /* long relatives back to root */
147d1b74578Sbeck for (i = 0; i < (PATH_MAX - 4); i += 3) {
148d1b74578Sbeck big[i] = '.';
149d1b74578Sbeck big[i+1] = '.';
150d1b74578Sbeck big[i+2] = '/';
151d1b74578Sbeck }
152d1b74578Sbeck i-= 3;
153d1b74578Sbeck strlcpy(big+i, "bsd", 4);
154d1b74578Sbeck RP_SHOULD_SUCCEED(big, r2, r3);
155d1b74578Sbeck
156d1b74578Sbeck for (i = 0; i < (PATH_MAX - 5); i += 3) {
157d1b74578Sbeck big[i] = '.';
158d1b74578Sbeck big[i+1] = '.';
159d1b74578Sbeck big[i+2] = '/';
160d1b74578Sbeck }
161d1b74578Sbeck i-= 3;
162d1b74578Sbeck strlcpy(big+i, "bsd/", 5);
163c7ce6e13Sbluhm RP_SHOULD_FAIL(big, r2, r3);
16498f1191fSbeck
16598f1191fSbeck for (i = 0; i < (PATH_MAX - 5); i += 3) {
16698f1191fSbeck big[i] = '.';
16798f1191fSbeck big[i+1] = '.';
16898f1191fSbeck big[i+2] = '/';
16998f1191fSbeck }
17098f1191fSbeck i-= 3;
17198f1191fSbeck strlcpy(big+i, "derp", 5);
1728430be28Sbluhm RP_SHOULD_FAIL(big, r2, r3);
17398f1191fSbeck
17498f1191fSbeck for (i = 0; i < (PATH_MAX - 6); i += 3) {
17598f1191fSbeck big[i] = '.';
17698f1191fSbeck big[i+1] = '.';
17798f1191fSbeck big[i+2] = '/';
17898f1191fSbeck }
17998f1191fSbeck i-= 3;
18098f1191fSbeck strlcpy(big+i, "derp/", 6);
1818430be28Sbluhm RP_SHOULD_FAIL(big, r2, r3);
182d1b74578Sbeck
183d1b74578Sbeck for (i = 0; i < (PATH_MAX - 4); i += 3) {
184d1b74578Sbeck big[i] = '.';
185d1b74578Sbeck big[i+1] = '.';
186d1b74578Sbeck big[i+2] = '/';
187d1b74578Sbeck }
188d1b74578Sbeck i-= 3;
189d1b74578Sbeck strlcpy(big+i, "xxx", 4);
1908430be28Sbluhm RP_SHOULD_FAIL(big, r2, r3);
191d1b74578Sbeck
192d1b74578Sbeck for (i = 0; i < (PATH_MAX - 8); i += 3) {
193d1b74578Sbeck big[i] = '.';
194d1b74578Sbeck big[i+1] = '.';
195d1b74578Sbeck big[i+2] = '/';
196d1b74578Sbeck }
197d1b74578Sbeck i-= 3;
198d1b74578Sbeck strlcpy(big+i, "xxx/../", 8);
199d1b74578Sbeck RP_SHOULD_FAIL(big, r2, r3);
200d1b74578Sbeck
201d1b74578Sbeck return (0);
202d1b74578Sbeck }
203