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