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