1 /*
2 * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
29 /*
30 * Copyright (c) 1982, 1986, 1989, 1991, 1993
31 * The Regents of the University of California. All rights reserved.
32 * (c) UNIX System Laboratories, Inc.
33 * All or some portions of this file are derived from material licensed
34 * to the University of California by American Telephone and Telegraph
35 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36 * the permission of UNIX System Laboratories, Inc.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 *
66 * @(#)kern_descrip.c 8.8 (Berkeley) 2/14/95
67 */
68 /*
69 * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
70 * support for mandatory and extensible security protections. This notice
71 * is included in support of clause 2.2 (b) of the Apple Public License,
72 * Version 2.0.
73 */
74
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/filedesc.h>
78 #include <sys/kernel.h>
79 #include <sys/vnode_internal.h>
80 #include <sys/proc_internal.h>
81 #include <sys/kauth.h>
82 #include <sys/file_internal.h>
83 #include <sys/guarded.h>
84 #include <sys/priv.h>
85 #include <sys/socket.h>
86 #include <sys/socketvar.h>
87 #include <sys/stat.h>
88 #include <sys/ioctl.h>
89 #include <sys/fcntl.h>
90 #include <sys/fsctl.h>
91 #include <sys/malloc.h>
92 #include <sys/mman.h>
93 #include <sys/mount.h>
94 #include <sys/syslog.h>
95 #include <sys/unistd.h>
96 #include <sys/resourcevar.h>
97 #include <sys/aio_kern.h>
98 #include <sys/ev.h>
99 #include <kern/locks.h>
100 #include <sys/uio_internal.h>
101 #include <sys/codesign.h>
102 #include <sys/codedir_internal.h>
103 #include <sys/mount_internal.h>
104 #include <sys/kdebug.h>
105 #include <sys/sysproto.h>
106 #include <sys/pipe.h>
107 #include <sys/spawn.h>
108 #include <sys/cprotect.h>
109 #include <sys/ubc_internal.h>
110
111 #include <kern/kern_types.h>
112 #include <kern/kalloc.h>
113 #include <kern/waitq.h>
114 #include <kern/ipc_kobject.h>
115 #include <kern/ipc_misc.h>
116 #include <kern/ast.h>
117
118 #include <vm/vm_protos.h>
119 #include <mach/mach_port.h>
120
121 #include <security/audit/audit.h>
122 #if CONFIG_MACF
123 #include <security/mac_framework.h>
124 #endif
125
126 #include <stdbool.h>
127 #include <os/atomic_private.h>
128 #include <os/overflow.h>
129 #include <IOKit/IOBSD.h>
130
131 void fileport_releasefg(struct fileglob *fg);
132
133 /* flags for fp_close_and_unlock */
134 #define FD_DUP2RESV 1
135
136 /* We don't want these exported */
137
138 __private_extern__
139 int unlink1(vfs_context_t, vnode_t, user_addr_t, enum uio_seg, int);
140
141 /* Conflict wait queue for when selects collide (opaque type) */
142 extern struct waitq select_conflict_queue;
143
144 #define f_flag fp_glob->fg_flag
145 #define f_type fp_glob->fg_ops->fo_type
146 #define f_cred fp_glob->fg_cred
147 #define f_ops fp_glob->fg_ops
148 #define f_offset fp_glob->fg_offset
149
150 ZONE_DEFINE_TYPE(fg_zone, "fileglob", struct fileglob, ZC_ZFREE_CLEARMEM);
151 ZONE_DEFINE_ID(ZONE_ID_FILEPROC, "fileproc", struct fileproc, ZC_ZFREE_CLEARMEM);
152
153 /*
154 * Descriptor management.
155 */
156 int nfiles; /* actual number of open files */
157 /*
158 * "uninitialized" ops -- ensure FILEGLOB_DTYPE(fg) always exists
159 */
160 static const struct fileops uninitops;
161
162 os_refgrp_decl(, f_refgrp, "files refcounts", NULL);
163 static LCK_GRP_DECLARE(file_lck_grp, "file");
164
165
166 #pragma mark fileglobs
167
168 /*!
169 * @function fg_alloc_init
170 *
171 * @brief
172 * Allocate and minimally initialize a file structure.
173 */
174 struct fileglob *
fg_alloc_init(vfs_context_t ctx)175 fg_alloc_init(vfs_context_t ctx)
176 {
177 struct fileglob *fg;
178
179 fg = zalloc_flags(fg_zone, Z_WAITOK | Z_ZERO);
180 lck_mtx_init(&fg->fg_lock, &file_lck_grp, LCK_ATTR_NULL);
181
182 os_ref_init_raw(&fg->fg_count, &f_refgrp);
183 fg->fg_ops = &uninitops;
184
185 kauth_cred_ref(ctx->vc_ucred);
186 fg->fg_cred = ctx->vc_ucred;
187
188 os_atomic_inc(&nfiles, relaxed);
189
190 return fg;
191 }
192
193 /*!
194 * @function fg_free
195 *
196 * @brief
197 * Free a file structure.
198 */
199 static void
fg_free(struct fileglob * fg)200 fg_free(struct fileglob *fg)
201 {
202 os_atomic_dec(&nfiles, relaxed);
203
204 if (fg->fg_vn_data) {
205 fg_vn_data_free(fg->fg_vn_data);
206 fg->fg_vn_data = NULL;
207 }
208
209 kauth_cred_t cred = fg->fg_cred;
210 if (IS_VALID_CRED(cred)) {
211 kauth_cred_unref(&cred);
212 fg->fg_cred = NOCRED;
213 }
214 lck_mtx_destroy(&fg->fg_lock, &file_lck_grp);
215
216 #if CONFIG_MACF && CONFIG_VNGUARD
217 vng_file_label_destroy(fg);
218 #endif
219 zfree(fg_zone, fg);
220 }
221
222 OS_ALWAYS_INLINE
223 void
fg_ref(proc_t p,struct fileglob * fg)224 fg_ref(proc_t p, struct fileglob *fg)
225 {
226 #if DEBUG || DEVELOPMENT
227 /* Allow fileglob refs to be taken outside of a process context. */
228 if (p != FG_NOPROC) {
229 proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
230 }
231 #else
232 (void)p;
233 #endif
234 os_ref_retain_raw(&fg->fg_count, &f_refgrp);
235 }
236
237 void
fg_drop_live(struct fileglob * fg)238 fg_drop_live(struct fileglob *fg)
239 {
240 os_ref_release_live_raw(&fg->fg_count, &f_refgrp);
241 }
242
243 int
fg_drop(proc_t p,struct fileglob * fg)244 fg_drop(proc_t p, struct fileglob *fg)
245 {
246 struct vnode *vp;
247 struct vfs_context context;
248 int error = 0;
249
250 if (fg == NULL) {
251 return 0;
252 }
253
254 /* Set up context with cred stashed in fg */
255 if (p == current_proc()) {
256 context.vc_thread = current_thread();
257 } else {
258 context.vc_thread = NULL;
259 }
260 context.vc_ucred = fg->fg_cred;
261
262 /*
263 * POSIX record locking dictates that any close releases ALL
264 * locks owned by this process. This is handled by setting
265 * a flag in the unlock to free ONLY locks obeying POSIX
266 * semantics, and not to free BSD-style file locks.
267 * If the descriptor was in a message, POSIX-style locks
268 * aren't passed with the descriptor.
269 */
270 if (p != FG_NOPROC && DTYPE_VNODE == FILEGLOB_DTYPE(fg) &&
271 (p->p_ladvflag & P_LADVLOCK)) {
272 struct flock lf = {
273 .l_whence = SEEK_SET,
274 .l_type = F_UNLCK,
275 };
276
277 vp = (struct vnode *)fg_get_data(fg);
278 if ((error = vnode_getwithref(vp)) == 0) {
279 (void)VNOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX, &context, NULL);
280 (void)vnode_put(vp);
281 }
282 }
283
284 if (os_ref_release_raw(&fg->fg_count, &f_refgrp) == 0) {
285 /*
286 * Since we ensure that fg->fg_ops is always initialized,
287 * it is safe to invoke fo_close on the fg
288 */
289 error = fo_close(fg, &context);
290
291 fg_free(fg);
292 }
293
294 return error;
295 }
296
297 inline
298 void
fg_set_data(struct fileglob * fg,void * fg_data)299 fg_set_data(
300 struct fileglob *fg,
301 void *fg_data)
302 {
303 uintptr_t *store = &fg->fg_data;
304
305 #if __has_feature(ptrauth_calls)
306 int type = FILEGLOB_DTYPE(fg);
307
308 if (fg_data) {
309 type ^= OS_PTRAUTH_DISCRIMINATOR("fileglob.fg_data");
310 fg_data = ptrauth_sign_unauthenticated(fg_data,
311 ptrauth_key_process_independent_data,
312 ptrauth_blend_discriminator(store, type));
313 }
314 #endif // __has_feature(ptrauth_calls)
315
316 *store = (uintptr_t)fg_data;
317 }
318
319 inline
320 void *
fg_get_data_volatile(struct fileglob * fg)321 fg_get_data_volatile(struct fileglob *fg)
322 {
323 uintptr_t *store = &fg->fg_data;
324 void *fg_data = (void *)*store;
325
326 #if __has_feature(ptrauth_calls)
327 int type = FILEGLOB_DTYPE(fg);
328
329 if (fg_data) {
330 type ^= OS_PTRAUTH_DISCRIMINATOR("fileglob.fg_data");
331 fg_data = ptrauth_auth_data(fg_data,
332 ptrauth_key_process_independent_data,
333 ptrauth_blend_discriminator(store, type));
334 }
335 #endif // __has_feature(ptrauth_calls)
336
337 return fg_data;
338 }
339
340 static void
fg_transfer_filelocks(proc_t p,struct fileglob * fg,thread_t thread)341 fg_transfer_filelocks(proc_t p, struct fileglob *fg, thread_t thread)
342 {
343 struct vnode *vp;
344 struct vfs_context context;
345 struct proc *old_proc = current_proc();
346
347 assert(fg != NULL);
348
349 assert(p != old_proc);
350 context.vc_thread = thread;
351 context.vc_ucred = fg->fg_cred;
352
353 /* Transfer all POSIX Style locks to new proc */
354 if (p && DTYPE_VNODE == FILEGLOB_DTYPE(fg) &&
355 (p->p_ladvflag & P_LADVLOCK)) {
356 struct flock lf = {
357 .l_whence = SEEK_SET,
358 .l_start = 0,
359 .l_len = 0,
360 .l_type = F_TRANSFER,
361 };
362
363 vp = (struct vnode *)fg_get_data(fg);
364 if (vnode_getwithref(vp) == 0) {
365 (void)VNOP_ADVLOCK(vp, (caddr_t)old_proc, F_TRANSFER, &lf, F_POSIX, &context, NULL);
366 (void)vnode_put(vp);
367 }
368 }
369
370 /* Transfer all OFD Style locks to new proc */
371 if (p && DTYPE_VNODE == FILEGLOB_DTYPE(fg) &&
372 (fg->fg_lflags & FG_HAS_OFDLOCK)) {
373 struct flock lf = {
374 .l_whence = SEEK_SET,
375 .l_start = 0,
376 .l_len = 0,
377 .l_type = F_TRANSFER,
378 };
379
380 vp = (struct vnode *)fg_get_data(fg);
381 if (vnode_getwithref(vp) == 0) {
382 (void)VNOP_ADVLOCK(vp, ofd_to_id(fg), F_TRANSFER, &lf, F_OFD_LOCK, &context, NULL);
383 (void)vnode_put(vp);
384 }
385 }
386 return;
387 }
388
389 bool
fg_sendable(struct fileglob * fg)390 fg_sendable(struct fileglob *fg)
391 {
392 switch (FILEGLOB_DTYPE(fg)) {
393 case DTYPE_VNODE:
394 case DTYPE_SOCKET:
395 case DTYPE_PIPE:
396 case DTYPE_PSXSHM:
397 case DTYPE_NETPOLICY:
398 return (fg->fg_lflags & FG_CONFINED) == 0;
399
400 default:
401 return false;
402 }
403 }
404
405 #pragma mark file descriptor table (static helpers)
406
407 static void
procfdtbl_reservefd(struct proc * p,int fd)408 procfdtbl_reservefd(struct proc * p, int fd)
409 {
410 p->p_fd.fd_ofiles[fd] = NULL;
411 p->p_fd.fd_ofileflags[fd] |= UF_RESERVED;
412 }
413
414 void
procfdtbl_releasefd(struct proc * p,int fd,struct fileproc * fp)415 procfdtbl_releasefd(struct proc * p, int fd, struct fileproc * fp)
416 {
417 if (fp != NULL) {
418 p->p_fd.fd_ofiles[fd] = fp;
419 }
420 p->p_fd.fd_ofileflags[fd] &= ~UF_RESERVED;
421 if ((p->p_fd.fd_ofileflags[fd] & UF_RESVWAIT) == UF_RESVWAIT) {
422 p->p_fd.fd_ofileflags[fd] &= ~UF_RESVWAIT;
423 wakeup(&p->p_fd);
424 }
425 }
426
427 static void
procfdtbl_waitfd(struct proc * p,int fd)428 procfdtbl_waitfd(struct proc * p, int fd)
429 {
430 p->p_fd.fd_ofileflags[fd] |= UF_RESVWAIT;
431 msleep(&p->p_fd, &p->p_fd.fd_lock, PRIBIO, "ftbl_waitfd", NULL);
432 }
433
434 static void
procfdtbl_clearfd(struct proc * p,int fd)435 procfdtbl_clearfd(struct proc * p, int fd)
436 {
437 int waiting;
438
439 waiting = (p->p_fd.fd_ofileflags[fd] & UF_RESVWAIT);
440 p->p_fd.fd_ofiles[fd] = NULL;
441 p->p_fd.fd_ofileflags[fd] = 0;
442 if (waiting == UF_RESVWAIT) {
443 wakeup(&p->p_fd);
444 }
445 }
446
447 /*
448 * fdrelse
449 *
450 * Description: Inline utility function to free an fd in a filedesc
451 *
452 * Parameters: fdp Pointer to filedesc fd lies in
453 * fd fd to free
454 * reserv fd should be reserved
455 *
456 * Returns: void
457 *
458 * Locks: Assumes proc_fdlock for process pointing to fdp is held by
459 * the caller
460 */
461 void
fdrelse(struct proc * p,int fd)462 fdrelse(struct proc * p, int fd)
463 {
464 struct filedesc *fdp = &p->p_fd;
465 int nfd = 0;
466
467 if (fd < fdp->fd_freefile) {
468 fdp->fd_freefile = fd;
469 }
470 #if DIAGNOSTIC
471 if (fd >= fdp->fd_afterlast) {
472 panic("fdrelse: fd_afterlast inconsistent");
473 }
474 #endif
475 procfdtbl_clearfd(p, fd);
476
477 nfd = fdp->fd_afterlast;
478 while (nfd > 0 && fdp->fd_ofiles[nfd - 1] == NULL &&
479 !(fdp->fd_ofileflags[nfd - 1] & UF_RESERVED)) {
480 nfd--;
481 }
482 fdp->fd_afterlast = nfd;
483
484 #if CONFIG_PROC_RESOURCE_LIMITS
485 fdp->fd_nfiles_open--;
486 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
487 }
488
489
490 /*
491 * finishdup
492 *
493 * Description: Common code for dup, dup2, and fcntl(F_DUPFD).
494 *
495 * Parameters: p Process performing the dup
496 * old The fd to dup
497 * new The fd to dup it to
498 * fp_flags Flags to augment the new fp
499 * retval Pointer to the call return area
500 *
501 * Returns: 0 Success
502 * EBADF
503 * ENOMEM
504 *
505 * Implicit returns:
506 * *retval (modified) The new descriptor
507 *
508 * Locks: Assumes proc_fdlock for process pointing to fdp is held by
509 * the caller
510 *
511 * Notes: This function may drop and reacquire this lock; it is unsafe
512 * for a caller to assume that other state protected by the lock
513 * has not been subsequently changed out from under it.
514 */
515 static int
finishdup(proc_t p,kauth_cred_t p_cred,int old,int new,fileproc_flags_t fp_flags,int32_t * retval)516 finishdup(
517 proc_t p,
518 kauth_cred_t p_cred,
519 int old,
520 int new,
521 fileproc_flags_t fp_flags,
522 int32_t *retval)
523 {
524 struct filedesc *fdp = &p->p_fd;
525 struct fileproc *nfp;
526 struct fileproc *ofp;
527 #if CONFIG_MACF
528 int error;
529 #endif
530
531 #if DIAGNOSTIC
532 proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
533 #endif
534 if ((ofp = fdp->fd_ofiles[old]) == NULL ||
535 (fdp->fd_ofileflags[old] & UF_RESERVED)) {
536 fdrelse(p, new);
537 return EBADF;
538 }
539
540 #if CONFIG_MACF
541 error = mac_file_check_dup(p_cred, ofp->fp_glob, new);
542
543 if (error) {
544 fdrelse(p, new);
545 return error;
546 }
547 #else
548 (void)p_cred;
549 #endif
550
551 fg_ref(p, ofp->fp_glob);
552
553 proc_fdunlock(p);
554
555 nfp = fileproc_alloc_init();
556
557 if (fp_flags) {
558 nfp->fp_flags |= fp_flags;
559 }
560 nfp->fp_glob = ofp->fp_glob;
561
562 proc_fdlock(p);
563
564 #if DIAGNOSTIC
565 if (fdp->fd_ofiles[new] != 0) {
566 panic("finishdup: overwriting fd_ofiles with new %d", new);
567 }
568 if ((fdp->fd_ofileflags[new] & UF_RESERVED) == 0) {
569 panic("finishdup: unreserved fileflags with new %d", new);
570 }
571 #endif
572
573 if (new >= fdp->fd_afterlast) {
574 fdp->fd_afterlast = new + 1;
575 }
576 procfdtbl_releasefd(p, new, nfp);
577 *retval = new;
578 return 0;
579 }
580
581
582 #pragma mark file descriptor table (exported functions)
583
584 void
proc_dirs_lock_shared(proc_t p)585 proc_dirs_lock_shared(proc_t p)
586 {
587 lck_rw_lock_shared(&p->p_fd.fd_dirs_lock);
588 }
589
590 void
proc_dirs_unlock_shared(proc_t p)591 proc_dirs_unlock_shared(proc_t p)
592 {
593 lck_rw_unlock_shared(&p->p_fd.fd_dirs_lock);
594 }
595
596 void
proc_dirs_lock_exclusive(proc_t p)597 proc_dirs_lock_exclusive(proc_t p)
598 {
599 lck_rw_lock_exclusive(&p->p_fd.fd_dirs_lock);
600 }
601
602 void
proc_dirs_unlock_exclusive(proc_t p)603 proc_dirs_unlock_exclusive(proc_t p)
604 {
605 lck_rw_unlock_exclusive(&p->p_fd.fd_dirs_lock);
606 }
607
608 /*
609 * proc_fdlock, proc_fdlock_spin
610 *
611 * Description: Lock to control access to the per process struct fileproc
612 * and struct filedesc
613 *
614 * Parameters: p Process to take the lock on
615 *
616 * Returns: void
617 *
618 * Notes: The lock is initialized in forkproc() and destroyed in
619 * reap_child_process().
620 */
621 void
proc_fdlock(proc_t p)622 proc_fdlock(proc_t p)
623 {
624 lck_mtx_lock(&p->p_fd.fd_lock);
625 }
626
627 void
proc_fdlock_spin(proc_t p)628 proc_fdlock_spin(proc_t p)
629 {
630 lck_mtx_lock_spin(&p->p_fd.fd_lock);
631 }
632
633 void
proc_fdlock_assert(proc_t p,int assertflags)634 proc_fdlock_assert(proc_t p, int assertflags)
635 {
636 lck_mtx_assert(&p->p_fd.fd_lock, assertflags);
637 }
638
639
640 /*
641 * proc_fdunlock
642 *
643 * Description: Unlock the lock previously locked by a call to proc_fdlock()
644 *
645 * Parameters: p Process to drop the lock on
646 *
647 * Returns: void
648 */
649 void
proc_fdunlock(proc_t p)650 proc_fdunlock(proc_t p)
651 {
652 lck_mtx_unlock(&p->p_fd.fd_lock);
653 }
654
655 bool
fdt_available_locked(proc_t p,int n)656 fdt_available_locked(proc_t p, int n)
657 {
658 struct filedesc *fdp = &p->p_fd;
659 struct fileproc **fpp;
660 char *flags;
661 int i;
662 int lim = proc_limitgetcur_nofile(p);
663
664 if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0) {
665 return true;
666 }
667 fpp = &fdp->fd_ofiles[fdp->fd_freefile];
668 flags = &fdp->fd_ofileflags[fdp->fd_freefile];
669 for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++, flags++) {
670 if (*fpp == NULL && !(*flags & UF_RESERVED) && --n <= 0) {
671 return true;
672 }
673 }
674 return false;
675 }
676
677
678 struct fdt_iterator
fdt_next(proc_t p,int fd,bool only_settled)679 fdt_next(proc_t p, int fd, bool only_settled)
680 {
681 struct fdt_iterator it;
682 struct filedesc *fdp = &p->p_fd;
683 struct fileproc *fp;
684 int nfds = fdp->fd_afterlast;
685
686 while (++fd < nfds) {
687 fp = fdp->fd_ofiles[fd];
688 if (fp == NULL || fp->fp_glob == NULL) {
689 continue;
690 }
691 if (only_settled && (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
692 continue;
693 }
694 it.fdti_fd = fd;
695 it.fdti_fp = fp;
696 return it;
697 }
698
699 it.fdti_fd = nfds;
700 it.fdti_fp = NULL;
701 return it;
702 }
703
704 struct fdt_iterator
fdt_prev(proc_t p,int fd,bool only_settled)705 fdt_prev(proc_t p, int fd, bool only_settled)
706 {
707 struct fdt_iterator it;
708 struct filedesc *fdp = &p->p_fd;
709 struct fileproc *fp;
710
711 while (--fd >= 0) {
712 fp = fdp->fd_ofiles[fd];
713 if (fp == NULL || fp->fp_glob == NULL) {
714 continue;
715 }
716 if (only_settled && (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
717 continue;
718 }
719 it.fdti_fd = fd;
720 it.fdti_fp = fp;
721 return it;
722 }
723
724 it.fdti_fd = -1;
725 it.fdti_fp = NULL;
726 return it;
727 }
728
729 void
fdt_init(proc_t p)730 fdt_init(proc_t p)
731 {
732 struct filedesc *fdp = &p->p_fd;
733
734 lck_mtx_init(&fdp->fd_kqhashlock, &proc_kqhashlock_grp, &proc_lck_attr);
735 lck_mtx_init(&fdp->fd_knhashlock, &proc_knhashlock_grp, &proc_lck_attr);
736 lck_mtx_init(&fdp->fd_lock, &proc_fdmlock_grp, &proc_lck_attr);
737 lck_rw_init(&fdp->fd_dirs_lock, &proc_dirslock_grp, &proc_lck_attr);
738 }
739
740 void
fdt_destroy(proc_t p)741 fdt_destroy(proc_t p)
742 {
743 struct filedesc *fdp = &p->p_fd;
744
745 lck_mtx_destroy(&fdp->fd_kqhashlock, &proc_kqhashlock_grp);
746 lck_mtx_destroy(&fdp->fd_knhashlock, &proc_knhashlock_grp);
747 lck_mtx_destroy(&fdp->fd_lock, &proc_fdmlock_grp);
748 lck_rw_destroy(&fdp->fd_dirs_lock, &proc_dirslock_grp);
749 }
750
751 void
fdt_exec(proc_t p,kauth_cred_t p_cred,short posix_spawn_flags,thread_t thread,bool in_exec)752 fdt_exec(proc_t p, kauth_cred_t p_cred, short posix_spawn_flags, thread_t thread, bool in_exec)
753 {
754 struct filedesc *fdp = &p->p_fd;
755 thread_t self = current_thread();
756 struct uthread *ut = get_bsdthread_info(self);
757 struct kqworkq *dealloc_kqwq = NULL;
758
759 /*
760 * If the current thread is bound as a workq/workloop
761 * servicing thread, we need to unbind it first.
762 */
763 if (ut->uu_kqr_bound && get_bsdthreadtask_info(self) == p) {
764 kqueue_threadreq_unbind(p, ut->uu_kqr_bound);
765 }
766
767 /*
768 * Deallocate the knotes for this process
769 * and mark the tables non-existent so
770 * subsequent kqueue closes go faster.
771 */
772 knotes_dealloc(p);
773 assert(fdp->fd_knlistsize == 0);
774 assert(fdp->fd_knhashmask == 0);
775
776 proc_fdlock(p);
777
778 /* Set the P_LADVLOCK flag if the flag set on old proc */
779 if (in_exec && (current_proc()->p_ladvflag & P_LADVLOCK)) {
780 os_atomic_or(&p->p_ladvflag, P_LADVLOCK, relaxed);
781 }
782
783 for (int i = fdp->fd_afterlast; i-- > 0;) {
784 struct fileproc *fp = fdp->fd_ofiles[i];
785 char *flagp = &fdp->fd_ofileflags[i];
786 bool inherit_file = true;
787
788 if (fp == FILEPROC_NULL) {
789 continue;
790 }
791
792 /*
793 * no file descriptor should be in flux when in exec,
794 * because we stopped all other threads
795 */
796 if (*flagp & ~UF_INHERIT) {
797 panic("file %d/%p in flux during exec of %p", i, fp, p);
798 }
799
800 if (fp->fp_flags & FP_CLOEXEC) {
801 inherit_file = false;
802 } else if ((posix_spawn_flags & POSIX_SPAWN_CLOEXEC_DEFAULT) &&
803 !(*flagp & UF_INHERIT)) {
804 /*
805 * Reverse the usual semantics of file descriptor
806 * inheritance - all of them should be closed
807 * except files marked explicitly as "inherit" and
808 * not marked close-on-exec.
809 */
810 inherit_file = false;
811 #if CONFIG_MACF
812 } else if (mac_file_check_inherit(p_cred, fp->fp_glob)) {
813 inherit_file = false;
814 #endif
815 }
816
817 *flagp = 0; /* clear UF_INHERIT */
818
819 if (!inherit_file) {
820 fp_close_and_unlock(p, p_cred, i, fp, 0);
821 proc_fdlock(p);
822 } else if (in_exec) {
823 /* Transfer F_POSIX style lock to new proc */
824 proc_fdunlock(p);
825 fg_transfer_filelocks(p, fp->fp_glob, thread);
826 proc_fdlock(p);
827 }
828 }
829
830 /* release the per-process workq kq */
831 if (fdp->fd_wqkqueue) {
832 dealloc_kqwq = fdp->fd_wqkqueue;
833 fdp->fd_wqkqueue = NULL;
834 }
835
836 proc_fdunlock(p);
837
838 /* Anything to free? */
839 if (dealloc_kqwq) {
840 kqworkq_dealloc(dealloc_kqwq);
841 }
842 }
843
844
845 int
fdt_fork(struct filedesc * newfdp,proc_t p,vnode_t uth_cdir,bool in_exec)846 fdt_fork(struct filedesc *newfdp, proc_t p, vnode_t uth_cdir, bool in_exec)
847 {
848 struct filedesc *fdp = &p->p_fd;
849 struct fileproc **ofiles;
850 char *ofileflags;
851 int n_files, afterlast, freefile;
852 vnode_t v_dir;
853 #if CONFIG_PROC_RESOURCE_LIMITS
854 int fd_nfiles_open = 0;
855 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
856 proc_fdlock(p);
857
858 newfdp->fd_flags = (fdp->fd_flags & FILEDESC_FORK_INHERITED_MASK);
859 newfdp->fd_cmask = fdp->fd_cmask;
860 #if CONFIG_PROC_RESOURCE_LIMITS
861 newfdp->fd_nfiles_soft_limit = fdp->fd_nfiles_soft_limit;
862 newfdp->fd_nfiles_hard_limit = fdp->fd_nfiles_hard_limit;
863
864 newfdp->kqwl_dyn_soft_limit = fdp->kqwl_dyn_soft_limit;
865 newfdp->kqwl_dyn_hard_limit = fdp->kqwl_dyn_hard_limit;
866 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
867
868 /*
869 * For both fd_cdir and fd_rdir make sure we get
870 * a valid reference... if we can't, than set
871 * set the pointer(s) to NULL in the child... this
872 * will keep us from using a non-referenced vp
873 * and allows us to do the vnode_rele only on
874 * a properly referenced vp
875 */
876 if ((v_dir = fdp->fd_rdir)) {
877 if (vnode_getwithref(v_dir) == 0) {
878 if (vnode_ref(v_dir) == 0) {
879 newfdp->fd_rdir = v_dir;
880 }
881 vnode_put(v_dir);
882 }
883 if (newfdp->fd_rdir == NULL) {
884 /*
885 * We couldn't get a new reference on
886 * the chroot directory being
887 * inherited... this is fatal, since
888 * otherwise it would constitute an
889 * escape from a chroot environment by
890 * the new process.
891 */
892 proc_fdunlock(p);
893 return EPERM;
894 }
895 }
896
897 /*
898 * If we are running with per-thread current working directories,
899 * inherit the new current working directory from the current thread.
900 */
901 if ((v_dir = uth_cdir ? uth_cdir : fdp->fd_cdir)) {
902 if (vnode_getwithref(v_dir) == 0) {
903 if (vnode_ref(v_dir) == 0) {
904 newfdp->fd_cdir = v_dir;
905 }
906 vnode_put(v_dir);
907 }
908 if (newfdp->fd_cdir == NULL && v_dir == fdp->fd_cdir) {
909 /*
910 * we couldn't get a new reference on
911 * the current working directory being
912 * inherited... we might as well drop
913 * our reference from the parent also
914 * since the vnode has gone DEAD making
915 * it useless... by dropping it we'll
916 * be that much closer to recycling it
917 */
918 vnode_rele(fdp->fd_cdir);
919 fdp->fd_cdir = NULL;
920 }
921 }
922
923 /*
924 * If the number of open files fits in the internal arrays
925 * of the open file structure, use them, otherwise allocate
926 * additional memory for the number of descriptors currently
927 * in use.
928 */
929 afterlast = fdp->fd_afterlast;
930 freefile = fdp->fd_freefile;
931 if (afterlast <= NDFILE) {
932 n_files = NDFILE;
933 } else {
934 n_files = roundup(afterlast, NDEXTENT);
935 }
936
937 proc_fdunlock(p);
938
939 ofiles = kalloc_type(struct fileproc *, n_files, Z_WAITOK | Z_ZERO);
940 ofileflags = kalloc_data(n_files, Z_WAITOK | Z_ZERO);
941 if (ofiles == NULL || ofileflags == NULL) {
942 kfree_type(struct fileproc *, n_files, ofiles);
943 kfree_data(ofileflags, n_files);
944 if (newfdp->fd_cdir) {
945 vnode_rele(newfdp->fd_cdir);
946 newfdp->fd_cdir = NULL;
947 }
948 if (newfdp->fd_rdir) {
949 vnode_rele(newfdp->fd_rdir);
950 newfdp->fd_rdir = NULL;
951 }
952 return ENOMEM;
953 }
954
955 proc_fdlock(p);
956
957 for (int i = afterlast; i-- > 0;) {
958 struct fileproc *ofp, *nfp;
959 char flags;
960
961 ofp = fdp->fd_ofiles[i];
962 flags = fdp->fd_ofileflags[i];
963
964 if (ofp == NULL ||
965 (ofp->fp_glob->fg_lflags & FG_CONFINED) ||
966 ((ofp->fp_flags & FP_CLOFORK) && !in_exec) ||
967 ((ofp->fp_flags & FP_CLOEXEC) && in_exec) ||
968 (flags & UF_RESERVED)) {
969 if (i + 1 == afterlast) {
970 afterlast = i;
971 }
972 if (i < freefile) {
973 freefile = i;
974 }
975
976 continue;
977 }
978
979 nfp = fileproc_alloc_init();
980 nfp->fp_glob = ofp->fp_glob;
981 if (in_exec) {
982 nfp->fp_flags = (ofp->fp_flags & (FP_CLOEXEC | FP_CLOFORK));
983 if (ofp->fp_guard_attrs) {
984 guarded_fileproc_copy_guard(ofp, nfp);
985 }
986 } else {
987 assert(ofp->fp_guard_attrs == 0);
988 nfp->fp_flags = (ofp->fp_flags & FP_CLOEXEC);
989 }
990 fg_ref(p, nfp->fp_glob);
991
992 ofiles[i] = nfp;
993 #if CONFIG_PROC_RESOURCE_LIMITS
994 fd_nfiles_open++;
995 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
996 }
997
998 proc_fdunlock(p);
999
1000 newfdp->fd_ofiles = ofiles;
1001 newfdp->fd_ofileflags = ofileflags;
1002 newfdp->fd_nfiles = n_files;
1003 newfdp->fd_afterlast = afterlast;
1004 newfdp->fd_freefile = freefile;
1005
1006 #if CONFIG_PROC_RESOURCE_LIMITS
1007 newfdp->fd_nfiles_open = fd_nfiles_open;
1008 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
1009
1010 return 0;
1011 }
1012
1013 void
fdt_invalidate(proc_t p)1014 fdt_invalidate(proc_t p)
1015 {
1016 struct filedesc *fdp = &p->p_fd;
1017 struct fileproc *fp, **ofiles;
1018 kauth_cred_t p_cred;
1019 char *ofileflags;
1020 struct kqworkq *kqwq = NULL;
1021 vnode_t vn1 = NULL, vn2 = NULL;
1022 struct kqwllist *kqhash = NULL;
1023 u_long kqhashmask = 0;
1024 int n_files = 0;
1025
1026 /*
1027 * deallocate all the knotes up front and claim empty
1028 * tables to make any subsequent kqueue closes faster.
1029 */
1030 knotes_dealloc(p);
1031 assert(fdp->fd_knlistsize == 0);
1032 assert(fdp->fd_knhashmask == 0);
1033
1034 /*
1035 * dealloc all workloops that have outstanding retains
1036 * when created with scheduling parameters.
1037 */
1038 kqworkloops_dealloc(p);
1039
1040 proc_fdlock(p);
1041
1042 /* proc_ucred_unsafe() is ok: process is terminating */
1043 p_cred = proc_ucred_unsafe(p);
1044
1045 /* close file descriptors */
1046 if (fdp->fd_nfiles > 0 && fdp->fd_ofiles) {
1047 for (int i = fdp->fd_afterlast; i-- > 0;) {
1048 if ((fp = fdp->fd_ofiles[i]) != NULL) {
1049 if (fdp->fd_ofileflags[i] & UF_RESERVED) {
1050 panic("fdfree: found fp with UF_RESERVED");
1051 }
1052 /* proc_ucred_unsafe() is ok: process is terminating */
1053 fp_close_and_unlock(p, p_cred, i, fp, 0);
1054 proc_fdlock(p);
1055 }
1056 }
1057 }
1058
1059 n_files = fdp->fd_nfiles;
1060 ofileflags = fdp->fd_ofileflags;
1061 ofiles = fdp->fd_ofiles;
1062 kqwq = fdp->fd_wqkqueue;
1063 vn1 = fdp->fd_cdir;
1064 vn2 = fdp->fd_rdir;
1065
1066 fdp->fd_ofileflags = NULL;
1067 fdp->fd_ofiles = NULL;
1068 fdp->fd_nfiles = 0;
1069 fdp->fd_wqkqueue = NULL;
1070 fdp->fd_cdir = NULL;
1071 fdp->fd_rdir = NULL;
1072
1073 proc_fdunlock(p);
1074
1075 lck_mtx_lock(&fdp->fd_kqhashlock);
1076
1077 kqhash = fdp->fd_kqhash;
1078 kqhashmask = fdp->fd_kqhashmask;
1079
1080 fdp->fd_kqhash = 0;
1081 fdp->fd_kqhashmask = 0;
1082
1083 lck_mtx_unlock(&fdp->fd_kqhashlock);
1084
1085 kfree_type(struct fileproc *, n_files, ofiles);
1086 kfree_data(ofileflags, n_files);
1087
1088 if (kqwq) {
1089 kqworkq_dealloc(kqwq);
1090 }
1091 if (vn1) {
1092 vnode_rele(vn1);
1093 }
1094 if (vn2) {
1095 vnode_rele(vn2);
1096 }
1097 if (kqhash) {
1098 for (uint32_t i = 0; i <= kqhashmask; i++) {
1099 assert(LIST_EMPTY(&kqhash[i]));
1100 }
1101 hashdestroy(kqhash, M_KQUEUE, kqhashmask);
1102 }
1103 }
1104
1105
1106 struct fileproc *
fileproc_alloc_init(void)1107 fileproc_alloc_init(void)
1108 {
1109 struct fileproc *fp;
1110
1111 fp = zalloc_id(ZONE_ID_FILEPROC, Z_WAITOK | Z_ZERO | Z_NOFAIL);
1112 os_ref_init(&fp->fp_iocount, &f_refgrp);
1113 return fp;
1114 }
1115
1116
1117 void
fileproc_free(struct fileproc * fp)1118 fileproc_free(struct fileproc *fp)
1119 {
1120 os_ref_release_last(&fp->fp_iocount);
1121 if (fp->fp_guard_attrs) {
1122 guarded_fileproc_unguard(fp);
1123 }
1124 assert(fp->fp_wset == NULL);
1125 zfree_id(ZONE_ID_FILEPROC, fp);
1126 }
1127
1128
1129 /*
1130 * Statistics counter for the number of times a process calling fdalloc()
1131 * has resulted in an expansion of the per process open file table.
1132 *
1133 * XXX This would likely be of more use if it were per process
1134 */
1135 int fdexpand;
1136
1137 #if CONFIG_PROC_RESOURCE_LIMITS
1138 /*
1139 * Should be called only with the proc_fdlock held.
1140 */
1141 void
fd_check_limit_exceeded(struct filedesc * fdp)1142 fd_check_limit_exceeded(struct filedesc *fdp)
1143 {
1144 #if DIAGNOSTIC
1145 proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
1146 #endif
1147
1148 if (!fd_above_soft_limit_notified(fdp) && fdp->fd_nfiles_soft_limit &&
1149 (fdp->fd_nfiles_open > fdp->fd_nfiles_soft_limit)) {
1150 fd_above_soft_limit_send_notification(fdp);
1151 act_set_astproc_resource(current_thread());
1152 } else if (!fd_above_hard_limit_notified(fdp) && fdp->fd_nfiles_hard_limit &&
1153 (fdp->fd_nfiles_open > fdp->fd_nfiles_hard_limit)) {
1154 fd_above_hard_limit_send_notification(fdp);
1155 act_set_astproc_resource(current_thread());
1156 }
1157 }
1158 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
1159
1160 /*
1161 * fdalloc
1162 *
1163 * Description: Allocate a file descriptor for the process.
1164 *
1165 * Parameters: p Process to allocate the fd in
1166 * want The fd we would prefer to get
1167 * result Pointer to fd we got
1168 *
1169 * Returns: 0 Success
1170 * EMFILE
1171 * ENOMEM
1172 *
1173 * Implicit returns:
1174 * *result (modified) The fd which was allocated
1175 */
1176 int
fdalloc(proc_t p,int want,int * result)1177 fdalloc(proc_t p, int want, int *result)
1178 {
1179 struct filedesc *fdp = &p->p_fd;
1180 int i;
1181 int last, numfiles, oldnfiles;
1182 struct fileproc **newofiles;
1183 char *newofileflags;
1184 int lim = proc_limitgetcur_nofile(p);
1185
1186 /*
1187 * Search for a free descriptor starting at the higher
1188 * of want or fd_freefile. If that fails, consider
1189 * expanding the ofile array.
1190 */
1191 #if DIAGNOSTIC
1192 proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
1193 #endif
1194
1195 for (;;) {
1196 last = (int)MIN((unsigned int)fdp->fd_nfiles, (unsigned int)lim);
1197 if ((i = want) < fdp->fd_freefile) {
1198 i = fdp->fd_freefile;
1199 }
1200 for (; i < last; i++) {
1201 if (fdp->fd_ofiles[i] == NULL && !(fdp->fd_ofileflags[i] & UF_RESERVED)) {
1202 procfdtbl_reservefd(p, i);
1203 if (i >= fdp->fd_afterlast) {
1204 fdp->fd_afterlast = i + 1;
1205 }
1206 if (want <= fdp->fd_freefile) {
1207 fdp->fd_freefile = i;
1208 }
1209 *result = i;
1210 #if CONFIG_PROC_RESOURCE_LIMITS
1211 fdp->fd_nfiles_open++;
1212 fd_check_limit_exceeded(fdp);
1213 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
1214 return 0;
1215 }
1216 }
1217
1218 /*
1219 * No space in current array. Expand?
1220 */
1221 if ((rlim_t)fdp->fd_nfiles >= lim) {
1222 return EMFILE;
1223 }
1224 if (fdp->fd_nfiles < NDEXTENT) {
1225 numfiles = NDEXTENT;
1226 } else {
1227 numfiles = 2 * fdp->fd_nfiles;
1228 }
1229 /* Enforce lim */
1230 if ((rlim_t)numfiles > lim) {
1231 numfiles = (int)lim;
1232 }
1233 proc_fdunlock(p);
1234 newofiles = kalloc_type(struct fileproc *, numfiles, Z_WAITOK | Z_ZERO);
1235 newofileflags = kalloc_data(numfiles, Z_WAITOK | Z_ZERO);
1236 proc_fdlock(p);
1237 if (newofileflags == NULL || newofiles == NULL) {
1238 kfree_type(struct fileproc *, numfiles, newofiles);
1239 kfree_data(newofileflags, numfiles);
1240 return ENOMEM;
1241 }
1242 if (fdp->fd_nfiles >= numfiles) {
1243 kfree_type(struct fileproc *, numfiles, newofiles);
1244 kfree_data(newofileflags, numfiles);
1245 continue;
1246 }
1247
1248 /*
1249 * Copy the existing ofile and ofileflags arrays
1250 * and zero the new portion of each array.
1251 */
1252 oldnfiles = fdp->fd_nfiles;
1253 memcpy(newofiles, fdp->fd_ofiles,
1254 oldnfiles * sizeof(*fdp->fd_ofiles));
1255 memcpy(newofileflags, fdp->fd_ofileflags, oldnfiles);
1256
1257 kfree_type(struct fileproc *, oldnfiles, fdp->fd_ofiles);
1258 kfree_data(fdp->fd_ofileflags, oldnfiles);
1259 fdp->fd_ofiles = newofiles;
1260 fdp->fd_ofileflags = newofileflags;
1261 fdp->fd_nfiles = numfiles;
1262 fdexpand++;
1263 }
1264 }
1265
1266
1267 #pragma mark fileprocs
1268
1269 void
fileproc_modify_vflags(struct fileproc * fp,fileproc_vflags_t vflags,boolean_t clearflags)1270 fileproc_modify_vflags(struct fileproc *fp, fileproc_vflags_t vflags, boolean_t clearflags)
1271 {
1272 if (clearflags) {
1273 os_atomic_andnot(&fp->fp_vflags, vflags, relaxed);
1274 } else {
1275 os_atomic_or(&fp->fp_vflags, vflags, relaxed);
1276 }
1277 }
1278
1279 fileproc_vflags_t
fileproc_get_vflags(struct fileproc * fp)1280 fileproc_get_vflags(struct fileproc *fp)
1281 {
1282 return os_atomic_load(&fp->fp_vflags, relaxed);
1283 }
1284
1285 /*
1286 * falloc_withinit
1287 *
1288 * Create a new open file structure and allocate
1289 * a file descriptor for the process that refers to it.
1290 *
1291 * Returns: 0 Success
1292 *
1293 * Description: Allocate an entry in the per process open file table and
1294 * return the corresponding fileproc and fd.
1295 *
1296 * Parameters: p The process in whose open file
1297 * table the fd is to be allocated
1298 * resultfp Pointer to fileproc pointer
1299 * return area
1300 * resultfd Pointer to fd return area
1301 * ctx VFS context
1302 * fp_zalloc fileproc allocator to use
1303 * crarg allocator args
1304 *
1305 * Returns: 0 Success
1306 * ENFILE Too many open files in system
1307 * fdalloc:EMFILE Too many open files in process
1308 * fdalloc:ENOMEM M_OFILETABL zone exhausted
1309 * ENOMEM fp_zone or fg_zone zone
1310 * exhausted
1311 *
1312 * Implicit returns:
1313 * *resultfd (modified) Returned fileproc pointer
1314 * *resultfd (modified) Returned fd
1315 *
1316 * Notes: This function takes separate process and context arguments
1317 * solely to support kern_exec.c; otherwise, it would take
1318 * neither, and use the vfs_context_current() routine internally.
1319 */
1320 int
falloc_withinit(proc_t p,struct ucred * p_cred,struct vfs_context * ctx,struct fileproc ** resultfp,int * resultfd,fp_initfn_t fp_init,void * initarg)1321 falloc_withinit(
1322 proc_t p,
1323 struct ucred *p_cred,
1324 struct vfs_context *ctx,
1325 struct fileproc **resultfp,
1326 int *resultfd,
1327 fp_initfn_t fp_init,
1328 void *initarg)
1329 {
1330 struct fileproc *fp;
1331 struct fileglob *fg;
1332 int error, nfd;
1333
1334 /* Make sure we don't go beyond the system-wide limit */
1335 if (nfiles >= maxfiles) {
1336 tablefull("file");
1337 return ENFILE;
1338 }
1339
1340 proc_fdlock(p);
1341
1342 /* fdalloc will make sure the process stays below per-process limit */
1343 if ((error = fdalloc(p, 0, &nfd))) {
1344 proc_fdunlock(p);
1345 return error;
1346 }
1347
1348 #if CONFIG_MACF
1349 error = mac_file_check_create(p_cred);
1350 if (error) {
1351 proc_fdunlock(p);
1352 return error;
1353 }
1354 #else
1355 (void)p_cred;
1356 #endif
1357
1358 /*
1359 * Allocate a new file descriptor.
1360 * If the process has file descriptor zero open, add to the list
1361 * of open files at that point, otherwise put it at the front of
1362 * the list of open files.
1363 */
1364 proc_fdunlock(p);
1365
1366 fp = fileproc_alloc_init();
1367 if (fp_init) {
1368 fp_init(fp, initarg);
1369 }
1370
1371 fg = fg_alloc_init(ctx);
1372
1373 os_ref_retain_locked(&fp->fp_iocount);
1374 fp->fp_glob = fg;
1375
1376 proc_fdlock(p);
1377
1378 p->p_fd.fd_ofiles[nfd] = fp;
1379
1380 proc_fdunlock(p);
1381
1382 if (resultfp) {
1383 *resultfp = fp;
1384 }
1385 if (resultfd) {
1386 *resultfd = nfd;
1387 }
1388
1389 return 0;
1390 }
1391
1392 /*
1393 * fp_free
1394 *
1395 * Description: Release the fd and free the fileproc associated with the fd
1396 * in the per process open file table of the specified process;
1397 * these values must correspond.
1398 *
1399 * Parameters: p Process containing fd
1400 * fd fd to be released
1401 * fp fileproc to be freed
1402 */
1403 void
fp_free(proc_t p,int fd,struct fileproc * fp)1404 fp_free(proc_t p, int fd, struct fileproc * fp)
1405 {
1406 proc_fdlock_spin(p);
1407 fdrelse(p, fd);
1408 proc_fdunlock(p);
1409
1410 fg_free(fp->fp_glob);
1411 os_ref_release_live(&fp->fp_iocount);
1412 fileproc_free(fp);
1413 }
1414
1415
1416 struct fileproc *
fp_get_noref_locked(proc_t p,int fd)1417 fp_get_noref_locked(proc_t p, int fd)
1418 {
1419 struct filedesc *fdp = &p->p_fd;
1420 struct fileproc *fp;
1421
1422 if (fd < 0 || fd >= fdp->fd_nfiles ||
1423 (fp = fdp->fd_ofiles[fd]) == NULL ||
1424 (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
1425 return NULL;
1426 }
1427
1428 zone_id_require(ZONE_ID_FILEPROC, sizeof(*fp), fp);
1429 return fp;
1430 }
1431
1432 struct fileproc *
fp_get_noref_locked_with_iocount(proc_t p,int fd)1433 fp_get_noref_locked_with_iocount(proc_t p, int fd)
1434 {
1435 struct filedesc *fdp = &p->p_fd;
1436 struct fileproc *fp = NULL;
1437
1438 if (fd < 0 || fd >= fdp->fd_nfiles ||
1439 (fp = fdp->fd_ofiles[fd]) == NULL ||
1440 os_ref_get_count(&fp->fp_iocount) <= 1 ||
1441 ((fdp->fd_ofileflags[fd] & UF_RESERVED) &&
1442 !(fdp->fd_ofileflags[fd] & UF_CLOSING))) {
1443 panic("%s: caller without an ioccount on fileproc (%d/:%p)",
1444 __func__, fd, fp);
1445 }
1446
1447 zone_id_require(ZONE_ID_FILEPROC, sizeof(*fp), fp);
1448 return fp;
1449 }
1450
1451
1452 /*
1453 * fp_lookup
1454 *
1455 * Description: Get fileproc pointer for a given fd from the per process
1456 * open file table of the specified process and if successful,
1457 * increment the fp_iocount
1458 *
1459 * Parameters: p Process in which fd lives
1460 * fd fd to get information for
1461 * resultfp Pointer to result fileproc
1462 * pointer area, or 0 if none
1463 * locked !0 if the caller holds the
1464 * proc_fdlock, 0 otherwise
1465 *
1466 * Returns: 0 Success
1467 * EBADF Bad file descriptor
1468 *
1469 * Implicit returns:
1470 * *resultfp (modified) Fileproc pointer
1471 *
1472 * Locks: If the argument 'locked' is non-zero, then the caller is
1473 * expected to have taken and held the proc_fdlock; if it is
1474 * zero, than this routine internally takes and drops this lock.
1475 */
1476 int
fp_lookup(proc_t p,int fd,struct fileproc ** resultfp,int locked)1477 fp_lookup(proc_t p, int fd, struct fileproc **resultfp, int locked)
1478 {
1479 struct filedesc *fdp = &p->p_fd;
1480 struct fileproc *fp;
1481
1482 if (!locked) {
1483 proc_fdlock_spin(p);
1484 }
1485 if (fd < 0 || fdp == NULL || fd >= fdp->fd_nfiles ||
1486 (fp = fdp->fd_ofiles[fd]) == NULL ||
1487 (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
1488 if (!locked) {
1489 proc_fdunlock(p);
1490 }
1491 return EBADF;
1492 }
1493
1494 zone_id_require(ZONE_ID_FILEPROC, sizeof(*fp), fp);
1495 os_ref_retain_locked(&fp->fp_iocount);
1496
1497 if (resultfp) {
1498 *resultfp = fp;
1499 }
1500 if (!locked) {
1501 proc_fdunlock(p);
1502 }
1503
1504 return 0;
1505 }
1506
1507
1508 int
fp_get_ftype(proc_t p,int fd,file_type_t ftype,int err,struct fileproc ** fpp)1509 fp_get_ftype(proc_t p, int fd, file_type_t ftype, int err, struct fileproc **fpp)
1510 {
1511 struct filedesc *fdp = &p->p_fd;
1512 struct fileproc *fp;
1513
1514 proc_fdlock_spin(p);
1515 if (fd < 0 || fd >= fdp->fd_nfiles ||
1516 (fp = fdp->fd_ofiles[fd]) == NULL ||
1517 (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
1518 proc_fdunlock(p);
1519 return EBADF;
1520 }
1521
1522 if (fp->f_type != ftype) {
1523 proc_fdunlock(p);
1524 return err;
1525 }
1526
1527 zone_id_require(ZONE_ID_FILEPROC, sizeof(*fp), fp);
1528 os_ref_retain_locked(&fp->fp_iocount);
1529 proc_fdunlock(p);
1530
1531 *fpp = fp;
1532 return 0;
1533 }
1534
1535
1536 /*
1537 * fp_drop
1538 *
1539 * Description: Drop the I/O reference previously taken by calling fp_lookup
1540 * et. al.
1541 *
1542 * Parameters: p Process in which the fd lives
1543 * fd fd associated with the fileproc
1544 * fp fileproc on which to set the
1545 * flag and drop the reference
1546 * locked flag to internally take and
1547 * drop proc_fdlock if it is not
1548 * already held by the caller
1549 *
1550 * Returns: 0 Success
1551 * EBADF Bad file descriptor
1552 *
1553 * Locks: This function internally takes and drops the proc_fdlock for
1554 * the supplied process if 'locked' is non-zero, and assumes that
1555 * the caller already holds this lock if 'locked' is non-zero.
1556 *
1557 * Notes: The fileproc must correspond to the fd in the supplied proc
1558 */
1559 int
fp_drop(proc_t p,int fd,struct fileproc * fp,int locked)1560 fp_drop(proc_t p, int fd, struct fileproc *fp, int locked)
1561 {
1562 struct filedesc *fdp = &p->p_fd;
1563 int needwakeup = 0;
1564
1565 if (!locked) {
1566 proc_fdlock_spin(p);
1567 }
1568 if ((fp == FILEPROC_NULL) && (fd < 0 || fd >= fdp->fd_nfiles ||
1569 (fp = fdp->fd_ofiles[fd]) == NULL ||
1570 ((fdp->fd_ofileflags[fd] & UF_RESERVED) &&
1571 !(fdp->fd_ofileflags[fd] & UF_CLOSING)))) {
1572 if (!locked) {
1573 proc_fdunlock(p);
1574 }
1575 return EBADF;
1576 }
1577
1578 if (1 == os_ref_release_locked(&fp->fp_iocount)) {
1579 if (fp->fp_flags & FP_SELCONFLICT) {
1580 fp->fp_flags &= ~FP_SELCONFLICT;
1581 }
1582
1583 if (fdp->fd_fpdrainwait) {
1584 fdp->fd_fpdrainwait = 0;
1585 needwakeup = 1;
1586 }
1587 }
1588 if (!locked) {
1589 proc_fdunlock(p);
1590 }
1591 if (needwakeup) {
1592 wakeup(&fdp->fd_fpdrainwait);
1593 }
1594
1595 return 0;
1596 }
1597
1598
1599 /*
1600 * fileproc_drain
1601 *
1602 * Description: Drain out pending I/O operations
1603 *
1604 * Parameters: p Process closing this file
1605 * fp fileproc struct for the open
1606 * instance on the file
1607 *
1608 * Returns: void
1609 *
1610 * Locks: Assumes the caller holds the proc_fdlock
1611 *
1612 * Notes: For character devices, this occurs on the last close of the
1613 * device; for all other file descriptors, this occurs on each
1614 * close to prevent fd's from being closed out from under
1615 * operations currently in progress and blocked
1616 *
1617 * See Also: file_vnode(), file_socket(), file_drop(), and the cautions
1618 * regarding their use and interaction with this function.
1619 */
1620 static void
fileproc_drain(proc_t p,struct fileproc * fp)1621 fileproc_drain(proc_t p, struct fileproc * fp)
1622 {
1623 struct filedesc *fdp = &p->p_fd;
1624 struct vfs_context context;
1625 thread_t thread;
1626 bool is_current_proc;
1627
1628 is_current_proc = (p == current_proc());
1629
1630 if (!is_current_proc) {
1631 proc_lock(p);
1632 thread = proc_thread(p); /* XXX */
1633 thread_reference(thread);
1634 proc_unlock(p);
1635 } else {
1636 thread = current_thread();
1637 }
1638
1639 context.vc_thread = thread;
1640 context.vc_ucred = fp->fp_glob->fg_cred;
1641
1642 /* Set the vflag for drain */
1643 fileproc_modify_vflags(fp, FPV_DRAIN, FALSE);
1644
1645 while (os_ref_get_count(&fp->fp_iocount) > 1) {
1646 lck_mtx_convert_spin(&fdp->fd_lock);
1647
1648 fo_drain(fp, &context);
1649 if ((fp->fp_flags & FP_INSELECT) == FP_INSELECT) {
1650 struct select_set *selset;
1651
1652 if (fp->fp_guard_attrs) {
1653 selset = fp->fp_guard->fpg_wset;
1654 } else {
1655 selset = fp->fp_wset;
1656 }
1657 if (waitq_wakeup64_all(selset, NO_EVENT64,
1658 THREAD_INTERRUPTED, WAITQ_WAKEUP_DEFAULT) == KERN_INVALID_ARGUMENT) {
1659 panic("bad wait queue for waitq_wakeup64_all %p (%sfp:%p)",
1660 selset, fp->fp_guard_attrs ? "guarded " : "", fp);
1661 }
1662 }
1663 if ((fp->fp_flags & FP_SELCONFLICT) == FP_SELCONFLICT) {
1664 if (waitq_wakeup64_all(&select_conflict_queue, NO_EVENT64,
1665 THREAD_INTERRUPTED, WAITQ_WAKEUP_DEFAULT) == KERN_INVALID_ARGUMENT) {
1666 panic("bad select_conflict_queue");
1667 }
1668 }
1669 fdp->fd_fpdrainwait = 1;
1670 msleep(&fdp->fd_fpdrainwait, &fdp->fd_lock, PRIBIO, "fpdrain", NULL);
1671 }
1672 #if DIAGNOSTIC
1673 if ((fp->fp_flags & FP_INSELECT) != 0) {
1674 panic("FP_INSELECT set on drained fp");
1675 }
1676 #endif
1677 if ((fp->fp_flags & FP_SELCONFLICT) == FP_SELCONFLICT) {
1678 fp->fp_flags &= ~FP_SELCONFLICT;
1679 }
1680
1681 if (!is_current_proc) {
1682 thread_deallocate(thread);
1683 }
1684 }
1685
1686
1687 int
fp_close_and_unlock(proc_t p,kauth_cred_t cred,int fd,struct fileproc * fp,int flags)1688 fp_close_and_unlock(proc_t p, kauth_cred_t cred, int fd, struct fileproc *fp, int flags)
1689 {
1690 struct filedesc *fdp = &p->p_fd;
1691 struct fileglob *fg = fp->fp_glob;
1692
1693 #if DIAGNOSTIC
1694 proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
1695 #endif
1696
1697 /*
1698 * Keep most people from finding the filedesc while we are closing it.
1699 *
1700 * Callers are:
1701 *
1702 * - dup2() which always waits for UF_RESERVED to clear
1703 *
1704 * - close/guarded_close/... who will fail the fileproc lookup if
1705 * UF_RESERVED is set,
1706 *
1707 * - fdexec()/fdfree() who only run once all threads in the proc
1708 * are properly canceled, hence no fileproc in this proc should
1709 * be in flux.
1710 *
1711 * Which means that neither UF_RESERVED nor UF_CLOSING should be set.
1712 *
1713 * Callers of fp_get_noref_locked_with_iocount() can still find
1714 * this entry so that they can drop their I/O reference despite
1715 * not having remembered the fileproc pointer (namely select() and
1716 * file_drop()).
1717 */
1718 if (p->p_fd.fd_ofileflags[fd] & (UF_RESERVED | UF_CLOSING)) {
1719 panic("%s: called with fileproc in flux (%d/:%p)",
1720 __func__, fd, fp);
1721 }
1722 p->p_fd.fd_ofileflags[fd] |= (UF_RESERVED | UF_CLOSING);
1723
1724 if ((fp->fp_flags & FP_AIOISSUED) ||
1725 #if CONFIG_MACF
1726 (FILEGLOB_DTYPE(fg) == DTYPE_VNODE)
1727 #else
1728 kauth_authorize_fileop_has_listeners()
1729 #endif
1730 ) {
1731 proc_fdunlock(p);
1732
1733 if (FILEGLOB_DTYPE(fg) == DTYPE_VNODE) {
1734 vnode_t vp = (vnode_t)fg_get_data(fg);
1735
1736 /*
1737 * call out to allow 3rd party notification of close.
1738 * Ignore result of kauth_authorize_fileop call.
1739 */
1740 #if CONFIG_MACF
1741 mac_file_notify_close(cred, fp->fp_glob);
1742 #else
1743 (void)cred;
1744 #endif
1745
1746 if (kauth_authorize_fileop_has_listeners() &&
1747 vnode_getwithref(vp) == 0) {
1748 u_int fileop_flags = 0;
1749 if (fg->fg_flag & FWASWRITTEN) {
1750 fileop_flags |= KAUTH_FILEOP_CLOSE_MODIFIED;
1751 }
1752 kauth_authorize_fileop(fg->fg_cred, KAUTH_FILEOP_CLOSE,
1753 (uintptr_t)vp, (uintptr_t)fileop_flags);
1754
1755 vnode_put(vp);
1756 }
1757 }
1758
1759 if (fp->fp_flags & FP_AIOISSUED) {
1760 /*
1761 * cancel all async IO requests that can be cancelled.
1762 */
1763 _aio_close( p, fd );
1764 }
1765
1766 proc_fdlock(p);
1767 }
1768
1769 if (fd < fdp->fd_knlistsize) {
1770 knote_fdclose(p, fd);
1771 }
1772
1773 fileproc_drain(p, fp);
1774
1775 if (flags & FD_DUP2RESV) {
1776 fdp->fd_ofiles[fd] = NULL;
1777 fdp->fd_ofileflags[fd] &= ~UF_CLOSING;
1778 } else {
1779 fdrelse(p, fd);
1780 }
1781
1782 proc_fdunlock(p);
1783
1784 if (ENTR_SHOULDTRACE && FILEGLOB_DTYPE(fg) == DTYPE_SOCKET) {
1785 KERNEL_ENERGYTRACE(kEnTrActKernSocket, DBG_FUNC_END,
1786 fd, 0, (int64_t)VM_KERNEL_ADDRPERM(fg_get_data(fg)));
1787 }
1788
1789 fileproc_free(fp);
1790
1791 return fg_drop(p, fg);
1792 }
1793
1794 /*
1795 * dupfdopen
1796 *
1797 * Description: Duplicate the specified descriptor to a free descriptor;
1798 * this is the second half of fdopen(), above.
1799 *
1800 * Parameters: p current process pointer
1801 * indx fd to dup to
1802 * dfd fd to dup from
1803 * mode mode to set on new fd
1804 * error command code
1805 *
1806 * Returns: 0 Success
1807 * EBADF Source fd is bad
1808 * EACCES Requested mode not allowed
1809 * !0 'error', if not ENODEV or
1810 * ENXIO
1811 *
1812 * Notes: XXX This is not thread safe; see fdopen() above
1813 */
1814 int
dupfdopen(proc_t p,int indx,int dfd,int flags,int error)1815 dupfdopen(proc_t p, int indx, int dfd, int flags, int error)
1816 {
1817 struct filedesc *fdp = &p->p_fd;
1818 struct fileproc *wfp;
1819 struct fileproc *fp;
1820 #if CONFIG_MACF
1821 int myerror;
1822 #endif
1823
1824 /*
1825 * If the to-be-dup'd fd number is greater than the allowed number
1826 * of file descriptors, or the fd to be dup'd has already been
1827 * closed, reject. Note, check for new == old is necessary as
1828 * falloc could allocate an already closed to-be-dup'd descriptor
1829 * as the new descriptor.
1830 */
1831 proc_fdlock(p);
1832
1833 fp = fdp->fd_ofiles[indx];
1834 if (dfd < 0 || dfd >= fdp->fd_nfiles ||
1835 (wfp = fdp->fd_ofiles[dfd]) == NULL || wfp == fp ||
1836 (fdp->fd_ofileflags[dfd] & UF_RESERVED)) {
1837 proc_fdunlock(p);
1838 return EBADF;
1839 }
1840 #if CONFIG_MACF
1841 myerror = mac_file_check_dup(kauth_cred_get(), wfp->fp_glob, dfd);
1842 if (myerror) {
1843 proc_fdunlock(p);
1844 return myerror;
1845 }
1846 #endif
1847 /*
1848 * There are two cases of interest here.
1849 *
1850 * For ENODEV simply dup (dfd) to file descriptor
1851 * (indx) and return.
1852 *
1853 * For ENXIO steal away the file structure from (dfd) and
1854 * store it in (indx). (dfd) is effectively closed by
1855 * this operation.
1856 *
1857 * Any other error code is just returned.
1858 */
1859 switch (error) {
1860 case ENODEV:
1861 if (fp_isguarded(wfp, GUARD_DUP)) {
1862 proc_fdunlock(p);
1863 return EPERM;
1864 }
1865
1866 if (wfp->f_type == DTYPE_VNODE) {
1867 vnode_t vp = (vnode_t)fp_get_data(wfp);
1868
1869 /* Don't allow opening symlink if O_SYMLINK was not specified. */
1870 if (vp && (vp->v_type == VLNK) && ((flags & O_SYMLINK) == 0)) {
1871 proc_fdunlock(p);
1872 return ELOOP;
1873 }
1874 }
1875
1876 /*
1877 * Check that the mode the file is being opened for is a
1878 * subset of the mode of the existing descriptor.
1879 */
1880 if (((flags & (FREAD | FWRITE)) | wfp->f_flag) != wfp->f_flag) {
1881 proc_fdunlock(p);
1882 return EACCES;
1883 }
1884 if (indx >= fdp->fd_afterlast) {
1885 fdp->fd_afterlast = indx + 1;
1886 }
1887
1888 if (fp->fp_glob) {
1889 fg_free(fp->fp_glob);
1890 }
1891 fg_ref(p, wfp->fp_glob);
1892 fp->fp_glob = wfp->fp_glob;
1893 /*
1894 * Historically, open(/dev/fd/<n>) preserves close on fork/exec,
1895 * unlike dup(), dup2() or fcntl(F_DUPFD).
1896 *
1897 * open1() already handled O_CLO{EXEC,FORK}
1898 */
1899 fp->fp_flags |= (wfp->fp_flags & (FP_CLOFORK | FP_CLOEXEC));
1900
1901 procfdtbl_releasefd(p, indx, NULL);
1902 fp_drop(p, indx, fp, 1);
1903 proc_fdunlock(p);
1904 return 0;
1905
1906 default:
1907 proc_fdunlock(p);
1908 return error;
1909 }
1910 /* NOTREACHED */
1911 }
1912
1913
1914 #pragma mark KPIS (sys/file.h)
1915
1916 /*
1917 * fg_get_vnode
1918 *
1919 * Description: Return vnode associated with the file structure, if
1920 * any. The lifetime of the returned vnode is bound to
1921 * the lifetime of the file structure.
1922 *
1923 * Parameters: fg Pointer to fileglob to
1924 * inspect
1925 *
1926 * Returns: vnode_t
1927 */
1928 vnode_t
fg_get_vnode(struct fileglob * fg)1929 fg_get_vnode(struct fileglob *fg)
1930 {
1931 if (FILEGLOB_DTYPE(fg) == DTYPE_VNODE) {
1932 return (vnode_t)fg_get_data(fg);
1933 } else {
1934 return NULL;
1935 }
1936 }
1937
1938
1939 /*
1940 * fp_getfvp
1941 *
1942 * Description: Get fileproc and vnode pointer for a given fd from the per
1943 * process open file table of the specified process, and if
1944 * successful, increment the fp_iocount
1945 *
1946 * Parameters: p Process in which fd lives
1947 * fd fd to get information for
1948 * resultfp Pointer to result fileproc
1949 * pointer area, or 0 if none
1950 * resultvp Pointer to result vnode pointer
1951 * area, or 0 if none
1952 *
1953 * Returns: 0 Success
1954 * EBADF Bad file descriptor
1955 * ENOTSUP fd does not refer to a vnode
1956 *
1957 * Implicit returns:
1958 * *resultfp (modified) Fileproc pointer
1959 * *resultvp (modified) vnode pointer
1960 *
1961 * Notes: The resultfp and resultvp fields are optional, and may be
1962 * independently specified as NULL to skip returning information
1963 *
1964 * Locks: Internally takes and releases proc_fdlock
1965 */
1966 int
fp_getfvp(proc_t p,int fd,struct fileproc ** resultfp,struct vnode ** resultvp)1967 fp_getfvp(proc_t p, int fd, struct fileproc **resultfp, struct vnode **resultvp)
1968 {
1969 struct fileproc *fp;
1970 int error;
1971
1972 error = fp_get_ftype(p, fd, DTYPE_VNODE, ENOTSUP, &fp);
1973 if (error == 0) {
1974 if (resultfp) {
1975 *resultfp = fp;
1976 }
1977 if (resultvp) {
1978 *resultvp = (struct vnode *)fp_get_data(fp);
1979 }
1980 }
1981
1982 return error;
1983 }
1984
1985
1986 /*
1987 * fp_get_pipe_id
1988 *
1989 * Description: Get pipe id for a given fd from the per process open file table
1990 * of the specified process.
1991 *
1992 * Parameters: p Process in which fd lives
1993 * fd fd to get information for
1994 * result_pipe_id Pointer to result pipe id
1995 *
1996 * Returns: 0 Success
1997 * EIVAL NULL pointer arguments passed
1998 * fp_lookup:EBADF Bad file descriptor
1999 * ENOTSUP fd does not refer to a pipe
2000 *
2001 * Implicit returns:
2002 * *result_pipe_id (modified) pipe id
2003 *
2004 * Locks: Internally takes and releases proc_fdlock
2005 */
2006 int
fp_get_pipe_id(proc_t p,int fd,uint64_t * result_pipe_id)2007 fp_get_pipe_id(proc_t p, int fd, uint64_t *result_pipe_id)
2008 {
2009 struct fileproc *fp = FILEPROC_NULL;
2010 struct fileglob *fg = NULL;
2011 int error = 0;
2012
2013 if (p == NULL || result_pipe_id == NULL) {
2014 return EINVAL;
2015 }
2016
2017 proc_fdlock(p);
2018 if ((error = fp_lookup(p, fd, &fp, 1))) {
2019 proc_fdunlock(p);
2020 return error;
2021 }
2022 fg = fp->fp_glob;
2023
2024 if (FILEGLOB_DTYPE(fg) == DTYPE_PIPE) {
2025 *result_pipe_id = pipe_id((struct pipe*)fg_get_data(fg));
2026 } else {
2027 error = ENOTSUP;
2028 }
2029
2030 fp_drop(p, fd, fp, 1);
2031 proc_fdunlock(p);
2032 return error;
2033 }
2034
2035
2036 /*
2037 * file_vnode
2038 *
2039 * Description: Given an fd, look it up in the current process's per process
2040 * open file table, and return its internal vnode pointer.
2041 *
2042 * Parameters: fd fd to obtain vnode from
2043 * vpp pointer to vnode return area
2044 *
2045 * Returns: 0 Success
2046 * EINVAL The fd does not refer to a
2047 * vnode fileproc entry
2048 * fp_lookup:EBADF Bad file descriptor
2049 *
2050 * Implicit returns:
2051 * *vpp (modified) Returned vnode pointer
2052 *
2053 * Locks: This function internally takes and drops the proc_fdlock for
2054 * the current process
2055 *
2056 * Notes: If successful, this function increments the fp_iocount on the
2057 * fd's corresponding fileproc.
2058 *
2059 * The fileproc referenced is not returned; because of this, care
2060 * must be taken to not drop the last reference (e.g. by closing
2061 * the file). This is inherently unsafe, since the reference may
2062 * not be recoverable from the vnode, if there is a subsequent
2063 * close that destroys the associate fileproc. The caller should
2064 * therefore retain their own reference on the fileproc so that
2065 * the fp_iocount can be dropped subsequently. Failure to do this
2066 * can result in the returned pointer immediately becoming invalid
2067 * following the call.
2068 *
2069 * Use of this function is discouraged.
2070 */
2071 int
file_vnode(int fd,struct vnode ** vpp)2072 file_vnode(int fd, struct vnode **vpp)
2073 {
2074 return file_vnode_withvid(fd, vpp, NULL);
2075 }
2076
2077
2078 /*
2079 * file_vnode_withvid
2080 *
2081 * Description: Given an fd, look it up in the current process's per process
2082 * open file table, and return its internal vnode pointer.
2083 *
2084 * Parameters: fd fd to obtain vnode from
2085 * vpp pointer to vnode return area
2086 * vidp pointer to vid of the returned vnode
2087 *
2088 * Returns: 0 Success
2089 * EINVAL The fd does not refer to a
2090 * vnode fileproc entry
2091 * fp_lookup:EBADF Bad file descriptor
2092 *
2093 * Implicit returns:
2094 * *vpp (modified) Returned vnode pointer
2095 *
2096 * Locks: This function internally takes and drops the proc_fdlock for
2097 * the current process
2098 *
2099 * Notes: If successful, this function increments the fp_iocount on the
2100 * fd's corresponding fileproc.
2101 *
2102 * The fileproc referenced is not returned; because of this, care
2103 * must be taken to not drop the last reference (e.g. by closing
2104 * the file). This is inherently unsafe, since the reference may
2105 * not be recoverable from the vnode, if there is a subsequent
2106 * close that destroys the associate fileproc. The caller should
2107 * therefore retain their own reference on the fileproc so that
2108 * the fp_iocount can be dropped subsequently. Failure to do this
2109 * can result in the returned pointer immediately becoming invalid
2110 * following the call.
2111 *
2112 * Use of this function is discouraged.
2113 */
2114 int
file_vnode_withvid(int fd,struct vnode ** vpp,uint32_t * vidp)2115 file_vnode_withvid(int fd, struct vnode **vpp, uint32_t *vidp)
2116 {
2117 struct fileproc *fp;
2118 int error;
2119
2120 error = fp_get_ftype(current_proc(), fd, DTYPE_VNODE, EINVAL, &fp);
2121 if (error == 0) {
2122 if (vpp) {
2123 *vpp = (struct vnode *)fp_get_data(fp);
2124 }
2125 if (vidp) {
2126 *vidp = vnode_vid((struct vnode *)fp_get_data(fp));
2127 }
2128 }
2129 return error;
2130 }
2131
2132 /*
2133 * file_socket
2134 *
2135 * Description: Given an fd, look it up in the current process's per process
2136 * open file table, and return its internal socket pointer.
2137 *
2138 * Parameters: fd fd to obtain vnode from
2139 * sp pointer to socket return area
2140 *
2141 * Returns: 0 Success
2142 * ENOTSOCK Not a socket
2143 * fp_lookup:EBADF Bad file descriptor
2144 *
2145 * Implicit returns:
2146 * *sp (modified) Returned socket pointer
2147 *
2148 * Locks: This function internally takes and drops the proc_fdlock for
2149 * the current process
2150 *
2151 * Notes: If successful, this function increments the fp_iocount on the
2152 * fd's corresponding fileproc.
2153 *
2154 * The fileproc referenced is not returned; because of this, care
2155 * must be taken to not drop the last reference (e.g. by closing
2156 * the file). This is inherently unsafe, since the reference may
2157 * not be recoverable from the socket, if there is a subsequent
2158 * close that destroys the associate fileproc. The caller should
2159 * therefore retain their own reference on the fileproc so that
2160 * the fp_iocount can be dropped subsequently. Failure to do this
2161 * can result in the returned pointer immediately becoming invalid
2162 * following the call.
2163 *
2164 * Use of this function is discouraged.
2165 */
2166 int
file_socket(int fd,struct socket ** sp)2167 file_socket(int fd, struct socket **sp)
2168 {
2169 struct fileproc *fp;
2170 int error;
2171
2172 error = fp_get_ftype(current_proc(), fd, DTYPE_SOCKET, ENOTSOCK, &fp);
2173 if (error == 0) {
2174 if (sp) {
2175 *sp = (struct socket *)fp_get_data(fp);
2176 }
2177 }
2178 return error;
2179 }
2180
2181
2182 /*
2183 * file_flags
2184 *
2185 * Description: Given an fd, look it up in the current process's per process
2186 * open file table, and return its fileproc's flags field.
2187 *
2188 * Parameters: fd fd whose flags are to be
2189 * retrieved
2190 * flags pointer to flags data area
2191 *
2192 * Returns: 0 Success
2193 * ENOTSOCK Not a socket
2194 * fp_lookup:EBADF Bad file descriptor
2195 *
2196 * Implicit returns:
2197 * *flags (modified) Returned flags field
2198 *
2199 * Locks: This function internally takes and drops the proc_fdlock for
2200 * the current process
2201 */
2202 int
file_flags(int fd,int * flags)2203 file_flags(int fd, int *flags)
2204 {
2205 proc_t p = current_proc();
2206 struct fileproc *fp;
2207 int error = EBADF;
2208
2209 proc_fdlock_spin(p);
2210 fp = fp_get_noref_locked(p, fd);
2211 if (fp) {
2212 *flags = (int)fp->f_flag;
2213 error = 0;
2214 }
2215 proc_fdunlock(p);
2216
2217 return error;
2218 }
2219
2220
2221 /*
2222 * file_drop
2223 *
2224 * Description: Drop an iocount reference on an fd, and wake up any waiters
2225 * for draining (i.e. blocked in fileproc_drain() called during
2226 * the last attempt to close a file).
2227 *
2228 * Parameters: fd fd on which an ioreference is
2229 * to be dropped
2230 *
2231 * Returns: 0 Success
2232 *
2233 * Description: Given an fd, look it up in the current process's per process
2234 * open file table, and drop it's fileproc's fp_iocount by one
2235 *
2236 * Notes: This is intended as a corresponding operation to the functions
2237 * file_vnode() and file_socket() operations.
2238 *
2239 * If the caller can't possibly hold an I/O reference,
2240 * this function will panic the kernel rather than allowing
2241 * for memory corruption. Callers should always call this
2242 * because they acquired an I/O reference on this file before.
2243 *
2244 * Use of this function is discouraged.
2245 */
2246 int
file_drop(int fd)2247 file_drop(int fd)
2248 {
2249 struct fileproc *fp;
2250 proc_t p = current_proc();
2251 struct filedesc *fdp = &p->p_fd;
2252 int needwakeup = 0;
2253
2254 proc_fdlock_spin(p);
2255 fp = fp_get_noref_locked_with_iocount(p, fd);
2256
2257 if (1 == os_ref_release_locked(&fp->fp_iocount)) {
2258 if (fp->fp_flags & FP_SELCONFLICT) {
2259 fp->fp_flags &= ~FP_SELCONFLICT;
2260 }
2261
2262 if (fdp->fd_fpdrainwait) {
2263 fdp->fd_fpdrainwait = 0;
2264 needwakeup = 1;
2265 }
2266 }
2267 proc_fdunlock(p);
2268
2269 if (needwakeup) {
2270 wakeup(&fdp->fd_fpdrainwait);
2271 }
2272 return 0;
2273 }
2274
2275
2276 #pragma mark syscalls
2277
2278 #ifndef HFS_GET_BOOT_INFO
2279 #define HFS_GET_BOOT_INFO (FCNTL_FS_SPECIFIC_BASE + 0x00004)
2280 #endif
2281
2282 #ifndef HFS_SET_BOOT_INFO
2283 #define HFS_SET_BOOT_INFO (FCNTL_FS_SPECIFIC_BASE + 0x00005)
2284 #endif
2285
2286 #ifndef APFSIOC_REVERT_TO_SNAPSHOT
2287 #define APFSIOC_REVERT_TO_SNAPSHOT _IOW('J', 1, u_int64_t)
2288 #endif
2289
2290 #ifndef APFSIOC_IS_GRAFT_SUPPORTED
2291 #define APFSIOC_IS_GRAFT_SUPPORTED _IO('J', 133)
2292 #endif
2293
2294 #define CHECK_ADD_OVERFLOW_INT64L(x, y) \
2295 (((((x) > 0) && ((y) > 0) && ((x) > LLONG_MAX - (y))) || \
2296 (((x) < 0) && ((y) < 0) && ((x) < LLONG_MIN - (y)))) \
2297 ? 1 : 0)
2298
2299 /*
2300 * sys_getdtablesize
2301 *
2302 * Description: Returns the per process maximum size of the descriptor table
2303 *
2304 * Parameters: p Process being queried
2305 * retval Pointer to the call return area
2306 *
2307 * Returns: 0 Success
2308 *
2309 * Implicit returns:
2310 * *retval (modified) Size of dtable
2311 */
2312 int
sys_getdtablesize(proc_t p,__unused struct getdtablesize_args * uap,int32_t * retval)2313 sys_getdtablesize(proc_t p, __unused struct getdtablesize_args *uap, int32_t *retval)
2314 {
2315 *retval = proc_limitgetcur_nofile(p);
2316 return 0;
2317 }
2318
2319
2320 /*
2321 * check_file_seek_range
2322 *
2323 * Description: Checks if seek offsets are in the range of 0 to LLONG_MAX.
2324 *
2325 * Parameters: fl Flock structure.
2326 * cur_file_offset Current offset in the file.
2327 *
2328 * Returns: 0 on Success.
2329 * EOVERFLOW on overflow.
2330 * EINVAL on offset less than zero.
2331 */
2332
2333 static int
check_file_seek_range(struct flock * fl,off_t cur_file_offset)2334 check_file_seek_range(struct flock *fl, off_t cur_file_offset)
2335 {
2336 if (fl->l_whence == SEEK_CUR) {
2337 /* Check if the start marker is beyond LLONG_MAX. */
2338 if (CHECK_ADD_OVERFLOW_INT64L(fl->l_start, cur_file_offset)) {
2339 /* Check if start marker is negative */
2340 if (fl->l_start < 0) {
2341 return EINVAL;
2342 }
2343 return EOVERFLOW;
2344 }
2345 /* Check if the start marker is negative. */
2346 if (fl->l_start + cur_file_offset < 0) {
2347 return EINVAL;
2348 }
2349 /* Check if end marker is beyond LLONG_MAX. */
2350 if ((fl->l_len > 0) && (CHECK_ADD_OVERFLOW_INT64L(fl->l_start +
2351 cur_file_offset, fl->l_len - 1))) {
2352 return EOVERFLOW;
2353 }
2354 /* Check if the end marker is negative. */
2355 if ((fl->l_len <= 0) && (fl->l_start + cur_file_offset +
2356 fl->l_len < 0)) {
2357 return EINVAL;
2358 }
2359 } else if (fl->l_whence == SEEK_SET) {
2360 /* Check if the start marker is negative. */
2361 if (fl->l_start < 0) {
2362 return EINVAL;
2363 }
2364 /* Check if the end marker is beyond LLONG_MAX. */
2365 if ((fl->l_len > 0) &&
2366 CHECK_ADD_OVERFLOW_INT64L(fl->l_start, fl->l_len - 1)) {
2367 return EOVERFLOW;
2368 }
2369 /* Check if the end marker is negative. */
2370 if ((fl->l_len < 0) && fl->l_start + fl->l_len < 0) {
2371 return EINVAL;
2372 }
2373 }
2374 return 0;
2375 }
2376
2377
2378 /*
2379 * sys_dup
2380 *
2381 * Description: Duplicate a file descriptor.
2382 *
2383 * Parameters: p Process performing the dup
2384 * uap->fd The fd to dup
2385 * retval Pointer to the call return area
2386 *
2387 * Returns: 0 Success
2388 * !0 Errno
2389 *
2390 * Implicit returns:
2391 * *retval (modified) The new descriptor
2392 */
2393 int
sys_dup(proc_t p,struct dup_args * uap,int32_t * retval)2394 sys_dup(proc_t p, struct dup_args *uap, int32_t *retval)
2395 {
2396 int old = uap->fd;
2397 int new, error;
2398 struct fileproc *fp;
2399 kauth_cred_t p_cred;
2400
2401 proc_fdlock(p);
2402 if ((error = fp_lookup(p, old, &fp, 1))) {
2403 proc_fdunlock(p);
2404 return error;
2405 }
2406 if (fp_isguarded(fp, GUARD_DUP)) {
2407 error = fp_guard_exception(p, old, fp, kGUARD_EXC_DUP);
2408 (void) fp_drop(p, old, fp, 1);
2409 proc_fdunlock(p);
2410 return error;
2411 }
2412 if ((error = fdalloc(p, 0, &new))) {
2413 fp_drop(p, old, fp, 1);
2414 proc_fdunlock(p);
2415 return error;
2416 }
2417 p_cred = current_cached_proc_cred(p);
2418 error = finishdup(p, p_cred, old, new, 0, retval);
2419
2420 if (ENTR_SHOULDTRACE && FILEGLOB_DTYPE(fp->fp_glob) == DTYPE_SOCKET) {
2421 KERNEL_ENERGYTRACE(kEnTrActKernSocket, DBG_FUNC_START,
2422 new, 0, (int64_t)VM_KERNEL_ADDRPERM(fp_get_data(fp)));
2423 }
2424
2425 fp_drop(p, old, fp, 1);
2426 proc_fdunlock(p);
2427
2428 return error;
2429 }
2430
2431 /*
2432 * sys_dup2
2433 *
2434 * Description: Duplicate a file descriptor to a particular value.
2435 *
2436 * Parameters: p Process performing the dup
2437 * uap->from The fd to dup
2438 * uap->to The fd to dup it to
2439 * retval Pointer to the call return area
2440 *
2441 * Returns: 0 Success
2442 * !0 Errno
2443 *
2444 * Implicit returns:
2445 * *retval (modified) The new descriptor
2446 */
2447 int
sys_dup2(proc_t p,struct dup2_args * uap,int32_t * retval)2448 sys_dup2(proc_t p, struct dup2_args *uap, int32_t *retval)
2449 {
2450 kauth_cred_t p_cred = current_cached_proc_cred(p);
2451
2452 return dup2(p, p_cred, uap->from, uap->to, retval);
2453 }
2454
2455 int
dup2(proc_t p,kauth_cred_t p_cred,int old,int new,int * retval)2456 dup2(proc_t p, kauth_cred_t p_cred, int old, int new, int *retval)
2457 {
2458 struct filedesc *fdp = &p->p_fd;
2459 struct fileproc *fp, *nfp;
2460 int i, error;
2461
2462 proc_fdlock(p);
2463
2464 startover:
2465 if ((error = fp_lookup(p, old, &fp, 1))) {
2466 proc_fdunlock(p);
2467 return error;
2468 }
2469 if (fp_isguarded(fp, GUARD_DUP)) {
2470 error = fp_guard_exception(p, old, fp, kGUARD_EXC_DUP);
2471 (void) fp_drop(p, old, fp, 1);
2472 proc_fdunlock(p);
2473 return error;
2474 }
2475 if (new < 0 || new >= proc_limitgetcur_nofile(p)) {
2476 fp_drop(p, old, fp, 1);
2477 proc_fdunlock(p);
2478 return EBADF;
2479 }
2480 if (old == new) {
2481 fp_drop(p, old, fp, 1);
2482 *retval = new;
2483 proc_fdunlock(p);
2484 return 0;
2485 }
2486 if (new < 0 || new >= fdp->fd_nfiles) {
2487 if ((error = fdalloc(p, new, &i))) {
2488 fp_drop(p, old, fp, 1);
2489 proc_fdunlock(p);
2490 return error;
2491 }
2492 if (new != i) {
2493 fdrelse(p, i);
2494 goto closeit;
2495 }
2496 } else {
2497 closeit:
2498 if ((fdp->fd_ofileflags[new] & UF_RESERVED) == UF_RESERVED) {
2499 fp_drop(p, old, fp, 1);
2500 procfdtbl_waitfd(p, new);
2501 #if DIAGNOSTIC
2502 proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
2503 #endif
2504 goto startover;
2505 }
2506
2507 if ((nfp = fdp->fd_ofiles[new]) != NULL) {
2508 if (fp_isguarded(nfp, GUARD_CLOSE)) {
2509 fp_drop(p, old, fp, 1);
2510 error = fp_guard_exception(p,
2511 new, nfp, kGUARD_EXC_CLOSE);
2512 proc_fdunlock(p);
2513 return error;
2514 }
2515 (void)fp_close_and_unlock(p, p_cred, new, nfp, FD_DUP2RESV);
2516 proc_fdlock(p);
2517 assert(fdp->fd_ofileflags[new] & UF_RESERVED);
2518 } else {
2519 #if DIAGNOSTIC
2520 if (fdp->fd_ofiles[new] != NULL) {
2521 panic("dup2: no ref on fileproc %d", new);
2522 }
2523 #endif
2524 procfdtbl_reservefd(p, new);
2525 }
2526 }
2527 #if DIAGNOSTIC
2528 if (fdp->fd_ofiles[new] != 0) {
2529 panic("dup2: overwriting fd_ofiles with new %d", new);
2530 }
2531 if ((fdp->fd_ofileflags[new] & UF_RESERVED) == 0) {
2532 panic("dup2: unreserved fileflags with new %d", new);
2533 }
2534 #endif
2535 error = finishdup(p, p_cred, old, new, 0, retval);
2536 fp_drop(p, old, fp, 1);
2537 proc_fdunlock(p);
2538
2539 return error;
2540 }
2541
2542
2543 /*
2544 * fcntl
2545 *
2546 * Description: The file control system call.
2547 *
2548 * Parameters: p Process performing the fcntl
2549 * uap->fd The fd to operate against
2550 * uap->cmd The command to perform
2551 * uap->arg Pointer to the command argument
2552 * retval Pointer to the call return area
2553 *
2554 * Returns: 0 Success
2555 * !0 Errno (see fcntl_nocancel)
2556 *
2557 * Implicit returns:
2558 * *retval (modified) fcntl return value (if any)
2559 *
2560 * Notes: This system call differs from fcntl_nocancel() in that it
2561 * tests for cancellation prior to performing a potentially
2562 * blocking operation.
2563 */
2564 int
sys_fcntl(proc_t p,struct fcntl_args * uap,int32_t * retval)2565 sys_fcntl(proc_t p, struct fcntl_args *uap, int32_t *retval)
2566 {
2567 __pthread_testcancel(1);
2568 return sys_fcntl_nocancel(p, (struct fcntl_nocancel_args *)uap, retval);
2569 }
2570
2571 #define ACCOUNT_OPENFROM_ENTITLEMENT \
2572 "com.apple.private.vfs.role-account-openfrom"
2573
2574 /*
2575 * sys_fcntl_nocancel
2576 *
2577 * Description: A non-cancel-testing file control system call.
2578 *
2579 * Parameters: p Process performing the fcntl
2580 * uap->fd The fd to operate against
2581 * uap->cmd The command to perform
2582 * uap->arg Pointer to the command argument
2583 * retval Pointer to the call return area
2584 *
2585 * Returns: 0 Success
2586 * EINVAL
2587 * fp_lookup:EBADF Bad file descriptor
2588 * [F_DUPFD]
2589 * fdalloc:EMFILE
2590 * fdalloc:ENOMEM
2591 * finishdup:EBADF
2592 * finishdup:ENOMEM
2593 * [F_SETOWN]
2594 * ESRCH
2595 * [F_SETLK]
2596 * EBADF
2597 * EOVERFLOW
2598 * copyin:EFAULT
2599 * vnode_getwithref:???
2600 * VNOP_ADVLOCK:???
2601 * msleep:ETIMEDOUT
2602 * [F_GETLK]
2603 * EBADF
2604 * EOVERFLOW
2605 * copyin:EFAULT
2606 * copyout:EFAULT
2607 * vnode_getwithref:???
2608 * VNOP_ADVLOCK:???
2609 * [F_PREALLOCATE]
2610 * EBADF
2611 * EFBIG
2612 * EINVAL
2613 * ENOSPC
2614 * copyin:EFAULT
2615 * copyout:EFAULT
2616 * vnode_getwithref:???
2617 * VNOP_ALLOCATE:???
2618 * [F_SETSIZE,F_RDADVISE]
2619 * EBADF
2620 * EINVAL
2621 * copyin:EFAULT
2622 * vnode_getwithref:???
2623 * [F_RDAHEAD,F_NOCACHE]
2624 * EBADF
2625 * vnode_getwithref:???
2626 * [???]
2627 *
2628 * Implicit returns:
2629 * *retval (modified) fcntl return value (if any)
2630 */
2631 #define SYS_FCNTL_DECLARE_VFS_CONTEXT(context) \
2632 struct vfs_context context = { \
2633 .vc_thread = current_thread(), \
2634 .vc_ucred = fp->f_cred, \
2635 }
2636
2637 static user_addr_t
sys_fnctl_parse_arg(proc_t p,user_long_t arg)2638 sys_fnctl_parse_arg(proc_t p, user_long_t arg)
2639 {
2640 /*
2641 * Since the arg parameter is defined as a long but may be
2642 * either a long or a pointer we must take care to handle
2643 * sign extension issues. Our sys call munger will sign
2644 * extend a long when we are called from a 32-bit process.
2645 * Since we can never have an address greater than 32-bits
2646 * from a 32-bit process we lop off the top 32-bits to avoid
2647 * getting the wrong address
2648 */
2649 return proc_is64bit(p) ? arg : CAST_USER_ADDR_T((uint32_t)arg);
2650 }
2651
2652 /* cleanup code common to fnctl functions, for when the fdlock is still held */
2653 static int
sys_fcntl_out(proc_t p,int fd,struct fileproc * fp,int error)2654 sys_fcntl_out(proc_t p, int fd, struct fileproc *fp, int error)
2655 {
2656 fp_drop(p, fd, fp, 1);
2657 proc_fdunlock(p);
2658 return error;
2659 }
2660
2661 /* cleanup code common to fnctl acting on vnodes, once they unlocked the fdlock */
2662 static int
sys_fcntl_outdrop(proc_t p,int fd,struct fileproc * fp,struct vnode * vp,int error)2663 sys_fcntl_outdrop(proc_t p, int fd, struct fileproc *fp, struct vnode *vp, int error)
2664 {
2665 #pragma unused(vp)
2666
2667 AUDIT_ARG(vnpath_withref, vp, ARG_VNODE1);
2668 fp_drop(p, fd, fp, 0);
2669 return error;
2670 }
2671
2672 typedef int (*sys_fnctl_handler_t)(proc_t p, int fd, int cmd, user_long_t arg,
2673 struct fileproc *fp, int32_t *retval);
2674
2675 typedef int (*sys_fnctl_vnode_handler_t)(proc_t p, int fd, int cmd,
2676 user_long_t arg, struct fileproc *fp, struct vnode *vp, int32_t *retval);
2677
2678 /*
2679 * SPI (private) for opening a file starting from a dir fd
2680 *
2681 * Note: do not inline to keep stack usage under control.
2682 */
2683 __attribute__((noinline))
2684 static int
sys_fcntl__OPENFROM(proc_t p,int fd,int cmd,user_long_t arg,struct fileproc * fp,struct vnode * vp,int32_t * retval)2685 sys_fcntl__OPENFROM(proc_t p, int fd, int cmd, user_long_t arg,
2686 struct fileproc *fp, struct vnode *vp, int32_t *retval)
2687 {
2688 #pragma unused(cmd)
2689
2690 user_addr_t argp = sys_fnctl_parse_arg(p, arg);
2691 struct user_fopenfrom fopen;
2692 struct vnode_attr *va;
2693 struct nameidata *nd;
2694 int error, cmode;
2695 bool has_entitlement;
2696
2697 /* Check if this isn't a valid file descriptor */
2698 if ((fp->f_flag & FREAD) == 0) {
2699 return sys_fcntl_out(p, fd, fp, EBADF);
2700 }
2701 proc_fdunlock(p);
2702
2703 if (vnode_getwithref(vp)) {
2704 error = ENOENT;
2705 goto outdrop;
2706 }
2707
2708 /* Only valid for directories */
2709 if (vp->v_type != VDIR) {
2710 vnode_put(vp);
2711 error = ENOTDIR;
2712 goto outdrop;
2713 }
2714
2715 /*
2716 * Only entitled apps may use the credentials of the thread
2717 * that opened the file descriptor.
2718 * Non-entitled threads will use their own context.
2719 */
2720 has_entitlement = IOCurrentTaskHasEntitlement(ACCOUNT_OPENFROM_ENTITLEMENT);
2721
2722 /* Get flags, mode and pathname arguments. */
2723 if (IS_64BIT_PROCESS(p)) {
2724 error = copyin(argp, &fopen, sizeof(fopen));
2725 } else {
2726 struct user32_fopenfrom fopen32;
2727
2728 error = copyin(argp, &fopen32, sizeof(fopen32));
2729 fopen.o_flags = fopen32.o_flags;
2730 fopen.o_mode = fopen32.o_mode;
2731 fopen.o_pathname = CAST_USER_ADDR_T(fopen32.o_pathname);
2732 }
2733 if (error) {
2734 vnode_put(vp);
2735 goto outdrop;
2736 }
2737
2738 /* open1() can have really deep stacks, so allocate those */
2739 va = kalloc_type(struct vnode_attr, Z_WAITOK | Z_ZERO | Z_NOFAIL);
2740 nd = kalloc_type(struct nameidata, Z_WAITOK | Z_ZERO | Z_NOFAIL);
2741
2742 AUDIT_ARG(fflags, fopen.o_flags);
2743 AUDIT_ARG(mode, fopen.o_mode);
2744 VATTR_INIT(va);
2745 /* Mask off all but regular access permissions */
2746 cmode = ((fopen.o_mode & ~p->p_fd.fd_cmask) & ALLPERMS) & ~S_ISTXT;
2747 VATTR_SET(va, va_mode, cmode & ACCESSPERMS);
2748
2749 SYS_FCNTL_DECLARE_VFS_CONTEXT(context);
2750
2751 /* Start the lookup relative to the file descriptor's vnode. */
2752 NDINIT(nd, LOOKUP, OP_OPEN, USEDVP | FOLLOW | AUDITVNPATH1, UIO_USERSPACE,
2753 fopen.o_pathname, has_entitlement ? &context : vfs_context_current());
2754 nd->ni_dvp = vp;
2755
2756 error = open1(has_entitlement ? &context : vfs_context_current(),
2757 nd, fopen.o_flags, va, NULL, NULL, retval, AUTH_OPEN_NOAUTHFD);
2758
2759 kfree_type(struct vnode_attr, va);
2760 kfree_type(struct nameidata, nd);
2761
2762 vnode_put(vp);
2763
2764 outdrop:
2765 return sys_fcntl_outdrop(p, fd, fp, vp, error);
2766 }
2767
2768 int
sys_fcntl_nocancel(proc_t p,struct fcntl_nocancel_args * uap,int32_t * retval)2769 sys_fcntl_nocancel(proc_t p, struct fcntl_nocancel_args *uap, int32_t *retval)
2770 {
2771 int fd = uap->fd;
2772 int cmd = uap->cmd;
2773 struct fileproc *fp;
2774 struct vnode *vp = NULLVP; /* for AUDIT_ARG() at end */
2775 unsigned int oflags, nflags;
2776 int i, tmp, error, error2, flg = 0;
2777 struct flock fl = {};
2778 struct flocktimeout fltimeout;
2779 struct user32_flocktimeout user32_fltimeout;
2780 struct timespec *timeout = NULL;
2781 off_t offset;
2782 int newmin;
2783 daddr64_t lbn, bn;
2784 unsigned int fflag;
2785 user_addr_t argp;
2786 boolean_t is64bit;
2787 int has_entitlement = 0;
2788 kauth_cred_t p_cred;
2789 cs_blob_add_flags_t csblob_add_flags = 0;
2790
2791 AUDIT_ARG(fd, uap->fd);
2792 AUDIT_ARG(cmd, uap->cmd);
2793
2794 proc_fdlock(p);
2795 if ((error = fp_lookup(p, fd, &fp, 1))) {
2796 proc_fdunlock(p);
2797 return error;
2798 }
2799
2800 SYS_FCNTL_DECLARE_VFS_CONTEXT(context);
2801
2802 is64bit = proc_is64bit(p);
2803 if (is64bit) {
2804 argp = uap->arg;
2805 } else {
2806 /*
2807 * Since the arg parameter is defined as a long but may be
2808 * either a long or a pointer we must take care to handle
2809 * sign extension issues. Our sys call munger will sign
2810 * extend a long when we are called from a 32-bit process.
2811 * Since we can never have an address greater than 32-bits
2812 * from a 32-bit process we lop off the top 32-bits to avoid
2813 * getting the wrong address
2814 */
2815 argp = CAST_USER_ADDR_T((uint32_t)uap->arg);
2816 }
2817
2818 #if CONFIG_MACF
2819 error = mac_file_check_fcntl(kauth_cred_get(), fp->fp_glob, cmd, uap->arg);
2820 if (error) {
2821 goto out;
2822 }
2823 #endif
2824
2825 switch (cmd) {
2826 case F_DUPFD:
2827 case F_DUPFD_CLOEXEC:
2828 if (fp_isguarded(fp, GUARD_DUP)) {
2829 error = fp_guard_exception(p, fd, fp, kGUARD_EXC_DUP);
2830 goto out;
2831 }
2832 newmin = CAST_DOWN_EXPLICIT(int, uap->arg); /* arg is an int, so we won't lose bits */
2833 AUDIT_ARG(value32, newmin);
2834 if (newmin < 0 || newmin >= proc_limitgetcur_nofile(p)) {
2835 error = EINVAL;
2836 goto out;
2837 }
2838 if ((error = fdalloc(p, newmin, &i))) {
2839 goto out;
2840 }
2841 p_cred = current_cached_proc_cred(p);
2842 error = finishdup(p, p_cred, fd, i,
2843 cmd == F_DUPFD_CLOEXEC ? FP_CLOEXEC : 0, retval);
2844 goto out;
2845
2846 case F_GETFD:
2847 *retval = (fp->fp_flags & FP_CLOEXEC) ? FD_CLOEXEC : 0;
2848 error = 0;
2849 goto out;
2850
2851 case F_SETFD:
2852 AUDIT_ARG(value32, (uint32_t)uap->arg);
2853 if (uap->arg & FD_CLOEXEC) {
2854 fp->fp_flags |= FP_CLOEXEC;
2855 error = 0;
2856 } else if (!fp->fp_guard_attrs) {
2857 fp->fp_flags &= ~FP_CLOEXEC;
2858 error = 0;
2859 } else {
2860 error = fp_guard_exception(p,
2861 fd, fp, kGUARD_EXC_NOCLOEXEC);
2862 }
2863 goto out;
2864
2865 case F_GETFL:
2866 fflag = fp->f_flag;
2867 if ((fflag & O_EVTONLY) && proc_disallow_rw_for_o_evtonly(p)) {
2868 /*
2869 * We insert back F_READ so that conversion back to open flags with
2870 * OFLAGS() will come out right. We only need to set 'FREAD' as the
2871 * 'O_RDONLY' is always implied.
2872 */
2873 fflag |= FREAD;
2874 }
2875 *retval = OFLAGS(fflag);
2876 error = 0;
2877 goto out;
2878
2879 case F_SETFL:
2880 // FIXME (rdar://54898652)
2881 //
2882 // this code is broken if fnctl(F_SETFL), ioctl() are
2883 // called concurrently for the same fileglob.
2884
2885 tmp = CAST_DOWN_EXPLICIT(int, uap->arg); /* arg is an int, so we won't lose bits */
2886 AUDIT_ARG(value32, tmp);
2887
2888 os_atomic_rmw_loop(&fp->f_flag, oflags, nflags, relaxed, {
2889 nflags = oflags & ~FCNTLFLAGS;
2890 nflags |= FFLAGS(tmp) & FCNTLFLAGS;
2891 });
2892 tmp = nflags & FNONBLOCK;
2893 error = fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, &context);
2894 if (error) {
2895 goto out;
2896 }
2897 tmp = nflags & FASYNC;
2898 error = fo_ioctl(fp, FIOASYNC, (caddr_t)&tmp, &context);
2899 if (!error) {
2900 goto out;
2901 }
2902 os_atomic_andnot(&fp->f_flag, FNONBLOCK, relaxed);
2903 tmp = 0;
2904 (void)fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, &context);
2905 goto out;
2906
2907 case F_GETOWN:
2908 if (fp->f_type == DTYPE_SOCKET) {
2909 *retval = ((struct socket *)fp_get_data(fp))->so_pgid;
2910 error = 0;
2911 goto out;
2912 }
2913 error = fo_ioctl(fp, TIOCGPGRP, (caddr_t)retval, &context);
2914 *retval = -*retval;
2915 goto out;
2916
2917 case F_SETOWN:
2918 tmp = CAST_DOWN_EXPLICIT(pid_t, uap->arg); /* arg is an int, so we won't lose bits */
2919 AUDIT_ARG(value32, tmp);
2920 if (fp->f_type == DTYPE_SOCKET) {
2921 ((struct socket *)fp_get_data(fp))->so_pgid = tmp;
2922 error = 0;
2923 goto out;
2924 }
2925 if (fp->f_type == DTYPE_PIPE) {
2926 error = fo_ioctl(fp, TIOCSPGRP, (caddr_t)&tmp, &context);
2927 goto out;
2928 }
2929
2930 if (tmp <= 0) {
2931 tmp = -tmp;
2932 } else {
2933 proc_t p1 = proc_find(tmp);
2934 if (p1 == 0) {
2935 error = ESRCH;
2936 goto out;
2937 }
2938 tmp = (int)p1->p_pgrpid;
2939 proc_rele(p1);
2940 }
2941 error = fo_ioctl(fp, TIOCSPGRP, (caddr_t)&tmp, &context);
2942 goto out;
2943
2944 case F_SETNOSIGPIPE:
2945 tmp = CAST_DOWN_EXPLICIT(int, uap->arg);
2946 if (fp->f_type == DTYPE_SOCKET) {
2947 #if SOCKETS
2948 error = sock_setsockopt((struct socket *)fp_get_data(fp),
2949 SOL_SOCKET, SO_NOSIGPIPE, &tmp, sizeof(tmp));
2950 #else
2951 error = EINVAL;
2952 #endif
2953 } else {
2954 struct fileglob *fg = fp->fp_glob;
2955
2956 lck_mtx_lock_spin(&fg->fg_lock);
2957 if (tmp) {
2958 fg->fg_lflags |= FG_NOSIGPIPE;
2959 } else {
2960 fg->fg_lflags &= ~FG_NOSIGPIPE;
2961 }
2962 lck_mtx_unlock(&fg->fg_lock);
2963 error = 0;
2964 }
2965 goto out;
2966
2967 case F_GETNOSIGPIPE:
2968 if (fp->f_type == DTYPE_SOCKET) {
2969 #if SOCKETS
2970 int retsize = sizeof(*retval);
2971 error = sock_getsockopt((struct socket *)fp_get_data(fp),
2972 SOL_SOCKET, SO_NOSIGPIPE, retval, &retsize);
2973 #else
2974 error = EINVAL;
2975 #endif
2976 } else {
2977 *retval = (fp->fp_glob->fg_lflags & FG_NOSIGPIPE) ?
2978 1 : 0;
2979 error = 0;
2980 }
2981 goto out;
2982
2983 case F_SETCONFINED:
2984 /*
2985 * If this is the only reference to this fglob in the process
2986 * and it's already marked as close-on-fork then mark it as
2987 * (immutably) "confined" i.e. any fd that points to it will
2988 * forever be close-on-fork, and attempts to use an IPC
2989 * mechanism to move the descriptor elsewhere will fail.
2990 */
2991 if (CAST_DOWN_EXPLICIT(int, uap->arg)) {
2992 struct fileglob *fg = fp->fp_glob;
2993
2994 lck_mtx_lock_spin(&fg->fg_lock);
2995 if (fg->fg_lflags & FG_CONFINED) {
2996 error = 0;
2997 } else if (1 != os_ref_get_count_raw(&fg->fg_count)) {
2998 error = EAGAIN; /* go close the dup .. */
2999 } else if (fp->fp_flags & FP_CLOFORK) {
3000 fg->fg_lflags |= FG_CONFINED;
3001 error = 0;
3002 } else {
3003 error = EBADF; /* open without O_CLOFORK? */
3004 }
3005 lck_mtx_unlock(&fg->fg_lock);
3006 } else {
3007 /*
3008 * Other subsystems may have built on the immutability
3009 * of FG_CONFINED; clearing it may be tricky.
3010 */
3011 error = EPERM; /* immutable */
3012 }
3013 goto out;
3014
3015 case F_GETCONFINED:
3016 *retval = (fp->fp_glob->fg_lflags & FG_CONFINED) ? 1 : 0;
3017 error = 0;
3018 goto out;
3019
3020 case F_SETLKWTIMEOUT:
3021 case F_SETLKW:
3022 case F_OFD_SETLKWTIMEOUT:
3023 case F_OFD_SETLKW:
3024 flg |= F_WAIT;
3025 OS_FALLTHROUGH;
3026
3027 case F_SETLK:
3028 case F_OFD_SETLK:
3029 if (fp->f_type != DTYPE_VNODE) {
3030 error = EBADF;
3031 goto out;
3032 }
3033 vp = (struct vnode *)fp_get_data(fp);
3034
3035 fflag = fp->f_flag;
3036 offset = fp->f_offset;
3037 proc_fdunlock(p);
3038
3039 /* Copy in the lock structure */
3040 if (F_SETLKWTIMEOUT == cmd || F_OFD_SETLKWTIMEOUT == cmd) {
3041 /* timespec uses long, so munge when we're dealing with 32-bit userspace */
3042 if (is64bit) {
3043 error = copyin(argp, (caddr_t) &fltimeout, sizeof(fltimeout));
3044 if (error) {
3045 goto outdrop;
3046 }
3047 } else {
3048 error = copyin(argp, (caddr_t) &user32_fltimeout, sizeof(user32_fltimeout));
3049 if (error) {
3050 goto outdrop;
3051 }
3052 fltimeout.fl = user32_fltimeout.fl;
3053 fltimeout.timeout.tv_sec = user32_fltimeout.timeout.tv_sec;
3054 fltimeout.timeout.tv_nsec = user32_fltimeout.timeout.tv_nsec;
3055 }
3056 fl = fltimeout.fl;
3057 timeout = &fltimeout.timeout;
3058 } else {
3059 error = copyin(argp, (caddr_t)&fl, sizeof(fl));
3060 if (error) {
3061 goto outdrop;
3062 }
3063 }
3064
3065 /* Check starting byte and ending byte for EOVERFLOW in SEEK_CUR */
3066 /* and ending byte for EOVERFLOW in SEEK_SET */
3067 error = check_file_seek_range(&fl, offset);
3068 if (error) {
3069 goto outdrop;
3070 }
3071
3072 if ((error = vnode_getwithref(vp))) {
3073 goto outdrop;
3074 }
3075 if (fl.l_whence == SEEK_CUR) {
3076 fl.l_start += offset;
3077 }
3078
3079 #if CONFIG_MACF
3080 error = mac_file_check_lock(kauth_cred_get(), fp->fp_glob,
3081 F_SETLK, &fl);
3082 if (error) {
3083 (void)vnode_put(vp);
3084 goto outdrop;
3085 }
3086 #endif
3087
3088 #if CONFIG_FILE_LEASES
3089 (void)vnode_breaklease(vp, O_WRONLY, vfs_context_current());
3090 #endif
3091
3092 switch (cmd) {
3093 case F_OFD_SETLK:
3094 case F_OFD_SETLKW:
3095 case F_OFD_SETLKWTIMEOUT:
3096 flg |= F_OFD_LOCK;
3097 if (fp->fp_glob->fg_lflags & FG_CONFINED) {
3098 flg |= F_CONFINED;
3099 }
3100 switch (fl.l_type) {
3101 case F_RDLCK:
3102 if ((fflag & FREAD) == 0) {
3103 error = EBADF;
3104 break;
3105 }
3106 error = VNOP_ADVLOCK(vp, ofd_to_id(fp->fp_glob),
3107 F_SETLK, &fl, flg, &context, timeout);
3108 break;
3109 case F_WRLCK:
3110 if ((fflag & FWRITE) == 0) {
3111 error = EBADF;
3112 break;
3113 }
3114 error = VNOP_ADVLOCK(vp, ofd_to_id(fp->fp_glob),
3115 F_SETLK, &fl, flg, &context, timeout);
3116 break;
3117 case F_UNLCK:
3118 error = VNOP_ADVLOCK(vp, ofd_to_id(fp->fp_glob),
3119 F_UNLCK, &fl, F_OFD_LOCK, &context,
3120 timeout);
3121 break;
3122 default:
3123 error = EINVAL;
3124 break;
3125 }
3126 if (0 == error &&
3127 (F_RDLCK == fl.l_type || F_WRLCK == fl.l_type)) {
3128 struct fileglob *fg = fp->fp_glob;
3129
3130 /*
3131 * arrange F_UNLCK on last close (once
3132 * set, FG_HAS_OFDLOCK is immutable)
3133 */
3134 if ((fg->fg_lflags & FG_HAS_OFDLOCK) == 0) {
3135 lck_mtx_lock_spin(&fg->fg_lock);
3136 fg->fg_lflags |= FG_HAS_OFDLOCK;
3137 lck_mtx_unlock(&fg->fg_lock);
3138 }
3139 }
3140 break;
3141 default:
3142 flg |= F_POSIX;
3143 switch (fl.l_type) {
3144 case F_RDLCK:
3145 if ((fflag & FREAD) == 0) {
3146 error = EBADF;
3147 break;
3148 }
3149 // XXX UInt32 unsafe for LP64 kernel
3150 os_atomic_or(&p->p_ladvflag, P_LADVLOCK, relaxed);
3151 error = VNOP_ADVLOCK(vp, (caddr_t)p,
3152 F_SETLK, &fl, flg, &context, timeout);
3153 break;
3154 case F_WRLCK:
3155 if ((fflag & FWRITE) == 0) {
3156 error = EBADF;
3157 break;
3158 }
3159 // XXX UInt32 unsafe for LP64 kernel
3160 os_atomic_or(&p->p_ladvflag, P_LADVLOCK, relaxed);
3161 error = VNOP_ADVLOCK(vp, (caddr_t)p,
3162 F_SETLK, &fl, flg, &context, timeout);
3163 break;
3164 case F_UNLCK:
3165 error = VNOP_ADVLOCK(vp, (caddr_t)p,
3166 F_UNLCK, &fl, F_POSIX, &context, timeout);
3167 break;
3168 default:
3169 error = EINVAL;
3170 break;
3171 }
3172 break;
3173 }
3174 (void) vnode_put(vp);
3175 goto outdrop;
3176
3177 case F_GETLK:
3178 case F_OFD_GETLK:
3179 case F_GETLKPID:
3180 case F_OFD_GETLKPID:
3181 if (fp->f_type != DTYPE_VNODE) {
3182 error = EBADF;
3183 goto out;
3184 }
3185 vp = (struct vnode *)fp_get_data(fp);
3186
3187 offset = fp->f_offset;
3188 proc_fdunlock(p);
3189
3190 /* Copy in the lock structure */
3191 error = copyin(argp, (caddr_t)&fl, sizeof(fl));
3192 if (error) {
3193 goto outdrop;
3194 }
3195
3196 /* Check starting byte and ending byte for EOVERFLOW in SEEK_CUR */
3197 /* and ending byte for EOVERFLOW in SEEK_SET */
3198 error = check_file_seek_range(&fl, offset);
3199 if (error) {
3200 goto outdrop;
3201 }
3202
3203 if ((fl.l_whence == SEEK_SET) && (fl.l_start < 0)) {
3204 error = EINVAL;
3205 goto outdrop;
3206 }
3207
3208 switch (fl.l_type) {
3209 case F_RDLCK:
3210 case F_UNLCK:
3211 case F_WRLCK:
3212 break;
3213 default:
3214 error = EINVAL;
3215 goto outdrop;
3216 }
3217
3218 switch (fl.l_whence) {
3219 case SEEK_CUR:
3220 case SEEK_SET:
3221 case SEEK_END:
3222 break;
3223 default:
3224 error = EINVAL;
3225 goto outdrop;
3226 }
3227
3228 if ((error = vnode_getwithref(vp)) == 0) {
3229 if (fl.l_whence == SEEK_CUR) {
3230 fl.l_start += offset;
3231 }
3232
3233 #if CONFIG_MACF
3234 error = mac_file_check_lock(kauth_cred_get(), fp->fp_glob,
3235 cmd, &fl);
3236 if (error == 0)
3237 #endif
3238 switch (cmd) {
3239 case F_OFD_GETLK:
3240 error = VNOP_ADVLOCK(vp, ofd_to_id(fp->fp_glob),
3241 F_GETLK, &fl, F_OFD_LOCK, &context, NULL);
3242 break;
3243 case F_OFD_GETLKPID:
3244 error = VNOP_ADVLOCK(vp, ofd_to_id(fp->fp_glob),
3245 F_GETLKPID, &fl, F_OFD_LOCK, &context, NULL);
3246 break;
3247 default:
3248 error = VNOP_ADVLOCK(vp, (caddr_t)p,
3249 cmd, &fl, F_POSIX, &context, NULL);
3250 break;
3251 }
3252
3253 (void)vnode_put(vp);
3254
3255 if (error == 0) {
3256 error = copyout((caddr_t)&fl, argp, sizeof(fl));
3257 }
3258 }
3259 goto outdrop;
3260
3261 case F_PREALLOCATE: {
3262 fstore_t alloc_struct; /* structure for allocate command */
3263 u_int32_t alloc_flags = 0;
3264
3265 if (fp->f_type != DTYPE_VNODE) {
3266 error = EBADF;
3267 goto out;
3268 }
3269
3270 vp = (struct vnode *)fp_get_data(fp);
3271 proc_fdunlock(p);
3272
3273 /* make sure that we have write permission */
3274 if ((fp->f_flag & FWRITE) == 0) {
3275 error = EBADF;
3276 goto outdrop;
3277 }
3278
3279 error = copyin(argp, (caddr_t)&alloc_struct, sizeof(alloc_struct));
3280 if (error) {
3281 goto outdrop;
3282 }
3283
3284 /* now set the space allocated to 0 */
3285 alloc_struct.fst_bytesalloc = 0;
3286
3287 /*
3288 * Do some simple parameter checking
3289 */
3290
3291 /* set up the flags */
3292
3293 alloc_flags |= PREALLOCATE;
3294
3295 if (alloc_struct.fst_flags & F_ALLOCATECONTIG) {
3296 alloc_flags |= ALLOCATECONTIG;
3297 }
3298
3299 if (alloc_struct.fst_flags & F_ALLOCATEALL) {
3300 alloc_flags |= ALLOCATEALL;
3301 }
3302
3303 if (alloc_struct.fst_flags & F_ALLOCATEPERSIST) {
3304 alloc_flags |= ALLOCATEPERSIST;
3305 }
3306
3307 /*
3308 * Do any position mode specific stuff. The only
3309 * position mode supported now is PEOFPOSMODE
3310 */
3311
3312 switch (alloc_struct.fst_posmode) {
3313 case F_PEOFPOSMODE:
3314 if (alloc_struct.fst_offset != 0) {
3315 error = EINVAL;
3316 goto outdrop;
3317 }
3318
3319 alloc_flags |= ALLOCATEFROMPEOF;
3320 break;
3321
3322 case F_VOLPOSMODE:
3323 if (alloc_struct.fst_offset <= 0) {
3324 error = EINVAL;
3325 goto outdrop;
3326 }
3327
3328 alloc_flags |= ALLOCATEFROMVOL;
3329 break;
3330
3331 default: {
3332 error = EINVAL;
3333 goto outdrop;
3334 }
3335 }
3336 if ((error = vnode_getwithref(vp)) == 0) {
3337 /*
3338 * call allocate to get the space
3339 */
3340 error = VNOP_ALLOCATE(vp, alloc_struct.fst_length, alloc_flags,
3341 &alloc_struct.fst_bytesalloc, alloc_struct.fst_offset,
3342 &context);
3343 (void)vnode_put(vp);
3344
3345 error2 = copyout((caddr_t)&alloc_struct, argp, sizeof(alloc_struct));
3346
3347 if (error == 0) {
3348 error = error2;
3349 }
3350 }
3351 goto outdrop;
3352 }
3353 case F_PUNCHHOLE: {
3354 fpunchhole_t args;
3355
3356 if (fp->f_type != DTYPE_VNODE) {
3357 error = EBADF;
3358 goto out;
3359 }
3360
3361 vp = (struct vnode *)fp_get_data(fp);
3362 proc_fdunlock(p);
3363
3364 /* need write permissions */
3365 if ((fp->f_flag & FWRITE) == 0) {
3366 error = EPERM;
3367 goto outdrop;
3368 }
3369
3370 if ((error = copyin(argp, (caddr_t)&args, sizeof(args)))) {
3371 goto outdrop;
3372 }
3373
3374 if ((error = vnode_getwithref(vp))) {
3375 goto outdrop;
3376 }
3377
3378 #if CONFIG_MACF
3379 if ((error = mac_vnode_check_write(&context, fp->fp_glob->fg_cred, vp))) {
3380 (void)vnode_put(vp);
3381 goto outdrop;
3382 }
3383 #endif
3384
3385 error = VNOP_IOCTL(vp, F_PUNCHHOLE, (caddr_t)&args, 0, &context);
3386 (void)vnode_put(vp);
3387
3388 goto outdrop;
3389 }
3390 case F_TRIM_ACTIVE_FILE: {
3391 ftrimactivefile_t args;
3392
3393 if (priv_check_cred(kauth_cred_get(), PRIV_TRIM_ACTIVE_FILE, 0)) {
3394 error = EACCES;
3395 goto out;
3396 }
3397
3398 if (fp->f_type != DTYPE_VNODE) {
3399 error = EBADF;
3400 goto out;
3401 }
3402
3403 vp = (struct vnode *)fp_get_data(fp);
3404 proc_fdunlock(p);
3405
3406 /* need write permissions */
3407 if ((fp->f_flag & FWRITE) == 0) {
3408 error = EPERM;
3409 goto outdrop;
3410 }
3411
3412 if ((error = copyin(argp, (caddr_t)&args, sizeof(args)))) {
3413 goto outdrop;
3414 }
3415
3416 if ((error = vnode_getwithref(vp))) {
3417 goto outdrop;
3418 }
3419
3420 error = VNOP_IOCTL(vp, F_TRIM_ACTIVE_FILE, (caddr_t)&args, 0, &context);
3421 (void)vnode_put(vp);
3422
3423 goto outdrop;
3424 }
3425 case F_SPECULATIVE_READ: {
3426 fspecread_t args;
3427 off_t temp_length = 0;
3428
3429 if (fp->f_type != DTYPE_VNODE) {
3430 error = EBADF;
3431 goto out;
3432 }
3433
3434 vp = (struct vnode *)fp_get_data(fp);
3435 proc_fdunlock(p);
3436
3437 if ((error = copyin(argp, (caddr_t)&args, sizeof(args)))) {
3438 goto outdrop;
3439 }
3440
3441 /* Discard invalid offsets or lengths */
3442 if ((args.fsr_offset < 0) || (args.fsr_length < 0)) {
3443 error = EINVAL;
3444 goto outdrop;
3445 }
3446
3447 /*
3448 * Round the file offset down to a page-size boundary (or to 0).
3449 * The filesystem will need to round the length up to the end of the page boundary
3450 * or to the EOF of the file.
3451 */
3452 uint64_t foff = (((uint64_t)args.fsr_offset) & ~((uint64_t)PAGE_MASK));
3453 uint64_t foff_delta = args.fsr_offset - foff;
3454 args.fsr_offset = (off_t) foff;
3455
3456 /*
3457 * Now add in the delta to the supplied length. Since we may have adjusted the
3458 * offset, increase it by the amount that we adjusted.
3459 */
3460 if (os_add_overflow(args.fsr_length, foff_delta, &args.fsr_length)) {
3461 error = EOVERFLOW;
3462 goto outdrop;
3463 }
3464
3465 /*
3466 * Make sure (fsr_offset + fsr_length) does not overflow.
3467 */
3468 if (os_add_overflow(args.fsr_offset, args.fsr_length, &temp_length)) {
3469 error = EOVERFLOW;
3470 goto outdrop;
3471 }
3472
3473 if ((error = vnode_getwithref(vp))) {
3474 goto outdrop;
3475 }
3476 error = VNOP_IOCTL(vp, F_SPECULATIVE_READ, (caddr_t)&args, 0, &context);
3477 (void)vnode_put(vp);
3478
3479 goto outdrop;
3480 }
3481 case F_ATTRIBUTION_TAG: {
3482 fattributiontag_t args;
3483
3484 if (fp->f_type != DTYPE_VNODE) {
3485 error = EBADF;
3486 goto out;
3487 }
3488
3489 vp = (struct vnode *)fp_get_data(fp);
3490 proc_fdunlock(p);
3491
3492 if ((error = copyin(argp, (caddr_t)&args, sizeof(args)))) {
3493 goto outdrop;
3494 }
3495
3496 if ((error = vnode_getwithref(vp))) {
3497 goto outdrop;
3498 }
3499
3500 error = VNOP_IOCTL(vp, F_ATTRIBUTION_TAG, (caddr_t)&args, 0, &context);
3501 (void)vnode_put(vp);
3502
3503 if (error == 0) {
3504 error = copyout((caddr_t)&args, argp, sizeof(args));
3505 }
3506
3507 goto outdrop;
3508 }
3509 case F_SETSIZE: {
3510 struct vnode_attr va;
3511
3512 if (fp->f_type != DTYPE_VNODE) {
3513 error = EBADF;
3514 goto out;
3515 }
3516
3517 if ((fp->fp_glob->fg_flag & FWRITE) == 0) {
3518 error = EBADF;
3519 goto out;
3520 }
3521 vp = (struct vnode *)fp_get_data(fp);
3522 proc_fdunlock(p);
3523
3524 error = copyin(argp, (caddr_t)&offset, sizeof(off_t));
3525 if (error) {
3526 goto outdrop;
3527 }
3528 AUDIT_ARG(value64, offset);
3529
3530 error = vnode_getwithref(vp);
3531 if (error) {
3532 goto outdrop;
3533 }
3534
3535 VATTR_INIT(&va);
3536 VATTR_WANTED(&va, va_flags);
3537
3538 error = vnode_getattr(vp, &va, vfs_context_current());
3539 if (error) {
3540 vnode_put(vp);
3541 goto outdrop;
3542 }
3543
3544 /* Don't allow F_SETSIZE if the file has append-only flag set. */
3545 if (va.va_flags & APPEND) {
3546 error = EPERM;
3547 vnode_put(vp);
3548 goto outdrop;
3549 }
3550
3551 #if CONFIG_MACF
3552 error = mac_vnode_check_truncate(&context,
3553 fp->fp_glob->fg_cred, vp);
3554 if (error) {
3555 (void)vnode_put(vp);
3556 goto outdrop;
3557 }
3558 #endif
3559 /*
3560 * Make sure that we are root. Growing a file
3561 * without zero filling the data is a security hole.
3562 */
3563 if (!kauth_cred_issuser(kauth_cred_get())) {
3564 error = EACCES;
3565 } else {
3566 /*
3567 * Require privilege to change file size without zerofill,
3568 * else will change the file size and zerofill it.
3569 */
3570 error = priv_check_cred(kauth_cred_get(), PRIV_VFS_SETSIZE, 0);
3571 if (error == 0) {
3572 error = vnode_setsize(vp, offset, IO_NOZEROFILL, &context);
3573 } else {
3574 error = vnode_setsize(vp, offset, 0, &context);
3575 }
3576
3577 #if CONFIG_MACF
3578 if (error == 0) {
3579 mac_vnode_notify_truncate(&context, fp->fp_glob->fg_cred, vp);
3580 }
3581 #endif
3582 }
3583
3584 (void)vnode_put(vp);
3585 goto outdrop;
3586 }
3587
3588 case F_RDAHEAD:
3589 if (fp->f_type != DTYPE_VNODE) {
3590 error = EBADF;
3591 goto out;
3592 }
3593 if (uap->arg) {
3594 os_atomic_andnot(&fp->fp_glob->fg_flag, FNORDAHEAD, relaxed);
3595 } else {
3596 os_atomic_or(&fp->fp_glob->fg_flag, FNORDAHEAD, relaxed);
3597 }
3598 goto out;
3599
3600 case F_NOCACHE:
3601 case F_NOCACHE_EXT:
3602 if ((fp->f_type != DTYPE_VNODE) || (cmd == F_NOCACHE_EXT &&
3603 (vnode_vtype((struct vnode *)fp_get_data(fp)) != VREG))) {
3604 error = EBADF;
3605 goto out;
3606 }
3607 if (uap->arg) {
3608 os_atomic_or(&fp->fp_glob->fg_flag, FNOCACHE, relaxed);
3609 if (cmd == F_NOCACHE_EXT) {
3610 /*
3611 * We're reusing the O_NOCTTY bit for this purpose as it is only
3612 * used for open(2) and is mutually exclusive with a regular file.
3613 */
3614 os_atomic_or(&fp->fp_glob->fg_flag, O_NOCTTY, relaxed);
3615 }
3616 } else {
3617 os_atomic_andnot(&fp->fp_glob->fg_flag, FNOCACHE | O_NOCTTY, relaxed);
3618 }
3619 goto out;
3620
3621 case F_NODIRECT:
3622 if (fp->f_type != DTYPE_VNODE) {
3623 error = EBADF;
3624 goto out;
3625 }
3626 if (uap->arg) {
3627 os_atomic_or(&fp->fp_glob->fg_flag, FNODIRECT, relaxed);
3628 } else {
3629 os_atomic_andnot(&fp->fp_glob->fg_flag, FNODIRECT, relaxed);
3630 }
3631 goto out;
3632
3633 case F_SINGLE_WRITER:
3634 if (fp->f_type != DTYPE_VNODE) {
3635 error = EBADF;
3636 goto out;
3637 }
3638 if (uap->arg) {
3639 os_atomic_or(&fp->fp_glob->fg_flag, FSINGLE_WRITER, relaxed);
3640 } else {
3641 os_atomic_andnot(&fp->fp_glob->fg_flag, FSINGLE_WRITER, relaxed);
3642 }
3643 goto out;
3644
3645 case F_GLOBAL_NOCACHE:
3646 if (fp->f_type != DTYPE_VNODE) {
3647 error = EBADF;
3648 goto out;
3649 }
3650 vp = (struct vnode *)fp_get_data(fp);
3651 proc_fdunlock(p);
3652
3653 if ((error = vnode_getwithref(vp)) == 0) {
3654 *retval = vnode_isnocache(vp);
3655
3656 if (uap->arg) {
3657 vnode_setnocache(vp);
3658 } else {
3659 vnode_clearnocache(vp);
3660 }
3661
3662 (void)vnode_put(vp);
3663 }
3664 goto outdrop;
3665
3666 case F_CHECK_OPENEVT:
3667 if (fp->f_type != DTYPE_VNODE) {
3668 error = EBADF;
3669 goto out;
3670 }
3671 vp = (struct vnode *)fp_get_data(fp);
3672 proc_fdunlock(p);
3673
3674 if ((error = vnode_getwithref(vp)) == 0) {
3675 *retval = vnode_is_openevt(vp);
3676
3677 if (uap->arg) {
3678 vnode_set_openevt(vp);
3679 } else {
3680 vnode_clear_openevt(vp);
3681 }
3682
3683 (void)vnode_put(vp);
3684 }
3685 goto outdrop;
3686
3687 case F_RDADVISE: {
3688 struct radvisory ra_struct;
3689
3690 if (fp->f_type != DTYPE_VNODE) {
3691 error = EBADF;
3692 goto out;
3693 }
3694 vp = (struct vnode *)fp_get_data(fp);
3695 proc_fdunlock(p);
3696
3697 if ((error = copyin(argp, (caddr_t)&ra_struct, sizeof(ra_struct)))) {
3698 goto outdrop;
3699 }
3700 if (ra_struct.ra_offset < 0 || ra_struct.ra_count < 0) {
3701 error = EINVAL;
3702 goto outdrop;
3703 }
3704 if ((error = vnode_getwithref(vp)) == 0) {
3705 error = VNOP_IOCTL(vp, F_RDADVISE, (caddr_t)&ra_struct, 0, &context);
3706
3707 (void)vnode_put(vp);
3708 }
3709 goto outdrop;
3710 }
3711
3712 case F_FLUSH_DATA:
3713
3714 if (fp->f_type != DTYPE_VNODE) {
3715 error = EBADF;
3716 goto out;
3717 }
3718 vp = (struct vnode *)fp_get_data(fp);
3719 proc_fdunlock(p);
3720
3721 if ((error = vnode_getwithref(vp)) == 0) {
3722 error = VNOP_FSYNC(vp, MNT_NOWAIT, &context);
3723
3724 (void)vnode_put(vp);
3725 }
3726 goto outdrop;
3727
3728 case F_LOG2PHYS:
3729 case F_LOG2PHYS_EXT: {
3730 struct log2phys l2p_struct = {}; /* structure for allocate command */
3731 int devBlockSize;
3732
3733 off_t file_offset = 0;
3734 size_t a_size = 0;
3735 size_t run = 0;
3736
3737 if (cmd == F_LOG2PHYS_EXT) {
3738 error = copyin(argp, (caddr_t)&l2p_struct, sizeof(l2p_struct));
3739 if (error) {
3740 goto out;
3741 }
3742 file_offset = l2p_struct.l2p_devoffset;
3743 } else {
3744 file_offset = fp->f_offset;
3745 }
3746 if (fp->f_type != DTYPE_VNODE) {
3747 error = EBADF;
3748 goto out;
3749 }
3750 vp = (struct vnode *)fp_get_data(fp);
3751 proc_fdunlock(p);
3752 if ((error = vnode_getwithref(vp))) {
3753 goto outdrop;
3754 }
3755 error = VNOP_OFFTOBLK(vp, file_offset, &lbn);
3756 if (error) {
3757 (void)vnode_put(vp);
3758 goto outdrop;
3759 }
3760 error = VNOP_BLKTOOFF(vp, lbn, &offset);
3761 if (error) {
3762 (void)vnode_put(vp);
3763 goto outdrop;
3764 }
3765 devBlockSize = vfs_devblocksize(vnode_mount(vp));
3766 if (cmd == F_LOG2PHYS_EXT) {
3767 if (l2p_struct.l2p_contigbytes < 0) {
3768 vnode_put(vp);
3769 error = EINVAL;
3770 goto outdrop;
3771 }
3772
3773 a_size = (size_t)MIN((uint64_t)l2p_struct.l2p_contigbytes, SIZE_MAX);
3774 } else {
3775 a_size = devBlockSize;
3776 }
3777
3778 error = VNOP_BLOCKMAP(vp, offset, a_size, &bn, &run, NULL, 0, &context);
3779
3780 (void)vnode_put(vp);
3781
3782 if (!error) {
3783 l2p_struct.l2p_flags = 0; /* for now */
3784 if (cmd == F_LOG2PHYS_EXT) {
3785 l2p_struct.l2p_contigbytes = run - (file_offset - offset);
3786 } else {
3787 l2p_struct.l2p_contigbytes = 0; /* for now */
3788 }
3789
3790 /*
3791 * The block number being -1 suggests that the file offset is not backed
3792 * by any real blocks on-disk. As a result, just let it be passed back up wholesale.
3793 */
3794 if (bn == -1) {
3795 /* Don't multiply it by the block size */
3796 l2p_struct.l2p_devoffset = bn;
3797 } else {
3798 l2p_struct.l2p_devoffset = bn * devBlockSize;
3799 l2p_struct.l2p_devoffset += file_offset - offset;
3800 }
3801 error = copyout((caddr_t)&l2p_struct, argp, sizeof(l2p_struct));
3802 }
3803 goto outdrop;
3804 }
3805 case F_GETPATH:
3806 case F_GETPATH_NOFIRMLINK: {
3807 char *pathbufp;
3808 size_t pathlen;
3809
3810 if (fp->f_type != DTYPE_VNODE) {
3811 error = EBADF;
3812 goto out;
3813 }
3814 vp = (struct vnode *)fp_get_data(fp);
3815 proc_fdunlock(p);
3816
3817 pathlen = MAXPATHLEN;
3818 pathbufp = zalloc(ZV_NAMEI);
3819
3820 if ((error = vnode_getwithref(vp)) == 0) {
3821 error = vn_getpath_ext(vp, NULL, pathbufp,
3822 &pathlen, cmd == F_GETPATH_NOFIRMLINK ?
3823 VN_GETPATH_NO_FIRMLINK : 0);
3824 (void)vnode_put(vp);
3825
3826 if (error == 0) {
3827 error = copyout((caddr_t)pathbufp, argp, pathlen);
3828 }
3829 }
3830 zfree(ZV_NAMEI, pathbufp);
3831 goto outdrop;
3832 }
3833
3834 case F_PATHPKG_CHECK: {
3835 char *pathbufp;
3836 size_t pathlen;
3837
3838 if (fp->f_type != DTYPE_VNODE) {
3839 error = EBADF;
3840 goto out;
3841 }
3842 vp = (struct vnode *)fp_get_data(fp);
3843 proc_fdunlock(p);
3844
3845 pathlen = MAXPATHLEN;
3846 pathbufp = zalloc(ZV_NAMEI);
3847
3848 if ((error = copyinstr(argp, pathbufp, MAXPATHLEN, &pathlen)) == 0) {
3849 if ((error = vnode_getwithref(vp)) == 0) {
3850 AUDIT_ARG(text, pathbufp);
3851 error = vn_path_package_check(vp, pathbufp, (int)pathlen, retval);
3852
3853 (void)vnode_put(vp);
3854 }
3855 }
3856 zfree(ZV_NAMEI, pathbufp);
3857 goto outdrop;
3858 }
3859
3860 case F_CHKCLEAN: // used by regression tests to see if all dirty pages got cleaned by fsync()
3861 case F_FULLFSYNC: // fsync + flush the journal + DKIOCSYNCHRONIZE
3862 case F_BARRIERFSYNC: // fsync + barrier
3863 case F_FREEZE_FS: // freeze all other fs operations for the fs of this fd
3864 case F_THAW_FS: { // thaw all frozen fs operations for the fs of this fd
3865 if (fp->f_type != DTYPE_VNODE) {
3866 error = EBADF;
3867 goto out;
3868 }
3869 vp = (struct vnode *)fp_get_data(fp);
3870 proc_fdunlock(p);
3871
3872 if ((error = vnode_getwithref(vp)) == 0) {
3873 if ((cmd == F_BARRIERFSYNC) &&
3874 (vp->v_mount->mnt_supl_kern_flag & MNTK_SUPL_USE_FULLSYNC)) {
3875 cmd = F_FULLFSYNC;
3876 }
3877 error = VNOP_IOCTL(vp, cmd, (caddr_t)NULL, 0, &context);
3878
3879 /*
3880 * Promote F_BARRIERFSYNC to F_FULLFSYNC if the underlying
3881 * filesystem doesn't support it.
3882 */
3883 if ((error == ENOTTY || error == ENOTSUP || error == EINVAL) &&
3884 (cmd == F_BARRIERFSYNC)) {
3885 os_atomic_or(&vp->v_mount->mnt_supl_kern_flag,
3886 MNTK_SUPL_USE_FULLSYNC, relaxed);
3887
3888 error = VNOP_IOCTL(vp, F_FULLFSYNC, (caddr_t)NULL, 0, &context);
3889 }
3890
3891 (void)vnode_put(vp);
3892 }
3893 break;
3894 }
3895
3896 /*
3897 * SPI (private) for opening a file starting from a dir fd
3898 */
3899 case F_OPENFROM: {
3900 /* Check if this isn't a valid file descriptor */
3901 if (fp->f_type != DTYPE_VNODE) {
3902 error = EBADF;
3903 goto out;
3904 }
3905 vp = (struct vnode *)fp_get_data(fp);
3906
3907 return sys_fcntl__OPENFROM(p, fd, cmd, uap->arg, fp, vp, retval);
3908 }
3909
3910 /*
3911 * SPI (private) for unlinking a file starting from a dir fd
3912 */
3913 case F_UNLINKFROM: {
3914 user_addr_t pathname;
3915
3916 /* Check if this isn't a valid file descriptor */
3917 if ((fp->f_type != DTYPE_VNODE) ||
3918 (fp->f_flag & FREAD) == 0) {
3919 error = EBADF;
3920 goto out;
3921 }
3922 vp = (struct vnode *)fp_get_data(fp);
3923 proc_fdunlock(p);
3924
3925 if (vnode_getwithref(vp)) {
3926 error = ENOENT;
3927 goto outdrop;
3928 }
3929
3930 /* Only valid for directories */
3931 if (vp->v_type != VDIR) {
3932 vnode_put(vp);
3933 error = ENOTDIR;
3934 goto outdrop;
3935 }
3936
3937 /*
3938 * Only entitled apps may use the credentials of the thread
3939 * that opened the file descriptor.
3940 * Non-entitled threads will use their own context.
3941 */
3942 if (IOCurrentTaskHasEntitlement(ACCOUNT_OPENFROM_ENTITLEMENT)) {
3943 has_entitlement = 1;
3944 }
3945
3946 /* Get flags, mode and pathname arguments. */
3947 if (IS_64BIT_PROCESS(p)) {
3948 pathname = (user_addr_t)argp;
3949 } else {
3950 pathname = CAST_USER_ADDR_T(argp);
3951 }
3952
3953 /* Start the lookup relative to the file descriptor's vnode. */
3954 error = unlink1(has_entitlement ? &context : vfs_context_current(),
3955 vp, pathname, UIO_USERSPACE, 0);
3956
3957 vnode_put(vp);
3958 break;
3959 }
3960
3961 #if DEVELOPMENT || DEBUG
3962 case F_ADDSIGS_MAIN_BINARY:
3963 csblob_add_flags |= CS_BLOB_ADD_ALLOW_MAIN_BINARY;
3964 OS_FALLTHROUGH;
3965 #endif
3966 case F_ADDSIGS:
3967 case F_ADDFILESIGS:
3968 case F_ADDFILESIGS_FOR_DYLD_SIM:
3969 case F_ADDFILESIGS_RETURN:
3970 case F_ADDFILESIGS_INFO:
3971 {
3972 struct cs_blob *blob = NULL;
3973 struct user_fsignatures fs;
3974 kern_return_t kr;
3975 vm_offset_t kernel_blob_addr;
3976 vm_size_t kernel_blob_size;
3977 int blob_add_flags = 0;
3978 const size_t sizeof_fs = (cmd == F_ADDFILESIGS_INFO ?
3979 offsetof(struct user_fsignatures, fs_cdhash /* first output element */) :
3980 offsetof(struct user_fsignatures, fs_fsignatures_size /* compat */));
3981
3982 if (fp->f_type != DTYPE_VNODE) {
3983 error = EBADF;
3984 goto out;
3985 }
3986 vp = (struct vnode *)fp_get_data(fp);
3987 proc_fdunlock(p);
3988
3989 if (cmd == F_ADDFILESIGS_FOR_DYLD_SIM) {
3990 blob_add_flags |= MAC_VNODE_CHECK_DYLD_SIM;
3991 if ((proc_getcsflags(p) & CS_KILL) == 0) {
3992 proc_lock(p);
3993 proc_csflags_set(p, CS_KILL);
3994 proc_unlock(p);
3995 }
3996 }
3997
3998 error = vnode_getwithref(vp);
3999 if (error) {
4000 goto outdrop;
4001 }
4002
4003 if (IS_64BIT_PROCESS(p)) {
4004 error = copyin(argp, &fs, sizeof_fs);
4005 } else {
4006 if (cmd == F_ADDFILESIGS_INFO) {
4007 error = EINVAL;
4008 vnode_put(vp);
4009 goto outdrop;
4010 }
4011
4012 struct user32_fsignatures fs32;
4013
4014 error = copyin(argp, &fs32, sizeof(fs32));
4015 fs.fs_file_start = fs32.fs_file_start;
4016 fs.fs_blob_start = CAST_USER_ADDR_T(fs32.fs_blob_start);
4017 fs.fs_blob_size = fs32.fs_blob_size;
4018 }
4019
4020 if (error) {
4021 vnode_put(vp);
4022 goto outdrop;
4023 }
4024
4025 /*
4026 * First check if we have something loaded a this offset
4027 */
4028 blob = ubc_cs_blob_get(vp, CPU_TYPE_ANY, CPU_SUBTYPE_ANY, fs.fs_file_start);
4029 if (blob != NULL) {
4030 /* If this is for dyld_sim revalidate the blob */
4031 if (cmd == F_ADDFILESIGS_FOR_DYLD_SIM) {
4032 error = ubc_cs_blob_revalidate(vp, blob, NULL, blob_add_flags, proc_platform(p));
4033 if (error) {
4034 blob = NULL;
4035 if (error != EAGAIN) {
4036 vnode_put(vp);
4037 goto outdrop;
4038 }
4039 }
4040 }
4041 }
4042
4043 if (blob == NULL) {
4044 /*
4045 * An arbitrary limit, to prevent someone from mapping in a 20GB blob. This should cover
4046 * our use cases for the immediate future, but note that at the time of this commit, some
4047 * platforms are nearing 2MB blob sizes (with a prior soft limit of 2.5MB).
4048 *
4049 * We should consider how we can manage this more effectively; the above means that some
4050 * platforms are using megabytes of memory for signing data; it merely hasn't crossed the
4051 * threshold considered ridiculous at the time of this change.
4052 */
4053 #define CS_MAX_BLOB_SIZE (40ULL * 1024ULL * 1024ULL)
4054 if (fs.fs_blob_size > CS_MAX_BLOB_SIZE) {
4055 error = E2BIG;
4056 vnode_put(vp);
4057 goto outdrop;
4058 }
4059
4060 kernel_blob_size = CAST_DOWN(vm_size_t, fs.fs_blob_size);
4061 kr = ubc_cs_blob_allocate(&kernel_blob_addr, &kernel_blob_size);
4062 if (kr != KERN_SUCCESS || kernel_blob_size < fs.fs_blob_size) {
4063 error = ENOMEM;
4064 vnode_put(vp);
4065 goto outdrop;
4066 }
4067
4068 if (cmd == F_ADDSIGS || cmd == F_ADDSIGS_MAIN_BINARY) {
4069 error = copyin(fs.fs_blob_start,
4070 (void *) kernel_blob_addr,
4071 fs.fs_blob_size);
4072 } else { /* F_ADDFILESIGS || F_ADDFILESIGS_RETURN || F_ADDFILESIGS_FOR_DYLD_SIM || F_ADDFILESIGS_INFO */
4073 int resid;
4074
4075 error = vn_rdwr(UIO_READ,
4076 vp,
4077 (caddr_t) kernel_blob_addr,
4078 (int)kernel_blob_size,
4079 fs.fs_file_start + fs.fs_blob_start,
4080 UIO_SYSSPACE,
4081 0,
4082 kauth_cred_get(),
4083 &resid,
4084 p);
4085 if ((error == 0) && resid) {
4086 /* kernel_blob_size rounded to a page size, but signature may be at end of file */
4087 memset((void *)(kernel_blob_addr + (kernel_blob_size - resid)), 0x0, resid);
4088 }
4089 }
4090
4091 if (error) {
4092 ubc_cs_blob_deallocate(kernel_blob_addr,
4093 kernel_blob_size);
4094 vnode_put(vp);
4095 goto outdrop;
4096 }
4097
4098 blob = NULL;
4099 error = ubc_cs_blob_add(vp,
4100 proc_platform(p),
4101 CPU_TYPE_ANY, /* not for a specific architecture */
4102 CPU_SUBTYPE_ANY,
4103 fs.fs_file_start,
4104 &kernel_blob_addr,
4105 kernel_blob_size,
4106 NULL,
4107 blob_add_flags,
4108 &blob,
4109 csblob_add_flags);
4110
4111 /* ubc_blob_add() has consumed "kernel_blob_addr" if it is zeroed */
4112 if (error) {
4113 if (kernel_blob_addr) {
4114 ubc_cs_blob_deallocate(kernel_blob_addr,
4115 kernel_blob_size);
4116 }
4117 vnode_put(vp);
4118 goto outdrop;
4119 } else {
4120 #if CHECK_CS_VALIDATION_BITMAP
4121 ubc_cs_validation_bitmap_allocate( vp );
4122 #endif
4123 }
4124 }
4125
4126 if (cmd == F_ADDFILESIGS_RETURN || cmd == F_ADDFILESIGS_FOR_DYLD_SIM ||
4127 cmd == F_ADDFILESIGS_INFO) {
4128 /*
4129 * The first element of the structure is a
4130 * off_t that happen to have the same size for
4131 * all archs. Lets overwrite that.
4132 */
4133 off_t end_offset = 0;
4134 if (blob) {
4135 end_offset = blob->csb_end_offset;
4136 }
4137 error = copyout(&end_offset, argp, sizeof(end_offset));
4138
4139 if (error) {
4140 vnode_put(vp);
4141 goto outdrop;
4142 }
4143 }
4144
4145 if (cmd == F_ADDFILESIGS_INFO) {
4146 /* Return information. What we copy out depends on the size of the
4147 * passed in structure, to keep binary compatibility. */
4148
4149 if (fs.fs_fsignatures_size >= sizeof(struct user_fsignatures)) {
4150 // enough room for fs_cdhash[20]+fs_hash_type
4151
4152 if (blob != NULL) {
4153 error = copyout(blob->csb_cdhash,
4154 (vm_address_t)argp + offsetof(struct user_fsignatures, fs_cdhash),
4155 USER_FSIGNATURES_CDHASH_LEN);
4156 if (error) {
4157 vnode_put(vp);
4158 goto outdrop;
4159 }
4160 int hashtype = cs_hash_type(blob->csb_hashtype);
4161 error = copyout(&hashtype,
4162 (vm_address_t)argp + offsetof(struct user_fsignatures, fs_hash_type),
4163 sizeof(int));
4164 if (error) {
4165 vnode_put(vp);
4166 goto outdrop;
4167 }
4168 }
4169 }
4170 }
4171
4172 (void) vnode_put(vp);
4173 break;
4174 }
4175 #if CONFIG_SUPPLEMENTAL_SIGNATURES
4176 case F_ADDFILESUPPL:
4177 {
4178 struct vnode *ivp;
4179 struct cs_blob *blob = NULL;
4180 struct user_fsupplement fs;
4181 int orig_fd;
4182 struct fileproc* orig_fp = NULL;
4183 kern_return_t kr;
4184 vm_offset_t kernel_blob_addr;
4185 vm_size_t kernel_blob_size;
4186
4187 if (!IS_64BIT_PROCESS(p)) {
4188 error = EINVAL;
4189 goto out; // drop fp and unlock fds
4190 }
4191
4192 if (fp->f_type != DTYPE_VNODE) {
4193 error = EBADF;
4194 goto out;
4195 }
4196
4197 error = copyin(argp, &fs, sizeof(fs));
4198 if (error) {
4199 goto out;
4200 }
4201
4202 orig_fd = fs.fs_orig_fd;
4203 if ((error = fp_lookup(p, orig_fd, &orig_fp, 1))) {
4204 printf("CODE SIGNING: Failed to find original file for supplemental signature attachment\n");
4205 goto out;
4206 }
4207
4208 if (orig_fp->f_type != DTYPE_VNODE) {
4209 error = EBADF;
4210 fp_drop(p, orig_fd, orig_fp, 1);
4211 goto out;
4212 }
4213
4214 ivp = (struct vnode *)fp_get_data(orig_fp);
4215
4216 vp = (struct vnode *)fp_get_data(fp);
4217
4218 proc_fdunlock(p);
4219
4220 error = vnode_getwithref(ivp);
4221 if (error) {
4222 fp_drop(p, orig_fd, orig_fp, 0);
4223 goto outdrop; //drop fp
4224 }
4225
4226 error = vnode_getwithref(vp);
4227 if (error) {
4228 vnode_put(ivp);
4229 fp_drop(p, orig_fd, orig_fp, 0);
4230 goto outdrop;
4231 }
4232
4233 if (fs.fs_blob_size > CS_MAX_BLOB_SIZE) {
4234 error = E2BIG;
4235 goto dropboth; // drop iocounts on vp and ivp, drop orig_fp then drop fp via outdrop
4236 }
4237
4238 kernel_blob_size = CAST_DOWN(vm_size_t, fs.fs_blob_size);
4239 kr = ubc_cs_blob_allocate(&kernel_blob_addr, &kernel_blob_size);
4240 if (kr != KERN_SUCCESS) {
4241 error = ENOMEM;
4242 goto dropboth;
4243 }
4244
4245 int resid;
4246 error = vn_rdwr(UIO_READ, vp,
4247 (caddr_t)kernel_blob_addr, (int)kernel_blob_size,
4248 fs.fs_file_start + fs.fs_blob_start,
4249 UIO_SYSSPACE, 0,
4250 kauth_cred_get(), &resid, p);
4251 if ((error == 0) && resid) {
4252 /* kernel_blob_size rounded to a page size, but signature may be at end of file */
4253 memset((void *)(kernel_blob_addr + (kernel_blob_size - resid)), 0x0, resid);
4254 }
4255
4256 if (error) {
4257 ubc_cs_blob_deallocate(kernel_blob_addr,
4258 kernel_blob_size);
4259 goto dropboth;
4260 }
4261
4262 error = ubc_cs_blob_add_supplement(vp, ivp, fs.fs_file_start,
4263 &kernel_blob_addr, kernel_blob_size, &blob);
4264
4265 /* ubc_blob_add_supplement() has consumed kernel_blob_addr if it is zeroed */
4266 if (error) {
4267 if (kernel_blob_addr) {
4268 ubc_cs_blob_deallocate(kernel_blob_addr,
4269 kernel_blob_size);
4270 }
4271 goto dropboth;
4272 }
4273 vnode_put(ivp);
4274 vnode_put(vp);
4275 fp_drop(p, orig_fd, orig_fp, 0);
4276 break;
4277
4278 dropboth:
4279 vnode_put(ivp);
4280 vnode_put(vp);
4281 fp_drop(p, orig_fd, orig_fp, 0);
4282 goto outdrop;
4283 }
4284 #endif
4285 case F_GETCODEDIR:
4286 case F_FINDSIGS: {
4287 error = ENOTSUP;
4288 goto out;
4289 }
4290 case F_CHECK_LV: {
4291 struct fileglob *fg;
4292 fchecklv_t lv = {};
4293
4294 if (fp->f_type != DTYPE_VNODE) {
4295 error = EBADF;
4296 goto out;
4297 }
4298 fg = fp->fp_glob;
4299 proc_fdunlock(p);
4300
4301 if (IS_64BIT_PROCESS(p)) {
4302 error = copyin(argp, &lv, sizeof(lv));
4303 } else {
4304 struct user32_fchecklv lv32 = {};
4305
4306 error = copyin(argp, &lv32, sizeof(lv32));
4307 lv.lv_file_start = lv32.lv_file_start;
4308 lv.lv_error_message = (void *)(uintptr_t)lv32.lv_error_message;
4309 lv.lv_error_message_size = lv32.lv_error_message_size;
4310 }
4311 if (error) {
4312 goto outdrop;
4313 }
4314
4315 #if CONFIG_MACF
4316 error = mac_file_check_library_validation(p, fg, lv.lv_file_start,
4317 (user_long_t)lv.lv_error_message, lv.lv_error_message_size);
4318 #endif
4319
4320 break;
4321 }
4322 case F_GETSIGSINFO: {
4323 struct cs_blob *blob = NULL;
4324 fgetsigsinfo_t sigsinfo = {};
4325
4326 if (fp->f_type != DTYPE_VNODE) {
4327 error = EBADF;
4328 goto out;
4329 }
4330 vp = (struct vnode *)fp_get_data(fp);
4331 proc_fdunlock(p);
4332
4333 error = vnode_getwithref(vp);
4334 if (error) {
4335 goto outdrop;
4336 }
4337
4338 error = copyin(argp, &sigsinfo, sizeof(sigsinfo));
4339 if (error) {
4340 vnode_put(vp);
4341 goto outdrop;
4342 }
4343
4344 blob = ubc_cs_blob_get(vp, CPU_TYPE_ANY, CPU_SUBTYPE_ANY, sigsinfo.fg_file_start);
4345 if (blob == NULL) {
4346 error = ENOENT;
4347 vnode_put(vp);
4348 goto outdrop;
4349 }
4350 switch (sigsinfo.fg_info_request) {
4351 case GETSIGSINFO_PLATFORM_BINARY:
4352 sigsinfo.fg_sig_is_platform = blob->csb_platform_binary;
4353 error = copyout(&sigsinfo.fg_sig_is_platform,
4354 (vm_address_t)argp + offsetof(struct fgetsigsinfo, fg_sig_is_platform),
4355 sizeof(sigsinfo.fg_sig_is_platform));
4356 if (error) {
4357 vnode_put(vp);
4358 goto outdrop;
4359 }
4360 break;
4361 default:
4362 error = EINVAL;
4363 vnode_put(vp);
4364 goto outdrop;
4365 }
4366 vnode_put(vp);
4367 break;
4368 }
4369 #if CONFIG_PROTECT
4370 case F_GETPROTECTIONCLASS: {
4371 if (fp->f_type != DTYPE_VNODE) {
4372 error = EBADF;
4373 goto out;
4374 }
4375 vp = (struct vnode *)fp_get_data(fp);
4376
4377 proc_fdunlock(p);
4378
4379 if (vnode_getwithref(vp)) {
4380 error = ENOENT;
4381 goto outdrop;
4382 }
4383
4384 struct vnode_attr va;
4385
4386 VATTR_INIT(&va);
4387 VATTR_WANTED(&va, va_dataprotect_class);
4388 error = VNOP_GETATTR(vp, &va, &context);
4389 if (!error) {
4390 if (VATTR_IS_SUPPORTED(&va, va_dataprotect_class)) {
4391 *retval = va.va_dataprotect_class;
4392 } else {
4393 error = ENOTSUP;
4394 }
4395 }
4396
4397 vnode_put(vp);
4398 break;
4399 }
4400
4401 case F_SETPROTECTIONCLASS: {
4402 /* tmp must be a valid PROTECTION_CLASS_* */
4403 tmp = CAST_DOWN_EXPLICIT(uint32_t, uap->arg);
4404
4405 if (fp->f_type != DTYPE_VNODE) {
4406 error = EBADF;
4407 goto out;
4408 }
4409 vp = (struct vnode *)fp_get_data(fp);
4410
4411 proc_fdunlock(p);
4412
4413 if (vnode_getwithref(vp)) {
4414 error = ENOENT;
4415 goto outdrop;
4416 }
4417
4418 /* Only go forward if you have write access */
4419 vfs_context_t ctx = vfs_context_current();
4420 if (vnode_authorize(vp, NULLVP, (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), ctx) != 0) {
4421 vnode_put(vp);
4422 error = EBADF;
4423 goto outdrop;
4424 }
4425
4426 struct vnode_attr va;
4427
4428 #if CONFIG_MACF
4429 // tmp has already explicitly downcast to uint32_t above.
4430 uint32_t dataprotect_class = (uint32_t)tmp;
4431 if ((error = mac_vnode_check_dataprotect_set(ctx, vp, &dataprotect_class))) {
4432 vnode_put(vp);
4433 goto outdrop;
4434 }
4435 tmp = (int)dataprotect_class;
4436 #endif
4437
4438 VATTR_INIT(&va);
4439 VATTR_SET(&va, va_dataprotect_class, tmp);
4440
4441 error = VNOP_SETATTR(vp, &va, ctx);
4442
4443 vnode_put(vp);
4444 break;
4445 }
4446
4447 case F_TRANSCODEKEY: {
4448 if (fp->f_type != DTYPE_VNODE) {
4449 error = EBADF;
4450 goto out;
4451 }
4452
4453 vp = (struct vnode *)fp_get_data(fp);
4454 proc_fdunlock(p);
4455
4456 if (vnode_getwithref(vp)) {
4457 error = ENOENT;
4458 goto outdrop;
4459 }
4460
4461 cp_key_t k = {
4462 .len = CP_MAX_WRAPPEDKEYSIZE,
4463 };
4464
4465 k.key = kalloc_data(CP_MAX_WRAPPEDKEYSIZE, Z_WAITOK | Z_ZERO);
4466 if (k.key == NULL) {
4467 error = ENOMEM;
4468 } else {
4469 error = VNOP_IOCTL(vp, F_TRANSCODEKEY, (caddr_t)&k, 1, &context);
4470 }
4471
4472 vnode_put(vp);
4473
4474 if (error == 0) {
4475 error = copyout(k.key, argp, k.len);
4476 *retval = k.len;
4477 }
4478 kfree_data(k.key, CP_MAX_WRAPPEDKEYSIZE);
4479
4480 break;
4481 }
4482
4483 case F_GETPROTECTIONLEVEL: {
4484 if (fp->f_type != DTYPE_VNODE) {
4485 error = EBADF;
4486 goto out;
4487 }
4488
4489 vp = (struct vnode*)fp_get_data(fp);
4490 proc_fdunlock(p);
4491
4492 if (vnode_getwithref(vp)) {
4493 error = ENOENT;
4494 goto outdrop;
4495 }
4496
4497 error = VNOP_IOCTL(vp, F_GETPROTECTIONLEVEL, (caddr_t)retval, 0, &context);
4498
4499 vnode_put(vp);
4500 break;
4501 }
4502
4503 case F_GETDEFAULTPROTLEVEL: {
4504 if (fp->f_type != DTYPE_VNODE) {
4505 error = EBADF;
4506 goto out;
4507 }
4508
4509 vp = (struct vnode*)fp_get_data(fp);
4510 proc_fdunlock(p);
4511
4512 if (vnode_getwithref(vp)) {
4513 error = ENOENT;
4514 goto outdrop;
4515 }
4516
4517 /*
4518 * if cp_get_major_vers fails, error will be set to proper errno
4519 * and cp_version will still be 0.
4520 */
4521
4522 error = VNOP_IOCTL(vp, F_GETDEFAULTPROTLEVEL, (caddr_t)retval, 0, &context);
4523
4524 vnode_put(vp);
4525 break;
4526 }
4527
4528 #endif /* CONFIG_PROTECT */
4529
4530 case F_MOVEDATAEXTENTS: {
4531 struct fileproc *fp2 = NULL;
4532 struct vnode *src_vp = NULLVP;
4533 struct vnode *dst_vp = NULLVP;
4534 /* We need to grab the 2nd FD out of the arguments before moving on. */
4535 int fd2 = CAST_DOWN_EXPLICIT(int32_t, uap->arg);
4536
4537 error = priv_check_cred(kauth_cred_get(), PRIV_VFS_MOVE_DATA_EXTENTS, 0);
4538 if (error) {
4539 goto out;
4540 }
4541
4542 if (fp->f_type != DTYPE_VNODE) {
4543 error = EBADF;
4544 goto out;
4545 }
4546
4547 /*
4548 * For now, special case HFS+ and APFS only, since this
4549 * is SPI.
4550 */
4551 src_vp = (struct vnode *)fp_get_data(fp);
4552 if (src_vp->v_tag != VT_HFS && src_vp->v_tag != VT_APFS) {
4553 error = ENOTSUP;
4554 goto out;
4555 }
4556
4557 /*
4558 * Get the references before we start acquiring iocounts on the vnodes,
4559 * while we still hold the proc fd lock
4560 */
4561 if ((error = fp_lookup(p, fd2, &fp2, 1))) {
4562 error = EBADF;
4563 goto out;
4564 }
4565 if (fp2->f_type != DTYPE_VNODE) {
4566 fp_drop(p, fd2, fp2, 1);
4567 error = EBADF;
4568 goto out;
4569 }
4570 dst_vp = (struct vnode *)fp_get_data(fp2);
4571 if (dst_vp->v_tag != VT_HFS && dst_vp->v_tag != VT_APFS) {
4572 fp_drop(p, fd2, fp2, 1);
4573 error = ENOTSUP;
4574 goto out;
4575 }
4576
4577 #if CONFIG_MACF
4578 /* Re-do MAC checks against the new FD, pass in a fake argument */
4579 error = mac_file_check_fcntl(kauth_cred_get(), fp2->fp_glob, cmd, 0);
4580 if (error) {
4581 fp_drop(p, fd2, fp2, 1);
4582 goto out;
4583 }
4584 #endif
4585 /* Audit the 2nd FD */
4586 AUDIT_ARG(fd, fd2);
4587
4588 proc_fdunlock(p);
4589
4590 if (vnode_getwithref(src_vp)) {
4591 fp_drop(p, fd2, fp2, 0);
4592 error = ENOENT;
4593 goto outdrop;
4594 }
4595 if (vnode_getwithref(dst_vp)) {
4596 vnode_put(src_vp);
4597 fp_drop(p, fd2, fp2, 0);
4598 error = ENOENT;
4599 goto outdrop;
4600 }
4601
4602 /*
4603 * Basic asserts; validate they are not the same and that
4604 * both live on the same filesystem.
4605 */
4606 if (dst_vp == src_vp) {
4607 vnode_put(src_vp);
4608 vnode_put(dst_vp);
4609 fp_drop(p, fd2, fp2, 0);
4610 error = EINVAL;
4611 goto outdrop;
4612 }
4613
4614 if (dst_vp->v_mount != src_vp->v_mount) {
4615 vnode_put(src_vp);
4616 vnode_put(dst_vp);
4617 fp_drop(p, fd2, fp2, 0);
4618 error = EXDEV;
4619 goto outdrop;
4620 }
4621
4622 /* Now we have a legit pair of FDs. Go to work */
4623
4624 /* Now check for write access to the target files */
4625 if (vnode_authorize(src_vp, NULLVP,
4626 (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), &context) != 0) {
4627 vnode_put(src_vp);
4628 vnode_put(dst_vp);
4629 fp_drop(p, fd2, fp2, 0);
4630 error = EBADF;
4631 goto outdrop;
4632 }
4633
4634 if (vnode_authorize(dst_vp, NULLVP,
4635 (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), &context) != 0) {
4636 vnode_put(src_vp);
4637 vnode_put(dst_vp);
4638 fp_drop(p, fd2, fp2, 0);
4639 error = EBADF;
4640 goto outdrop;
4641 }
4642
4643 /* Verify that both vps point to files and not directories */
4644 if (!vnode_isreg(src_vp) || !vnode_isreg(dst_vp)) {
4645 error = EINVAL;
4646 vnode_put(src_vp);
4647 vnode_put(dst_vp);
4648 fp_drop(p, fd2, fp2, 0);
4649 goto outdrop;
4650 }
4651
4652 /*
4653 * The exchangedata syscall handler passes in 0 for the flags to VNOP_EXCHANGE.
4654 * We'll pass in our special bit indicating that the new behavior is expected
4655 */
4656
4657 error = VNOP_EXCHANGE(src_vp, dst_vp, FSOPT_EXCHANGE_DATA_ONLY, &context);
4658
4659 vnode_put(src_vp);
4660 vnode_put(dst_vp);
4661 fp_drop(p, fd2, fp2, 0);
4662 break;
4663 }
4664
4665 case F_TRANSFEREXTENTS: {
4666 struct fileproc *fp2 = NULL;
4667 struct vnode *src_vp = NULLVP;
4668 struct vnode *dst_vp = NULLVP;
4669
4670 /* Get 2nd FD out of the arguments. */
4671 int fd2 = CAST_DOWN_EXPLICIT(int, uap->arg);
4672 if (fd2 < 0) {
4673 error = EINVAL;
4674 goto out;
4675 }
4676
4677 if (fp->f_type != DTYPE_VNODE) {
4678 error = EBADF;
4679 goto out;
4680 }
4681
4682 /*
4683 * Only allow this for APFS
4684 */
4685 src_vp = (struct vnode *)fp_get_data(fp);
4686 if (src_vp->v_tag != VT_APFS) {
4687 error = ENOTSUP;
4688 goto out;
4689 }
4690
4691 /*
4692 * Get the references before we start acquiring iocounts on the vnodes,
4693 * while we still hold the proc fd lock
4694 */
4695 if ((error = fp_lookup(p, fd2, &fp2, 1))) {
4696 error = EBADF;
4697 goto out;
4698 }
4699 if (fp2->f_type != DTYPE_VNODE) {
4700 fp_drop(p, fd2, fp2, 1);
4701 error = EBADF;
4702 goto out;
4703 }
4704 dst_vp = (struct vnode *)fp_get_data(fp2);
4705 if (dst_vp->v_tag != VT_APFS) {
4706 fp_drop(p, fd2, fp2, 1);
4707 error = ENOTSUP;
4708 goto out;
4709 }
4710
4711 #if CONFIG_MACF
4712 /* Re-do MAC checks against the new FD, pass in a fake argument */
4713 error = mac_file_check_fcntl(kauth_cred_get(), fp2->fp_glob, cmd, 0);
4714 if (error) {
4715 fp_drop(p, fd2, fp2, 1);
4716 goto out;
4717 }
4718 #endif
4719 /* Audit the 2nd FD */
4720 AUDIT_ARG(fd, fd2);
4721
4722 proc_fdunlock(p);
4723
4724 if (vnode_getwithref(src_vp)) {
4725 fp_drop(p, fd2, fp2, 0);
4726 error = ENOENT;
4727 goto outdrop;
4728 }
4729 if (vnode_getwithref(dst_vp)) {
4730 vnode_put(src_vp);
4731 fp_drop(p, fd2, fp2, 0);
4732 error = ENOENT;
4733 goto outdrop;
4734 }
4735
4736 /*
4737 * Validate they are not the same and that
4738 * both live on the same filesystem.
4739 */
4740 if (dst_vp == src_vp) {
4741 vnode_put(src_vp);
4742 vnode_put(dst_vp);
4743 fp_drop(p, fd2, fp2, 0);
4744 error = EINVAL;
4745 goto outdrop;
4746 }
4747 if (dst_vp->v_mount != src_vp->v_mount) {
4748 vnode_put(src_vp);
4749 vnode_put(dst_vp);
4750 fp_drop(p, fd2, fp2, 0);
4751 error = EXDEV;
4752 goto outdrop;
4753 }
4754
4755 /* Verify that both vps point to files and not directories */
4756 if (!vnode_isreg(src_vp) || !vnode_isreg(dst_vp)) {
4757 error = EINVAL;
4758 vnode_put(src_vp);
4759 vnode_put(dst_vp);
4760 fp_drop(p, fd2, fp2, 0);
4761 goto outdrop;
4762 }
4763
4764
4765 /*
4766 * Okay, vps are legit. Check access. We'll require write access
4767 * to both files.
4768 */
4769 if (vnode_authorize(src_vp, NULLVP,
4770 (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), &context) != 0) {
4771 vnode_put(src_vp);
4772 vnode_put(dst_vp);
4773 fp_drop(p, fd2, fp2, 0);
4774 error = EBADF;
4775 goto outdrop;
4776 }
4777 if (vnode_authorize(dst_vp, NULLVP,
4778 (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), &context) != 0) {
4779 vnode_put(src_vp);
4780 vnode_put(dst_vp);
4781 fp_drop(p, fd2, fp2, 0);
4782 error = EBADF;
4783 goto outdrop;
4784 }
4785
4786 /* Pass it on through to the fs */
4787 error = VNOP_IOCTL(src_vp, cmd, (caddr_t)dst_vp, 0, &context);
4788
4789 vnode_put(src_vp);
4790 vnode_put(dst_vp);
4791 fp_drop(p, fd2, fp2, 0);
4792 break;
4793 }
4794
4795 /*
4796 * SPI for making a file compressed.
4797 */
4798 case F_MAKECOMPRESSED: {
4799 uint32_t gcounter = CAST_DOWN_EXPLICIT(uint32_t, uap->arg);
4800
4801 if (fp->f_type != DTYPE_VNODE) {
4802 error = EBADF;
4803 goto out;
4804 }
4805
4806 vp = (struct vnode*)fp_get_data(fp);
4807 proc_fdunlock(p);
4808
4809 /* get the vnode */
4810 if (vnode_getwithref(vp)) {
4811 error = ENOENT;
4812 goto outdrop;
4813 }
4814
4815 /* Is it a file? */
4816 if ((vnode_isreg(vp) == 0) && (vnode_islnk(vp) == 0)) {
4817 vnode_put(vp);
4818 error = EBADF;
4819 goto outdrop;
4820 }
4821
4822 /* invoke ioctl to pass off to FS */
4823 /* Only go forward if you have write access */
4824 vfs_context_t ctx = vfs_context_current();
4825 if (vnode_authorize(vp, NULLVP, (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), ctx) != 0) {
4826 vnode_put(vp);
4827 error = EBADF;
4828 goto outdrop;
4829 }
4830
4831 error = VNOP_IOCTL(vp, cmd, (caddr_t)&gcounter, 0, &context);
4832
4833 vnode_put(vp);
4834 break;
4835 }
4836
4837 /*
4838 * SPI (private) for indicating to a filesystem that subsequent writes to
4839 * the open FD will written to the Fastflow.
4840 */
4841 case F_SET_GREEDY_MODE:
4842 /* intentionally drop through to the same handler as F_SETSTATIC.
4843 * both fcntls should pass the argument and their selector into VNOP_IOCTL.
4844 */
4845
4846 /*
4847 * SPI (private) for indicating to a filesystem that subsequent writes to
4848 * the open FD will represent static content.
4849 */
4850 case F_SETSTATICCONTENT: {
4851 caddr_t ioctl_arg = NULL;
4852
4853 if (uap->arg) {
4854 ioctl_arg = (caddr_t) 1;
4855 }
4856
4857 if (fp->f_type != DTYPE_VNODE) {
4858 error = EBADF;
4859 goto out;
4860 }
4861 vp = (struct vnode *)fp_get_data(fp);
4862 proc_fdunlock(p);
4863
4864 error = vnode_getwithref(vp);
4865 if (error) {
4866 error = ENOENT;
4867 goto outdrop;
4868 }
4869
4870 /* Only go forward if you have write access */
4871 vfs_context_t ctx = vfs_context_current();
4872 if (vnode_authorize(vp, NULLVP, (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), ctx) != 0) {
4873 vnode_put(vp);
4874 error = EBADF;
4875 goto outdrop;
4876 }
4877
4878 error = VNOP_IOCTL(vp, cmd, ioctl_arg, 0, &context);
4879 (void)vnode_put(vp);
4880
4881 break;
4882 }
4883
4884 /*
4885 * SPI (private) for indicating to the lower level storage driver that the
4886 * subsequent writes should be of a particular IO type (burst, greedy, static),
4887 * or other flavors that may be necessary.
4888 */
4889 case F_SETIOTYPE: {
4890 caddr_t param_ptr;
4891 uint32_t param;
4892
4893 if (uap->arg) {
4894 /* extract 32 bits of flags from userland */
4895 param_ptr = (caddr_t) uap->arg;
4896 param = (uint32_t) param_ptr;
4897 } else {
4898 /* If no argument is specified, error out */
4899 error = EINVAL;
4900 goto out;
4901 }
4902
4903 /*
4904 * Validate the different types of flags that can be specified:
4905 * all of them are mutually exclusive for now.
4906 */
4907 switch (param) {
4908 case F_IOTYPE_ISOCHRONOUS:
4909 break;
4910
4911 default:
4912 error = EINVAL;
4913 goto out;
4914 }
4915
4916
4917 if (fp->f_type != DTYPE_VNODE) {
4918 error = EBADF;
4919 goto out;
4920 }
4921 vp = (struct vnode *)fp_get_data(fp);
4922 proc_fdunlock(p);
4923
4924 error = vnode_getwithref(vp);
4925 if (error) {
4926 error = ENOENT;
4927 goto outdrop;
4928 }
4929
4930 /* Only go forward if you have write access */
4931 vfs_context_t ctx = vfs_context_current();
4932 if (vnode_authorize(vp, NULLVP, (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), ctx) != 0) {
4933 vnode_put(vp);
4934 error = EBADF;
4935 goto outdrop;
4936 }
4937
4938 error = VNOP_IOCTL(vp, cmd, param_ptr, 0, &context);
4939 (void)vnode_put(vp);
4940
4941 break;
4942 }
4943
4944 /*
4945 * Set the vnode pointed to by 'fd'
4946 * and tag it as the (potentially future) backing store
4947 * for another filesystem
4948 */
4949 case F_SETBACKINGSTORE: {
4950 if (fp->f_type != DTYPE_VNODE) {
4951 error = EBADF;
4952 goto out;
4953 }
4954
4955 vp = (struct vnode *)fp_get_data(fp);
4956
4957 if (vp->v_tag != VT_HFS) {
4958 error = EINVAL;
4959 goto out;
4960 }
4961 proc_fdunlock(p);
4962
4963 if (vnode_getwithref(vp)) {
4964 error = ENOENT;
4965 goto outdrop;
4966 }
4967
4968 /* only proceed if you have write access */
4969 vfs_context_t ctx = vfs_context_current();
4970 if (vnode_authorize(vp, NULLVP, (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), ctx) != 0) {
4971 vnode_put(vp);
4972 error = EBADF;
4973 goto outdrop;
4974 }
4975
4976
4977 /* If arg != 0, set, otherwise unset */
4978 if (uap->arg) {
4979 error = VNOP_IOCTL(vp, cmd, (caddr_t)1, 0, &context);
4980 } else {
4981 error = VNOP_IOCTL(vp, cmd, (caddr_t)NULL, 0, &context);
4982 }
4983
4984 vnode_put(vp);
4985 break;
4986 }
4987
4988 /*
4989 * like F_GETPATH, but special semantics for
4990 * the mobile time machine handler.
4991 */
4992 case F_GETPATH_MTMINFO: {
4993 char *pathbufp;
4994 int pathlen;
4995
4996 if (fp->f_type != DTYPE_VNODE) {
4997 error = EBADF;
4998 goto out;
4999 }
5000 vp = (struct vnode *)fp_get_data(fp);
5001 proc_fdunlock(p);
5002
5003 pathlen = MAXPATHLEN;
5004 pathbufp = zalloc(ZV_NAMEI);
5005
5006 if ((error = vnode_getwithref(vp)) == 0) {
5007 int backingstore = 0;
5008
5009 /* Check for error from vn_getpath before moving on */
5010 if ((error = vn_getpath(vp, pathbufp, &pathlen)) == 0) {
5011 if (vp->v_tag == VT_HFS) {
5012 error = VNOP_IOCTL(vp, cmd, (caddr_t) &backingstore, 0, &context);
5013 }
5014 (void)vnode_put(vp);
5015
5016 if (error == 0) {
5017 error = copyout((caddr_t)pathbufp, argp, pathlen);
5018 }
5019 if (error == 0) {
5020 /*
5021 * If the copyout was successful, now check to ensure
5022 * that this vnode is not a BACKINGSTORE vnode. mtmd
5023 * wants the path regardless.
5024 */
5025 if (backingstore) {
5026 error = EBUSY;
5027 }
5028 }
5029 } else {
5030 (void)vnode_put(vp);
5031 }
5032 }
5033
5034 zfree(ZV_NAMEI, pathbufp);
5035 goto outdrop;
5036 }
5037
5038 case F_RECYCLE: {
5039 #if !DEBUG && !DEVELOPMENT
5040 bool allowed = false;
5041
5042 //
5043 // non-debug and non-development kernels have restrictions
5044 // on who can all this fcntl. the process has to be marked
5045 // with the dataless-manipulator entitlement and either the
5046 // process or thread have to be marked rapid-aging.
5047 //
5048 if (!vfs_context_is_dataless_manipulator(&context)) {
5049 error = EPERM;
5050 goto out;
5051 }
5052
5053 proc_t proc = vfs_context_proc(&context);
5054 if (proc && (proc->p_lflag & P_LRAGE_VNODES)) {
5055 allowed = true;
5056 } else {
5057 thread_t thr = vfs_context_thread(&context);
5058 if (thr) {
5059 struct uthread *ut = get_bsdthread_info(thr);
5060
5061 if (ut && (ut->uu_flag & UT_RAGE_VNODES)) {
5062 allowed = true;
5063 }
5064 }
5065 }
5066 if (!allowed) {
5067 error = EPERM;
5068 goto out;
5069 }
5070 #endif
5071
5072 if (fp->f_type != DTYPE_VNODE) {
5073 error = EBADF;
5074 goto out;
5075 }
5076 vp = (struct vnode *)fp_get_data(fp);
5077 proc_fdunlock(p);
5078
5079 vnode_recycle(vp);
5080 break;
5081 }
5082
5083 #if CONFIG_FILE_LEASES
5084 case F_SETLEASE: {
5085 struct fileglob *fg;
5086 int fl_type;
5087 int expcounts;
5088
5089 if (fp->f_type != DTYPE_VNODE) {
5090 error = EBADF;
5091 goto out;
5092 }
5093 vp = (struct vnode *)fp_get_data(fp);
5094 fg = fp->fp_glob;;
5095 proc_fdunlock(p);
5096
5097 /*
5098 * In order to allow a process to avoid breaking
5099 * its own leases, the expected open count needs
5100 * to be provided to F_SETLEASE when placing write lease.
5101 * Similarly, in order to allow a process to place a read lease
5102 * after opening the file multiple times in RW mode, the expected
5103 * write count needs to be provided to F_SETLEASE when placing a
5104 * read lease.
5105 *
5106 * We use the upper 30 bits of the integer argument (way more than
5107 * enough) as the expected open/write count.
5108 *
5109 * If the caller passed 0 for the expected open count,
5110 * assume 1.
5111 */
5112 fl_type = CAST_DOWN_EXPLICIT(int, uap->arg);
5113 expcounts = (unsigned int)fl_type >> 2;
5114 fl_type &= 3;
5115
5116 if (fl_type == F_WRLCK && expcounts == 0) {
5117 expcounts = 1;
5118 }
5119
5120 AUDIT_ARG(value32, fl_type);
5121
5122 if ((error = vnode_getwithref(vp))) {
5123 goto outdrop;
5124 }
5125
5126 /*
5127 * Only support for regular file/dir mounted on local-based filesystem.
5128 */
5129 if ((vnode_vtype(vp) != VREG && vnode_vtype(vp) != VDIR) ||
5130 !(vfs_flags(vnode_mount(vp)) & MNT_LOCAL)) {
5131 error = EBADF;
5132 vnode_put(vp);
5133 goto outdrop;
5134 }
5135
5136 /* For directory, we only support read lease. */
5137 if (vnode_vtype(vp) == VDIR && fl_type == F_WRLCK) {
5138 error = ENOTSUP;
5139 vnode_put(vp);
5140 goto outdrop;
5141 }
5142
5143 switch (fl_type) {
5144 case F_RDLCK:
5145 case F_WRLCK:
5146 case F_UNLCK:
5147 error = vnode_setlease(vp, fg, fl_type, expcounts,
5148 vfs_context_current());
5149 break;
5150 default:
5151 error = EINVAL;
5152 break;
5153 }
5154
5155 vnode_put(vp);
5156 goto outdrop;
5157 }
5158
5159 case F_GETLEASE: {
5160 if (fp->f_type != DTYPE_VNODE) {
5161 error = EBADF;
5162 goto out;
5163 }
5164 vp = (struct vnode *)fp_get_data(fp);
5165 proc_fdunlock(p);
5166
5167 if ((error = vnode_getwithref(vp))) {
5168 goto outdrop;
5169 }
5170
5171 if ((vnode_vtype(vp) != VREG && vnode_vtype(vp) != VDIR) ||
5172 !(vfs_flags(vnode_mount(vp)) & MNT_LOCAL)) {
5173 error = EBADF;
5174 vnode_put(vp);
5175 goto outdrop;
5176 }
5177
5178 error = 0;
5179 *retval = vnode_getlease(vp);
5180 vnode_put(vp);
5181 goto outdrop;
5182 }
5183 #endif /* CONFIG_FILE_LEASES */
5184
5185 /* SPI (private) for asserting background access to a file */
5186 case F_ASSERT_BG_ACCESS:
5187 /* SPI (private) for releasing background access to a file */
5188 case F_RELEASE_BG_ACCESS: {
5189 /*
5190 * Check if the process is platform code, which means
5191 * that it is considered part of the Operating System.
5192 */
5193 if (!csproc_get_platform_binary(p)) {
5194 error = EPERM;
5195 goto out;
5196 }
5197
5198 if (fp->f_type != DTYPE_VNODE) {
5199 error = EBADF;
5200 goto out;
5201 }
5202
5203 vp = (struct vnode *)fp_get_data(fp);
5204 proc_fdunlock(p);
5205
5206 if (vnode_getwithref(vp)) {
5207 error = ENOENT;
5208 goto outdrop;
5209 }
5210
5211 /* Verify that vp points to a file and not a directory */
5212 if (!vnode_isreg(vp)) {
5213 vnode_put(vp);
5214 error = EINVAL;
5215 goto outdrop;
5216 }
5217
5218 /* Only proceed if you have read access */
5219 if (vnode_authorize(vp, NULLVP, (KAUTH_VNODE_ACCESS | KAUTH_VNODE_READ_DATA), &context) != 0) {
5220 vnode_put(vp);
5221 error = EBADF;
5222 goto outdrop;
5223 }
5224
5225 if (cmd == F_ASSERT_BG_ACCESS) {
5226 fassertbgaccess_t args;
5227
5228 if ((error = copyin(argp, (caddr_t)&args, sizeof(args)))) {
5229 vnode_put(vp);
5230 goto outdrop;
5231 }
5232
5233 error = VNOP_IOCTL(vp, F_ASSERT_BG_ACCESS, (caddr_t)&args, 0, &context);
5234 } else {
5235 // cmd == F_RELEASE_BG_ACCESS
5236 error = VNOP_IOCTL(vp, F_RELEASE_BG_ACCESS, (caddr_t)NULL, 0, &context);
5237 }
5238
5239 vnode_put(vp);
5240
5241 goto outdrop;
5242 }
5243
5244 default:
5245 /*
5246 * This is an fcntl() that we d not recognize at this level;
5247 * if this is a vnode, we send it down into the VNOP_IOCTL
5248 * for this vnode; this can include special devices, and will
5249 * effectively overload fcntl() to send ioctl()'s.
5250 */
5251 if ((cmd & IOC_VOID) && (cmd & IOC_INOUT)) {
5252 error = EINVAL;
5253 goto out;
5254 }
5255
5256 /*
5257 * Catch any now-invalid fcntl() selectors.
5258 * (When adding a selector to this list, it may be prudent
5259 * to consider adding it to the list in fsctl_internal() as well.)
5260 */
5261 switch (cmd) {
5262 case (int)APFSIOC_REVERT_TO_SNAPSHOT:
5263 case (int)FSIOC_FIOSEEKHOLE:
5264 case (int)FSIOC_FIOSEEKDATA:
5265 case (int)FSIOC_CAS_BSDFLAGS:
5266 case (int)FSIOC_KERNEL_ROOTAUTH:
5267 case (int)FSIOC_GRAFT_FS:
5268 case (int)FSIOC_UNGRAFT_FS:
5269 case (int)APFSIOC_IS_GRAFT_SUPPORTED:
5270 case (int)FSIOC_AUTH_FS:
5271 case HFS_GET_BOOT_INFO:
5272 case HFS_SET_BOOT_INFO:
5273 case FIOPINSWAP:
5274 case F_MARKDEPENDENCY:
5275 case TIOCREVOKE:
5276 case TIOCREVOKECLEAR:
5277 error = EINVAL;
5278 goto out;
5279 default:
5280 break;
5281 }
5282
5283 if (fp->f_type != DTYPE_VNODE) {
5284 error = EBADF;
5285 goto out;
5286 }
5287 vp = (struct vnode *)fp_get_data(fp);
5288 proc_fdunlock(p);
5289
5290 if ((error = vnode_getwithref(vp)) == 0) {
5291 #define STK_PARAMS 128
5292 char stkbuf[STK_PARAMS] = {0};
5293 unsigned int size;
5294 caddr_t data, memp;
5295 /*
5296 * For this to work properly, we have to copy in the
5297 * ioctl() cmd argument if there is one; we must also
5298 * check that a command parameter, if present, does
5299 * not exceed the maximum command length dictated by
5300 * the number of bits we have available in the command
5301 * to represent a structure length. Finally, we have
5302 * to copy the results back out, if it is that type of
5303 * ioctl().
5304 */
5305 size = IOCPARM_LEN(cmd);
5306 if (size > IOCPARM_MAX) {
5307 (void)vnode_put(vp);
5308 error = EINVAL;
5309 break;
5310 }
5311
5312 memp = NULL;
5313 if (size > sizeof(stkbuf)) {
5314 memp = (caddr_t)kalloc_data(size, Z_WAITOK);
5315 if (memp == 0) {
5316 (void)vnode_put(vp);
5317 error = ENOMEM;
5318 goto outdrop;
5319 }
5320 data = memp;
5321 } else {
5322 data = &stkbuf[0];
5323 }
5324
5325 if (cmd & IOC_IN) {
5326 if (size) {
5327 /* structure */
5328 error = copyin(argp, data, size);
5329 if (error) {
5330 (void)vnode_put(vp);
5331 if (memp) {
5332 kfree_data(memp, size);
5333 }
5334 goto outdrop;
5335 }
5336
5337 /* Bzero the section beyond that which was needed */
5338 if (size <= sizeof(stkbuf)) {
5339 bzero((((uint8_t*)data) + size), (sizeof(stkbuf) - size));
5340 }
5341 } else {
5342 /* int */
5343 if (is64bit) {
5344 *(user_addr_t *)data = argp;
5345 } else {
5346 *(uint32_t *)data = (uint32_t)argp;
5347 }
5348 };
5349 } else if ((cmd & IOC_OUT) && size) {
5350 /*
5351 * Zero the buffer so the user always
5352 * gets back something deterministic.
5353 */
5354 bzero(data, size);
5355 } else if (cmd & IOC_VOID) {
5356 if (is64bit) {
5357 *(user_addr_t *)data = argp;
5358 } else {
5359 *(uint32_t *)data = (uint32_t)argp;
5360 }
5361 }
5362
5363 error = VNOP_IOCTL(vp, cmd, CAST_DOWN(caddr_t, data), 0, &context);
5364
5365 (void)vnode_put(vp);
5366
5367 /* Copy any output data to user */
5368 if (error == 0 && (cmd & IOC_OUT) && size) {
5369 error = copyout(data, argp, size);
5370 }
5371 if (memp) {
5372 kfree_data(memp, size);
5373 }
5374 }
5375 break;
5376 }
5377
5378 outdrop:
5379 return sys_fcntl_outdrop(p, fd, fp, vp, error);
5380
5381 out:
5382 return sys_fcntl_out(p, fd, fp, error);
5383 }
5384
5385
5386 /*
5387 * sys_close
5388 *
5389 * Description: The implementation of the close(2) system call
5390 *
5391 * Parameters: p Process in whose per process file table
5392 * the close is to occur
5393 * uap->fd fd to be closed
5394 * retval <unused>
5395 *
5396 * Returns: 0 Success
5397 * fp_lookup:EBADF Bad file descriptor
5398 * fp_guard_exception:??? Guarded file descriptor
5399 * close_internal:EBADF
5400 * close_internal:??? Anything returnable by a per-fileops
5401 * close function
5402 */
5403 int
sys_close(proc_t p,struct close_args * uap,__unused int32_t * retval)5404 sys_close(proc_t p, struct close_args *uap, __unused int32_t *retval)
5405 {
5406 kauth_cred_t p_cred = current_cached_proc_cred(p);
5407
5408 __pthread_testcancel(1);
5409 return close_nocancel(p, p_cred, uap->fd);
5410 }
5411
5412 int
sys_close_nocancel(proc_t p,struct close_nocancel_args * uap,__unused int32_t * retval)5413 sys_close_nocancel(proc_t p, struct close_nocancel_args *uap, __unused int32_t *retval)
5414 {
5415 kauth_cred_t p_cred = current_cached_proc_cred(p);
5416
5417 return close_nocancel(p, p_cred, uap->fd);
5418 }
5419
5420 int
close_nocancel(proc_t p,kauth_cred_t p_cred,int fd)5421 close_nocancel(proc_t p, kauth_cred_t p_cred, int fd)
5422 {
5423 struct fileproc *fp;
5424
5425 AUDIT_SYSCLOSE(p, fd);
5426
5427 proc_fdlock(p);
5428 if ((fp = fp_get_noref_locked(p, fd)) == NULL) {
5429 proc_fdunlock(p);
5430 return EBADF;
5431 }
5432
5433 if (fp_isguarded(fp, GUARD_CLOSE)) {
5434 int error = fp_guard_exception(p, fd, fp, kGUARD_EXC_CLOSE);
5435 proc_fdunlock(p);
5436 return error;
5437 }
5438
5439 return fp_close_and_unlock(p, p_cred, fd, fp, 0);
5440 }
5441
5442
5443 /*
5444 * fstat
5445 *
5446 * Description: Return status information about a file descriptor.
5447 *
5448 * Parameters: p The process doing the fstat
5449 * fd The fd to stat
5450 * ub The user stat buffer
5451 * xsecurity The user extended security
5452 * buffer, or 0 if none
5453 * xsecurity_size The size of xsecurity, or 0
5454 * if no xsecurity
5455 * isstat64 Flag to indicate 64 bit version
5456 * for inode size, etc.
5457 *
5458 * Returns: 0 Success
5459 * EBADF
5460 * EFAULT
5461 * fp_lookup:EBADF Bad file descriptor
5462 * vnode_getwithref:???
5463 * copyout:EFAULT
5464 * vnode_getwithref:???
5465 * vn_stat:???
5466 * soo_stat:???
5467 * pipe_stat:???
5468 * pshm_stat:???
5469 * kqueue_stat:???
5470 *
5471 * Notes: Internal implementation for all other fstat() related
5472 * functions
5473 *
5474 * XXX switch on node type is bogus; need a stat in struct
5475 * XXX fileops instead.
5476 */
5477 static int
fstat(proc_t p,int fd,user_addr_t ub,user_addr_t xsecurity,user_addr_t xsecurity_size,int isstat64)5478 fstat(proc_t p, int fd, user_addr_t ub, user_addr_t xsecurity,
5479 user_addr_t xsecurity_size, int isstat64)
5480 {
5481 struct fileproc *fp;
5482 union {
5483 struct stat sb;
5484 struct stat64 sb64;
5485 } source;
5486 union {
5487 struct user64_stat user64_sb;
5488 struct user32_stat user32_sb;
5489 struct user64_stat64 user64_sb64;
5490 struct user32_stat64 user32_sb64;
5491 } dest;
5492 int error, my_size;
5493 file_type_t type;
5494 caddr_t data;
5495 kauth_filesec_t fsec;
5496 user_size_t xsecurity_bufsize;
5497 vfs_context_t ctx = vfs_context_current();
5498 void * sbptr;
5499
5500
5501 AUDIT_ARG(fd, fd);
5502
5503 if ((error = fp_lookup(p, fd, &fp, 0)) != 0) {
5504 return error;
5505 }
5506 type = fp->f_type;
5507 data = (caddr_t)fp_get_data(fp);
5508 fsec = KAUTH_FILESEC_NONE;
5509
5510 sbptr = (void *)&source;
5511
5512 switch (type) {
5513 case DTYPE_VNODE:
5514 if ((error = vnode_getwithref((vnode_t)data)) == 0) {
5515 /*
5516 * If the caller has the file open for reading, and is
5517 * not requesting extended security information, we are
5518 * going to let them get the basic stat information.
5519 */
5520 if ((fp->f_flag & FREAD) && (xsecurity == USER_ADDR_NULL)) {
5521 error = vn_stat_noauth((vnode_t)data, sbptr, NULL, isstat64, 0, ctx,
5522 fp->fp_glob->fg_cred);
5523 } else {
5524 error = vn_stat((vnode_t)data, sbptr, &fsec, isstat64, 0, ctx);
5525 }
5526
5527 AUDIT_ARG(vnpath, (struct vnode *)data, ARG_VNODE1);
5528 (void)vnode_put((vnode_t)data);
5529 }
5530 break;
5531
5532 #if SOCKETS
5533 case DTYPE_SOCKET:
5534 error = soo_stat((struct socket *)data, sbptr, isstat64);
5535 break;
5536 #endif /* SOCKETS */
5537
5538 case DTYPE_PIPE:
5539 error = pipe_stat((void *)data, sbptr, isstat64);
5540 break;
5541
5542 case DTYPE_PSXSHM:
5543 error = pshm_stat((void *)data, sbptr, isstat64);
5544 break;
5545
5546 case DTYPE_KQUEUE:
5547 error = kqueue_stat((void *)data, sbptr, isstat64, p);
5548 break;
5549
5550 default:
5551 error = EBADF;
5552 goto out;
5553 }
5554 if (error == 0) {
5555 caddr_t sbp;
5556
5557 if (isstat64 != 0) {
5558 source.sb64.st_lspare = 0;
5559 source.sb64.st_qspare[0] = 0LL;
5560 source.sb64.st_qspare[1] = 0LL;
5561
5562 if (IS_64BIT_PROCESS(p)) {
5563 munge_user64_stat64(&source.sb64, &dest.user64_sb64);
5564 my_size = sizeof(dest.user64_sb64);
5565 sbp = (caddr_t)&dest.user64_sb64;
5566 } else {
5567 munge_user32_stat64(&source.sb64, &dest.user32_sb64);
5568 my_size = sizeof(dest.user32_sb64);
5569 sbp = (caddr_t)&dest.user32_sb64;
5570 }
5571 } else {
5572 source.sb.st_lspare = 0;
5573 source.sb.st_qspare[0] = 0LL;
5574 source.sb.st_qspare[1] = 0LL;
5575 if (IS_64BIT_PROCESS(p)) {
5576 munge_user64_stat(&source.sb, &dest.user64_sb);
5577 my_size = sizeof(dest.user64_sb);
5578 sbp = (caddr_t)&dest.user64_sb;
5579 } else {
5580 munge_user32_stat(&source.sb, &dest.user32_sb);
5581 my_size = sizeof(dest.user32_sb);
5582 sbp = (caddr_t)&dest.user32_sb;
5583 }
5584 }
5585
5586 error = copyout(sbp, ub, my_size);
5587 }
5588
5589 /* caller wants extended security information? */
5590 if (xsecurity != USER_ADDR_NULL) {
5591 /* did we get any? */
5592 if (fsec == KAUTH_FILESEC_NONE) {
5593 if (susize(xsecurity_size, 0) != 0) {
5594 error = EFAULT;
5595 goto out;
5596 }
5597 } else {
5598 /* find the user buffer size */
5599 xsecurity_bufsize = fusize(xsecurity_size);
5600
5601 /* copy out the actual data size */
5602 if (susize(xsecurity_size, KAUTH_FILESEC_COPYSIZE(fsec)) != 0) {
5603 error = EFAULT;
5604 goto out;
5605 }
5606
5607 /* if the caller supplied enough room, copy out to it */
5608 if (xsecurity_bufsize >= KAUTH_FILESEC_COPYSIZE(fsec)) {
5609 error = copyout(fsec, xsecurity, KAUTH_FILESEC_COPYSIZE(fsec));
5610 }
5611 }
5612 }
5613 out:
5614 fp_drop(p, fd, fp, 0);
5615 if (fsec != NULL) {
5616 kauth_filesec_free(fsec);
5617 }
5618 return error;
5619 }
5620
5621
5622 /*
5623 * sys_fstat_extended
5624 *
5625 * Description: Extended version of fstat supporting returning extended
5626 * security information
5627 *
5628 * Parameters: p The process doing the fstat
5629 * uap->fd The fd to stat
5630 * uap->ub The user stat buffer
5631 * uap->xsecurity The user extended security
5632 * buffer, or 0 if none
5633 * uap->xsecurity_size The size of xsecurity, or 0
5634 *
5635 * Returns: 0 Success
5636 * !0 Errno (see fstat)
5637 */
5638 int
sys_fstat_extended(proc_t p,struct fstat_extended_args * uap,__unused int32_t * retval)5639 sys_fstat_extended(proc_t p, struct fstat_extended_args *uap, __unused int32_t *retval)
5640 {
5641 return fstat(p, uap->fd, uap->ub, uap->xsecurity, uap->xsecurity_size, 0);
5642 }
5643
5644
5645 /*
5646 * sys_fstat
5647 *
5648 * Description: Get file status for the file associated with fd
5649 *
5650 * Parameters: p The process doing the fstat
5651 * uap->fd The fd to stat
5652 * uap->ub The user stat buffer
5653 *
5654 * Returns: 0 Success
5655 * !0 Errno (see fstat)
5656 */
5657 int
sys_fstat(proc_t p,struct fstat_args * uap,__unused int32_t * retval)5658 sys_fstat(proc_t p, struct fstat_args *uap, __unused int32_t *retval)
5659 {
5660 return fstat(p, uap->fd, uap->ub, 0, 0, 0);
5661 }
5662
5663
5664 /*
5665 * sys_fstat64_extended
5666 *
5667 * Description: Extended version of fstat64 supporting returning extended
5668 * security information
5669 *
5670 * Parameters: p The process doing the fstat
5671 * uap->fd The fd to stat
5672 * uap->ub The user stat buffer
5673 * uap->xsecurity The user extended security
5674 * buffer, or 0 if none
5675 * uap->xsecurity_size The size of xsecurity, or 0
5676 *
5677 * Returns: 0 Success
5678 * !0 Errno (see fstat)
5679 */
5680 int
sys_fstat64_extended(proc_t p,struct fstat64_extended_args * uap,__unused int32_t * retval)5681 sys_fstat64_extended(proc_t p, struct fstat64_extended_args *uap, __unused int32_t *retval)
5682 {
5683 return fstat(p, uap->fd, uap->ub, uap->xsecurity, uap->xsecurity_size, 1);
5684 }
5685
5686
5687 /*
5688 * sys_fstat64
5689 *
5690 * Description: Get 64 bit version of the file status for the file associated
5691 * with fd
5692 *
5693 * Parameters: p The process doing the fstat
5694 * uap->fd The fd to stat
5695 * uap->ub The user stat buffer
5696 *
5697 * Returns: 0 Success
5698 * !0 Errno (see fstat)
5699 */
5700 int
sys_fstat64(proc_t p,struct fstat64_args * uap,__unused int32_t * retval)5701 sys_fstat64(proc_t p, struct fstat64_args *uap, __unused int32_t *retval)
5702 {
5703 return fstat(p, uap->fd, uap->ub, 0, 0, 1);
5704 }
5705
5706
5707 /*
5708 * sys_fpathconf
5709 *
5710 * Description: Return pathconf information about a file descriptor.
5711 *
5712 * Parameters: p Process making the request
5713 * uap->fd fd to get information about
5714 * uap->name Name of information desired
5715 * retval Pointer to the call return area
5716 *
5717 * Returns: 0 Success
5718 * EINVAL
5719 * fp_lookup:EBADF Bad file descriptor
5720 * vnode_getwithref:???
5721 * vn_pathconf:???
5722 *
5723 * Implicit returns:
5724 * *retval (modified) Returned information (numeric)
5725 */
5726 int
sys_fpathconf(proc_t p,struct fpathconf_args * uap,int32_t * retval)5727 sys_fpathconf(proc_t p, struct fpathconf_args *uap, int32_t *retval)
5728 {
5729 int fd = uap->fd;
5730 struct fileproc *fp;
5731 struct vnode *vp;
5732 int error = 0;
5733 file_type_t type;
5734
5735
5736 AUDIT_ARG(fd, uap->fd);
5737 if ((error = fp_lookup(p, fd, &fp, 0))) {
5738 return error;
5739 }
5740 type = fp->f_type;
5741
5742 switch (type) {
5743 case DTYPE_SOCKET:
5744 if (uap->name != _PC_PIPE_BUF) {
5745 error = EINVAL;
5746 goto out;
5747 }
5748 *retval = PIPE_BUF;
5749 error = 0;
5750 goto out;
5751
5752 case DTYPE_PIPE:
5753 if (uap->name != _PC_PIPE_BUF) {
5754 error = EINVAL;
5755 goto out;
5756 }
5757 *retval = PIPE_BUF;
5758 error = 0;
5759 goto out;
5760
5761 case DTYPE_VNODE:
5762 vp = (struct vnode *)fp_get_data(fp);
5763
5764 if ((error = vnode_getwithref(vp)) == 0) {
5765 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
5766
5767 error = vn_pathconf(vp, uap->name, retval, vfs_context_current());
5768
5769 (void)vnode_put(vp);
5770 }
5771 goto out;
5772
5773 default:
5774 error = EINVAL;
5775 goto out;
5776 }
5777 /*NOTREACHED*/
5778 out:
5779 fp_drop(p, fd, fp, 0);
5780 return error;
5781 }
5782
5783 /*
5784 * sys_flock
5785 *
5786 * Description: Apply an advisory lock on a file descriptor.
5787 *
5788 * Parameters: p Process making request
5789 * uap->fd fd on which the lock is to be
5790 * attempted
5791 * uap->how (Un)Lock bits, including type
5792 * retval Pointer to the call return area
5793 *
5794 * Returns: 0 Success
5795 * fp_getfvp:EBADF Bad file descriptor
5796 * fp_getfvp:ENOTSUP fd does not refer to a vnode
5797 * vnode_getwithref:???
5798 * VNOP_ADVLOCK:???
5799 *
5800 * Implicit returns:
5801 * *retval (modified) Size of dtable
5802 *
5803 * Notes: Just attempt to get a record lock of the requested type on
5804 * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
5805 */
5806 int
sys_flock(proc_t p,struct flock_args * uap,__unused int32_t * retval)5807 sys_flock(proc_t p, struct flock_args *uap, __unused int32_t *retval)
5808 {
5809 int fd = uap->fd;
5810 int how = uap->how;
5811 struct fileproc *fp;
5812 struct vnode *vp;
5813 struct flock lf;
5814 vfs_context_t ctx = vfs_context_current();
5815 int error = 0;
5816
5817 AUDIT_ARG(fd, uap->fd);
5818 if ((error = fp_getfvp(p, fd, &fp, &vp))) {
5819 return error;
5820 }
5821 if ((error = vnode_getwithref(vp))) {
5822 goto out1;
5823 }
5824 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
5825
5826 lf.l_whence = SEEK_SET;
5827 lf.l_start = 0;
5828 lf.l_len = 0;
5829 if (how & LOCK_UN) {
5830 lf.l_type = F_UNLCK;
5831 error = VNOP_ADVLOCK(vp, (caddr_t)fp->fp_glob, F_UNLCK, &lf, F_FLOCK, ctx, NULL);
5832 goto out;
5833 }
5834 if (how & LOCK_EX) {
5835 lf.l_type = F_WRLCK;
5836 } else if (how & LOCK_SH) {
5837 lf.l_type = F_RDLCK;
5838 } else {
5839 error = EBADF;
5840 goto out;
5841 }
5842 #if CONFIG_MACF
5843 error = mac_file_check_lock(kauth_cred_get(), fp->fp_glob, F_SETLK, &lf);
5844 if (error) {
5845 goto out;
5846 }
5847 #endif
5848 error = VNOP_ADVLOCK(vp, (caddr_t)fp->fp_glob, F_SETLK, &lf,
5849 (how & LOCK_NB ? F_FLOCK : F_FLOCK | F_WAIT),
5850 ctx, NULL);
5851 if (!error) {
5852 os_atomic_or(&fp->fp_glob->fg_flag, FWASLOCKED, relaxed);
5853 }
5854 out:
5855 (void)vnode_put(vp);
5856 out1:
5857 fp_drop(p, fd, fp, 0);
5858 return error;
5859 }
5860
5861 /*
5862 * sys_fileport_makeport
5863 *
5864 * Description: Obtain a Mach send right for a given file descriptor.
5865 *
5866 * Parameters: p Process calling fileport
5867 * uap->fd The fd to reference
5868 * uap->portnamep User address at which to place port name.
5869 *
5870 * Returns: 0 Success.
5871 * EBADF Bad file descriptor.
5872 * EINVAL File descriptor had type that cannot be sent, misc. other errors.
5873 * EFAULT Address at which to store port name is not valid.
5874 * EAGAIN Resource shortage.
5875 *
5876 * Implicit returns:
5877 * On success, name of send right is stored at user-specified address.
5878 */
5879 int
sys_fileport_makeport(proc_t p,struct fileport_makeport_args * uap,__unused int * retval)5880 sys_fileport_makeport(proc_t p, struct fileport_makeport_args *uap,
5881 __unused int *retval)
5882 {
5883 int err;
5884 int fd = uap->fd;
5885 user_addr_t user_portaddr = uap->portnamep;
5886 struct fileproc *fp = FILEPROC_NULL;
5887 struct fileglob *fg = NULL;
5888 ipc_port_t fileport;
5889 mach_port_name_t name = MACH_PORT_NULL;
5890
5891 proc_fdlock(p);
5892 err = fp_lookup(p, fd, &fp, 1);
5893 if (err != 0) {
5894 goto out_unlock;
5895 }
5896
5897 fg = fp->fp_glob;
5898 if (!fg_sendable(fg)) {
5899 err = EINVAL;
5900 goto out_unlock;
5901 }
5902
5903 if (fp_isguarded(fp, GUARD_FILEPORT)) {
5904 err = fp_guard_exception(p, fd, fp, kGUARD_EXC_FILEPORT);
5905 goto out_unlock;
5906 }
5907
5908 /* Dropped when port is deallocated */
5909 fg_ref(p, fg);
5910
5911 proc_fdunlock(p);
5912
5913 /* Allocate and initialize a port */
5914 fileport = fileport_alloc(fg);
5915 if (fileport == IPC_PORT_NULL) {
5916 fg_drop_live(fg);
5917 err = EAGAIN;
5918 goto out;
5919 }
5920
5921 /* Add an entry. Deallocates port on failure. */
5922 name = ipc_port_copyout_send(fileport, get_task_ipcspace(proc_task(p)));
5923 if (!MACH_PORT_VALID(name)) {
5924 err = EINVAL;
5925 goto out;
5926 }
5927
5928 err = copyout(&name, user_portaddr, sizeof(mach_port_name_t));
5929 if (err != 0) {
5930 goto out;
5931 }
5932
5933 /* Tag the fileglob for debugging purposes */
5934 lck_mtx_lock_spin(&fg->fg_lock);
5935 fg->fg_lflags |= FG_PORTMADE;
5936 lck_mtx_unlock(&fg->fg_lock);
5937
5938 fp_drop(p, fd, fp, 0);
5939
5940 return 0;
5941
5942 out_unlock:
5943 proc_fdunlock(p);
5944 out:
5945 if (MACH_PORT_VALID(name)) {
5946 /* Don't care if another thread races us to deallocate the entry */
5947 (void) mach_port_deallocate(get_task_ipcspace(proc_task(p)), name);
5948 }
5949
5950 if (fp != FILEPROC_NULL) {
5951 fp_drop(p, fd, fp, 0);
5952 }
5953
5954 return err;
5955 }
5956
5957 void
fileport_releasefg(struct fileglob * fg)5958 fileport_releasefg(struct fileglob *fg)
5959 {
5960 (void)fg_drop(FG_NOPROC, fg);
5961 }
5962
5963 /*
5964 * fileport_makefd
5965 *
5966 * Description: Obtain the file descriptor for a given Mach send right.
5967 *
5968 * Returns: 0 Success
5969 * EINVAL Invalid Mach port name, or port is not for a file.
5970 * fdalloc:EMFILE
5971 * fdalloc:ENOMEM Unable to allocate fileproc or extend file table.
5972 *
5973 * Implicit returns:
5974 * *retval (modified) The new descriptor
5975 */
5976 int
fileport_makefd(proc_t p,ipc_port_t port,fileproc_flags_t fp_flags,int * retval)5977 fileport_makefd(proc_t p, ipc_port_t port, fileproc_flags_t fp_flags, int *retval)
5978 {
5979 struct fileglob *fg;
5980 struct fileproc *fp = FILEPROC_NULL;
5981 int fd;
5982 int err;
5983
5984 fg = fileport_port_to_fileglob(port);
5985 if (fg == NULL) {
5986 err = EINVAL;
5987 goto out;
5988 }
5989
5990 fp = fileproc_alloc_init();
5991
5992 proc_fdlock(p);
5993 err = fdalloc(p, 0, &fd);
5994 if (err != 0) {
5995 proc_fdunlock(p);
5996 goto out;
5997 }
5998 if (fp_flags) {
5999 fp->fp_flags |= fp_flags;
6000 }
6001
6002 fp->fp_glob = fg;
6003 fg_ref(p, fg);
6004
6005 procfdtbl_releasefd(p, fd, fp);
6006 proc_fdunlock(p);
6007
6008 *retval = fd;
6009 err = 0;
6010 out:
6011 if ((fp != NULL) && (0 != err)) {
6012 fileproc_free(fp);
6013 }
6014
6015 return err;
6016 }
6017
6018 /*
6019 * sys_fileport_makefd
6020 *
6021 * Description: Obtain the file descriptor for a given Mach send right.
6022 *
6023 * Parameters: p Process calling fileport
6024 * uap->port Name of send right to file port.
6025 *
6026 * Returns: 0 Success
6027 * EINVAL Invalid Mach port name, or port is not for a file.
6028 * fdalloc:EMFILE
6029 * fdalloc:ENOMEM Unable to allocate fileproc or extend file table.
6030 *
6031 * Implicit returns:
6032 * *retval (modified) The new descriptor
6033 */
6034 int
sys_fileport_makefd(proc_t p,struct fileport_makefd_args * uap,int32_t * retval)6035 sys_fileport_makefd(proc_t p, struct fileport_makefd_args *uap, int32_t *retval)
6036 {
6037 ipc_port_t port = IPC_PORT_NULL;
6038 mach_port_name_t send = uap->port;
6039 kern_return_t res;
6040 int err;
6041
6042 res = ipc_typed_port_copyin_send(get_task_ipcspace(proc_task(p)),
6043 send, IKOT_FILEPORT, &port);
6044
6045 if (res == KERN_SUCCESS) {
6046 err = fileport_makefd(p, port, FP_CLOEXEC, retval);
6047 } else {
6048 err = EINVAL;
6049 }
6050
6051 if (IPC_PORT_NULL != port) {
6052 ipc_typed_port_release_send(port, IKOT_FILEPORT);
6053 }
6054
6055 return err;
6056 }
6057
6058
6059 #pragma mark fileops wrappers
6060
6061 /*
6062 * fo_read
6063 *
6064 * Description: Generic fileops read indirected through the fileops pointer
6065 * in the fileproc structure
6066 *
6067 * Parameters: fp fileproc structure pointer
6068 * uio user I/O structure pointer
6069 * flags FOF_ flags
6070 * ctx VFS context for operation
6071 *
6072 * Returns: 0 Success
6073 * !0 Errno from read
6074 */
6075 int
fo_read(struct fileproc * fp,struct uio * uio,int flags,vfs_context_t ctx)6076 fo_read(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
6077 {
6078 return (*fp->f_ops->fo_read)(fp, uio, flags, ctx);
6079 }
6080
6081 int
fo_no_read(struct fileproc * fp,struct uio * uio,int flags,vfs_context_t ctx)6082 fo_no_read(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
6083 {
6084 #pragma unused(fp, uio, flags, ctx)
6085 return ENXIO;
6086 }
6087
6088
6089 /*
6090 * fo_write
6091 *
6092 * Description: Generic fileops write indirected through the fileops pointer
6093 * in the fileproc structure
6094 *
6095 * Parameters: fp fileproc structure pointer
6096 * uio user I/O structure pointer
6097 * flags FOF_ flags
6098 * ctx VFS context for operation
6099 *
6100 * Returns: 0 Success
6101 * !0 Errno from write
6102 */
6103 int
fo_write(struct fileproc * fp,struct uio * uio,int flags,vfs_context_t ctx)6104 fo_write(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
6105 {
6106 return (*fp->f_ops->fo_write)(fp, uio, flags, ctx);
6107 }
6108
6109 int
fo_no_write(struct fileproc * fp,struct uio * uio,int flags,vfs_context_t ctx)6110 fo_no_write(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
6111 {
6112 #pragma unused(fp, uio, flags, ctx)
6113 return ENXIO;
6114 }
6115
6116
6117 /*
6118 * fo_ioctl
6119 *
6120 * Description: Generic fileops ioctl indirected through the fileops pointer
6121 * in the fileproc structure
6122 *
6123 * Parameters: fp fileproc structure pointer
6124 * com ioctl command
6125 * data pointer to internalized copy
6126 * of user space ioctl command
6127 * parameter data in kernel space
6128 * ctx VFS context for operation
6129 *
6130 * Returns: 0 Success
6131 * !0 Errno from ioctl
6132 *
6133 * Locks: The caller is assumed to have held the proc_fdlock; this
6134 * function releases and reacquires this lock. If the caller
6135 * accesses data protected by this lock prior to calling this
6136 * function, it will need to revalidate/reacquire any cached
6137 * protected data obtained prior to the call.
6138 */
6139 int
fo_ioctl(struct fileproc * fp,u_long com,caddr_t data,vfs_context_t ctx)6140 fo_ioctl(struct fileproc *fp, u_long com, caddr_t data, vfs_context_t ctx)
6141 {
6142 int error;
6143
6144 proc_fdunlock(vfs_context_proc(ctx));
6145 error = (*fp->f_ops->fo_ioctl)(fp, com, data, ctx);
6146 proc_fdlock(vfs_context_proc(ctx));
6147 return error;
6148 }
6149
6150 int
fo_no_ioctl(struct fileproc * fp,u_long com,caddr_t data,vfs_context_t ctx)6151 fo_no_ioctl(struct fileproc *fp, u_long com, caddr_t data, vfs_context_t ctx)
6152 {
6153 #pragma unused(fp, com, data, ctx)
6154 return ENOTTY;
6155 }
6156
6157
6158 /*
6159 * fo_select
6160 *
6161 * Description: Generic fileops select indirected through the fileops pointer
6162 * in the fileproc structure
6163 *
6164 * Parameters: fp fileproc structure pointer
6165 * which select which
6166 * wql pointer to wait queue list
6167 * ctx VFS context for operation
6168 *
6169 * Returns: 0 Success
6170 * !0 Errno from select
6171 */
6172 int
fo_select(struct fileproc * fp,int which,void * wql,vfs_context_t ctx)6173 fo_select(struct fileproc *fp, int which, void *wql, vfs_context_t ctx)
6174 {
6175 return (*fp->f_ops->fo_select)(fp, which, wql, ctx);
6176 }
6177
6178 int
fo_no_select(struct fileproc * fp,int which,void * wql,vfs_context_t ctx)6179 fo_no_select(struct fileproc *fp, int which, void *wql, vfs_context_t ctx)
6180 {
6181 #pragma unused(fp, which, wql, ctx)
6182 return ENOTSUP;
6183 }
6184
6185
6186 /*
6187 * fo_close
6188 *
6189 * Description: Generic fileops close indirected through the fileops pointer
6190 * in the fileproc structure
6191 *
6192 * Parameters: fp fileproc structure pointer for
6193 * file to close
6194 * ctx VFS context for operation
6195 *
6196 * Returns: 0 Success
6197 * !0 Errno from close
6198 */
6199 int
fo_close(struct fileglob * fg,vfs_context_t ctx)6200 fo_close(struct fileglob *fg, vfs_context_t ctx)
6201 {
6202 return (*fg->fg_ops->fo_close)(fg, ctx);
6203 }
6204
6205
6206 /*
6207 * fo_drain
6208 *
6209 * Description: Generic fileops kqueue filter indirected through the fileops
6210 * pointer in the fileproc structure
6211 *
6212 * Parameters: fp fileproc structure pointer
6213 * ctx VFS context for operation
6214 *
6215 * Returns: 0 Success
6216 * !0 errno from drain
6217 */
6218 int
fo_drain(struct fileproc * fp,vfs_context_t ctx)6219 fo_drain(struct fileproc *fp, vfs_context_t ctx)
6220 {
6221 return (*fp->f_ops->fo_drain)(fp, ctx);
6222 }
6223
6224 int
fo_no_drain(struct fileproc * fp,vfs_context_t ctx)6225 fo_no_drain(struct fileproc *fp, vfs_context_t ctx)
6226 {
6227 #pragma unused(fp, ctx)
6228 return ENOTSUP;
6229 }
6230
6231
6232 /*
6233 * fo_kqfilter
6234 *
6235 * Description: Generic fileops kqueue filter indirected through the fileops
6236 * pointer in the fileproc structure
6237 *
6238 * Parameters: fp fileproc structure pointer
6239 * kn pointer to knote to filter on
6240 *
6241 * Returns: (kn->kn_flags & EV_ERROR) error in kn->kn_data
6242 * 0 Filter is not active
6243 * !0 Filter is active
6244 */
6245 int
fo_kqfilter(struct fileproc * fp,struct knote * kn,struct kevent_qos_s * kev)6246 fo_kqfilter(struct fileproc *fp, struct knote *kn, struct kevent_qos_s *kev)
6247 {
6248 return (*fp->f_ops->fo_kqfilter)(fp, kn, kev);
6249 }
6250
6251 int
fo_no_kqfilter(struct fileproc * fp,struct knote * kn,struct kevent_qos_s * kev)6252 fo_no_kqfilter(struct fileproc *fp, struct knote *kn, struct kevent_qos_s *kev)
6253 {
6254 #pragma unused(fp, kev)
6255 knote_set_error(kn, ENOTSUP);
6256 return 0;
6257 }
6258