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 | 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 | 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 NDFREE(&nd, 0); 384 } 385 return (error); 386 } 387 388 /* 389 * Given a file path, set an ACL for it. 390 */ 391 int 392 sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap) 393 { 394 395 return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp, 396 FOLLOW)); 397 } 398 399 /* 400 * Given a file path, set an ACL for it; don't follow links. 401 */ 402 int 403 sys___acl_set_link(struct thread *td, struct __acl_set_link_args *uap) 404 { 405 406 return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp, 407 NOFOLLOW)); 408 } 409 410 static int 411 kern___acl_set_path(struct thread *td, const char *path, 412 acl_type_t type, const struct acl *aclp, int follow) 413 { 414 struct nameidata nd; 415 int error; 416 417 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path); 418 error = namei(&nd); 419 if (error == 0) { 420 error = vacl_set_acl(td, nd.ni_vp, type, aclp); 421 NDFREE(&nd, 0); 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(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 NDFREE(&nd, 0); 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(&nd, 0); 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(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