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