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 if (fp->f_type != DTYPE_VNODE) {
3511 error = EBADF;
3512 goto out;
3513 }
3514
3515 if ((fp->fp_glob->fg_flag & FWRITE) == 0) {
3516 error = EBADF;
3517 goto out;
3518 }
3519 vp = (struct vnode *)fp_get_data(fp);
3520 proc_fdunlock(p);
3521
3522 error = copyin(argp, (caddr_t)&offset, sizeof(off_t));
3523 if (error) {
3524 goto outdrop;
3525 }
3526 AUDIT_ARG(value64, offset);
3527
3528 error = vnode_getwithref(vp);
3529 if (error) {
3530 goto outdrop;
3531 }
3532
3533 /* Don't allow F_SETSIZE if the file has append-only flag set. */
3534 if (vnode_isappendonly(vp)) {
3535 error = EPERM;
3536 vnode_put(vp);
3537 goto outdrop;
3538 }
3539
3540 #if CONFIG_MACF
3541 error = mac_vnode_check_truncate(&context,
3542 fp->fp_glob->fg_cred, vp);
3543 if (error) {
3544 (void)vnode_put(vp);
3545 goto outdrop;
3546 }
3547 #endif
3548 /*
3549 * Make sure that we are root. Growing a file
3550 * without zero filling the data is a security hole.
3551 */
3552 if (!kauth_cred_issuser(kauth_cred_get())) {
3553 error = EACCES;
3554 } else {
3555 /*
3556 * Require privilege to change file size without zerofill,
3557 * else will change the file size and zerofill it.
3558 */
3559 error = priv_check_cred(kauth_cred_get(), PRIV_VFS_SETSIZE, 0);
3560 if (error == 0) {
3561 error = vnode_setsize(vp, offset, IO_NOZEROFILL, &context);
3562 } else {
3563 error = vnode_setsize(vp, offset, 0, &context);
3564 }
3565
3566 #if CONFIG_MACF
3567 if (error == 0) {
3568 mac_vnode_notify_truncate(&context, fp->fp_glob->fg_cred, vp);
3569 }
3570 #endif
3571 }
3572
3573 (void)vnode_put(vp);
3574 goto outdrop;
3575 }
3576
3577 case F_RDAHEAD:
3578 if (fp->f_type != DTYPE_VNODE) {
3579 error = EBADF;
3580 goto out;
3581 }
3582 if (uap->arg) {
3583 os_atomic_andnot(&fp->fp_glob->fg_flag, FNORDAHEAD, relaxed);
3584 } else {
3585 os_atomic_or(&fp->fp_glob->fg_flag, FNORDAHEAD, relaxed);
3586 }
3587 goto out;
3588
3589 case F_NOCACHE:
3590 case F_NOCACHE_EXT:
3591 if ((fp->f_type != DTYPE_VNODE) || (cmd == F_NOCACHE_EXT &&
3592 (vnode_vtype((struct vnode *)fp_get_data(fp)) != VREG))) {
3593 error = EBADF;
3594 goto out;
3595 }
3596 if (uap->arg) {
3597 os_atomic_or(&fp->fp_glob->fg_flag, FNOCACHE, relaxed);
3598 if (cmd == F_NOCACHE_EXT) {
3599 /*
3600 * We're reusing the O_NOCTTY bit for this purpose as it is only
3601 * used for open(2) and is mutually exclusive with a regular file.
3602 */
3603 os_atomic_or(&fp->fp_glob->fg_flag, O_NOCTTY, relaxed);
3604 }
3605 } else {
3606 os_atomic_andnot(&fp->fp_glob->fg_flag, FNOCACHE | O_NOCTTY, relaxed);
3607 }
3608 goto out;
3609
3610 case F_NODIRECT:
3611 if (fp->f_type != DTYPE_VNODE) {
3612 error = EBADF;
3613 goto out;
3614 }
3615 if (uap->arg) {
3616 os_atomic_or(&fp->fp_glob->fg_flag, FNODIRECT, relaxed);
3617 } else {
3618 os_atomic_andnot(&fp->fp_glob->fg_flag, FNODIRECT, relaxed);
3619 }
3620 goto out;
3621
3622 case F_SINGLE_WRITER:
3623 if (fp->f_type != DTYPE_VNODE) {
3624 error = EBADF;
3625 goto out;
3626 }
3627 if (uap->arg) {
3628 os_atomic_or(&fp->fp_glob->fg_flag, FSINGLE_WRITER, relaxed);
3629 } else {
3630 os_atomic_andnot(&fp->fp_glob->fg_flag, FSINGLE_WRITER, relaxed);
3631 }
3632 goto out;
3633
3634 case F_GLOBAL_NOCACHE:
3635 if (fp->f_type != DTYPE_VNODE) {
3636 error = EBADF;
3637 goto out;
3638 }
3639 vp = (struct vnode *)fp_get_data(fp);
3640 proc_fdunlock(p);
3641
3642 if ((error = vnode_getwithref(vp)) == 0) {
3643 *retval = vnode_isnocache(vp);
3644
3645 if (uap->arg) {
3646 vnode_setnocache(vp);
3647 } else {
3648 vnode_clearnocache(vp);
3649 }
3650
3651 (void)vnode_put(vp);
3652 }
3653 goto outdrop;
3654
3655 case F_CHECK_OPENEVT:
3656 if (fp->f_type != DTYPE_VNODE) {
3657 error = EBADF;
3658 goto out;
3659 }
3660 vp = (struct vnode *)fp_get_data(fp);
3661 proc_fdunlock(p);
3662
3663 if ((error = vnode_getwithref(vp)) == 0) {
3664 *retval = vnode_is_openevt(vp);
3665
3666 if (uap->arg) {
3667 vnode_set_openevt(vp);
3668 } else {
3669 vnode_clear_openevt(vp);
3670 }
3671
3672 (void)vnode_put(vp);
3673 }
3674 goto outdrop;
3675
3676 case F_RDADVISE: {
3677 struct radvisory ra_struct;
3678
3679 if (fp->f_type != DTYPE_VNODE) {
3680 error = EBADF;
3681 goto out;
3682 }
3683 vp = (struct vnode *)fp_get_data(fp);
3684 proc_fdunlock(p);
3685
3686 if ((error = copyin(argp, (caddr_t)&ra_struct, sizeof(ra_struct)))) {
3687 goto outdrop;
3688 }
3689 if (ra_struct.ra_offset < 0 || ra_struct.ra_count < 0) {
3690 error = EINVAL;
3691 goto outdrop;
3692 }
3693 if ((error = vnode_getwithref(vp)) == 0) {
3694 error = VNOP_IOCTL(vp, F_RDADVISE, (caddr_t)&ra_struct, 0, &context);
3695
3696 (void)vnode_put(vp);
3697 }
3698 goto outdrop;
3699 }
3700
3701 case F_FLUSH_DATA:
3702
3703 if (fp->f_type != DTYPE_VNODE) {
3704 error = EBADF;
3705 goto out;
3706 }
3707 vp = (struct vnode *)fp_get_data(fp);
3708 proc_fdunlock(p);
3709
3710 if ((error = vnode_getwithref(vp)) == 0) {
3711 error = VNOP_FSYNC(vp, MNT_NOWAIT, &context);
3712
3713 (void)vnode_put(vp);
3714 }
3715 goto outdrop;
3716
3717 case F_LOG2PHYS:
3718 case F_LOG2PHYS_EXT: {
3719 struct log2phys l2p_struct = {}; /* structure for allocate command */
3720 int devBlockSize;
3721
3722 off_t file_offset = 0;
3723 size_t a_size = 0;
3724 size_t run = 0;
3725
3726 if (cmd == F_LOG2PHYS_EXT) {
3727 error = copyin(argp, (caddr_t)&l2p_struct, sizeof(l2p_struct));
3728 if (error) {
3729 goto out;
3730 }
3731 file_offset = l2p_struct.l2p_devoffset;
3732 } else {
3733 file_offset = fp->f_offset;
3734 }
3735 if (fp->f_type != DTYPE_VNODE) {
3736 error = EBADF;
3737 goto out;
3738 }
3739 vp = (struct vnode *)fp_get_data(fp);
3740 proc_fdunlock(p);
3741 if ((error = vnode_getwithref(vp))) {
3742 goto outdrop;
3743 }
3744 error = VNOP_OFFTOBLK(vp, file_offset, &lbn);
3745 if (error) {
3746 (void)vnode_put(vp);
3747 goto outdrop;
3748 }
3749 error = VNOP_BLKTOOFF(vp, lbn, &offset);
3750 if (error) {
3751 (void)vnode_put(vp);
3752 goto outdrop;
3753 }
3754 devBlockSize = vfs_devblocksize(vnode_mount(vp));
3755 if (cmd == F_LOG2PHYS_EXT) {
3756 if (l2p_struct.l2p_contigbytes < 0) {
3757 vnode_put(vp);
3758 error = EINVAL;
3759 goto outdrop;
3760 }
3761
3762 a_size = (size_t)MIN((uint64_t)l2p_struct.l2p_contigbytes, SIZE_MAX);
3763 } else {
3764 a_size = devBlockSize;
3765 }
3766
3767 error = VNOP_BLOCKMAP(vp, offset, a_size, &bn, &run, NULL, 0, &context);
3768
3769 (void)vnode_put(vp);
3770
3771 if (!error) {
3772 l2p_struct.l2p_flags = 0; /* for now */
3773 if (cmd == F_LOG2PHYS_EXT) {
3774 l2p_struct.l2p_contigbytes = run - (file_offset - offset);
3775 } else {
3776 l2p_struct.l2p_contigbytes = 0; /* for now */
3777 }
3778
3779 /*
3780 * The block number being -1 suggests that the file offset is not backed
3781 * by any real blocks on-disk. As a result, just let it be passed back up wholesale.
3782 */
3783 if (bn == -1) {
3784 /* Don't multiply it by the block size */
3785 l2p_struct.l2p_devoffset = bn;
3786 } else {
3787 l2p_struct.l2p_devoffset = bn * devBlockSize;
3788 l2p_struct.l2p_devoffset += file_offset - offset;
3789 }
3790 error = copyout((caddr_t)&l2p_struct, argp, sizeof(l2p_struct));
3791 }
3792 goto outdrop;
3793 }
3794 case F_GETPATH:
3795 case F_GETPATH_NOFIRMLINK: {
3796 char *pathbufp;
3797 size_t pathlen;
3798
3799 if (fp->f_type != DTYPE_VNODE) {
3800 error = EBADF;
3801 goto out;
3802 }
3803 vp = (struct vnode *)fp_get_data(fp);
3804 proc_fdunlock(p);
3805
3806 pathlen = MAXPATHLEN;
3807 pathbufp = zalloc(ZV_NAMEI);
3808
3809 if ((error = vnode_getwithref(vp)) == 0) {
3810 error = vn_getpath_ext(vp, NULL, pathbufp,
3811 &pathlen, cmd == F_GETPATH_NOFIRMLINK ?
3812 VN_GETPATH_NO_FIRMLINK : 0);
3813 (void)vnode_put(vp);
3814
3815 if (error == 0) {
3816 error = copyout((caddr_t)pathbufp, argp, pathlen);
3817 }
3818 }
3819 zfree(ZV_NAMEI, pathbufp);
3820 goto outdrop;
3821 }
3822
3823 case F_PATHPKG_CHECK: {
3824 char *pathbufp;
3825 size_t pathlen;
3826
3827 if (fp->f_type != DTYPE_VNODE) {
3828 error = EBADF;
3829 goto out;
3830 }
3831 vp = (struct vnode *)fp_get_data(fp);
3832 proc_fdunlock(p);
3833
3834 pathlen = MAXPATHLEN;
3835 pathbufp = zalloc(ZV_NAMEI);
3836
3837 if ((error = copyinstr(argp, pathbufp, MAXPATHLEN, &pathlen)) == 0) {
3838 if ((error = vnode_getwithref(vp)) == 0) {
3839 AUDIT_ARG(text, pathbufp);
3840 error = vn_path_package_check(vp, pathbufp, (int)pathlen, retval);
3841
3842 (void)vnode_put(vp);
3843 }
3844 }
3845 zfree(ZV_NAMEI, pathbufp);
3846 goto outdrop;
3847 }
3848
3849 case F_CHKCLEAN: // used by regression tests to see if all dirty pages got cleaned by fsync()
3850 case F_FULLFSYNC: // fsync + flush the journal + DKIOCSYNCHRONIZE
3851 case F_BARRIERFSYNC: // fsync + barrier
3852 case F_FREEZE_FS: // freeze all other fs operations for the fs of this fd
3853 case F_THAW_FS: { // thaw all frozen fs operations for the fs of this fd
3854 if (fp->f_type != DTYPE_VNODE) {
3855 error = EBADF;
3856 goto out;
3857 }
3858 vp = (struct vnode *)fp_get_data(fp);
3859 proc_fdunlock(p);
3860
3861 if ((error = vnode_getwithref(vp)) == 0) {
3862 if ((cmd == F_BARRIERFSYNC) &&
3863 (vp->v_mount->mnt_supl_kern_flag & MNTK_SUPL_USE_FULLSYNC)) {
3864 cmd = F_FULLFSYNC;
3865 }
3866 error = VNOP_IOCTL(vp, cmd, (caddr_t)NULL, 0, &context);
3867
3868 /*
3869 * Promote F_BARRIERFSYNC to F_FULLFSYNC if the underlying
3870 * filesystem doesn't support it.
3871 */
3872 if ((error == ENOTTY || error == ENOTSUP || error == EINVAL) &&
3873 (cmd == F_BARRIERFSYNC)) {
3874 os_atomic_or(&vp->v_mount->mnt_supl_kern_flag,
3875 MNTK_SUPL_USE_FULLSYNC, relaxed);
3876
3877 error = VNOP_IOCTL(vp, F_FULLFSYNC, (caddr_t)NULL, 0, &context);
3878 }
3879
3880 (void)vnode_put(vp);
3881 }
3882 break;
3883 }
3884
3885 /*
3886 * SPI (private) for opening a file starting from a dir fd
3887 */
3888 case F_OPENFROM: {
3889 /* Check if this isn't a valid file descriptor */
3890 if (fp->f_type != DTYPE_VNODE) {
3891 error = EBADF;
3892 goto out;
3893 }
3894 vp = (struct vnode *)fp_get_data(fp);
3895
3896 return sys_fcntl__OPENFROM(p, fd, cmd, uap->arg, fp, vp, retval);
3897 }
3898
3899 /*
3900 * SPI (private) for unlinking a file starting from a dir fd
3901 */
3902 case F_UNLINKFROM: {
3903 user_addr_t pathname;
3904
3905 /* Check if this isn't a valid file descriptor */
3906 if ((fp->f_type != DTYPE_VNODE) ||
3907 (fp->f_flag & FREAD) == 0) {
3908 error = EBADF;
3909 goto out;
3910 }
3911 vp = (struct vnode *)fp_get_data(fp);
3912 proc_fdunlock(p);
3913
3914 if (vnode_getwithref(vp)) {
3915 error = ENOENT;
3916 goto outdrop;
3917 }
3918
3919 /* Only valid for directories */
3920 if (vp->v_type != VDIR) {
3921 vnode_put(vp);
3922 error = ENOTDIR;
3923 goto outdrop;
3924 }
3925
3926 /*
3927 * Only entitled apps may use the credentials of the thread
3928 * that opened the file descriptor.
3929 * Non-entitled threads will use their own context.
3930 */
3931 if (IOCurrentTaskHasEntitlement(ACCOUNT_OPENFROM_ENTITLEMENT)) {
3932 has_entitlement = 1;
3933 }
3934
3935 /* Get flags, mode and pathname arguments. */
3936 if (IS_64BIT_PROCESS(p)) {
3937 pathname = (user_addr_t)argp;
3938 } else {
3939 pathname = CAST_USER_ADDR_T(argp);
3940 }
3941
3942 /* Start the lookup relative to the file descriptor's vnode. */
3943 error = unlink1(has_entitlement ? &context : vfs_context_current(),
3944 vp, pathname, UIO_USERSPACE, 0);
3945
3946 vnode_put(vp);
3947 break;
3948 }
3949
3950 #if DEVELOPMENT || DEBUG
3951 case F_ADDSIGS_MAIN_BINARY:
3952 csblob_add_flags |= CS_BLOB_ADD_ALLOW_MAIN_BINARY;
3953 OS_FALLTHROUGH;
3954 #endif
3955 case F_ADDSIGS:
3956 case F_ADDFILESIGS:
3957 case F_ADDFILESIGS_FOR_DYLD_SIM:
3958 case F_ADDFILESIGS_RETURN:
3959 case F_ADDFILESIGS_INFO:
3960 {
3961 struct cs_blob *blob = NULL;
3962 struct user_fsignatures fs;
3963 kern_return_t kr;
3964 vm_offset_t kernel_blob_addr;
3965 vm_size_t kernel_blob_size;
3966 int blob_add_flags = 0;
3967 const size_t sizeof_fs = (cmd == F_ADDFILESIGS_INFO ?
3968 offsetof(struct user_fsignatures, fs_cdhash /* first output element */) :
3969 offsetof(struct user_fsignatures, fs_fsignatures_size /* compat */));
3970
3971 if (fp->f_type != DTYPE_VNODE) {
3972 error = EBADF;
3973 goto out;
3974 }
3975 vp = (struct vnode *)fp_get_data(fp);
3976 proc_fdunlock(p);
3977
3978 if (cmd == F_ADDFILESIGS_FOR_DYLD_SIM) {
3979 blob_add_flags |= MAC_VNODE_CHECK_DYLD_SIM;
3980 if ((proc_getcsflags(p) & CS_KILL) == 0) {
3981 proc_lock(p);
3982 proc_csflags_set(p, CS_KILL);
3983 proc_unlock(p);
3984 }
3985 }
3986
3987 error = vnode_getwithref(vp);
3988 if (error) {
3989 goto outdrop;
3990 }
3991
3992 if (IS_64BIT_PROCESS(p)) {
3993 error = copyin(argp, &fs, sizeof_fs);
3994 } else {
3995 if (cmd == F_ADDFILESIGS_INFO) {
3996 error = EINVAL;
3997 vnode_put(vp);
3998 goto outdrop;
3999 }
4000
4001 struct user32_fsignatures fs32;
4002
4003 error = copyin(argp, &fs32, sizeof(fs32));
4004 fs.fs_file_start = fs32.fs_file_start;
4005 fs.fs_blob_start = CAST_USER_ADDR_T(fs32.fs_blob_start);
4006 fs.fs_blob_size = fs32.fs_blob_size;
4007 }
4008
4009 if (error) {
4010 vnode_put(vp);
4011 goto outdrop;
4012 }
4013
4014 /*
4015 * First check if we have something loaded a this offset
4016 */
4017 blob = ubc_cs_blob_get(vp, CPU_TYPE_ANY, CPU_SUBTYPE_ANY, fs.fs_file_start);
4018 if (blob != NULL) {
4019 /* If this is for dyld_sim revalidate the blob */
4020 if (cmd == F_ADDFILESIGS_FOR_DYLD_SIM) {
4021 error = ubc_cs_blob_revalidate(vp, blob, NULL, blob_add_flags, proc_platform(p));
4022 if (error) {
4023 blob = NULL;
4024 if (error != EAGAIN) {
4025 vnode_put(vp);
4026 goto outdrop;
4027 }
4028 }
4029 }
4030 }
4031
4032 if (blob == NULL) {
4033 /*
4034 * An arbitrary limit, to prevent someone from mapping in a 20GB blob. This should cover
4035 * our use cases for the immediate future, but note that at the time of this commit, some
4036 * platforms are nearing 2MB blob sizes (with a prior soft limit of 2.5MB).
4037 *
4038 * We should consider how we can manage this more effectively; the above means that some
4039 * platforms are using megabytes of memory for signing data; it merely hasn't crossed the
4040 * threshold considered ridiculous at the time of this change.
4041 */
4042 #define CS_MAX_BLOB_SIZE (40ULL * 1024ULL * 1024ULL)
4043 if (fs.fs_blob_size > CS_MAX_BLOB_SIZE) {
4044 error = E2BIG;
4045 vnode_put(vp);
4046 goto outdrop;
4047 }
4048
4049 kernel_blob_size = CAST_DOWN(vm_size_t, fs.fs_blob_size);
4050 kr = ubc_cs_blob_allocate(&kernel_blob_addr, &kernel_blob_size);
4051 if (kr != KERN_SUCCESS || kernel_blob_size < fs.fs_blob_size) {
4052 error = ENOMEM;
4053 vnode_put(vp);
4054 goto outdrop;
4055 }
4056
4057 if (cmd == F_ADDSIGS || cmd == F_ADDSIGS_MAIN_BINARY) {
4058 error = copyin(fs.fs_blob_start,
4059 (void *) kernel_blob_addr,
4060 fs.fs_blob_size);
4061 } else { /* F_ADDFILESIGS || F_ADDFILESIGS_RETURN || F_ADDFILESIGS_FOR_DYLD_SIM || F_ADDFILESIGS_INFO */
4062 int resid;
4063
4064 error = vn_rdwr(UIO_READ,
4065 vp,
4066 (caddr_t) kernel_blob_addr,
4067 (int)kernel_blob_size,
4068 fs.fs_file_start + fs.fs_blob_start,
4069 UIO_SYSSPACE,
4070 0,
4071 kauth_cred_get(),
4072 &resid,
4073 p);
4074 if ((error == 0) && resid) {
4075 /* kernel_blob_size rounded to a page size, but signature may be at end of file */
4076 memset((void *)(kernel_blob_addr + (kernel_blob_size - resid)), 0x0, resid);
4077 }
4078 }
4079
4080 if (error) {
4081 ubc_cs_blob_deallocate(kernel_blob_addr,
4082 kernel_blob_size);
4083 vnode_put(vp);
4084 goto outdrop;
4085 }
4086
4087 blob = NULL;
4088 error = ubc_cs_blob_add(vp,
4089 proc_platform(p),
4090 CPU_TYPE_ANY, /* not for a specific architecture */
4091 CPU_SUBTYPE_ANY,
4092 fs.fs_file_start,
4093 &kernel_blob_addr,
4094 kernel_blob_size,
4095 NULL,
4096 blob_add_flags,
4097 &blob,
4098 csblob_add_flags);
4099
4100 /* ubc_blob_add() has consumed "kernel_blob_addr" if it is zeroed */
4101 if (error) {
4102 if (kernel_blob_addr) {
4103 ubc_cs_blob_deallocate(kernel_blob_addr,
4104 kernel_blob_size);
4105 }
4106 vnode_put(vp);
4107 goto outdrop;
4108 } else {
4109 #if CHECK_CS_VALIDATION_BITMAP
4110 ubc_cs_validation_bitmap_allocate( vp );
4111 #endif
4112 }
4113 }
4114
4115 if (cmd == F_ADDFILESIGS_RETURN || cmd == F_ADDFILESIGS_FOR_DYLD_SIM ||
4116 cmd == F_ADDFILESIGS_INFO) {
4117 /*
4118 * The first element of the structure is a
4119 * off_t that happen to have the same size for
4120 * all archs. Lets overwrite that.
4121 */
4122 off_t end_offset = 0;
4123 if (blob) {
4124 end_offset = blob->csb_end_offset;
4125 }
4126 error = copyout(&end_offset, argp, sizeof(end_offset));
4127
4128 if (error) {
4129 vnode_put(vp);
4130 goto outdrop;
4131 }
4132 }
4133
4134 if (cmd == F_ADDFILESIGS_INFO) {
4135 /* Return information. What we copy out depends on the size of the
4136 * passed in structure, to keep binary compatibility. */
4137
4138 if (fs.fs_fsignatures_size >= sizeof(struct user_fsignatures)) {
4139 // enough room for fs_cdhash[20]+fs_hash_type
4140
4141 if (blob != NULL) {
4142 error = copyout(blob->csb_cdhash,
4143 (vm_address_t)argp + offsetof(struct user_fsignatures, fs_cdhash),
4144 USER_FSIGNATURES_CDHASH_LEN);
4145 if (error) {
4146 vnode_put(vp);
4147 goto outdrop;
4148 }
4149 int hashtype = cs_hash_type(blob->csb_hashtype);
4150 error = copyout(&hashtype,
4151 (vm_address_t)argp + offsetof(struct user_fsignatures, fs_hash_type),
4152 sizeof(int));
4153 if (error) {
4154 vnode_put(vp);
4155 goto outdrop;
4156 }
4157 }
4158 }
4159 }
4160
4161 (void) vnode_put(vp);
4162 break;
4163 }
4164 #if CONFIG_SUPPLEMENTAL_SIGNATURES
4165 case F_ADDFILESUPPL:
4166 {
4167 struct vnode *ivp;
4168 struct cs_blob *blob = NULL;
4169 struct user_fsupplement fs;
4170 int orig_fd;
4171 struct fileproc* orig_fp = NULL;
4172 kern_return_t kr;
4173 vm_offset_t kernel_blob_addr;
4174 vm_size_t kernel_blob_size;
4175
4176 if (!IS_64BIT_PROCESS(p)) {
4177 error = EINVAL;
4178 goto out; // drop fp and unlock fds
4179 }
4180
4181 if (fp->f_type != DTYPE_VNODE) {
4182 error = EBADF;
4183 goto out;
4184 }
4185
4186 error = copyin(argp, &fs, sizeof(fs));
4187 if (error) {
4188 goto out;
4189 }
4190
4191 orig_fd = fs.fs_orig_fd;
4192 if ((error = fp_lookup(p, orig_fd, &orig_fp, 1))) {
4193 printf("CODE SIGNING: Failed to find original file for supplemental signature attachment\n");
4194 goto out;
4195 }
4196
4197 if (orig_fp->f_type != DTYPE_VNODE) {
4198 error = EBADF;
4199 fp_drop(p, orig_fd, orig_fp, 1);
4200 goto out;
4201 }
4202
4203 ivp = (struct vnode *)fp_get_data(orig_fp);
4204
4205 vp = (struct vnode *)fp_get_data(fp);
4206
4207 proc_fdunlock(p);
4208
4209 error = vnode_getwithref(ivp);
4210 if (error) {
4211 fp_drop(p, orig_fd, orig_fp, 0);
4212 goto outdrop; //drop fp
4213 }
4214
4215 error = vnode_getwithref(vp);
4216 if (error) {
4217 vnode_put(ivp);
4218 fp_drop(p, orig_fd, orig_fp, 0);
4219 goto outdrop;
4220 }
4221
4222 if (fs.fs_blob_size > CS_MAX_BLOB_SIZE) {
4223 error = E2BIG;
4224 goto dropboth; // drop iocounts on vp and ivp, drop orig_fp then drop fp via outdrop
4225 }
4226
4227 kernel_blob_size = CAST_DOWN(vm_size_t, fs.fs_blob_size);
4228 kr = ubc_cs_blob_allocate(&kernel_blob_addr, &kernel_blob_size);
4229 if (kr != KERN_SUCCESS) {
4230 error = ENOMEM;
4231 goto dropboth;
4232 }
4233
4234 int resid;
4235 error = vn_rdwr(UIO_READ, vp,
4236 (caddr_t)kernel_blob_addr, (int)kernel_blob_size,
4237 fs.fs_file_start + fs.fs_blob_start,
4238 UIO_SYSSPACE, 0,
4239 kauth_cred_get(), &resid, p);
4240 if ((error == 0) && resid) {
4241 /* kernel_blob_size rounded to a page size, but signature may be at end of file */
4242 memset((void *)(kernel_blob_addr + (kernel_blob_size - resid)), 0x0, resid);
4243 }
4244
4245 if (error) {
4246 ubc_cs_blob_deallocate(kernel_blob_addr,
4247 kernel_blob_size);
4248 goto dropboth;
4249 }
4250
4251 error = ubc_cs_blob_add_supplement(vp, ivp, fs.fs_file_start,
4252 &kernel_blob_addr, kernel_blob_size, &blob);
4253
4254 /* ubc_blob_add_supplement() has consumed kernel_blob_addr if it is zeroed */
4255 if (error) {
4256 if (kernel_blob_addr) {
4257 ubc_cs_blob_deallocate(kernel_blob_addr,
4258 kernel_blob_size);
4259 }
4260 goto dropboth;
4261 }
4262 vnode_put(ivp);
4263 vnode_put(vp);
4264 fp_drop(p, orig_fd, orig_fp, 0);
4265 break;
4266
4267 dropboth:
4268 vnode_put(ivp);
4269 vnode_put(vp);
4270 fp_drop(p, orig_fd, orig_fp, 0);
4271 goto outdrop;
4272 }
4273 #endif
4274 case F_GETCODEDIR:
4275 case F_FINDSIGS: {
4276 error = ENOTSUP;
4277 goto out;
4278 }
4279 case F_CHECK_LV: {
4280 struct fileglob *fg;
4281 fchecklv_t lv = {};
4282
4283 if (fp->f_type != DTYPE_VNODE) {
4284 error = EBADF;
4285 goto out;
4286 }
4287 fg = fp->fp_glob;
4288 proc_fdunlock(p);
4289
4290 if (IS_64BIT_PROCESS(p)) {
4291 error = copyin(argp, &lv, sizeof(lv));
4292 } else {
4293 struct user32_fchecklv lv32 = {};
4294
4295 error = copyin(argp, &lv32, sizeof(lv32));
4296 lv.lv_file_start = lv32.lv_file_start;
4297 lv.lv_error_message = (void *)(uintptr_t)lv32.lv_error_message;
4298 lv.lv_error_message_size = lv32.lv_error_message_size;
4299 }
4300 if (error) {
4301 goto outdrop;
4302 }
4303
4304 #if CONFIG_MACF
4305 error = mac_file_check_library_validation(p, fg, lv.lv_file_start,
4306 (user_long_t)lv.lv_error_message, lv.lv_error_message_size);
4307 #endif
4308
4309 break;
4310 }
4311 case F_GETSIGSINFO: {
4312 struct cs_blob *blob = NULL;
4313 fgetsigsinfo_t sigsinfo = {};
4314
4315 if (fp->f_type != DTYPE_VNODE) {
4316 error = EBADF;
4317 goto out;
4318 }
4319 vp = (struct vnode *)fp_get_data(fp);
4320 proc_fdunlock(p);
4321
4322 error = vnode_getwithref(vp);
4323 if (error) {
4324 goto outdrop;
4325 }
4326
4327 error = copyin(argp, &sigsinfo, sizeof(sigsinfo));
4328 if (error) {
4329 vnode_put(vp);
4330 goto outdrop;
4331 }
4332
4333 blob = ubc_cs_blob_get(vp, CPU_TYPE_ANY, CPU_SUBTYPE_ANY, sigsinfo.fg_file_start);
4334 if (blob == NULL) {
4335 error = ENOENT;
4336 vnode_put(vp);
4337 goto outdrop;
4338 }
4339 switch (sigsinfo.fg_info_request) {
4340 case GETSIGSINFO_PLATFORM_BINARY:
4341 sigsinfo.fg_sig_is_platform = blob->csb_platform_binary;
4342 error = copyout(&sigsinfo.fg_sig_is_platform,
4343 (vm_address_t)argp + offsetof(struct fgetsigsinfo, fg_sig_is_platform),
4344 sizeof(sigsinfo.fg_sig_is_platform));
4345 if (error) {
4346 vnode_put(vp);
4347 goto outdrop;
4348 }
4349 break;
4350 default:
4351 error = EINVAL;
4352 vnode_put(vp);
4353 goto outdrop;
4354 }
4355 vnode_put(vp);
4356 break;
4357 }
4358 #if CONFIG_PROTECT
4359 case F_GETPROTECTIONCLASS: {
4360 if (fp->f_type != DTYPE_VNODE) {
4361 error = EBADF;
4362 goto out;
4363 }
4364 vp = (struct vnode *)fp_get_data(fp);
4365
4366 proc_fdunlock(p);
4367
4368 if (vnode_getwithref(vp)) {
4369 error = ENOENT;
4370 goto outdrop;
4371 }
4372
4373 struct vnode_attr va;
4374
4375 VATTR_INIT(&va);
4376 VATTR_WANTED(&va, va_dataprotect_class);
4377 error = VNOP_GETATTR(vp, &va, &context);
4378 if (!error) {
4379 if (VATTR_IS_SUPPORTED(&va, va_dataprotect_class)) {
4380 *retval = va.va_dataprotect_class;
4381 } else {
4382 error = ENOTSUP;
4383 }
4384 }
4385
4386 vnode_put(vp);
4387 break;
4388 }
4389
4390 case F_SETPROTECTIONCLASS: {
4391 /* tmp must be a valid PROTECTION_CLASS_* */
4392 tmp = CAST_DOWN_EXPLICIT(uint32_t, uap->arg);
4393
4394 if (fp->f_type != DTYPE_VNODE) {
4395 error = EBADF;
4396 goto out;
4397 }
4398 vp = (struct vnode *)fp_get_data(fp);
4399
4400 proc_fdunlock(p);
4401
4402 if (vnode_getwithref(vp)) {
4403 error = ENOENT;
4404 goto outdrop;
4405 }
4406
4407 /* Only go forward if you have write access */
4408 vfs_context_t ctx = vfs_context_current();
4409 if (vnode_authorize(vp, NULLVP, (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), ctx) != 0) {
4410 vnode_put(vp);
4411 error = EBADF;
4412 goto outdrop;
4413 }
4414
4415 struct vnode_attr va;
4416
4417 #if CONFIG_MACF
4418 // tmp has already explicitly downcast to uint32_t above.
4419 uint32_t dataprotect_class = (uint32_t)tmp;
4420 if ((error = mac_vnode_check_dataprotect_set(ctx, vp, &dataprotect_class))) {
4421 vnode_put(vp);
4422 goto outdrop;
4423 }
4424 tmp = (int)dataprotect_class;
4425 #endif
4426
4427 VATTR_INIT(&va);
4428 VATTR_SET(&va, va_dataprotect_class, tmp);
4429
4430 error = VNOP_SETATTR(vp, &va, ctx);
4431
4432 vnode_put(vp);
4433 break;
4434 }
4435
4436 case F_TRANSCODEKEY: {
4437 if (fp->f_type != DTYPE_VNODE) {
4438 error = EBADF;
4439 goto out;
4440 }
4441
4442 vp = (struct vnode *)fp_get_data(fp);
4443 proc_fdunlock(p);
4444
4445 if (vnode_getwithref(vp)) {
4446 error = ENOENT;
4447 goto outdrop;
4448 }
4449
4450 cp_key_t k = {
4451 .len = CP_MAX_WRAPPEDKEYSIZE,
4452 };
4453
4454 k.key = kalloc_data(CP_MAX_WRAPPEDKEYSIZE, Z_WAITOK | Z_ZERO);
4455 if (k.key == NULL) {
4456 error = ENOMEM;
4457 } else {
4458 error = VNOP_IOCTL(vp, F_TRANSCODEKEY, (caddr_t)&k, 1, &context);
4459 }
4460
4461 vnode_put(vp);
4462
4463 if (error == 0) {
4464 error = copyout(k.key, argp, k.len);
4465 *retval = k.len;
4466 }
4467 kfree_data(k.key, CP_MAX_WRAPPEDKEYSIZE);
4468
4469 break;
4470 }
4471
4472 case F_GETPROTECTIONLEVEL: {
4473 if (fp->f_type != DTYPE_VNODE) {
4474 error = EBADF;
4475 goto out;
4476 }
4477
4478 vp = (struct vnode*)fp_get_data(fp);
4479 proc_fdunlock(p);
4480
4481 if (vnode_getwithref(vp)) {
4482 error = ENOENT;
4483 goto outdrop;
4484 }
4485
4486 error = VNOP_IOCTL(vp, F_GETPROTECTIONLEVEL, (caddr_t)retval, 0, &context);
4487
4488 vnode_put(vp);
4489 break;
4490 }
4491
4492 case F_GETDEFAULTPROTLEVEL: {
4493 if (fp->f_type != DTYPE_VNODE) {
4494 error = EBADF;
4495 goto out;
4496 }
4497
4498 vp = (struct vnode*)fp_get_data(fp);
4499 proc_fdunlock(p);
4500
4501 if (vnode_getwithref(vp)) {
4502 error = ENOENT;
4503 goto outdrop;
4504 }
4505
4506 /*
4507 * if cp_get_major_vers fails, error will be set to proper errno
4508 * and cp_version will still be 0.
4509 */
4510
4511 error = VNOP_IOCTL(vp, F_GETDEFAULTPROTLEVEL, (caddr_t)retval, 0, &context);
4512
4513 vnode_put(vp);
4514 break;
4515 }
4516
4517 #endif /* CONFIG_PROTECT */
4518
4519 case F_MOVEDATAEXTENTS: {
4520 struct fileproc *fp2 = NULL;
4521 struct vnode *src_vp = NULLVP;
4522 struct vnode *dst_vp = NULLVP;
4523 /* We need to grab the 2nd FD out of the arguments before moving on. */
4524 int fd2 = CAST_DOWN_EXPLICIT(int32_t, uap->arg);
4525
4526 error = priv_check_cred(kauth_cred_get(), PRIV_VFS_MOVE_DATA_EXTENTS, 0);
4527 if (error) {
4528 goto out;
4529 }
4530
4531 if (fp->f_type != DTYPE_VNODE) {
4532 error = EBADF;
4533 goto out;
4534 }
4535
4536 /*
4537 * For now, special case HFS+ and APFS only, since this
4538 * is SPI.
4539 */
4540 src_vp = (struct vnode *)fp_get_data(fp);
4541 if (src_vp->v_tag != VT_HFS && src_vp->v_tag != VT_APFS) {
4542 error = ENOTSUP;
4543 goto out;
4544 }
4545
4546 /*
4547 * Get the references before we start acquiring iocounts on the vnodes,
4548 * while we still hold the proc fd lock
4549 */
4550 if ((error = fp_lookup(p, fd2, &fp2, 1))) {
4551 error = EBADF;
4552 goto out;
4553 }
4554 if (fp2->f_type != DTYPE_VNODE) {
4555 fp_drop(p, fd2, fp2, 1);
4556 error = EBADF;
4557 goto out;
4558 }
4559 dst_vp = (struct vnode *)fp_get_data(fp2);
4560 if (dst_vp->v_tag != VT_HFS && dst_vp->v_tag != VT_APFS) {
4561 fp_drop(p, fd2, fp2, 1);
4562 error = ENOTSUP;
4563 goto out;
4564 }
4565
4566 #if CONFIG_MACF
4567 /* Re-do MAC checks against the new FD, pass in a fake argument */
4568 error = mac_file_check_fcntl(kauth_cred_get(), fp2->fp_glob, cmd, 0);
4569 if (error) {
4570 fp_drop(p, fd2, fp2, 1);
4571 goto out;
4572 }
4573 #endif
4574 /* Audit the 2nd FD */
4575 AUDIT_ARG(fd, fd2);
4576
4577 proc_fdunlock(p);
4578
4579 if (vnode_getwithref(src_vp)) {
4580 fp_drop(p, fd2, fp2, 0);
4581 error = ENOENT;
4582 goto outdrop;
4583 }
4584 if (vnode_getwithref(dst_vp)) {
4585 vnode_put(src_vp);
4586 fp_drop(p, fd2, fp2, 0);
4587 error = ENOENT;
4588 goto outdrop;
4589 }
4590
4591 /*
4592 * Basic asserts; validate they are not the same and that
4593 * both live on the same filesystem.
4594 */
4595 if (dst_vp == src_vp) {
4596 vnode_put(src_vp);
4597 vnode_put(dst_vp);
4598 fp_drop(p, fd2, fp2, 0);
4599 error = EINVAL;
4600 goto outdrop;
4601 }
4602
4603 if (dst_vp->v_mount != src_vp->v_mount) {
4604 vnode_put(src_vp);
4605 vnode_put(dst_vp);
4606 fp_drop(p, fd2, fp2, 0);
4607 error = EXDEV;
4608 goto outdrop;
4609 }
4610
4611 /* Now we have a legit pair of FDs. Go to work */
4612
4613 /* Now check for write access to the target files */
4614 if (vnode_authorize(src_vp, NULLVP,
4615 (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), &context) != 0) {
4616 vnode_put(src_vp);
4617 vnode_put(dst_vp);
4618 fp_drop(p, fd2, fp2, 0);
4619 error = EBADF;
4620 goto outdrop;
4621 }
4622
4623 if (vnode_authorize(dst_vp, NULLVP,
4624 (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), &context) != 0) {
4625 vnode_put(src_vp);
4626 vnode_put(dst_vp);
4627 fp_drop(p, fd2, fp2, 0);
4628 error = EBADF;
4629 goto outdrop;
4630 }
4631
4632 /* Verify that both vps point to files and not directories */
4633 if (!vnode_isreg(src_vp) || !vnode_isreg(dst_vp)) {
4634 error = EINVAL;
4635 vnode_put(src_vp);
4636 vnode_put(dst_vp);
4637 fp_drop(p, fd2, fp2, 0);
4638 goto outdrop;
4639 }
4640
4641 /*
4642 * The exchangedata syscall handler passes in 0 for the flags to VNOP_EXCHANGE.
4643 * We'll pass in our special bit indicating that the new behavior is expected
4644 */
4645
4646 error = VNOP_EXCHANGE(src_vp, dst_vp, FSOPT_EXCHANGE_DATA_ONLY, &context);
4647
4648 vnode_put(src_vp);
4649 vnode_put(dst_vp);
4650 fp_drop(p, fd2, fp2, 0);
4651 break;
4652 }
4653
4654 case F_TRANSFEREXTENTS: {
4655 struct fileproc *fp2 = NULL;
4656 struct vnode *src_vp = NULLVP;
4657 struct vnode *dst_vp = NULLVP;
4658
4659 /* Get 2nd FD out of the arguments. */
4660 int fd2 = CAST_DOWN_EXPLICIT(int, uap->arg);
4661 if (fd2 < 0) {
4662 error = EINVAL;
4663 goto out;
4664 }
4665
4666 if (fp->f_type != DTYPE_VNODE) {
4667 error = EBADF;
4668 goto out;
4669 }
4670
4671 /*
4672 * Only allow this for APFS
4673 */
4674 src_vp = (struct vnode *)fp_get_data(fp);
4675 if (src_vp->v_tag != VT_APFS) {
4676 error = ENOTSUP;
4677 goto out;
4678 }
4679
4680 /*
4681 * Get the references before we start acquiring iocounts on the vnodes,
4682 * while we still hold the proc fd lock
4683 */
4684 if ((error = fp_lookup(p, fd2, &fp2, 1))) {
4685 error = EBADF;
4686 goto out;
4687 }
4688 if (fp2->f_type != DTYPE_VNODE) {
4689 fp_drop(p, fd2, fp2, 1);
4690 error = EBADF;
4691 goto out;
4692 }
4693 dst_vp = (struct vnode *)fp_get_data(fp2);
4694 if (dst_vp->v_tag != VT_APFS) {
4695 fp_drop(p, fd2, fp2, 1);
4696 error = ENOTSUP;
4697 goto out;
4698 }
4699
4700 #if CONFIG_MACF
4701 /* Re-do MAC checks against the new FD, pass in a fake argument */
4702 error = mac_file_check_fcntl(kauth_cred_get(), fp2->fp_glob, cmd, 0);
4703 if (error) {
4704 fp_drop(p, fd2, fp2, 1);
4705 goto out;
4706 }
4707 #endif
4708 /* Audit the 2nd FD */
4709 AUDIT_ARG(fd, fd2);
4710
4711 proc_fdunlock(p);
4712
4713 if (vnode_getwithref(src_vp)) {
4714 fp_drop(p, fd2, fp2, 0);
4715 error = ENOENT;
4716 goto outdrop;
4717 }
4718 if (vnode_getwithref(dst_vp)) {
4719 vnode_put(src_vp);
4720 fp_drop(p, fd2, fp2, 0);
4721 error = ENOENT;
4722 goto outdrop;
4723 }
4724
4725 /*
4726 * Validate they are not the same and that
4727 * both live on the same filesystem.
4728 */
4729 if (dst_vp == src_vp) {
4730 vnode_put(src_vp);
4731 vnode_put(dst_vp);
4732 fp_drop(p, fd2, fp2, 0);
4733 error = EINVAL;
4734 goto outdrop;
4735 }
4736 if (dst_vp->v_mount != src_vp->v_mount) {
4737 vnode_put(src_vp);
4738 vnode_put(dst_vp);
4739 fp_drop(p, fd2, fp2, 0);
4740 error = EXDEV;
4741 goto outdrop;
4742 }
4743
4744 /* Verify that both vps point to files and not directories */
4745 if (!vnode_isreg(src_vp) || !vnode_isreg(dst_vp)) {
4746 error = EINVAL;
4747 vnode_put(src_vp);
4748 vnode_put(dst_vp);
4749 fp_drop(p, fd2, fp2, 0);
4750 goto outdrop;
4751 }
4752
4753
4754 /*
4755 * Okay, vps are legit. Check access. We'll require write access
4756 * to both files.
4757 */
4758 if (vnode_authorize(src_vp, NULLVP,
4759 (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), &context) != 0) {
4760 vnode_put(src_vp);
4761 vnode_put(dst_vp);
4762 fp_drop(p, fd2, fp2, 0);
4763 error = EBADF;
4764 goto outdrop;
4765 }
4766 if (vnode_authorize(dst_vp, NULLVP,
4767 (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), &context) != 0) {
4768 vnode_put(src_vp);
4769 vnode_put(dst_vp);
4770 fp_drop(p, fd2, fp2, 0);
4771 error = EBADF;
4772 goto outdrop;
4773 }
4774
4775 /* Pass it on through to the fs */
4776 error = VNOP_IOCTL(src_vp, cmd, (caddr_t)dst_vp, 0, &context);
4777
4778 vnode_put(src_vp);
4779 vnode_put(dst_vp);
4780 fp_drop(p, fd2, fp2, 0);
4781 break;
4782 }
4783
4784 /*
4785 * SPI for making a file compressed.
4786 */
4787 case F_MAKECOMPRESSED: {
4788 uint32_t gcounter = CAST_DOWN_EXPLICIT(uint32_t, uap->arg);
4789
4790 if (fp->f_type != DTYPE_VNODE) {
4791 error = EBADF;
4792 goto out;
4793 }
4794
4795 vp = (struct vnode*)fp_get_data(fp);
4796 proc_fdunlock(p);
4797
4798 /* get the vnode */
4799 if (vnode_getwithref(vp)) {
4800 error = ENOENT;
4801 goto outdrop;
4802 }
4803
4804 /* Is it a file? */
4805 if ((vnode_isreg(vp) == 0) && (vnode_islnk(vp) == 0)) {
4806 vnode_put(vp);
4807 error = EBADF;
4808 goto outdrop;
4809 }
4810
4811 /* invoke ioctl to pass off to FS */
4812 /* Only go forward if you have write access */
4813 vfs_context_t ctx = vfs_context_current();
4814 if (vnode_authorize(vp, NULLVP, (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), ctx) != 0) {
4815 vnode_put(vp);
4816 error = EBADF;
4817 goto outdrop;
4818 }
4819
4820 error = VNOP_IOCTL(vp, cmd, (caddr_t)&gcounter, 0, &context);
4821
4822 vnode_put(vp);
4823 break;
4824 }
4825
4826 /*
4827 * SPI (private) for indicating to a filesystem that subsequent writes to
4828 * the open FD will written to the Fastflow.
4829 */
4830 case F_SET_GREEDY_MODE:
4831 /* intentionally drop through to the same handler as F_SETSTATIC.
4832 * both fcntls should pass the argument and their selector into VNOP_IOCTL.
4833 */
4834
4835 /*
4836 * SPI (private) for indicating to a filesystem that subsequent writes to
4837 * the open FD will represent static content.
4838 */
4839 case F_SETSTATICCONTENT: {
4840 caddr_t ioctl_arg = NULL;
4841
4842 if (uap->arg) {
4843 ioctl_arg = (caddr_t) 1;
4844 }
4845
4846 if (fp->f_type != DTYPE_VNODE) {
4847 error = EBADF;
4848 goto out;
4849 }
4850 vp = (struct vnode *)fp_get_data(fp);
4851 proc_fdunlock(p);
4852
4853 error = vnode_getwithref(vp);
4854 if (error) {
4855 error = ENOENT;
4856 goto outdrop;
4857 }
4858
4859 /* Only go forward if you have write access */
4860 vfs_context_t ctx = vfs_context_current();
4861 if (vnode_authorize(vp, NULLVP, (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), ctx) != 0) {
4862 vnode_put(vp);
4863 error = EBADF;
4864 goto outdrop;
4865 }
4866
4867 error = VNOP_IOCTL(vp, cmd, ioctl_arg, 0, &context);
4868 (void)vnode_put(vp);
4869
4870 break;
4871 }
4872
4873 /*
4874 * SPI (private) for indicating to the lower level storage driver that the
4875 * subsequent writes should be of a particular IO type (burst, greedy, static),
4876 * or other flavors that may be necessary.
4877 */
4878 case F_SETIOTYPE: {
4879 caddr_t param_ptr;
4880 uint32_t param;
4881
4882 if (uap->arg) {
4883 /* extract 32 bits of flags from userland */
4884 param_ptr = (caddr_t) uap->arg;
4885 param = (uint32_t) param_ptr;
4886 } else {
4887 /* If no argument is specified, error out */
4888 error = EINVAL;
4889 goto out;
4890 }
4891
4892 /*
4893 * Validate the different types of flags that can be specified:
4894 * all of them are mutually exclusive for now.
4895 */
4896 switch (param) {
4897 case F_IOTYPE_ISOCHRONOUS:
4898 break;
4899
4900 default:
4901 error = EINVAL;
4902 goto out;
4903 }
4904
4905
4906 if (fp->f_type != DTYPE_VNODE) {
4907 error = EBADF;
4908 goto out;
4909 }
4910 vp = (struct vnode *)fp_get_data(fp);
4911 proc_fdunlock(p);
4912
4913 error = vnode_getwithref(vp);
4914 if (error) {
4915 error = ENOENT;
4916 goto outdrop;
4917 }
4918
4919 /* Only go forward if you have write access */
4920 vfs_context_t ctx = vfs_context_current();
4921 if (vnode_authorize(vp, NULLVP, (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), ctx) != 0) {
4922 vnode_put(vp);
4923 error = EBADF;
4924 goto outdrop;
4925 }
4926
4927 error = VNOP_IOCTL(vp, cmd, param_ptr, 0, &context);
4928 (void)vnode_put(vp);
4929
4930 break;
4931 }
4932
4933 /*
4934 * Set the vnode pointed to by 'fd'
4935 * and tag it as the (potentially future) backing store
4936 * for another filesystem
4937 */
4938 case F_SETBACKINGSTORE: {
4939 if (fp->f_type != DTYPE_VNODE) {
4940 error = EBADF;
4941 goto out;
4942 }
4943
4944 vp = (struct vnode *)fp_get_data(fp);
4945
4946 if (vp->v_tag != VT_HFS) {
4947 error = EINVAL;
4948 goto out;
4949 }
4950 proc_fdunlock(p);
4951
4952 if (vnode_getwithref(vp)) {
4953 error = ENOENT;
4954 goto outdrop;
4955 }
4956
4957 /* only proceed if you have write access */
4958 vfs_context_t ctx = vfs_context_current();
4959 if (vnode_authorize(vp, NULLVP, (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA), ctx) != 0) {
4960 vnode_put(vp);
4961 error = EBADF;
4962 goto outdrop;
4963 }
4964
4965
4966 /* If arg != 0, set, otherwise unset */
4967 if (uap->arg) {
4968 error = VNOP_IOCTL(vp, cmd, (caddr_t)1, 0, &context);
4969 } else {
4970 error = VNOP_IOCTL(vp, cmd, (caddr_t)NULL, 0, &context);
4971 }
4972
4973 vnode_put(vp);
4974 break;
4975 }
4976
4977 /*
4978 * like F_GETPATH, but special semantics for
4979 * the mobile time machine handler.
4980 */
4981 case F_GETPATH_MTMINFO: {
4982 char *pathbufp;
4983 int pathlen;
4984
4985 if (fp->f_type != DTYPE_VNODE) {
4986 error = EBADF;
4987 goto out;
4988 }
4989 vp = (struct vnode *)fp_get_data(fp);
4990 proc_fdunlock(p);
4991
4992 pathlen = MAXPATHLEN;
4993 pathbufp = zalloc(ZV_NAMEI);
4994
4995 if ((error = vnode_getwithref(vp)) == 0) {
4996 int backingstore = 0;
4997
4998 /* Check for error from vn_getpath before moving on */
4999 if ((error = vn_getpath(vp, pathbufp, &pathlen)) == 0) {
5000 if (vp->v_tag == VT_HFS) {
5001 error = VNOP_IOCTL(vp, cmd, (caddr_t) &backingstore, 0, &context);
5002 }
5003 (void)vnode_put(vp);
5004
5005 if (error == 0) {
5006 error = copyout((caddr_t)pathbufp, argp, pathlen);
5007 }
5008 if (error == 0) {
5009 /*
5010 * If the copyout was successful, now check to ensure
5011 * that this vnode is not a BACKINGSTORE vnode. mtmd
5012 * wants the path regardless.
5013 */
5014 if (backingstore) {
5015 error = EBUSY;
5016 }
5017 }
5018 } else {
5019 (void)vnode_put(vp);
5020 }
5021 }
5022
5023 zfree(ZV_NAMEI, pathbufp);
5024 goto outdrop;
5025 }
5026
5027 case F_RECYCLE: {
5028 #if !DEBUG && !DEVELOPMENT
5029 bool allowed = false;
5030
5031 //
5032 // non-debug and non-development kernels have restrictions
5033 // on who can all this fcntl. the process has to be marked
5034 // with the dataless-manipulator entitlement and either the
5035 // process or thread have to be marked rapid-aging.
5036 //
5037 if (!vfs_context_is_dataless_manipulator(&context)) {
5038 error = EPERM;
5039 goto out;
5040 }
5041
5042 proc_t proc = vfs_context_proc(&context);
5043 if (proc && (proc->p_lflag & P_LRAGE_VNODES)) {
5044 allowed = true;
5045 } else {
5046 thread_t thr = vfs_context_thread(&context);
5047 if (thr) {
5048 struct uthread *ut = get_bsdthread_info(thr);
5049
5050 if (ut && (ut->uu_flag & UT_RAGE_VNODES)) {
5051 allowed = true;
5052 }
5053 }
5054 }
5055 if (!allowed) {
5056 error = EPERM;
5057 goto out;
5058 }
5059 #endif
5060
5061 if (fp->f_type != DTYPE_VNODE) {
5062 error = EBADF;
5063 goto out;
5064 }
5065 vp = (struct vnode *)fp_get_data(fp);
5066 proc_fdunlock(p);
5067
5068 vnode_recycle(vp);
5069 break;
5070 }
5071
5072 #if CONFIG_FILE_LEASES
5073 case F_SETLEASE: {
5074 struct fileglob *fg;
5075 int fl_type;
5076 int expcounts;
5077
5078 if (fp->f_type != DTYPE_VNODE) {
5079 error = EBADF;
5080 goto out;
5081 }
5082 vp = (struct vnode *)fp_get_data(fp);
5083 fg = fp->fp_glob;;
5084 proc_fdunlock(p);
5085
5086 /*
5087 * In order to allow a process to avoid breaking
5088 * its own leases, the expected open count needs
5089 * to be provided to F_SETLEASE when placing write lease.
5090 * Similarly, in order to allow a process to place a read lease
5091 * after opening the file multiple times in RW mode, the expected
5092 * write count needs to be provided to F_SETLEASE when placing a
5093 * read lease.
5094 *
5095 * We use the upper 30 bits of the integer argument (way more than
5096 * enough) as the expected open/write count.
5097 *
5098 * If the caller passed 0 for the expected open count,
5099 * assume 1.
5100 */
5101 fl_type = CAST_DOWN_EXPLICIT(int, uap->arg);
5102 expcounts = (unsigned int)fl_type >> 2;
5103 fl_type &= 3;
5104
5105 if (fl_type == F_WRLCK && expcounts == 0) {
5106 expcounts = 1;
5107 }
5108
5109 AUDIT_ARG(value32, fl_type);
5110
5111 if ((error = vnode_getwithref(vp))) {
5112 goto outdrop;
5113 }
5114
5115 /*
5116 * Only support for regular file/dir mounted on local-based filesystem.
5117 */
5118 if ((vnode_vtype(vp) != VREG && vnode_vtype(vp) != VDIR) ||
5119 !(vfs_flags(vnode_mount(vp)) & MNT_LOCAL)) {
5120 error = EBADF;
5121 vnode_put(vp);
5122 goto outdrop;
5123 }
5124
5125 /* For directory, we only support read lease. */
5126 if (vnode_vtype(vp) == VDIR && fl_type == F_WRLCK) {
5127 error = ENOTSUP;
5128 vnode_put(vp);
5129 goto outdrop;
5130 }
5131
5132 switch (fl_type) {
5133 case F_RDLCK:
5134 case F_WRLCK:
5135 case F_UNLCK:
5136 error = vnode_setlease(vp, fg, fl_type, expcounts,
5137 vfs_context_current());
5138 break;
5139 default:
5140 error = EINVAL;
5141 break;
5142 }
5143
5144 vnode_put(vp);
5145 goto outdrop;
5146 }
5147
5148 case F_GETLEASE: {
5149 if (fp->f_type != DTYPE_VNODE) {
5150 error = EBADF;
5151 goto out;
5152 }
5153 vp = (struct vnode *)fp_get_data(fp);
5154 proc_fdunlock(p);
5155
5156 if ((error = vnode_getwithref(vp))) {
5157 goto outdrop;
5158 }
5159
5160 if ((vnode_vtype(vp) != VREG && vnode_vtype(vp) != VDIR) ||
5161 !(vfs_flags(vnode_mount(vp)) & MNT_LOCAL)) {
5162 error = EBADF;
5163 vnode_put(vp);
5164 goto outdrop;
5165 }
5166
5167 error = 0;
5168 *retval = vnode_getlease(vp);
5169 vnode_put(vp);
5170 goto outdrop;
5171 }
5172 #endif /* CONFIG_FILE_LEASES */
5173
5174 /* SPI (private) for asserting background access to a file */
5175 case F_ASSERT_BG_ACCESS:
5176 /* SPI (private) for releasing background access to a file */
5177 case F_RELEASE_BG_ACCESS: {
5178 /*
5179 * Check if the process is platform code, which means
5180 * that it is considered part of the Operating System.
5181 */
5182 if (!csproc_get_platform_binary(p)) {
5183 error = EPERM;
5184 goto out;
5185 }
5186
5187 if (fp->f_type != DTYPE_VNODE) {
5188 error = EBADF;
5189 goto out;
5190 }
5191
5192 vp = (struct vnode *)fp_get_data(fp);
5193 proc_fdunlock(p);
5194
5195 if (vnode_getwithref(vp)) {
5196 error = ENOENT;
5197 goto outdrop;
5198 }
5199
5200 /* Verify that vp points to a file and not a directory */
5201 if (!vnode_isreg(vp)) {
5202 vnode_put(vp);
5203 error = EINVAL;
5204 goto outdrop;
5205 }
5206
5207 /* Only proceed if you have read access */
5208 if (vnode_authorize(vp, NULLVP, (KAUTH_VNODE_ACCESS | KAUTH_VNODE_READ_DATA), &context) != 0) {
5209 vnode_put(vp);
5210 error = EBADF;
5211 goto outdrop;
5212 }
5213
5214 if (cmd == F_ASSERT_BG_ACCESS) {
5215 fassertbgaccess_t args;
5216
5217 if ((error = copyin(argp, (caddr_t)&args, sizeof(args)))) {
5218 vnode_put(vp);
5219 goto outdrop;
5220 }
5221
5222 error = VNOP_IOCTL(vp, F_ASSERT_BG_ACCESS, (caddr_t)&args, 0, &context);
5223 } else {
5224 // cmd == F_RELEASE_BG_ACCESS
5225 error = VNOP_IOCTL(vp, F_RELEASE_BG_ACCESS, (caddr_t)NULL, 0, &context);
5226 }
5227
5228 vnode_put(vp);
5229
5230 goto outdrop;
5231 }
5232
5233 default:
5234 /*
5235 * This is an fcntl() that we d not recognize at this level;
5236 * if this is a vnode, we send it down into the VNOP_IOCTL
5237 * for this vnode; this can include special devices, and will
5238 * effectively overload fcntl() to send ioctl()'s.
5239 */
5240 if ((cmd & IOC_VOID) && (cmd & IOC_INOUT)) {
5241 error = EINVAL;
5242 goto out;
5243 }
5244
5245 /*
5246 * Catch any now-invalid fcntl() selectors.
5247 * (When adding a selector to this list, it may be prudent
5248 * to consider adding it to the list in fsctl_internal() as well.)
5249 */
5250 switch (cmd) {
5251 case (int)APFSIOC_REVERT_TO_SNAPSHOT:
5252 case (int)FSIOC_FIOSEEKHOLE:
5253 case (int)FSIOC_FIOSEEKDATA:
5254 case (int)FSIOC_CAS_BSDFLAGS:
5255 case (int)FSIOC_KERNEL_ROOTAUTH:
5256 case (int)FSIOC_GRAFT_FS:
5257 case (int)FSIOC_UNGRAFT_FS:
5258 case (int)APFSIOC_IS_GRAFT_SUPPORTED:
5259 case (int)FSIOC_AUTH_FS:
5260 case HFS_GET_BOOT_INFO:
5261 case HFS_SET_BOOT_INFO:
5262 case FIOPINSWAP:
5263 case F_MARKDEPENDENCY:
5264 case TIOCREVOKE:
5265 case TIOCREVOKECLEAR:
5266 error = EINVAL;
5267 goto out;
5268 default:
5269 break;
5270 }
5271
5272 if (fp->f_type != DTYPE_VNODE) {
5273 error = EBADF;
5274 goto out;
5275 }
5276 vp = (struct vnode *)fp_get_data(fp);
5277 proc_fdunlock(p);
5278
5279 if ((error = vnode_getwithref(vp)) == 0) {
5280 #define STK_PARAMS 128
5281 char stkbuf[STK_PARAMS] = {0};
5282 unsigned int size;
5283 caddr_t data, memp;
5284 /*
5285 * For this to work properly, we have to copy in the
5286 * ioctl() cmd argument if there is one; we must also
5287 * check that a command parameter, if present, does
5288 * not exceed the maximum command length dictated by
5289 * the number of bits we have available in the command
5290 * to represent a structure length. Finally, we have
5291 * to copy the results back out, if it is that type of
5292 * ioctl().
5293 */
5294 size = IOCPARM_LEN(cmd);
5295 if (size > IOCPARM_MAX) {
5296 (void)vnode_put(vp);
5297 error = EINVAL;
5298 break;
5299 }
5300
5301 memp = NULL;
5302 if (size > sizeof(stkbuf)) {
5303 memp = (caddr_t)kalloc_data(size, Z_WAITOK);
5304 if (memp == 0) {
5305 (void)vnode_put(vp);
5306 error = ENOMEM;
5307 goto outdrop;
5308 }
5309 data = memp;
5310 } else {
5311 data = &stkbuf[0];
5312 }
5313
5314 if (cmd & IOC_IN) {
5315 if (size) {
5316 /* structure */
5317 error = copyin(argp, data, size);
5318 if (error) {
5319 (void)vnode_put(vp);
5320 if (memp) {
5321 kfree_data(memp, size);
5322 }
5323 goto outdrop;
5324 }
5325
5326 /* Bzero the section beyond that which was needed */
5327 if (size <= sizeof(stkbuf)) {
5328 bzero((((uint8_t*)data) + size), (sizeof(stkbuf) - size));
5329 }
5330 } else {
5331 /* int */
5332 if (is64bit) {
5333 *(user_addr_t *)data = argp;
5334 } else {
5335 *(uint32_t *)data = (uint32_t)argp;
5336 }
5337 };
5338 } else if ((cmd & IOC_OUT) && size) {
5339 /*
5340 * Zero the buffer so the user always
5341 * gets back something deterministic.
5342 */
5343 bzero(data, size);
5344 } else if (cmd & IOC_VOID) {
5345 if (is64bit) {
5346 *(user_addr_t *)data = argp;
5347 } else {
5348 *(uint32_t *)data = (uint32_t)argp;
5349 }
5350 }
5351
5352 error = VNOP_IOCTL(vp, cmd, CAST_DOWN(caddr_t, data), 0, &context);
5353
5354 (void)vnode_put(vp);
5355
5356 /* Copy any output data to user */
5357 if (error == 0 && (cmd & IOC_OUT) && size) {
5358 error = copyout(data, argp, size);
5359 }
5360 if (memp) {
5361 kfree_data(memp, size);
5362 }
5363 }
5364 break;
5365 }
5366
5367 outdrop:
5368 return sys_fcntl_outdrop(p, fd, fp, vp, error);
5369
5370 out:
5371 return sys_fcntl_out(p, fd, fp, error);
5372 }
5373
5374
5375 /*
5376 * sys_close
5377 *
5378 * Description: The implementation of the close(2) system call
5379 *
5380 * Parameters: p Process in whose per process file table
5381 * the close is to occur
5382 * uap->fd fd to be closed
5383 * retval <unused>
5384 *
5385 * Returns: 0 Success
5386 * fp_lookup:EBADF Bad file descriptor
5387 * fp_guard_exception:??? Guarded file descriptor
5388 * close_internal:EBADF
5389 * close_internal:??? Anything returnable by a per-fileops
5390 * close function
5391 */
5392 int
sys_close(proc_t p,struct close_args * uap,__unused int32_t * retval)5393 sys_close(proc_t p, struct close_args *uap, __unused int32_t *retval)
5394 {
5395 kauth_cred_t p_cred = current_cached_proc_cred(p);
5396
5397 __pthread_testcancel(1);
5398 return close_nocancel(p, p_cred, uap->fd);
5399 }
5400
5401 int
sys_close_nocancel(proc_t p,struct close_nocancel_args * uap,__unused int32_t * retval)5402 sys_close_nocancel(proc_t p, struct close_nocancel_args *uap, __unused int32_t *retval)
5403 {
5404 kauth_cred_t p_cred = current_cached_proc_cred(p);
5405
5406 return close_nocancel(p, p_cred, uap->fd);
5407 }
5408
5409 int
close_nocancel(proc_t p,kauth_cred_t p_cred,int fd)5410 close_nocancel(proc_t p, kauth_cred_t p_cred, int fd)
5411 {
5412 struct fileproc *fp;
5413
5414 AUDIT_SYSCLOSE(p, fd);
5415
5416 proc_fdlock(p);
5417 if ((fp = fp_get_noref_locked(p, fd)) == NULL) {
5418 proc_fdunlock(p);
5419 return EBADF;
5420 }
5421
5422 if (fp_isguarded(fp, GUARD_CLOSE)) {
5423 int error = fp_guard_exception(p, fd, fp, kGUARD_EXC_CLOSE);
5424 proc_fdunlock(p);
5425 return error;
5426 }
5427
5428 return fp_close_and_unlock(p, p_cred, fd, fp, 0);
5429 }
5430
5431
5432 /*
5433 * fstat
5434 *
5435 * Description: Return status information about a file descriptor.
5436 *
5437 * Parameters: p The process doing the fstat
5438 * fd The fd to stat
5439 * ub The user stat buffer
5440 * xsecurity The user extended security
5441 * buffer, or 0 if none
5442 * xsecurity_size The size of xsecurity, or 0
5443 * if no xsecurity
5444 * isstat64 Flag to indicate 64 bit version
5445 * for inode size, etc.
5446 *
5447 * Returns: 0 Success
5448 * EBADF
5449 * EFAULT
5450 * fp_lookup:EBADF Bad file descriptor
5451 * vnode_getwithref:???
5452 * copyout:EFAULT
5453 * vnode_getwithref:???
5454 * vn_stat:???
5455 * soo_stat:???
5456 * pipe_stat:???
5457 * pshm_stat:???
5458 * kqueue_stat:???
5459 *
5460 * Notes: Internal implementation for all other fstat() related
5461 * functions
5462 *
5463 * XXX switch on node type is bogus; need a stat in struct
5464 * XXX fileops instead.
5465 */
5466 static int
fstat(proc_t p,int fd,user_addr_t ub,user_addr_t xsecurity,user_addr_t xsecurity_size,int isstat64)5467 fstat(proc_t p, int fd, user_addr_t ub, user_addr_t xsecurity,
5468 user_addr_t xsecurity_size, int isstat64)
5469 {
5470 struct fileproc *fp;
5471 union {
5472 struct stat sb;
5473 struct stat64 sb64;
5474 } source;
5475 union {
5476 struct user64_stat user64_sb;
5477 struct user32_stat user32_sb;
5478 struct user64_stat64 user64_sb64;
5479 struct user32_stat64 user32_sb64;
5480 } dest;
5481 int error, my_size;
5482 file_type_t type;
5483 caddr_t data;
5484 kauth_filesec_t fsec;
5485 user_size_t xsecurity_bufsize;
5486 vfs_context_t ctx = vfs_context_current();
5487 void * sbptr;
5488
5489
5490 AUDIT_ARG(fd, fd);
5491
5492 if ((error = fp_lookup(p, fd, &fp, 0)) != 0) {
5493 return error;
5494 }
5495 type = fp->f_type;
5496 data = (caddr_t)fp_get_data(fp);
5497 fsec = KAUTH_FILESEC_NONE;
5498
5499 sbptr = (void *)&source;
5500
5501 switch (type) {
5502 case DTYPE_VNODE:
5503 if ((error = vnode_getwithref((vnode_t)data)) == 0) {
5504 /*
5505 * If the caller has the file open for reading, and is
5506 * not requesting extended security information, we are
5507 * going to let them get the basic stat information.
5508 */
5509 if ((fp->f_flag & FREAD) && (xsecurity == USER_ADDR_NULL)) {
5510 error = vn_stat_noauth((vnode_t)data, sbptr, NULL, isstat64, 0, ctx,
5511 fp->fp_glob->fg_cred);
5512 } else {
5513 error = vn_stat((vnode_t)data, sbptr, &fsec, isstat64, 0, ctx);
5514 }
5515
5516 AUDIT_ARG(vnpath, (struct vnode *)data, ARG_VNODE1);
5517 (void)vnode_put((vnode_t)data);
5518 }
5519 break;
5520
5521 #if SOCKETS
5522 case DTYPE_SOCKET:
5523 error = soo_stat((struct socket *)data, sbptr, isstat64);
5524 break;
5525 #endif /* SOCKETS */
5526
5527 case DTYPE_PIPE:
5528 error = pipe_stat((void *)data, sbptr, isstat64);
5529 break;
5530
5531 case DTYPE_PSXSHM:
5532 error = pshm_stat((void *)data, sbptr, isstat64);
5533 break;
5534
5535 case DTYPE_KQUEUE:
5536 error = kqueue_stat((void *)data, sbptr, isstat64, p);
5537 break;
5538
5539 default:
5540 error = EBADF;
5541 goto out;
5542 }
5543 if (error == 0) {
5544 caddr_t sbp;
5545
5546 if (isstat64 != 0) {
5547 source.sb64.st_lspare = 0;
5548 source.sb64.st_qspare[0] = 0LL;
5549 source.sb64.st_qspare[1] = 0LL;
5550
5551 if (IS_64BIT_PROCESS(p)) {
5552 munge_user64_stat64(&source.sb64, &dest.user64_sb64);
5553 my_size = sizeof(dest.user64_sb64);
5554 sbp = (caddr_t)&dest.user64_sb64;
5555 } else {
5556 munge_user32_stat64(&source.sb64, &dest.user32_sb64);
5557 my_size = sizeof(dest.user32_sb64);
5558 sbp = (caddr_t)&dest.user32_sb64;
5559 }
5560 } else {
5561 source.sb.st_lspare = 0;
5562 source.sb.st_qspare[0] = 0LL;
5563 source.sb.st_qspare[1] = 0LL;
5564 if (IS_64BIT_PROCESS(p)) {
5565 munge_user64_stat(&source.sb, &dest.user64_sb);
5566 my_size = sizeof(dest.user64_sb);
5567 sbp = (caddr_t)&dest.user64_sb;
5568 } else {
5569 munge_user32_stat(&source.sb, &dest.user32_sb);
5570 my_size = sizeof(dest.user32_sb);
5571 sbp = (caddr_t)&dest.user32_sb;
5572 }
5573 }
5574
5575 error = copyout(sbp, ub, my_size);
5576 }
5577
5578 /* caller wants extended security information? */
5579 if (xsecurity != USER_ADDR_NULL) {
5580 /* did we get any? */
5581 if (fsec == KAUTH_FILESEC_NONE) {
5582 if (susize(xsecurity_size, 0) != 0) {
5583 error = EFAULT;
5584 goto out;
5585 }
5586 } else {
5587 /* find the user buffer size */
5588 xsecurity_bufsize = fusize(xsecurity_size);
5589
5590 /* copy out the actual data size */
5591 if (susize(xsecurity_size, KAUTH_FILESEC_COPYSIZE(fsec)) != 0) {
5592 error = EFAULT;
5593 goto out;
5594 }
5595
5596 /* if the caller supplied enough room, copy out to it */
5597 if (xsecurity_bufsize >= KAUTH_FILESEC_COPYSIZE(fsec)) {
5598 error = copyout(fsec, xsecurity, KAUTH_FILESEC_COPYSIZE(fsec));
5599 }
5600 }
5601 }
5602 out:
5603 fp_drop(p, fd, fp, 0);
5604 if (fsec != NULL) {
5605 kauth_filesec_free(fsec);
5606 }
5607 return error;
5608 }
5609
5610
5611 /*
5612 * sys_fstat_extended
5613 *
5614 * Description: Extended version of fstat supporting returning extended
5615 * security information
5616 *
5617 * Parameters: p The process doing the fstat
5618 * uap->fd The fd to stat
5619 * uap->ub The user stat buffer
5620 * uap->xsecurity The user extended security
5621 * buffer, or 0 if none
5622 * uap->xsecurity_size The size of xsecurity, or 0
5623 *
5624 * Returns: 0 Success
5625 * !0 Errno (see fstat)
5626 */
5627 int
sys_fstat_extended(proc_t p,struct fstat_extended_args * uap,__unused int32_t * retval)5628 sys_fstat_extended(proc_t p, struct fstat_extended_args *uap, __unused int32_t *retval)
5629 {
5630 return fstat(p, uap->fd, uap->ub, uap->xsecurity, uap->xsecurity_size, 0);
5631 }
5632
5633
5634 /*
5635 * sys_fstat
5636 *
5637 * Description: Get file status for the file associated with fd
5638 *
5639 * Parameters: p The process doing the fstat
5640 * uap->fd The fd to stat
5641 * uap->ub The user stat buffer
5642 *
5643 * Returns: 0 Success
5644 * !0 Errno (see fstat)
5645 */
5646 int
sys_fstat(proc_t p,struct fstat_args * uap,__unused int32_t * retval)5647 sys_fstat(proc_t p, struct fstat_args *uap, __unused int32_t *retval)
5648 {
5649 return fstat(p, uap->fd, uap->ub, 0, 0, 0);
5650 }
5651
5652
5653 /*
5654 * sys_fstat64_extended
5655 *
5656 * Description: Extended version of fstat64 supporting returning extended
5657 * security information
5658 *
5659 * Parameters: p The process doing the fstat
5660 * uap->fd The fd to stat
5661 * uap->ub The user stat buffer
5662 * uap->xsecurity The user extended security
5663 * buffer, or 0 if none
5664 * uap->xsecurity_size The size of xsecurity, or 0
5665 *
5666 * Returns: 0 Success
5667 * !0 Errno (see fstat)
5668 */
5669 int
sys_fstat64_extended(proc_t p,struct fstat64_extended_args * uap,__unused int32_t * retval)5670 sys_fstat64_extended(proc_t p, struct fstat64_extended_args *uap, __unused int32_t *retval)
5671 {
5672 return fstat(p, uap->fd, uap->ub, uap->xsecurity, uap->xsecurity_size, 1);
5673 }
5674
5675
5676 /*
5677 * sys_fstat64
5678 *
5679 * Description: Get 64 bit version of the file status for the file associated
5680 * with fd
5681 *
5682 * Parameters: p The process doing the fstat
5683 * uap->fd The fd to stat
5684 * uap->ub The user stat buffer
5685 *
5686 * Returns: 0 Success
5687 * !0 Errno (see fstat)
5688 */
5689 int
sys_fstat64(proc_t p,struct fstat64_args * uap,__unused int32_t * retval)5690 sys_fstat64(proc_t p, struct fstat64_args *uap, __unused int32_t *retval)
5691 {
5692 return fstat(p, uap->fd, uap->ub, 0, 0, 1);
5693 }
5694
5695
5696 /*
5697 * sys_fpathconf
5698 *
5699 * Description: Return pathconf information about a file descriptor.
5700 *
5701 * Parameters: p Process making the request
5702 * uap->fd fd to get information about
5703 * uap->name Name of information desired
5704 * retval Pointer to the call return area
5705 *
5706 * Returns: 0 Success
5707 * EINVAL
5708 * fp_lookup:EBADF Bad file descriptor
5709 * vnode_getwithref:???
5710 * vn_pathconf:???
5711 *
5712 * Implicit returns:
5713 * *retval (modified) Returned information (numeric)
5714 */
5715 int
sys_fpathconf(proc_t p,struct fpathconf_args * uap,int32_t * retval)5716 sys_fpathconf(proc_t p, struct fpathconf_args *uap, int32_t *retval)
5717 {
5718 int fd = uap->fd;
5719 struct fileproc *fp;
5720 struct vnode *vp;
5721 int error = 0;
5722 file_type_t type;
5723
5724
5725 AUDIT_ARG(fd, uap->fd);
5726 if ((error = fp_lookup(p, fd, &fp, 0))) {
5727 return error;
5728 }
5729 type = fp->f_type;
5730
5731 switch (type) {
5732 case DTYPE_SOCKET:
5733 if (uap->name != _PC_PIPE_BUF) {
5734 error = EINVAL;
5735 goto out;
5736 }
5737 *retval = PIPE_BUF;
5738 error = 0;
5739 goto out;
5740
5741 case DTYPE_PIPE:
5742 if (uap->name != _PC_PIPE_BUF) {
5743 error = EINVAL;
5744 goto out;
5745 }
5746 *retval = PIPE_BUF;
5747 error = 0;
5748 goto out;
5749
5750 case DTYPE_VNODE:
5751 vp = (struct vnode *)fp_get_data(fp);
5752
5753 if ((error = vnode_getwithref(vp)) == 0) {
5754 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
5755
5756 error = vn_pathconf(vp, uap->name, retval, vfs_context_current());
5757
5758 (void)vnode_put(vp);
5759 }
5760 goto out;
5761
5762 default:
5763 error = EINVAL;
5764 goto out;
5765 }
5766 /*NOTREACHED*/
5767 out:
5768 fp_drop(p, fd, fp, 0);
5769 return error;
5770 }
5771
5772 /*
5773 * sys_flock
5774 *
5775 * Description: Apply an advisory lock on a file descriptor.
5776 *
5777 * Parameters: p Process making request
5778 * uap->fd fd on which the lock is to be
5779 * attempted
5780 * uap->how (Un)Lock bits, including type
5781 * retval Pointer to the call return area
5782 *
5783 * Returns: 0 Success
5784 * fp_getfvp:EBADF Bad file descriptor
5785 * fp_getfvp:ENOTSUP fd does not refer to a vnode
5786 * vnode_getwithref:???
5787 * VNOP_ADVLOCK:???
5788 *
5789 * Implicit returns:
5790 * *retval (modified) Size of dtable
5791 *
5792 * Notes: Just attempt to get a record lock of the requested type on
5793 * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
5794 */
5795 int
sys_flock(proc_t p,struct flock_args * uap,__unused int32_t * retval)5796 sys_flock(proc_t p, struct flock_args *uap, __unused int32_t *retval)
5797 {
5798 int fd = uap->fd;
5799 int how = uap->how;
5800 struct fileproc *fp;
5801 struct vnode *vp;
5802 struct flock lf;
5803 vfs_context_t ctx = vfs_context_current();
5804 int error = 0;
5805
5806 AUDIT_ARG(fd, uap->fd);
5807 if ((error = fp_getfvp(p, fd, &fp, &vp))) {
5808 return error;
5809 }
5810 if ((error = vnode_getwithref(vp))) {
5811 goto out1;
5812 }
5813 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
5814
5815 lf.l_whence = SEEK_SET;
5816 lf.l_start = 0;
5817 lf.l_len = 0;
5818 if (how & LOCK_UN) {
5819 lf.l_type = F_UNLCK;
5820 error = VNOP_ADVLOCK(vp, (caddr_t)fp->fp_glob, F_UNLCK, &lf, F_FLOCK, ctx, NULL);
5821 goto out;
5822 }
5823 if (how & LOCK_EX) {
5824 lf.l_type = F_WRLCK;
5825 } else if (how & LOCK_SH) {
5826 lf.l_type = F_RDLCK;
5827 } else {
5828 error = EBADF;
5829 goto out;
5830 }
5831 #if CONFIG_MACF
5832 error = mac_file_check_lock(kauth_cred_get(), fp->fp_glob, F_SETLK, &lf);
5833 if (error) {
5834 goto out;
5835 }
5836 #endif
5837 error = VNOP_ADVLOCK(vp, (caddr_t)fp->fp_glob, F_SETLK, &lf,
5838 (how & LOCK_NB ? F_FLOCK : F_FLOCK | F_WAIT),
5839 ctx, NULL);
5840 if (!error) {
5841 os_atomic_or(&fp->fp_glob->fg_flag, FWASLOCKED, relaxed);
5842 }
5843 out:
5844 (void)vnode_put(vp);
5845 out1:
5846 fp_drop(p, fd, fp, 0);
5847 return error;
5848 }
5849
5850 /*
5851 * sys_fileport_makeport
5852 *
5853 * Description: Obtain a Mach send right for a given file descriptor.
5854 *
5855 * Parameters: p Process calling fileport
5856 * uap->fd The fd to reference
5857 * uap->portnamep User address at which to place port name.
5858 *
5859 * Returns: 0 Success.
5860 * EBADF Bad file descriptor.
5861 * EINVAL File descriptor had type that cannot be sent, misc. other errors.
5862 * EFAULT Address at which to store port name is not valid.
5863 * EAGAIN Resource shortage.
5864 *
5865 * Implicit returns:
5866 * On success, name of send right is stored at user-specified address.
5867 */
5868 int
sys_fileport_makeport(proc_t p,struct fileport_makeport_args * uap,__unused int * retval)5869 sys_fileport_makeport(proc_t p, struct fileport_makeport_args *uap,
5870 __unused int *retval)
5871 {
5872 int err;
5873 int fd = uap->fd;
5874 user_addr_t user_portaddr = uap->portnamep;
5875 struct fileproc *fp = FILEPROC_NULL;
5876 struct fileglob *fg = NULL;
5877 ipc_port_t fileport;
5878 mach_port_name_t name = MACH_PORT_NULL;
5879
5880 proc_fdlock(p);
5881 err = fp_lookup(p, fd, &fp, 1);
5882 if (err != 0) {
5883 goto out_unlock;
5884 }
5885
5886 fg = fp->fp_glob;
5887 if (!fg_sendable(fg)) {
5888 err = EINVAL;
5889 goto out_unlock;
5890 }
5891
5892 if (fp_isguarded(fp, GUARD_FILEPORT)) {
5893 err = fp_guard_exception(p, fd, fp, kGUARD_EXC_FILEPORT);
5894 goto out_unlock;
5895 }
5896
5897 /* Dropped when port is deallocated */
5898 fg_ref(p, fg);
5899
5900 proc_fdunlock(p);
5901
5902 /* Allocate and initialize a port */
5903 fileport = fileport_alloc(fg);
5904 if (fileport == IPC_PORT_NULL) {
5905 fg_drop_live(fg);
5906 err = EAGAIN;
5907 goto out;
5908 }
5909
5910 /* Add an entry. Deallocates port on failure. */
5911 name = ipc_port_copyout_send(fileport, get_task_ipcspace(proc_task(p)));
5912 if (!MACH_PORT_VALID(name)) {
5913 err = EINVAL;
5914 goto out;
5915 }
5916
5917 err = copyout(&name, user_portaddr, sizeof(mach_port_name_t));
5918 if (err != 0) {
5919 goto out;
5920 }
5921
5922 /* Tag the fileglob for debugging purposes */
5923 lck_mtx_lock_spin(&fg->fg_lock);
5924 fg->fg_lflags |= FG_PORTMADE;
5925 lck_mtx_unlock(&fg->fg_lock);
5926
5927 fp_drop(p, fd, fp, 0);
5928
5929 return 0;
5930
5931 out_unlock:
5932 proc_fdunlock(p);
5933 out:
5934 if (MACH_PORT_VALID(name)) {
5935 /* Don't care if another thread races us to deallocate the entry */
5936 (void) mach_port_deallocate(get_task_ipcspace(proc_task(p)), name);
5937 }
5938
5939 if (fp != FILEPROC_NULL) {
5940 fp_drop(p, fd, fp, 0);
5941 }
5942
5943 return err;
5944 }
5945
5946 void
fileport_releasefg(struct fileglob * fg)5947 fileport_releasefg(struct fileglob *fg)
5948 {
5949 (void)fg_drop(FG_NOPROC, fg);
5950 }
5951
5952 /*
5953 * fileport_makefd
5954 *
5955 * Description: Obtain the file descriptor for a given Mach send right.
5956 *
5957 * Returns: 0 Success
5958 * EINVAL Invalid Mach port name, or port is not for a file.
5959 * fdalloc:EMFILE
5960 * fdalloc:ENOMEM Unable to allocate fileproc or extend file table.
5961 *
5962 * Implicit returns:
5963 * *retval (modified) The new descriptor
5964 */
5965 int
fileport_makefd(proc_t p,ipc_port_t port,fileproc_flags_t fp_flags,int * retval)5966 fileport_makefd(proc_t p, ipc_port_t port, fileproc_flags_t fp_flags, int *retval)
5967 {
5968 struct fileglob *fg;
5969 struct fileproc *fp = FILEPROC_NULL;
5970 int fd;
5971 int err;
5972
5973 fg = fileport_port_to_fileglob(port);
5974 if (fg == NULL) {
5975 err = EINVAL;
5976 goto out;
5977 }
5978
5979 fp = fileproc_alloc_init();
5980
5981 proc_fdlock(p);
5982 err = fdalloc(p, 0, &fd);
5983 if (err != 0) {
5984 proc_fdunlock(p);
5985 goto out;
5986 }
5987 if (fp_flags) {
5988 fp->fp_flags |= fp_flags;
5989 }
5990
5991 fp->fp_glob = fg;
5992 fg_ref(p, fg);
5993
5994 procfdtbl_releasefd(p, fd, fp);
5995 proc_fdunlock(p);
5996
5997 *retval = fd;
5998 err = 0;
5999 out:
6000 if ((fp != NULL) && (0 != err)) {
6001 fileproc_free(fp);
6002 }
6003
6004 return err;
6005 }
6006
6007 /*
6008 * sys_fileport_makefd
6009 *
6010 * Description: Obtain the file descriptor for a given Mach send right.
6011 *
6012 * Parameters: p Process calling fileport
6013 * uap->port Name of send right to file port.
6014 *
6015 * Returns: 0 Success
6016 * EINVAL Invalid Mach port name, or port is not for a file.
6017 * fdalloc:EMFILE
6018 * fdalloc:ENOMEM Unable to allocate fileproc or extend file table.
6019 *
6020 * Implicit returns:
6021 * *retval (modified) The new descriptor
6022 */
6023 int
sys_fileport_makefd(proc_t p,struct fileport_makefd_args * uap,int32_t * retval)6024 sys_fileport_makefd(proc_t p, struct fileport_makefd_args *uap, int32_t *retval)
6025 {
6026 ipc_port_t port = IPC_PORT_NULL;
6027 mach_port_name_t send = uap->port;
6028 kern_return_t res;
6029 int err;
6030
6031 res = ipc_typed_port_copyin_send(get_task_ipcspace(proc_task(p)),
6032 send, IKOT_FILEPORT, &port);
6033
6034 if (res == KERN_SUCCESS) {
6035 err = fileport_makefd(p, port, FP_CLOEXEC, retval);
6036 } else {
6037 err = EINVAL;
6038 }
6039
6040 if (IPC_PORT_NULL != port) {
6041 ipc_typed_port_release_send(port, IKOT_FILEPORT);
6042 }
6043
6044 return err;
6045 }
6046
6047
6048 #pragma mark fileops wrappers
6049
6050 /*
6051 * fo_read
6052 *
6053 * Description: Generic fileops read indirected through the fileops pointer
6054 * in the fileproc structure
6055 *
6056 * Parameters: fp fileproc structure pointer
6057 * uio user I/O structure pointer
6058 * flags FOF_ flags
6059 * ctx VFS context for operation
6060 *
6061 * Returns: 0 Success
6062 * !0 Errno from read
6063 */
6064 int
fo_read(struct fileproc * fp,struct uio * uio,int flags,vfs_context_t ctx)6065 fo_read(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
6066 {
6067 return (*fp->f_ops->fo_read)(fp, uio, flags, ctx);
6068 }
6069
6070 int
fo_no_read(struct fileproc * fp,struct uio * uio,int flags,vfs_context_t ctx)6071 fo_no_read(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
6072 {
6073 #pragma unused(fp, uio, flags, ctx)
6074 return ENXIO;
6075 }
6076
6077
6078 /*
6079 * fo_write
6080 *
6081 * Description: Generic fileops write indirected through the fileops pointer
6082 * in the fileproc structure
6083 *
6084 * Parameters: fp fileproc structure pointer
6085 * uio user I/O structure pointer
6086 * flags FOF_ flags
6087 * ctx VFS context for operation
6088 *
6089 * Returns: 0 Success
6090 * !0 Errno from write
6091 */
6092 int
fo_write(struct fileproc * fp,struct uio * uio,int flags,vfs_context_t ctx)6093 fo_write(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
6094 {
6095 return (*fp->f_ops->fo_write)(fp, uio, flags, ctx);
6096 }
6097
6098 int
fo_no_write(struct fileproc * fp,struct uio * uio,int flags,vfs_context_t ctx)6099 fo_no_write(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
6100 {
6101 #pragma unused(fp, uio, flags, ctx)
6102 return ENXIO;
6103 }
6104
6105
6106 /*
6107 * fo_ioctl
6108 *
6109 * Description: Generic fileops ioctl indirected through the fileops pointer
6110 * in the fileproc structure
6111 *
6112 * Parameters: fp fileproc structure pointer
6113 * com ioctl command
6114 * data pointer to internalized copy
6115 * of user space ioctl command
6116 * parameter data in kernel space
6117 * ctx VFS context for operation
6118 *
6119 * Returns: 0 Success
6120 * !0 Errno from ioctl
6121 *
6122 * Locks: The caller is assumed to have held the proc_fdlock; this
6123 * function releases and reacquires this lock. If the caller
6124 * accesses data protected by this lock prior to calling this
6125 * function, it will need to revalidate/reacquire any cached
6126 * protected data obtained prior to the call.
6127 */
6128 int
fo_ioctl(struct fileproc * fp,u_long com,caddr_t data,vfs_context_t ctx)6129 fo_ioctl(struct fileproc *fp, u_long com, caddr_t data, vfs_context_t ctx)
6130 {
6131 int error;
6132
6133 proc_fdunlock(vfs_context_proc(ctx));
6134 error = (*fp->f_ops->fo_ioctl)(fp, com, data, ctx);
6135 proc_fdlock(vfs_context_proc(ctx));
6136 return error;
6137 }
6138
6139 int
fo_no_ioctl(struct fileproc * fp,u_long com,caddr_t data,vfs_context_t ctx)6140 fo_no_ioctl(struct fileproc *fp, u_long com, caddr_t data, vfs_context_t ctx)
6141 {
6142 #pragma unused(fp, com, data, ctx)
6143 return ENOTTY;
6144 }
6145
6146
6147 /*
6148 * fo_select
6149 *
6150 * Description: Generic fileops select indirected through the fileops pointer
6151 * in the fileproc structure
6152 *
6153 * Parameters: fp fileproc structure pointer
6154 * which select which
6155 * wql pointer to wait queue list
6156 * ctx VFS context for operation
6157 *
6158 * Returns: 0 Success
6159 * !0 Errno from select
6160 */
6161 int
fo_select(struct fileproc * fp,int which,void * wql,vfs_context_t ctx)6162 fo_select(struct fileproc *fp, int which, void *wql, vfs_context_t ctx)
6163 {
6164 return (*fp->f_ops->fo_select)(fp, which, wql, ctx);
6165 }
6166
6167 int
fo_no_select(struct fileproc * fp,int which,void * wql,vfs_context_t ctx)6168 fo_no_select(struct fileproc *fp, int which, void *wql, vfs_context_t ctx)
6169 {
6170 #pragma unused(fp, which, wql, ctx)
6171 return ENOTSUP;
6172 }
6173
6174
6175 /*
6176 * fo_close
6177 *
6178 * Description: Generic fileops close indirected through the fileops pointer
6179 * in the fileproc structure
6180 *
6181 * Parameters: fp fileproc structure pointer for
6182 * file to close
6183 * ctx VFS context for operation
6184 *
6185 * Returns: 0 Success
6186 * !0 Errno from close
6187 */
6188 int
fo_close(struct fileglob * fg,vfs_context_t ctx)6189 fo_close(struct fileglob *fg, vfs_context_t ctx)
6190 {
6191 return (*fg->fg_ops->fo_close)(fg, ctx);
6192 }
6193
6194
6195 /*
6196 * fo_drain
6197 *
6198 * Description: Generic fileops kqueue filter indirected through the fileops
6199 * pointer in the fileproc structure
6200 *
6201 * Parameters: fp fileproc structure pointer
6202 * ctx VFS context for operation
6203 *
6204 * Returns: 0 Success
6205 * !0 errno from drain
6206 */
6207 int
fo_drain(struct fileproc * fp,vfs_context_t ctx)6208 fo_drain(struct fileproc *fp, vfs_context_t ctx)
6209 {
6210 return (*fp->f_ops->fo_drain)(fp, ctx);
6211 }
6212
6213 int
fo_no_drain(struct fileproc * fp,vfs_context_t ctx)6214 fo_no_drain(struct fileproc *fp, vfs_context_t ctx)
6215 {
6216 #pragma unused(fp, ctx)
6217 return ENOTSUP;
6218 }
6219
6220
6221 /*
6222 * fo_kqfilter
6223 *
6224 * Description: Generic fileops kqueue filter indirected through the fileops
6225 * pointer in the fileproc structure
6226 *
6227 * Parameters: fp fileproc structure pointer
6228 * kn pointer to knote to filter on
6229 *
6230 * Returns: (kn->kn_flags & EV_ERROR) error in kn->kn_data
6231 * 0 Filter is not active
6232 * !0 Filter is active
6233 */
6234 int
fo_kqfilter(struct fileproc * fp,struct knote * kn,struct kevent_qos_s * kev)6235 fo_kqfilter(struct fileproc *fp, struct knote *kn, struct kevent_qos_s *kev)
6236 {
6237 return (*fp->f_ops->fo_kqfilter)(fp, kn, kev);
6238 }
6239
6240 int
fo_no_kqfilter(struct fileproc * fp,struct knote * kn,struct kevent_qos_s * kev)6241 fo_no_kqfilter(struct fileproc *fp, struct knote *kn, struct kevent_qos_s *kev)
6242 {
6243 #pragma unused(fp, kev)
6244 knote_set_error(kn, ENOTSUP);
6245 return 0;
6246 }
6247