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