1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 1999-2006, 2016-2017 Robert N. M. Watson 5 * All rights reserved. 6 * 7 * This software was developed by Robert Watson for the TrustedBSD Project. 8 * 9 * Portions of this software were developed by BAE Systems, the University of 10 * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL 11 * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent 12 * Computing (TC) research program. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 /* 36 * Developed by the TrustedBSD Project. 37 * 38 * ACL system calls and other functions common across different ACL types. 39 * Type-specific routines go into subr_acl_<type>.c. 40 */ 41 42 #include <sys/cdefs.h> 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/sysproto.h> 46 #include <sys/capsicum.h> 47 #include <sys/fcntl.h> 48 #include <sys/kernel.h> 49 #include <sys/malloc.h> 50 #include <sys/mount.h> 51 #include <sys/vnode.h> 52 #include <sys/lock.h> 53 #include <sys/mutex.h> 54 #include <sys/namei.h> 55 #include <sys/file.h> 56 #include <sys/filedesc.h> 57 #include <sys/proc.h> 58 #include <sys/acl.h> 59 60 #include <security/audit/audit.h> 61 #include <security/mac/mac_framework.h> 62 63 CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES); 64 65 MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists"); 66 67 static int kern___acl_aclcheck_path(struct thread *td, const char *path, 68 acl_type_t type, struct acl *aclp, int follow); 69 static int kern___acl_delete_path(struct thread *td, const char *path, 70 acl_type_t type, int follow); 71 static int kern___acl_get_path(struct thread *td, const char *path, 72 acl_type_t type, struct acl *aclp, int follow); 73 static int kern___acl_set_path(struct thread *td, const char *path, 74 acl_type_t type, const struct acl *aclp, int follow); 75 static int vacl_set_acl(struct thread *td, struct vnode *vp, 76 acl_type_t type, const struct acl *aclp); 77 static int vacl_get_acl(struct thread *td, struct vnode *vp, 78 acl_type_t type, struct acl *aclp); 79 static int vacl_aclcheck(struct thread *td, struct vnode *vp, 80 acl_type_t type, const struct acl *aclp); 81 82 int 83 acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest) 84 { 85 int i; 86 87 if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES) 88 return (EINVAL); 89 90 bzero(dest, sizeof(*dest)); 91 92 dest->acl_cnt = source->acl_cnt; 93 dest->acl_maxcnt = ACL_MAX_ENTRIES; 94 95 for (i = 0; i < dest->acl_cnt; i++) { 96 dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag; 97 dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id; 98 dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm; 99 } 100 101 return (0); 102 } 103 104 int 105 acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest) 106 { 107 int i; 108 109 if (source->acl_cnt > OLDACL_MAX_ENTRIES) 110 return (EINVAL); 111 112 bzero(dest, sizeof(*dest)); 113 114 dest->acl_cnt = source->acl_cnt; 115 116 for (i = 0; i < dest->acl_cnt; i++) { 117 dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag; 118 dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id; 119 dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm; 120 } 121 122 return (0); 123 } 124 125 /* 126 * At one time, "struct ACL" was extended in order to add support for NFSv4 127 * ACLs. Instead of creating compatibility versions of all the ACL-related 128 * syscalls, they were left intact. It's possible to find out what the code 129 * calling these syscalls (libc) expects basing on "type" argument - if it's 130 * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were 131 * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct 132 * oldacl". If it's something else, then it's the new "struct acl". In the 133 * latter case, the routines below just copyin/copyout the contents. In the 134 * former case, they copyin the "struct oldacl" and convert it to the new 135 * format. 136 */ 137 static int 138 acl_copyin(const void *user_acl, struct acl *kernel_acl, acl_type_t type) 139 { 140 int error; 141 struct oldacl old; 142 143 switch (type) { 144 case ACL_TYPE_ACCESS_OLD: 145 case ACL_TYPE_DEFAULT_OLD: 146 error = copyin(user_acl, &old, sizeof(old)); 147 if (error != 0) 148 break; 149 acl_copy_oldacl_into_acl(&old, kernel_acl); 150 break; 151 152 default: 153 error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl)); 154 if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES) 155 return (EINVAL); 156 } 157 158 return (error); 159 } 160 161 static int 162 acl_copyout(const struct acl *kernel_acl, void *user_acl, acl_type_t type) 163 { 164 uint32_t am; 165 int error; 166 struct oldacl old; 167 168 switch (type) { 169 case ACL_TYPE_ACCESS_OLD: 170 case ACL_TYPE_DEFAULT_OLD: 171 error = acl_copy_acl_into_oldacl(kernel_acl, &old); 172 if (error != 0) 173 break; 174 175 error = copyout(&old, user_acl, sizeof(old)); 176 break; 177 178 default: 179 error = fueword32((char *)user_acl + 180 offsetof(struct acl, acl_maxcnt), &am); 181 if (error == -1) 182 return (EFAULT); 183 if (am != ACL_MAX_ENTRIES) 184 return (EINVAL); 185 186 error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl)); 187 } 188 189 return (error); 190 } 191 192 /* 193 * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new" 194 * counterpart. It's required for old (pre-NFSv4 ACLs) libc to work 195 * with new kernel. Fixing 'type' for old binaries with new libc 196 * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold(). 197 */ 198 static int 199 acl_type_unold(int type) 200 { 201 switch (type) { 202 case ACL_TYPE_ACCESS_OLD: 203 return (ACL_TYPE_ACCESS); 204 205 case ACL_TYPE_DEFAULT_OLD: 206 return (ACL_TYPE_DEFAULT); 207 208 default: 209 return (type); 210 } 211 } 212 213 /* 214 * These calls wrap the real vnode operations, and are called by the syscall 215 * code once the syscall has converted the path or file descriptor to a vnode 216 * (unlocked). The aclp pointer is assumed still to point to userland, so 217 * this should not be consumed within the kernel except by syscall code. 218 * Other code should directly invoke VOP_{SET,GET}ACL. 219 */ 220 221 /* 222 * Given a vnode, set its ACL. 223 */ 224 static int 225 vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type, 226 const struct acl *aclp) 227 { 228 struct acl *inkernelacl; 229 struct mount *mp; 230 int error; 231 232 AUDIT_ARG_VALUE(type); 233 inkernelacl = acl_alloc(M_WAITOK); 234 error = acl_copyin(aclp, inkernelacl, type); 235 if (error != 0) 236 goto out; 237 error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH); 238 if (error != 0) 239 goto out; 240 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 241 AUDIT_ARG_VNODE1(vp); 242 #ifdef MAC 243 error = mac_vnode_check_setacl(td->td_ucred, vp, type, inkernelacl); 244 if (error != 0) 245 goto out_unlock; 246 #endif 247 error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl, 248 td->td_ucred, td); 249 #ifdef MAC 250 out_unlock: 251 #endif 252 VOP_UNLOCK(vp); 253 vn_finished_write(mp); 254 out: 255 acl_free(inkernelacl); 256 return (error); 257 } 258 259 /* 260 * Given a vnode, get its ACL. 261 */ 262 static int 263 vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type, 264 struct acl *aclp) 265 { 266 struct acl *inkernelacl; 267 int error; 268 269 AUDIT_ARG_VALUE(type); 270 inkernelacl = acl_alloc(M_WAITOK | M_ZERO); 271 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 272 AUDIT_ARG_VNODE1(vp); 273 #ifdef MAC 274 error = mac_vnode_check_getacl(td->td_ucred, vp, type); 275 if (error != 0) 276 goto out; 277 #endif 278 error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl, 279 td->td_ucred, td); 280 281 #ifdef MAC 282 out: 283 #endif 284 VOP_UNLOCK(vp); 285 if (error == 0) 286 error = acl_copyout(inkernelacl, aclp, type); 287 acl_free(inkernelacl); 288 return (error); 289 } 290 291 /* 292 * Given a vnode, delete its ACL. 293 */ 294 static int 295 vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type) 296 { 297 struct mount *mp; 298 int error; 299 300 AUDIT_ARG_VALUE(type); 301 error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH); 302 if (error != 0) 303 return (error); 304 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 305 AUDIT_ARG_VNODE1(vp); 306 #ifdef MAC 307 error = mac_vnode_check_deleteacl(td->td_ucred, vp, type); 308 if (error != 0) 309 goto out; 310 #endif 311 error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td); 312 #ifdef MAC 313 out: 314 #endif 315 VOP_UNLOCK(vp); 316 vn_finished_write(mp); 317 return (error); 318 } 319 320 /* 321 * Given a vnode, check whether an ACL is appropriate for it 322 * 323 * XXXRW: No vnode lock held so can't audit vnode state...? 324 */ 325 static int 326 vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type, 327 const struct acl *aclp) 328 { 329 struct acl *inkernelacl; 330 int error; 331 332 inkernelacl = acl_alloc(M_WAITOK); 333 error = acl_copyin(aclp, inkernelacl, type); 334 if (error != 0) 335 goto out; 336 error = VOP_ACLCHECK(vp, acl_type_unold(type), inkernelacl, 337 td->td_ucred, td); 338 out: 339 acl_free(inkernelacl); 340 return (error); 341 } 342 343 /* 344 * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. Don't 345 * need to lock, as the vacl_ code will get/release any locks required. 346 */ 347 348 /* 349 * Given a file path, get an ACL for it 350 */ 351 int 352 sys___acl_get_file(struct thread *td, struct __acl_get_file_args *uap) 353 { 354 355 return (kern___acl_get_path(td, uap->path, uap->type, uap->aclp, 356 FOLLOW)); 357 } 358 359 /* 360 * Given a file path, get an ACL for it; don't follow links. 361 */ 362 int 363 sys___acl_get_link(struct thread *td, struct __acl_get_link_args *uap) 364 { 365 366 return(kern___acl_get_path(td, uap->path, uap->type, uap->aclp, 367 NOFOLLOW)); 368 } 369 370 static int 371 kern___acl_get_path(struct thread *td, const char *path, acl_type_t type, 372 struct acl *aclp, int follow) 373 { 374 struct nameidata nd; 375 int error; 376 377 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path); 378 error = namei(&nd); 379 if (error == 0) { 380 error = vacl_get_acl(td, nd.ni_vp, type, aclp); 381 vrele(nd.ni_vp); 382 NDFREE_PNBUF(&nd); 383 } 384 return (error); 385 } 386 387 /* 388 * Given a file path, set an ACL for it. 389 */ 390 int 391 sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap) 392 { 393 394 return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp, 395 FOLLOW)); 396 } 397 398 /* 399 * Given a file path, set an ACL for it; don't follow links. 400 */ 401 int 402 sys___acl_set_link(struct thread *td, struct __acl_set_link_args *uap) 403 { 404 405 return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp, 406 NOFOLLOW)); 407 } 408 409 static int 410 kern___acl_set_path(struct thread *td, const char *path, 411 acl_type_t type, const struct acl *aclp, int follow) 412 { 413 struct nameidata nd; 414 int error; 415 416 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path); 417 error = namei(&nd); 418 if (error == 0) { 419 error = vacl_set_acl(td, nd.ni_vp, type, aclp); 420 vrele(nd.ni_vp); 421 NDFREE_PNBUF(&nd); 422 } 423 return (error); 424 } 425 426 /* 427 * Given a file descriptor, get an ACL for it. 428 */ 429 int 430 sys___acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap) 431 { 432 struct file *fp; 433 cap_rights_t rights; 434 int error; 435 436 AUDIT_ARG_FD(uap->filedes); 437 error = getvnode_path(td, uap->filedes, 438 cap_rights_init_one(&rights, CAP_ACL_GET), &fp); 439 if (error == 0) { 440 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp); 441 fdrop(fp, td); 442 } 443 return (error); 444 } 445 446 /* 447 * Given a file descriptor, set an ACL for it. 448 */ 449 int 450 sys___acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap) 451 { 452 struct file *fp; 453 cap_rights_t rights; 454 int error; 455 456 AUDIT_ARG_FD(uap->filedes); 457 error = getvnode(td, uap->filedes, 458 cap_rights_init_one(&rights, CAP_ACL_SET), &fp); 459 if (error == 0) { 460 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp); 461 fdrop(fp, td); 462 } 463 return (error); 464 } 465 466 /* 467 * Given a file path, delete an ACL from it. 468 */ 469 int 470 sys___acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap) 471 { 472 473 return (kern___acl_delete_path(td, uap->path, uap->type, FOLLOW)); 474 } 475 476 /* 477 * Given a file path, delete an ACL from it; don't follow links. 478 */ 479 int 480 sys___acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap) 481 { 482 483 return (kern___acl_delete_path(td, uap->path, uap->type, NOFOLLOW)); 484 } 485 486 static int 487 kern___acl_delete_path(struct thread *td, const char *path, 488 acl_type_t type, int follow) 489 { 490 struct nameidata nd; 491 int error; 492 493 NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path); 494 error = namei(&nd); 495 if (error == 0) { 496 error = vacl_delete(td, nd.ni_vp, type); 497 vrele(nd.ni_vp); 498 NDFREE_PNBUF(&nd); 499 } 500 return (error); 501 } 502 503 /* 504 * Given a file path, delete an ACL from it. 505 */ 506 int 507 sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap) 508 { 509 struct file *fp; 510 cap_rights_t rights; 511 int error; 512 513 AUDIT_ARG_FD(uap->filedes); 514 error = getvnode(td, uap->filedes, 515 cap_rights_init_one(&rights, CAP_ACL_DELETE), &fp); 516 if (error == 0) { 517 error = vacl_delete(td, fp->f_vnode, uap->type); 518 fdrop(fp, td); 519 } 520 return (error); 521 } 522 523 /* 524 * Given a file path, check an ACL for it. 525 */ 526 int 527 sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap) 528 { 529 530 return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp, 531 FOLLOW)); 532 } 533 534 /* 535 * Given a file path, check an ACL for it; don't follow links. 536 */ 537 int 538 sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap) 539 { 540 return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp, 541 NOFOLLOW)); 542 } 543 544 static int 545 kern___acl_aclcheck_path(struct thread *td, const char *path, acl_type_t type, 546 struct acl *aclp, int follow) 547 { 548 struct nameidata nd; 549 int error; 550 551 NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path); 552 error = namei(&nd); 553 if (error == 0) { 554 error = vacl_aclcheck(td, nd.ni_vp, type, aclp); 555 NDFREE_PNBUF(&nd); 556 } 557 return (error); 558 } 559 560 /* 561 * Given a file descriptor, check an ACL for it. 562 */ 563 int 564 sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap) 565 { 566 struct file *fp; 567 cap_rights_t rights; 568 int error; 569 570 AUDIT_ARG_FD(uap->filedes); 571 error = getvnode_path(td, uap->filedes, 572 cap_rights_init_one(&rights, CAP_ACL_CHECK), &fp); 573 if (error == 0) { 574 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp); 575 fdrop(fp, td); 576 } 577 return (error); 578 } 579 580 struct acl * 581 acl_alloc(int flags) 582 { 583 struct acl *aclp; 584 585 aclp = malloc(sizeof(*aclp), M_ACL, flags); 586 if (aclp == NULL) 587 return (NULL); 588 589 aclp->acl_maxcnt = ACL_MAX_ENTRIES; 590 591 return (aclp); 592 } 593 594 void 595 acl_free(struct acl *aclp) 596 { 597 598 free(aclp, M_ACL); 599 } 600