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