xref: /xnu-12377.1.9/bsd/kern/kern_descrip.c (revision f6217f891ac0bb64f3d375211650a4c1ff8ca1ea)
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