1 1.10 kamil /* $NetBSD: t_o_search.c,v 1.10 2020/02/08 19:58:36 kamil Exp $ */ 2 1.1 manu 3 1.1 manu /*- 4 1.1 manu * Copyright (c) 2012 The NetBSD Foundation, Inc. 5 1.1 manu * All rights reserved. 6 1.1 manu * 7 1.1 manu * This code is derived from software contributed to The NetBSD Foundation 8 1.1 manu * by Emmanuel Dreyfus. 9 1.1 manu * 10 1.1 manu * Redistribution and use in source and binary forms, with or without 11 1.1 manu * modification, are permitted provided that the following conditions 12 1.1 manu * are met: 13 1.1 manu * 1. Redistributions of source code must retain the above copyright 14 1.1 manu * notice, this list of conditions and the following disclaimer. 15 1.1 manu * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 manu * notice, this list of conditions and the following disclaimer in the 17 1.1 manu * documentation and/or other materials provided with the distribution. 18 1.1 manu * 19 1.1 manu * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 manu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 manu * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 manu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 manu * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 manu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 manu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 manu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 manu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 manu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 manu * POSSIBILITY OF SUCH DAMAGE. 30 1.1 manu */ 31 1.1 manu #include <sys/cdefs.h> 32 1.10 kamil __RCSID("$NetBSD: t_o_search.c,v 1.10 2020/02/08 19:58:36 kamil Exp $"); 33 1.1 manu 34 1.1 manu #include <atf-c.h> 35 1.5 christos 36 1.9 martin #include <sys/types.h> 37 1.10 kamil #include <sys/mount.h> 38 1.10 kamil #include <sys/statvfs.h> 39 1.5 christos #include <sys/stat.h> 40 1.5 christos 41 1.9 martin #include <dirent.h> 42 1.1 manu #include <errno.h> 43 1.1 manu #include <fcntl.h> 44 1.1 manu #include <limits.h> 45 1.1 manu #include <paths.h> 46 1.1 manu #include <stdio.h> 47 1.1 manu #include <string.h> 48 1.1 manu #include <unistd.h> 49 1.1 manu #include <pwd.h> 50 1.1 manu 51 1.3 dholland /* 52 1.3 dholland * dholland 20130112: disable tests that require O_SEARCH semantics 53 1.3 dholland * until a decision is reached about the semantics of O_SEARCH and a 54 1.3 dholland * non-broken implementation is available. 55 1.3 dholland */ 56 1.9 martin #if defined(__FreeBSD__) || (O_MASK & O_SEARCH) != 0 57 1.3 dholland #define USE_O_SEARCH 58 1.3 dholland #endif 59 1.3 dholland 60 1.10 kamil #ifdef __FreeBSD__ 61 1.10 kamil #define statvfs statfs 62 1.10 kamil #define fstatvfs fstatfs 63 1.10 kamil #endif 64 1.10 kamil 65 1.1 manu #define DIR "dir" 66 1.1 manu #define FILE "dir/o_search" 67 1.1 manu #define BASEFILE "o_search" 68 1.1 manu 69 1.3 dholland 70 1.4 jmmv ATF_TC(o_search_perm1); 71 1.1 manu ATF_TC_HEAD(o_search_perm1, tc) 72 1.1 manu { 73 1.3 dholland atf_tc_set_md_var(tc, "descr", "See that openat enforces search permission"); 74 1.1 manu atf_tc_set_md_var(tc, "require.user", "unprivileged"); 75 1.1 manu } 76 1.1 manu ATF_TC_BODY(o_search_perm1, tc) 77 1.1 manu { 78 1.1 manu int dfd; 79 1.1 manu int fd; 80 1.1 manu 81 1.1 manu ATF_REQUIRE(mkdir(DIR, 0755) == 0); 82 1.1 manu ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1); 83 1.1 manu ATF_REQUIRE(close(fd) == 0); 84 1.1 manu 85 1.1 manu ATF_REQUIRE((dfd = open(DIR, O_RDONLY, 0)) != -1); 86 1.1 manu 87 1.1 manu ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1); 88 1.1 manu ATF_REQUIRE(close(fd) == 0); 89 1.1 manu 90 1.6 martin ATF_REQUIRE(fchmod(dfd, 0644) == 0); 91 1.1 manu 92 1.1 manu ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) == -1); 93 1.1 manu ATF_REQUIRE(errno == EACCES); 94 1.1 manu 95 1.1 manu ATF_REQUIRE(close(dfd) == 0); 96 1.1 manu } 97 1.1 manu 98 1.3 dholland #ifdef USE_O_SEARCH 99 1.3 dholland 100 1.4 jmmv ATF_TC(o_search_root_flag1); 101 1.2 martin ATF_TC_HEAD(o_search_root_flag1, tc) 102 1.1 manu { 103 1.3 dholland atf_tc_set_md_var(tc, "descr", "See that root openat honours O_SEARCH"); 104 1.2 martin atf_tc_set_md_var(tc, "require.user", "root"); 105 1.1 manu } 106 1.2 martin ATF_TC_BODY(o_search_root_flag1, tc) 107 1.1 manu { 108 1.1 manu int dfd; 109 1.1 manu int fd; 110 1.1 manu 111 1.1 manu ATF_REQUIRE(mkdir(DIR, 0755) == 0); 112 1.1 manu ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1); 113 1.1 manu ATF_REQUIRE(close(fd) == 0); 114 1.1 manu 115 1.1 manu ATF_REQUIRE((dfd = open(DIR, O_RDONLY|O_SEARCH, 0)) != -1); 116 1.1 manu 117 1.1 manu ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1); 118 1.1 manu ATF_REQUIRE(close(fd) == 0); 119 1.1 manu 120 1.6 martin ATF_REQUIRE(fchmod(dfd, 0644) == 0); 121 1.1 manu 122 1.1 manu ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1); 123 1.1 manu ATF_REQUIRE(close(fd) == 0); 124 1.1 manu 125 1.6 martin ATF_REQUIRE(fchmod(dfd, 0444) == 0); 126 1.1 manu 127 1.1 manu ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1); 128 1.1 manu 129 1.1 manu ATF_REQUIRE(close(dfd) == 0); 130 1.1 manu } 131 1.1 manu 132 1.4 jmmv ATF_TC(o_search_unpriv_flag1); 133 1.2 martin ATF_TC_HEAD(o_search_unpriv_flag1, tc) 134 1.2 martin { 135 1.2 martin atf_tc_set_md_var(tc, "descr", "See that openat honours O_SEARCH"); 136 1.2 martin atf_tc_set_md_var(tc, "require.user", "unprivileged"); 137 1.2 martin } 138 1.2 martin ATF_TC_BODY(o_search_unpriv_flag1, tc) 139 1.2 martin { 140 1.2 martin int dfd; 141 1.2 martin int fd; 142 1.2 martin 143 1.2 martin ATF_REQUIRE(mkdir(DIR, 0755) == 0); 144 1.2 martin ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1); 145 1.2 martin ATF_REQUIRE(close(fd) == 0); 146 1.2 martin 147 1.2 martin ATF_REQUIRE((dfd = open(DIR, O_RDONLY|O_SEARCH, 0)) != -1); 148 1.2 martin 149 1.2 martin ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1); 150 1.2 martin ATF_REQUIRE(close(fd) == 0); 151 1.2 martin 152 1.6 martin ATF_REQUIRE(fchmod(dfd, 0644) == 0); 153 1.2 martin 154 1.2 martin ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1); 155 1.2 martin ATF_REQUIRE(close(fd) == 0); 156 1.2 martin 157 1.6 martin ATF_REQUIRE(fchmod(dfd, 0444) == 0); 158 1.2 martin 159 1.3 dholland ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1); 160 1.2 martin 161 1.2 martin ATF_REQUIRE(close(dfd) == 0); 162 1.2 martin } 163 1.2 martin 164 1.3 dholland #endif /* USE_O_SEARCH */ 165 1.3 dholland 166 1.4 jmmv ATF_TC(o_search_perm2); 167 1.1 manu ATF_TC_HEAD(o_search_perm2, tc) 168 1.1 manu { 169 1.3 dholland atf_tc_set_md_var(tc, "descr", "See that faccessat enforces search permission"); 170 1.1 manu atf_tc_set_md_var(tc, "require.user", "unprivileged"); 171 1.1 manu } 172 1.1 manu ATF_TC_BODY(o_search_perm2, tc) 173 1.1 manu { 174 1.1 manu int dfd; 175 1.1 manu int fd; 176 1.1 manu ATF_REQUIRE(mkdir(DIR, 0755) == 0); 177 1.1 manu ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1); 178 1.1 manu ATF_REQUIRE(close(fd) == 0); 179 1.1 manu 180 1.1 manu ATF_REQUIRE((dfd = open(DIR, O_RDONLY, 0)) != -1); 181 1.1 manu 182 1.1 manu ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0); 183 1.1 manu 184 1.6 martin ATF_REQUIRE(fchmod(dfd, 0644) == 0); 185 1.1 manu 186 1.1 manu ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == -1); 187 1.1 manu ATF_REQUIRE(errno == EACCES); 188 1.1 manu 189 1.1 manu ATF_REQUIRE(close(dfd) == 0); 190 1.1 manu } 191 1.1 manu 192 1.3 dholland #ifdef USE_O_SEARCH 193 1.3 dholland 194 1.4 jmmv ATF_TC(o_search_root_flag2); 195 1.2 martin ATF_TC_HEAD(o_search_root_flag2, tc) 196 1.1 manu { 197 1.3 dholland atf_tc_set_md_var(tc, "descr", "See that root fstatat honours O_SEARCH"); 198 1.2 martin atf_tc_set_md_var(tc, "require.user", "root"); 199 1.1 manu } 200 1.2 martin ATF_TC_BODY(o_search_root_flag2, tc) 201 1.1 manu { 202 1.1 manu int dfd; 203 1.1 manu int fd; 204 1.1 manu 205 1.1 manu ATF_REQUIRE(mkdir(DIR, 0755) == 0); 206 1.1 manu ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1); 207 1.1 manu ATF_REQUIRE(close(fd) == 0); 208 1.1 manu 209 1.1 manu ATF_REQUIRE((dfd = open(DIR, O_RDONLY|O_SEARCH, 0)) != -1); 210 1.1 manu 211 1.1 manu ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0); 212 1.1 manu 213 1.6 martin ATF_REQUIRE(fchmod(dfd, 0644) == 0); 214 1.1 manu 215 1.1 manu ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0); 216 1.1 manu 217 1.6 martin ATF_REQUIRE(fchmod(dfd, 0444) == 0); 218 1.1 manu 219 1.1 manu ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0); 220 1.1 manu 221 1.1 manu ATF_REQUIRE(close(dfd) == 0); 222 1.1 manu } 223 1.1 manu 224 1.4 jmmv ATF_TC(o_search_unpriv_flag2); 225 1.2 martin ATF_TC_HEAD(o_search_unpriv_flag2, tc) 226 1.2 martin { 227 1.2 martin atf_tc_set_md_var(tc, "descr", "See that fstatat honours O_SEARCH"); 228 1.2 martin atf_tc_set_md_var(tc, "require.user", "unprivileged"); 229 1.2 martin } 230 1.2 martin ATF_TC_BODY(o_search_unpriv_flag2, tc) 231 1.2 martin { 232 1.2 martin int dfd; 233 1.2 martin int fd; 234 1.2 martin 235 1.2 martin ATF_REQUIRE(mkdir(DIR, 0755) == 0); 236 1.2 martin ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1); 237 1.2 martin ATF_REQUIRE(close(fd) == 0); 238 1.2 martin 239 1.2 martin ATF_REQUIRE((dfd = open(DIR, O_RDONLY|O_SEARCH, 0)) != -1); 240 1.2 martin 241 1.2 martin ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0); 242 1.2 martin 243 1.6 martin ATF_REQUIRE(fchmod(dfd, 0644) == 0); 244 1.2 martin 245 1.2 martin ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0); 246 1.2 martin 247 1.6 martin ATF_REQUIRE(fchmod(dfd, 0444) == 0); 248 1.2 martin 249 1.2 martin ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0); 250 1.2 martin 251 1.2 martin ATF_REQUIRE(close(dfd) == 0); 252 1.2 martin } 253 1.2 martin 254 1.3 dholland #endif /* USE_O_SEARCH */ 255 1.3 dholland 256 1.1 manu 257 1.4 jmmv ATF_TC(o_search_notdir); 258 1.1 manu ATF_TC_HEAD(o_search_notdir, tc) 259 1.1 manu { 260 1.1 manu atf_tc_set_md_var(tc, "descr", "See that openat fails with non dir fd"); 261 1.1 manu } 262 1.1 manu ATF_TC_BODY(o_search_notdir, tc) 263 1.1 manu { 264 1.1 manu int dfd; 265 1.1 manu int fd; 266 1.1 manu 267 1.1 manu ATF_REQUIRE(mkdir(DIR, 0755) == 0); 268 1.8 martin ATF_REQUIRE((dfd = open(FILE, O_CREAT|O_SEARCH, 0644)) != -1); 269 1.1 manu ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) == -1); 270 1.1 manu ATF_REQUIRE(errno == ENOTDIR); 271 1.7 martin ATF_REQUIRE(close(dfd) == 0); 272 1.1 manu } 273 1.1 manu 274 1.9 martin #ifdef USE_O_SEARCH 275 1.9 martin ATF_TC(o_search_nord); 276 1.9 martin ATF_TC_HEAD(o_search_nord, tc) 277 1.9 martin { 278 1.9 martin atf_tc_set_md_var(tc, "descr", "See that openat succeeds with no read permission"); 279 1.9 martin atf_tc_set_md_var(tc, "require.user", "unprivileged"); 280 1.9 martin } 281 1.9 martin ATF_TC_BODY(o_search_nord, tc) 282 1.9 martin { 283 1.9 martin int dfd, fd; 284 1.9 martin 285 1.9 martin ATF_REQUIRE(mkdir(DIR, 0755) == 0); 286 1.9 martin ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1); 287 1.9 martin ATF_REQUIRE(close(fd) == 0); 288 1.9 martin 289 1.9 martin ATF_REQUIRE(chmod(DIR, 0100) == 0); 290 1.9 martin ATF_REQUIRE((dfd = open(DIR, O_SEARCH, 0)) != -1); 291 1.9 martin 292 1.9 martin ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) != -1); 293 1.9 martin 294 1.9 martin ATF_REQUIRE(close(dfd) == 0); 295 1.9 martin } 296 1.9 martin 297 1.9 martin ATF_TC(o_search_getdents); 298 1.9 martin ATF_TC_HEAD(o_search_getdents, tc) 299 1.9 martin { 300 1.9 martin atf_tc_set_md_var(tc, "descr", "See that O_SEARCH forbids getdents"); 301 1.9 martin } 302 1.9 martin ATF_TC_BODY(o_search_getdents, tc) 303 1.9 martin { 304 1.9 martin char buf[1024]; 305 1.9 martin int dfd; 306 1.9 martin 307 1.9 martin ATF_REQUIRE(mkdir(DIR, 0755) == 0); 308 1.9 martin ATF_REQUIRE((dfd = open(DIR, O_SEARCH, 0)) != -1); 309 1.9 martin ATF_REQUIRE(getdents(dfd, buf, sizeof(buf)) < 0); 310 1.9 martin ATF_REQUIRE(close(dfd) == 0); 311 1.9 martin } 312 1.9 martin 313 1.9 martin ATF_TC(o_search_revokex); 314 1.9 martin ATF_TC_HEAD(o_search_revokex, tc) 315 1.9 martin { 316 1.9 martin atf_tc_set_md_var(tc, "descr", "See that *at behaves after chmod -x"); 317 1.9 martin atf_tc_set_md_var(tc, "require.user", "unprivileged"); 318 1.9 martin } 319 1.9 martin ATF_TC_BODY(o_search_revokex, tc) 320 1.9 martin { 321 1.10 kamil struct statvfs vst; 322 1.10 kamil struct stat sb; 323 1.9 martin int dfd, fd; 324 1.9 martin 325 1.9 martin ATF_REQUIRE(mkdir(DIR, 0755) == 0); 326 1.9 martin ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1); 327 1.9 martin ATF_REQUIRE(close(fd) == 0); 328 1.9 martin 329 1.9 martin ATF_REQUIRE((dfd = open(DIR, O_SEARCH, 0)) != -1); 330 1.9 martin 331 1.9 martin /* Drop permissions. The kernel must still not check the exec bit. */ 332 1.9 martin ATF_REQUIRE(chmod(DIR, 0000) == 0); 333 1.10 kamil 334 1.10 kamil fstatvfs(dfd, &vst); 335 1.10 kamil if (strcmp(vst.f_fstypename, "nfs") == 0) 336 1.10 kamil atf_tc_expect_fail("NFS protocol cannot observe O_SEARCH semantics"); 337 1.10 kamil 338 1.9 martin ATF_REQUIRE(fstatat(dfd, BASEFILE, &sb, 0) == 0); 339 1.9 martin 340 1.9 martin ATF_REQUIRE(close(dfd) == 0); 341 1.9 martin } 342 1.9 martin #endif /* USE_O_SEARCH */ 343 1.9 martin 344 1.1 manu ATF_TP_ADD_TCS(tp) 345 1.1 manu { 346 1.1 manu 347 1.1 manu ATF_TP_ADD_TC(tp, o_search_perm1); 348 1.3 dholland #ifdef USE_O_SEARCH 349 1.2 martin ATF_TP_ADD_TC(tp, o_search_root_flag1); 350 1.2 martin ATF_TP_ADD_TC(tp, o_search_unpriv_flag1); 351 1.3 dholland #endif 352 1.1 manu ATF_TP_ADD_TC(tp, o_search_perm2); 353 1.3 dholland #ifdef USE_O_SEARCH 354 1.2 martin ATF_TP_ADD_TC(tp, o_search_root_flag2); 355 1.2 martin ATF_TP_ADD_TC(tp, o_search_unpriv_flag2); 356 1.3 dholland #endif 357 1.1 manu ATF_TP_ADD_TC(tp, o_search_notdir); 358 1.9 martin #ifdef USE_O_SEARCH 359 1.9 martin ATF_TP_ADD_TC(tp, o_search_nord); 360 1.9 martin ATF_TP_ADD_TC(tp, o_search_getdents); 361 1.9 martin ATF_TP_ADD_TC(tp, o_search_revokex); 362 1.9 martin #endif 363 1.1 manu 364 1.1 manu return atf_no_error(); 365 1.1 manu } 366