xref: /xnu-12377.61.12/bsd/vfs/vfs_xattr.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1 /*
2  * Copyright (c) 2004-2012 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 /*
29  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
30  * support for mandatory and extensible security protections.  This notice
31  * is included in support of clause 2.2 (b) of the Apple Public License,
32  * Version 2.0.
33  */
34 
35 #include <sys/param.h>
36 
37 #include <sys/fcntl.h>
38 #include <sys/file_internal.h>
39 #include <sys/fsevents.h>
40 #include <sys/kernel.h>
41 #include <sys/kauth.h>
42 #include <sys/mount_internal.h>
43 #include <sys/namei.h>
44 #include <sys/proc_internal.h>
45 #include <sys/stat.h>
46 #include <sys/uio.h>
47 #include <sys/utfconv.h>
48 #include <sys/vnode.h>
49 #include <sys/vnode_internal.h>
50 #include <sys/xattr.h>
51 
52 #include <kern/kalloc.h>
53 #include <kern/kern_types.h>
54 #include <kern/host.h>
55 #include <kern/ipc_misc.h>
56 
57 #include <mach/doubleagent_mig_server.h>
58 #include <mach/doubleagent_types.h>
59 #include <mach/host_priv.h>
60 #include <mach/host_special_ports.h>
61 
62 #include <libkern/OSByteOrder.h>
63 #include <vm/vm_kern.h>
64 #include <vm/vm_protos.h>       /* XXX for ipc_port_release_send() */
65 
66 #if CONFIG_MACF
67 #include <security/mac_framework.h>
68 #endif
69 
70 
71 #if NAMEDSTREAMS
72 
73 static int shadow_sequence;
74 
75 /*
76  * We use %p to prevent loss of precision for pointers on varying architectures.
77  */
78 
79 #define SHADOW_NAME_FMT         ".vfs_rsrc_stream_%p%08x%p"
80 #define SHADOW_DIR_FMT          ".vfs_rsrc_streams_%p%x"
81 #define SHADOW_DIR_CONTAINER    "/private/var/run"
82 
83 #define MAKE_SHADOW_NAME(VP, NAME)  \
84 	snprintf((NAME), sizeof((NAME)), (SHADOW_NAME_FMT), \
85 	                ((void*)(VM_KERNEL_ADDRPERM(VP))), \
86 	                (VP)->v_id, \
87 	                ((void*)(VM_KERNEL_ADDRPERM((VP)->v_data))))
88 
89 /* The full path to the shadow directory */
90 #define MAKE_SHADOW_DIRNAME(VP, NAME)   \
91 	snprintf((NAME), sizeof((NAME)), (SHADOW_DIR_CONTAINER "/" SHADOW_DIR_FMT), \
92 	                ((void*)(VM_KERNEL_ADDRPERM(VP))), shadow_sequence)
93 
94 /* The shadow directory as a 'leaf' entry */
95 #define MAKE_SHADOW_DIR_LEAF(VP, NAME)  \
96 	snprintf((NAME), sizeof((NAME)), (SHADOW_DIR_FMT), \
97 	                ((void*)(VM_KERNEL_ADDRPERM(VP))), shadow_sequence)
98 
99 static int  default_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, vfs_context_t context);
100 
101 static int  default_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, vfs_context_t context);
102 
103 static int  default_removenamedstream(vnode_t vp, const char *name, vfs_context_t context);
104 
105 static int  getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize, int *creator, vfs_context_t context);
106 
107 static int  get_shadow_dir(vnode_t *sdvpp);
108 
109 #endif /* NAMEDSTREAMS */
110 
111 /*
112  * Default xattr support routines.
113  */
114 
115 static int default_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size, int options,
116     vfs_context_t context);
117 static int default_setxattr(vnode_t vp, const char *name, uio_t uio, int options,
118     vfs_context_t context);
119 static int default_listxattr(vnode_t vp, uio_t uio, size_t *size, int options,
120     vfs_context_t context);
121 static int default_removexattr(vnode_t vp, const char *name, int options,
122     vfs_context_t context);
123 
124 /*
125  *  Retrieve the data of an extended attribute.
126  */
127 int
vn_getxattr(vnode_t vp,const char * name,uio_t uio,size_t * size,int options,vfs_context_t context)128 vn_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size,
129     int options, vfs_context_t context)
130 {
131 	int error;
132 
133 	if (!XATTR_VNODE_SUPPORTED(vp)) {
134 		return EPERM;
135 	}
136 #if NAMEDSTREAMS
137 	/* getxattr calls are not allowed for streams. */
138 	if (vp->v_flag & VISNAMEDSTREAM) {
139 		error = EPERM;
140 		goto out;
141 	}
142 #endif
143 	/*
144 	 * Non-kernel request need extra checks performed.
145 	 *
146 	 * The XATTR_NOSECURITY flag implies a kernel request.
147 	 */
148 	if (!(options & XATTR_NOSECURITY)) {
149 #if CONFIG_MACF
150 		error = mac_vnode_check_getextattr(context, vp, name, uio);
151 		if (error) {
152 			goto out;
153 		}
154 #endif /* MAC */
155 		if ((error = xattr_validatename(name))) {
156 			goto out;
157 		}
158 		if ((error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_EXTATTRIBUTES, context))) {
159 			goto out;
160 		}
161 	}
162 
163 	/* The offset can only be non-zero for resource forks. */
164 	if (uio_offset(uio) != 0 &&
165 	    strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
166 		error = EINVAL;
167 		goto out;
168 	}
169 
170 	error = VNOP_GETXATTR(vp, name, uio, size, options, context);
171 	if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
172 		/*
173 		 * A filesystem may keep some EAs natively and return ENOTSUP for others.
174 		 */
175 		error = default_getxattr(vp, name, uio, size, options, context);
176 	}
177 out:
178 	return error;
179 }
180 
181 /*
182  * Set the data of an extended attribute.
183  */
184 int
vn_setxattr(vnode_t vp,const char * name,uio_t uio,int options,vfs_context_t context)185 vn_setxattr(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t context)
186 {
187 	int error;
188 
189 	if (!XATTR_VNODE_SUPPORTED(vp)) {
190 		return EPERM;
191 	}
192 #if NAMEDSTREAMS
193 	/* setxattr calls are not allowed for streams. */
194 	if (vp->v_flag & VISNAMEDSTREAM) {
195 		error = EPERM;
196 		goto out;
197 	}
198 #endif
199 	if ((options & (XATTR_REPLACE | XATTR_CREATE)) == (XATTR_REPLACE | XATTR_CREATE)) {
200 		return EINVAL;
201 	}
202 	if ((error = xattr_validatename(name))) {
203 		return error;
204 	}
205 	if (!(options & XATTR_NOSECURITY)) {
206 #if CONFIG_MACF
207 		error = mac_vnode_check_setextattr(context, vp, name, uio);
208 		if (error) {
209 			goto out;
210 		}
211 #endif /* MAC */
212 		error = vnode_authorize(vp, NULL, KAUTH_VNODE_WRITE_EXTATTRIBUTES, context);
213 		if (error) {
214 			goto out;
215 		}
216 	}
217 	/* The offset can only be non-zero for resource forks. */
218 	if (uio_offset(uio) != 0 &&
219 	    strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
220 		error = EINVAL;
221 		goto out;
222 	}
223 
224 	error = VNOP_SETXATTR(vp, name, uio, options, context);
225 #ifdef DUAL_EAS
226 	/*
227 	 * An EJUSTRETURN is from a filesystem which keeps this xattr
228 	 * natively as well as in a dot-underscore file.  In this case the
229 	 * EJUSTRETURN means the filesytem has done nothing, but identifies the
230 	 * EA as one which may be represented natively and/or in a DU, and
231 	 * since XATTR_CREATE or XATTR_REPLACE was specified, only up here in
232 	 * in vn_setxattr can we do the getxattrs needed to ascertain whether
233 	 * the XATTR_{CREATE,REPLACE} should yield an error.
234 	 */
235 	if (error == EJUSTRETURN) {
236 		int native = 0, dufile = 0;
237 		size_t sz;      /* not used */
238 
239 		native = VNOP_GETXATTR(vp, name, NULL, &sz, 0, context) ? 0 : 1;
240 		dufile = default_getxattr(vp, name, NULL, &sz, 0, context) ? 0 : 1;
241 		if (options & XATTR_CREATE && (native || dufile)) {
242 			error = EEXIST;
243 			goto out;
244 		}
245 		if (options & XATTR_REPLACE && !(native || dufile)) {
246 			error = ENOATTR;
247 			goto out;
248 		}
249 		/*
250 		 * Having determined no CREATE/REPLACE error should result, we
251 		 * zero those bits, so both backing stores get written to.
252 		 */
253 		options &= ~(XATTR_CREATE | XATTR_REPLACE);
254 		error = VNOP_SETXATTR(vp, name, uio, options, context);
255 		/* the mainline path here is to have error==ENOTSUP ... */
256 	}
257 #endif /* DUAL_EAS */
258 	if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
259 		/*
260 		 * A filesystem may keep some EAs natively and return ENOTSUP for others.
261 		 */
262 		error = default_setxattr(vp, name, uio, options, context);
263 	}
264 #if CONFIG_MACF
265 	if ((error == 0) && !(options & XATTR_NOSECURITY)) {
266 		mac_vnode_notify_setextattr(context, vp, name, uio);
267 		if (vfs_flags(vnode_mount(vp)) & MNT_MULTILABEL) {
268 			mac_vnode_label_update_extattr(vnode_mount(vp), vp, name);
269 		}
270 	}
271 #endif
272 out:
273 	return error;
274 }
275 
276 /*
277  * Remove an extended attribute.
278  */
279 int
vn_removexattr(vnode_t vp,const char * name,int options,vfs_context_t context)280 vn_removexattr(vnode_t vp, const char * name, int options, vfs_context_t context)
281 {
282 	int error;
283 
284 	if (!XATTR_VNODE_SUPPORTED(vp)) {
285 		return EPERM;
286 	}
287 #if NAMEDSTREAMS
288 	/* removexattr calls are not allowed for streams. */
289 	if (vp->v_flag & VISNAMEDSTREAM) {
290 		error = EPERM;
291 		goto out;
292 	}
293 #endif
294 	if ((error = xattr_validatename(name))) {
295 		return error;
296 	}
297 	if (!(options & XATTR_NOSECURITY)) {
298 #if CONFIG_MACF
299 		error = mac_vnode_check_deleteextattr(context, vp, name);
300 		if (error) {
301 			goto out;
302 		}
303 #endif /* MAC */
304 		error = vnode_authorize(vp, NULL, KAUTH_VNODE_WRITE_EXTATTRIBUTES, context);
305 		if (error) {
306 			goto out;
307 		}
308 	}
309 	error = VNOP_REMOVEXATTR(vp, name, options, context);
310 	if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
311 		/*
312 		 * A filesystem may keep some EAs natively and return ENOTSUP for others.
313 		 */
314 		error = default_removexattr(vp, name, options, context);
315 #ifdef DUAL_EAS
316 	} else if (error == EJUSTRETURN) {
317 		/*
318 		 * EJUSTRETURN is from a filesystem which keeps this xattr natively as well
319 		 * as in a dot-underscore file.  EJUSTRETURN means the filesytem did remove
320 		 * a native xattr, so failure to find it in a DU file during
321 		 * default_removexattr should not be considered an error.
322 		 */
323 		error = default_removexattr(vp, name, options, context);
324 		if (error == ENOATTR) {
325 			error = 0;
326 		}
327 #endif /* DUAL_EAS */
328 	}
329 #if CONFIG_MACF
330 	if ((error == 0) && !(options & XATTR_NOSECURITY)) {
331 		mac_vnode_notify_deleteextattr(context, vp, name);
332 		if (vfs_flags(vnode_mount(vp)) & MNT_MULTILABEL) {
333 			mac_vnode_label_update_extattr(vnode_mount(vp), vp, name);
334 		}
335 	}
336 #endif
337 out:
338 	return error;
339 }
340 
341 /*
342  * Retrieve the list of extended attribute names.
343  */
344 int
vn_listxattr(vnode_t vp,uio_t uio,size_t * size,int options,vfs_context_t context)345 vn_listxattr(vnode_t vp, uio_t uio, size_t *size, int options, vfs_context_t context)
346 {
347 	int error;
348 
349 	if (!XATTR_VNODE_SUPPORTED(vp)) {
350 		return EPERM;
351 	}
352 #if NAMEDSTREAMS
353 	/* listxattr calls are not allowed for streams. */
354 	if (vp->v_flag & VISNAMEDSTREAM) {
355 		return EPERM;
356 	}
357 #endif
358 
359 	if (!(options & XATTR_NOSECURITY)) {
360 #if CONFIG_MACF
361 		error = mac_vnode_check_listextattr(context, vp);
362 		if (error) {
363 			goto out;
364 		}
365 #endif /* MAC */
366 
367 		error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_EXTATTRIBUTES, context);
368 		if (error) {
369 			goto out;
370 		}
371 	}
372 
373 	error = VNOP_LISTXATTR(vp, uio, size, options, context);
374 	if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
375 		/*
376 		 * A filesystem may keep some but not all EAs natively, in which case
377 		 * the native EA names will have been uiomove-d out (or *size updated)
378 		 * and the default_listxattr here will finish the job.
379 		 */
380 		error = default_listxattr(vp, uio, size, options, context);
381 	}
382 out:
383 	return error;
384 }
385 
386 int
xattr_validatename(const char * name)387 xattr_validatename(const char *name)
388 {
389 	size_t namelen;
390 
391 	if (name == NULL || name[0] == '\0') {
392 		return EINVAL;
393 	}
394 	namelen = strlen(name);
395 
396 	if (utf8_validatestr((const unsigned char *)name, namelen) != 0) {
397 		return EINVAL;
398 	}
399 
400 	return 0;
401 }
402 
403 
404 /*
405  * Determine whether an EA is a protected system attribute.
406  */
407 int
xattr_protected(const char * attrname)408 xattr_protected(const char *attrname)
409 {
410 	return !strncmp(attrname, "com.apple.system.", 17);
411 }
412 
413 
414 static void
vnode_setasnamedstream_internal(vnode_t vp,vnode_t svp)415 vnode_setasnamedstream_internal(vnode_t vp, vnode_t svp)
416 {
417 	uint32_t streamflags = VISNAMEDSTREAM;
418 
419 	if ((vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0) {
420 		streamflags |= VISSHADOW;
421 	}
422 
423 	/* Tag the vnode. */
424 	vnode_lock_spin(svp);
425 	svp->v_flag |= streamflags;
426 	vnode_unlock(svp);
427 
428 	/* Tag the parent so we know to flush credentials for streams on setattr */
429 	vnode_lock_spin(vp);
430 	vp->v_lflag |= VL_HASSTREAMS;
431 	vnode_unlock(vp);
432 
433 	/* Make the file it's parent.
434 	 * Note:  This parent link helps us distinguish vnodes for
435 	 * shadow stream files from vnodes for resource fork on file
436 	 * systems that support namedstream natively (both have
437 	 * VISNAMEDSTREAM set) by allowing access to mount structure
438 	 * for checking MNTK_NAMED_STREAMS bit at many places in the
439 	 * code.
440 	 */
441 	vnode_update_identity(svp, vp, NULL, 0, 0, (VNODE_UPDATE_NAMEDSTREAM_PARENT | VNODE_UPDATE_FORCE_PARENT_REF));
442 
443 	if (vnode_isdyldsharedcache(vp)) {
444 		vnode_lock_spin(svp);
445 		svp->v_flag |= VSHARED_DYLD;
446 		vnode_unlock(svp);
447 	}
448 
449 	return;
450 }
451 
452 errno_t
vnode_setasnamedstream(vnode_t vp,vnode_t svp)453 vnode_setasnamedstream(vnode_t vp, vnode_t svp)
454 {
455 	if ((vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0) {
456 		return EINVAL;
457 	}
458 
459 	vnode_setasnamedstream_internal(vp, svp);
460 	return 0;
461 }
462 
463 #if NAMEDSTREAMS
464 
465 /*
466  * Obtain a named stream from vnode vp.
467  */
468 errno_t
vnode_getnamedstream(vnode_t vp,vnode_t * svpp,const char * name,enum nsoperation op,int flags,vfs_context_t context)469 vnode_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, int flags, vfs_context_t context)
470 {
471 	int error;
472 
473 	if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) {
474 		error = VNOP_GETNAMEDSTREAM(vp, svpp, name, op, flags, context);
475 	} else {
476 		if (flags) {
477 			error = ENOTSUP;
478 		} else {
479 			error = default_getnamedstream(vp, svpp, name, op, context);
480 		}
481 	}
482 
483 	if (error == 0) {
484 		vnode_setasnamedstream_internal(vp, *svpp);
485 	}
486 
487 	return error;
488 }
489 
490 /*
491  * Make a named stream for vnode vp.
492  */
493 errno_t
vnode_makenamedstream(vnode_t vp,vnode_t * svpp,const char * name,int flags,vfs_context_t context)494 vnode_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, int flags, vfs_context_t context)
495 {
496 	int error;
497 
498 	if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) {
499 		error = VNOP_MAKENAMEDSTREAM(vp, svpp, name, flags, context);
500 	} else {
501 		error = default_makenamedstream(vp, svpp, name, context);
502 	}
503 
504 	if (error == 0) {
505 		vnode_setasnamedstream_internal(vp, *svpp);
506 	}
507 
508 	return error;
509 }
510 
511 /*
512  * Remove a named stream from vnode vp.
513  */
514 errno_t
vnode_removenamedstream(vnode_t vp,vnode_t svp,const char * name,int flags,vfs_context_t context)515 vnode_removenamedstream(vnode_t vp, vnode_t svp, const char *name, int flags, vfs_context_t context)
516 {
517 	int error;
518 
519 	if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) {
520 		error = VNOP_REMOVENAMEDSTREAM(vp, svp, name, flags, context);
521 	} else {
522 		error = default_removenamedstream(vp, name, context);
523 	}
524 
525 	return error;
526 }
527 
528 #define NS_IOBUFSIZE  (128 * 1024)
529 
530 /*
531  * Release a named stream shadow file.
532  *
533  * Note: This function is called from two places where we do not need
534  * to check if the vnode has any references held before deleting the
535  * shadow file.  Once from vclean() when the vnode is being reclaimed
536  * and we do not hold any references on the vnode.  Second time from
537  * default_getnamedstream() when we get an error during shadow stream
538  * file initialization so that other processes who are waiting for the
539  * shadow stream file initialization by the creator will get opportunity
540  * to create and initialize the file again.
541  */
542 errno_t
vnode_relenamedstream(vnode_t vp,vnode_t svp)543 vnode_relenamedstream(vnode_t vp, vnode_t svp)
544 {
545 	vnode_t dvp;
546 	struct componentname cn;
547 	char tmpname[80];
548 	errno_t err;
549 
550 	/*
551 	 * We need to use the kernel context here.  If we used the supplied
552 	 * VFS context we have no clue whether or not it originated from userland
553 	 * where it could be subject to a chroot jail.  We need to ensure that all
554 	 * filesystem access to shadow files is done on the same FS regardless of
555 	 * userland process restrictions.
556 	 */
557 	vfs_context_t kernelctx = vfs_context_kernel();
558 
559 	cache_purge(svp);
560 
561 	vnode_lock(svp);
562 	MAKE_SHADOW_NAME(vp, tmpname);
563 	vnode_unlock(svp);
564 
565 	cn.cn_nameiop = DELETE;
566 	cn.cn_flags = ISLASTCN;
567 	cn.cn_context = kernelctx;
568 	cn.cn_pnbuf = tmpname;
569 	cn.cn_pnlen = sizeof(tmpname);
570 	cn.cn_nameptr = cn.cn_pnbuf;
571 	cn.cn_namelen = (int)strlen(tmpname);
572 
573 	/*
574 	 * Obtain the vnode for the shadow files directory.  Make sure to
575 	 * use the kernel ctx as described above.
576 	 */
577 	err = get_shadow_dir(&dvp);
578 	if (err != 0) {
579 		return err;
580 	}
581 
582 	(void) VNOP_REMOVE(dvp, svp, &cn, 0, kernelctx);
583 	vnode_put(dvp);
584 
585 	return 0;
586 }
587 
588 /*
589  * Flush a named stream shadow file.
590  *
591  * 'vp' represents the AppleDouble file.
592  * 'svp' represents the shadow file.
593  */
594 errno_t
vnode_flushnamedstream(vnode_t vp,vnode_t svp,vfs_context_t context)595 vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
596 {
597 	struct vnode_attr va;
598 	uio_t auio = NULL;
599 	caddr_t  bufptr = NULL;
600 	size_t  bufsize = 0;
601 	size_t  offset;
602 	size_t  iosize;
603 	size_t datasize;
604 	int error;
605 	/*
606 	 * The kernel context must be used for all I/O to the shadow file
607 	 * and its namespace operations
608 	 */
609 	vfs_context_t kernelctx = vfs_context_kernel();
610 
611 	/* The supplied context is used for access to the AD file itself */
612 
613 	VATTR_INIT(&va);
614 	VATTR_WANTED(&va, va_data_size);
615 	if (VNOP_GETATTR(svp, &va, context) != 0 ||
616 	    !VATTR_IS_SUPPORTED(&va, va_data_size)) {
617 		return 0;
618 	}
619 	if (va.va_data_size > UINT32_MAX) {
620 		return EINVAL;
621 	}
622 	datasize = (size_t)va.va_data_size;
623 	if (datasize == 0) {
624 		(void) default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
625 		return 0;
626 	}
627 
628 	iosize = bufsize = MIN(datasize, NS_IOBUFSIZE);
629 	bufptr = kalloc_data(bufsize, Z_WAITOK);
630 	if (bufptr == NULL) {
631 		return ENOMEM;
632 	}
633 	auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
634 	offset = 0;
635 
636 	/*
637 	 * Copy the shadow stream file data into the resource fork.
638 	 */
639 	error = VNOP_OPEN(svp, 0, kernelctx);
640 	if (error) {
641 		printf("vnode_flushnamedstream: err %d opening file\n", error);
642 		goto out;
643 	}
644 	while (offset < datasize) {
645 		iosize = MIN(datasize - offset, iosize);
646 
647 		uio_reset(auio, offset, UIO_SYSSPACE, UIO_READ);
648 		uio_addiov(auio, (uintptr_t)bufptr, iosize);
649 		error = VNOP_READ(svp, auio, 0, kernelctx);
650 		if (error) {
651 			break;
652 		}
653 		/* Since there's no truncate xattr we must remove the resource fork. */
654 		if (offset == 0) {
655 			error = default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
656 			if ((error != 0) && (error != ENOATTR)) {
657 				break;
658 			}
659 		}
660 		uio_reset(auio, offset, UIO_SYSSPACE, UIO_WRITE);
661 		uio_addiov(auio, (uintptr_t)bufptr, iosize);
662 		error = vn_setxattr(vp, XATTR_RESOURCEFORK_NAME, auio, XATTR_NOSECURITY, context);
663 		if (error) {
664 			break;
665 		}
666 		offset += iosize;
667 	}
668 
669 	/* close shadowfile */
670 	(void) VNOP_CLOSE(svp, 0, kernelctx);
671 out:
672 	kfree_data(bufptr, bufsize);
673 	if (auio) {
674 		uio_free(auio);
675 	}
676 	return error;
677 }
678 
679 
680 /*
681  * Verify that the vnode 'vp' is a vnode that lives in the shadow
682  * directory.  We can't just query the parent pointer directly since
683  * the shadowfile is hooked up to the actual file it's a stream for.
684  */
685 errno_t
vnode_verifynamedstream(vnode_t vp)686 vnode_verifynamedstream(vnode_t vp)
687 {
688 	int error;
689 	struct vnode *shadow_dvp = NULL;
690 	struct vnode *shadowfile = NULL;
691 	struct componentname cn;
692 
693 	/*
694 	 * We need to use the kernel context here.  If we used the supplied
695 	 * VFS context we have no clue whether or not it originated from userland
696 	 * where it could be subject to a chroot jail.  We need to ensure that all
697 	 * filesystem access to shadow files is done on the same FS regardless of
698 	 * userland process restrictions.
699 	 */
700 	vfs_context_t kernelctx = vfs_context_kernel();
701 	char tmpname[80];
702 
703 
704 	/* Get the shadow directory vnode */
705 	error = get_shadow_dir(&shadow_dvp);
706 	if (error) {
707 		return error;
708 	}
709 
710 	/* Re-generate the shadow name in the buffer */
711 	MAKE_SHADOW_NAME(vp, tmpname);
712 
713 	/* Look up item in shadow dir */
714 	bzero(&cn, sizeof(cn));
715 	cn.cn_nameiop = LOOKUP;
716 	cn.cn_flags = ISLASTCN | CN_ALLOWRSRCFORK;
717 	cn.cn_context = kernelctx;
718 	cn.cn_pnbuf = tmpname;
719 	cn.cn_pnlen = sizeof(tmpname);
720 	cn.cn_nameptr = cn.cn_pnbuf;
721 	cn.cn_namelen = (int)strlen(tmpname);
722 
723 	if (VNOP_LOOKUP(shadow_dvp, &shadowfile, &cn, kernelctx) == 0) {
724 		/* is the pointer the same? */
725 		if (shadowfile == vp) {
726 			error = 0;
727 		} else {
728 			error = EPERM;
729 		}
730 		/* drop the iocount acquired */
731 		vnode_put(shadowfile);
732 	}
733 
734 	/* Drop iocount on shadow dir */
735 	vnode_put(shadow_dvp);
736 	return error;
737 }
738 
739 /*
740  * Access or create the shadow file as needed.
741  *
742  * 'makestream' with non-zero value means that we need to guarantee we were the
743  * creator of the shadow file.
744  *
745  * 'context' is the user supplied context for the original VFS operation that
746  * caused us to need a shadow file.
747  *
748  * int pointed to by 'creator' is nonzero if we created the shadowfile.
749  */
750 static int
getshadowfile(vnode_t vp,vnode_t * svpp,int makestream,size_t * rsrcsize,int * creator,vfs_context_t context)751 getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize,
752     int *creator, vfs_context_t context)
753 {
754 	vnode_t  dvp = NULLVP;
755 	vnode_t  svp = NULLVP;
756 	struct componentname cn;
757 	struct vnode_attr va;
758 	char tmpname[80];
759 	size_t datasize = 0;
760 	int  error = 0;
761 	int retries = 0;
762 	vfs_context_t kernelctx = vfs_context_kernel();
763 
764 retry_create:
765 	*creator = 0;
766 	/* Establish a unique file name. */
767 	MAKE_SHADOW_NAME(vp, tmpname);
768 	bzero(&cn, sizeof(cn));
769 	cn.cn_nameiop = LOOKUP;
770 	cn.cn_flags = ISLASTCN | MARKISSHADOW;
771 	cn.cn_context = context;
772 	cn.cn_pnbuf = tmpname;
773 	cn.cn_pnlen = sizeof(tmpname);
774 	cn.cn_nameptr = cn.cn_pnbuf;
775 	cn.cn_namelen = (int)strlen(tmpname);
776 
777 	/* Pick up uid, gid, mode and date from original file. */
778 	VATTR_INIT(&va);
779 	VATTR_WANTED(&va, va_uid);
780 	VATTR_WANTED(&va, va_gid);
781 	VATTR_WANTED(&va, va_mode);
782 	VATTR_WANTED(&va, va_create_time);
783 	VATTR_WANTED(&va, va_modify_time);
784 	if (VNOP_GETATTR(vp, &va, context) != 0 ||
785 	    !VATTR_IS_SUPPORTED(&va, va_uid) ||
786 	    !VATTR_IS_SUPPORTED(&va, va_gid) ||
787 	    !VATTR_IS_SUPPORTED(&va, va_mode)) {
788 		va.va_uid = KAUTH_UID_NONE;
789 		va.va_gid = KAUTH_GID_NONE;
790 		va.va_mode = S_IRUSR | S_IWUSR;
791 	}
792 	va.va_vaflags = VA_EXCLUSIVE;
793 	VATTR_SET(&va, va_type, VREG);
794 	/* We no longer change the access, but we still hide it. */
795 	VATTR_SET(&va, va_flags, UF_HIDDEN);
796 
797 	/* Obtain the vnode for the shadow files directory. */
798 	if (get_shadow_dir(&dvp) != 0) {
799 		error = ENOTDIR;
800 		goto out;
801 	}
802 	if (!makestream) {
803 		/* See if someone else already has it open. */
804 		if (VNOP_LOOKUP(dvp, &svp, &cn, kernelctx) == 0) {
805 			/* Double check existence by asking for size. */
806 			VATTR_INIT(&va);
807 			VATTR_WANTED(&va, va_data_size);
808 			if (VNOP_GETATTR(svp, &va, context) == 0 &&
809 			    VATTR_IS_SUPPORTED(&va, va_data_size)) {
810 				goto out;  /* OK to use. */
811 			}
812 		}
813 
814 		/*
815 		 * Otherwise make sure the resource fork data exists.
816 		 * Use the supplied context for accessing the AD file.
817 		 */
818 		error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, NULL, &datasize,
819 		    XATTR_NOSECURITY, context);
820 		/*
821 		 * To maintain binary compatibility with legacy Carbon
822 		 * emulated resource fork support, if the resource fork
823 		 * doesn't exist but the Finder Info does,  then act as
824 		 * if an empty resource fork is present (see 4724359).
825 		 */
826 		if ((error == ENOATTR) &&
827 		    (vn_getxattr(vp, XATTR_FINDERINFO_NAME, NULL, &datasize,
828 		    XATTR_NOSECURITY, context) == 0)) {
829 			datasize = 0;
830 			error = 0;
831 		} else {
832 			if (error) {
833 				goto out;
834 			}
835 
836 			/* If the resource fork exists, its size is expected to be non-zero. */
837 			if (datasize == 0) {
838 				error = ENOATTR;
839 				goto out;
840 			}
841 		}
842 	}
843 	/* Create the shadow stream file. */
844 	error = VNOP_CREATE(dvp, &svp, &cn, &va, kernelctx);
845 	if (error == 0) {
846 		vnode_recycle(svp);
847 		*creator = 1;
848 	} else if ((error == EEXIST) && !makestream) {
849 		error = VNOP_LOOKUP(dvp, &svp, &cn, kernelctx);
850 	} else if ((error == ENOENT) && !makestream) {
851 		/*
852 		 * We could have raced with a rmdir on the shadow directory
853 		 * post-lookup.  Retry from the beginning, 1x only, to
854 		 * try and see if we need to re-create the shadow directory
855 		 * in get_shadow_dir.
856 		 */
857 		if (retries == 0) {
858 			retries++;
859 			if (dvp) {
860 				vnode_put(dvp);
861 				dvp = NULLVP;
862 			}
863 			if (svp) {
864 				vnode_put(svp);
865 				svp = NULLVP;
866 			}
867 			goto retry_create;
868 		}
869 		/* Otherwise, just error out normally below */
870 	}
871 
872 out:
873 	if (dvp) {
874 		vnode_put(dvp);
875 	}
876 	if (error) {
877 		/* On errors, clean up shadow stream file. */
878 		if (svp) {
879 			vnode_put(svp);
880 			svp = NULLVP;
881 		}
882 	}
883 	*svpp = svp;
884 	if (rsrcsize) {
885 		*rsrcsize = datasize;
886 	}
887 	return error;
888 }
889 
890 
891 static int
default_getnamedstream(vnode_t vp,vnode_t * svpp,const char * name,enum nsoperation op,vfs_context_t context)892 default_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, vfs_context_t context)
893 {
894 	vnode_t  svp = NULLVP;
895 	uio_t auio = NULL;
896 	caddr_t  bufptr = NULL;
897 	size_t  bufsize = 0;
898 	size_t  datasize = 0;
899 	int  creator;
900 	int  error;
901 
902 	/* need the kernel context for accessing the shadowfile */
903 	vfs_context_t kernelctx = vfs_context_kernel();
904 
905 	/*
906 	 * Only the "com.apple.ResourceFork" stream is supported here.
907 	 */
908 	if (strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
909 		*svpp = NULLVP;
910 		return ENOATTR;
911 	}
912 retry:
913 	/*
914 	 * Obtain a shadow file for the resource fork I/O.
915 	 *
916 	 * Need to pass along the supplied context so that getshadowfile
917 	 * can access the AD file as needed, using it.
918 	 */
919 	error = getshadowfile(vp, &svp, 0, &datasize, &creator, context);
920 	if (error) {
921 		*svpp = NULLVP;
922 		return error;
923 	}
924 
925 	/*
926 	 * The creator of the shadow file provides its file data,
927 	 * all other threads should wait until its ready.  In order to
928 	 * prevent a deadlock during error codepaths, we need to check if the
929 	 * vnode is being created, or if it has failed out. Regardless of success or
930 	 * failure, we set the VISSHADOW bit on the vnode, so we check that
931 	 * if the vnode's flags don't have VISNAMEDSTREAM set.  If it doesn't,
932 	 * then we can infer the creator isn't done yet.  If it's there, but
933 	 * VISNAMEDSTREAM is not set, then we can infer it errored out and we should
934 	 * try again.
935 	 */
936 	if (!creator) {
937 		vnode_lock(svp);
938 		if (svp->v_flag & VISNAMEDSTREAM) {
939 			/* data is ready, go use it */
940 			vnode_unlock(svp);
941 			goto out;
942 		} else {
943 			/* It's not ready, wait for it (sleep using v_parent as channel) */
944 			if ((svp->v_flag & VISSHADOW)) {
945 				/*
946 				 * No VISNAMEDSTREAM, but we did see VISSHADOW, indicating that the other
947 				 * thread is done with this vnode. Just unlock the vnode and try again
948 				 */
949 				vnode_unlock(svp);
950 			} else {
951 				/* Otherwise, sleep if the shadow file is not created yet */
952 				msleep((caddr_t)&svp->v_parent, &svp->v_lock, PINOD | PDROP,
953 				    "getnamedstream", NULL);
954 			}
955 			vnode_put(svp);
956 			svp = NULLVP;
957 			goto retry;
958 		}
959 	}
960 
961 	/*
962 	 * Copy the real resource fork data into shadow stream file.
963 	 */
964 	if (op == NS_OPEN && datasize != 0) {
965 		size_t  offset;
966 		size_t  iosize;
967 
968 		iosize = bufsize = MIN(datasize, NS_IOBUFSIZE);
969 		bufptr = kalloc_data(bufsize, Z_WAITOK);
970 		if (bufptr == NULL) {
971 			error = ENOMEM;
972 			goto out;
973 		}
974 
975 		auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
976 		offset = 0;
977 
978 		/* open the shadow file */
979 		error = VNOP_OPEN(svp, 0, kernelctx);
980 		if (error) {
981 			goto out;
982 		}
983 		while (offset < datasize) {
984 			size_t  tmpsize;
985 
986 			iosize = MIN(datasize - offset, iosize);
987 
988 			uio_reset(auio, offset, UIO_SYSSPACE, UIO_READ);
989 			uio_addiov(auio, (uintptr_t)bufptr, iosize);
990 			/* use supplied ctx for AD file */
991 			error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, auio, &tmpsize,
992 			    XATTR_NOSECURITY, context);
993 			if (error) {
994 				break;
995 			}
996 
997 			uio_reset(auio, offset, UIO_SYSSPACE, UIO_WRITE);
998 			uio_addiov(auio, (uintptr_t)bufptr, iosize);
999 			/* kernel context for writing shadowfile */
1000 			error = VNOP_WRITE(svp, auio, 0, kernelctx);
1001 			if (error) {
1002 				break;
1003 			}
1004 			offset += iosize;
1005 		}
1006 
1007 		/* close shadow file */
1008 		(void) VNOP_CLOSE(svp, 0, kernelctx);
1009 	}
1010 out:
1011 	/* Wake up anyone waiting for svp file content */
1012 	if (creator) {
1013 		if (error == 0) {
1014 			vnode_lock(svp);
1015 			/* VISSHADOW would be set later on anyway, so we set it now */
1016 			svp->v_flag |= (VISNAMEDSTREAM | VISSHADOW);
1017 			wakeup((caddr_t)&svp->v_parent);
1018 			vnode_unlock(svp);
1019 		} else {
1020 			/* On post create errors, get rid of the shadow file.  This
1021 			 * way if there is another process waiting for initialization
1022 			 * of the shadowfile by the current process will wake up and
1023 			 * retry by creating and initializing the shadow file again.
1024 			 * Also add the VISSHADOW bit here to indicate we're done operating
1025 			 * on this vnode.
1026 			 */
1027 			(void)vnode_relenamedstream(vp, svp);
1028 			vnode_lock(svp);
1029 			svp->v_flag |= VISSHADOW;
1030 			wakeup((caddr_t)&svp->v_parent);
1031 			vnode_unlock(svp);
1032 		}
1033 	}
1034 
1035 	kfree_data(bufptr, bufsize);
1036 	if (auio) {
1037 		uio_free(auio);
1038 	}
1039 	if (error) {
1040 		/* On errors, clean up shadow stream file. */
1041 		if (svp) {
1042 			vnode_put(svp);
1043 			svp = NULLVP;
1044 		}
1045 	}
1046 	*svpp = svp;
1047 	return error;
1048 }
1049 
1050 static int
default_makenamedstream(vnode_t vp,vnode_t * svpp,const char * name,vfs_context_t context)1051 default_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, vfs_context_t context)
1052 {
1053 	int creator;
1054 	int error;
1055 
1056 	/*
1057 	 * Only the "com.apple.ResourceFork" stream is supported here.
1058 	 */
1059 	if (strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
1060 		*svpp = NULLVP;
1061 		return ENOATTR;
1062 	}
1063 
1064 	/* Supply the context to getshadowfile so it can manipulate the AD file */
1065 	error = getshadowfile(vp, svpp, 1, NULL, &creator, context);
1066 
1067 	/*
1068 	 * Wake up any waiters over in default_getnamedstream().
1069 	 */
1070 	if ((error == 0) && (*svpp != NULL) && creator) {
1071 		vnode_t svp = *svpp;
1072 
1073 		vnode_lock(svp);
1074 		/* If we're the creator, mark it as a named stream */
1075 		svp->v_flag |= (VISNAMEDSTREAM | VISSHADOW);
1076 		/* Wakeup any waiters on the v_parent channel */
1077 		wakeup((caddr_t)&svp->v_parent);
1078 		vnode_unlock(svp);
1079 	}
1080 
1081 	return error;
1082 }
1083 
1084 static int
default_removenamedstream(vnode_t vp,const char * name,vfs_context_t context)1085 default_removenamedstream(vnode_t vp, const char *name, vfs_context_t context)
1086 {
1087 	/*
1088 	 * Only the "com.apple.ResourceFork" stream is supported here.
1089 	 */
1090 	if (strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
1091 		return ENOATTR;
1092 	}
1093 	/*
1094 	 * XXX - what about other opened instances?
1095 	 */
1096 	return default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
1097 }
1098 
1099 static bool
is_shadow_dir_valid(vnode_t parent_sdvp,vnode_t sdvp,vfs_context_t kernelctx)1100 is_shadow_dir_valid(vnode_t parent_sdvp, vnode_t sdvp, vfs_context_t kernelctx)
1101 {
1102 	struct vnode_attr va;
1103 	uint32_t tmp_fsid;
1104 	bool is_valid = false;
1105 
1106 	/* Make sure it's in fact a directory */
1107 	if (sdvp->v_type != VDIR) {
1108 		goto out;
1109 	}
1110 
1111 	/* Obtain the fsid for what should be the /private/var/run directory. */
1112 	VATTR_INIT(&va);
1113 	VATTR_WANTED(&va, va_fsid);
1114 	if (VNOP_GETATTR(parent_sdvp, &va, kernelctx) != 0 ||
1115 	    !VATTR_IS_SUPPORTED(&va, va_fsid)) {
1116 		goto out;
1117 	}
1118 
1119 	tmp_fsid = va.va_fsid;
1120 
1121 	VATTR_INIT(&va);
1122 	VATTR_WANTED(&va, va_uid);
1123 	VATTR_WANTED(&va, va_gid);
1124 	VATTR_WANTED(&va, va_mode);
1125 	VATTR_WANTED(&va, va_fsid);
1126 	VATTR_WANTED(&va, va_dirlinkcount);
1127 	VATTR_WANTED(&va, va_acl);
1128 	/* Provide defaults for attrs that may not be supported */
1129 	va.va_dirlinkcount = 1;
1130 	va.va_acl = (kauth_acl_t) KAUTH_FILESEC_NONE;
1131 
1132 	if (VNOP_GETATTR(sdvp, &va, kernelctx) != 0 ||
1133 	    !VATTR_IS_SUPPORTED(&va, va_uid) ||
1134 	    !VATTR_IS_SUPPORTED(&va, va_gid) ||
1135 	    !VATTR_IS_SUPPORTED(&va, va_mode) ||
1136 	    !VATTR_IS_SUPPORTED(&va, va_fsid)) {
1137 		goto out;
1138 	}
1139 
1140 	/*
1141 	 * Make sure its what we want:
1142 	 *      - owned by root
1143 	 *	- not writable by anyone
1144 	 *	- on same file system as /private/var/run
1145 	 *	- not a hard-linked directory
1146 	 *	- no ACLs (they might grant write access)
1147 	 */
1148 	if ((va.va_uid != 0) || (va.va_gid != 0) ||
1149 	    (va.va_mode & (S_IWUSR | S_IRWXG | S_IRWXO)) ||
1150 	    (va.va_fsid != tmp_fsid) ||
1151 	    (va.va_dirlinkcount != 1) ||
1152 	    (va.va_acl != (kauth_acl_t) KAUTH_FILESEC_NONE)) {
1153 		goto out;
1154 	}
1155 
1156 	/* If we get here, then the shadow dir is valid. */
1157 	is_valid = true;
1158 
1159 out:
1160 	return is_valid;
1161 }
1162 
1163 static int
get_shadow_dir(vnode_t * sdvpp)1164 get_shadow_dir(vnode_t *sdvpp)
1165 {
1166 	vnode_t  dvp = NULLVP;
1167 	vnode_t  sdvp = NULLVP;
1168 	struct componentname  cn;
1169 	struct vnode_attr  va;
1170 	char tmpname[80];
1171 	int  error;
1172 	vfs_context_t kernelctx = vfs_context_kernel();
1173 
1174 	/*
1175 	 * Make sure to use the kernel context.  We want a singular view of
1176 	 * the shadow dir regardless of chrooted processes.
1177 	 */
1178 
1179 	/*
1180 	 * Obtain the vnode for "/private/var/run" directory using the kernel
1181 	 * context.
1182 	 *
1183 	 * This is defined in the SHADOW_DIR_CONTAINER macro
1184 	 */
1185 	error = vnode_lookup(SHADOW_DIR_CONTAINER, VNODE_LOOKUP_NOFOLLOW_ANY, &dvp,
1186 	    kernelctx);
1187 	if (error) {
1188 		error = ENOTSUP;
1189 		goto out;
1190 	}
1191 
1192 	/*
1193 	 * Create the shadow stream directory.
1194 	 * 'dvp' below suggests the parent directory so
1195 	 * we only need to provide the leaf entry name
1196 	 */
1197 	bzero(tmpname, sizeof(tmpname));
1198 	MAKE_SHADOW_DIR_LEAF(rootvnode, tmpname);
1199 
1200 	/*
1201 	 * Look up the shadow directory to ensure that it still exists.
1202 	 * By looking it up, we get an iocounted sdvp to use, and avoid some
1203 	 * coherency issues in caching it when multiple threads may be trying to
1204 	 * manipulate the pointers.
1205 	 */
1206 	error = vnode_lookupat(tmpname, VNODE_LOOKUP_NOFOLLOW, &sdvp, kernelctx, dvp);
1207 	if (error == 0) {
1208 		if (is_shadow_dir_valid(dvp, sdvp, kernelctx)) {
1209 			/*
1210 			 * If we get here, then we have successfully looked up the shadow
1211 			 * dir, and it has an iocount from the lookup. Return the vp in the
1212 			 * output argument.
1213 			 */
1214 			goto out;
1215 		}
1216 
1217 		/*
1218 		 * Lookup returned us something that is not a valid shadow dir.
1219 		 * Remove it and proceed with recreating the shadow dir.
1220 		 */
1221 		bzero(&cn, sizeof(cn));
1222 		cn.cn_nameiop = DELETE;
1223 		cn.cn_flags = ISLASTCN;
1224 		cn.cn_context = kernelctx;
1225 		cn.cn_pnbuf = tmpname;
1226 		cn.cn_pnlen = sizeof(tmpname);
1227 		cn.cn_nameptr = cn.cn_pnbuf;
1228 		cn.cn_namelen = (int)strlen(tmpname);
1229 
1230 		error = VNOP_REMOVE(dvp, sdvp, &cn, 0, kernelctx);
1231 		if (error) {
1232 			error = ENOTSUP;
1233 			goto out;
1234 		}
1235 
1236 		vnode_put(sdvp);
1237 	}
1238 
1239 	/* In the failure case, no iocount is acquired */
1240 	sdvp = NULLVP;
1241 	bzero(&cn, sizeof(cn));
1242 	cn.cn_nameiop = LOOKUP;
1243 	cn.cn_flags = ISLASTCN;
1244 	cn.cn_context = kernelctx;
1245 	cn.cn_pnbuf = tmpname;
1246 	cn.cn_pnlen = sizeof(tmpname);
1247 	cn.cn_nameptr = cn.cn_pnbuf;
1248 	cn.cn_namelen = (int)strlen(tmpname);
1249 
1250 	/*
1251 	 * owned by root, only readable by root, hidden
1252 	 */
1253 	VATTR_INIT(&va);
1254 	VATTR_SET(&va, va_uid, 0);
1255 	VATTR_SET(&va, va_gid, 0);
1256 	VATTR_SET(&va, va_mode, S_IRUSR | S_IXUSR);
1257 	VATTR_SET(&va, va_type, VDIR);
1258 	VATTR_SET(&va, va_flags, UF_HIDDEN);
1259 	va.va_vaflags = VA_EXCLUSIVE;
1260 
1261 	error = VNOP_MKDIR(dvp, &sdvp, &cn, &va, kernelctx);
1262 
1263 	/*
1264 	 * There can be only one winner for an exclusive create.
1265 	 */
1266 	if (error == EEXIST) {
1267 		/* loser has to look up directory */
1268 		error = VNOP_LOOKUP(dvp, &sdvp, &cn, kernelctx);
1269 		if (error == 0 && is_shadow_dir_valid(dvp, sdvp, kernelctx) == false) {
1270 			goto baddir;
1271 		}
1272 	}
1273 out:
1274 	if (dvp) {
1275 		vnode_put(dvp);
1276 	}
1277 	if (error) {
1278 		/* On errors, clean up shadow stream directory. */
1279 		if (sdvp) {
1280 			vnode_put(sdvp);
1281 			sdvp = NULLVP;
1282 		}
1283 	}
1284 	*sdvpp = sdvp;
1285 	return error;
1286 
1287 baddir:
1288 	/* This is not the dir we're looking for, move along */
1289 	++shadow_sequence;  /* try something else next time */
1290 	error = ENOTDIR;
1291 	goto out;
1292 }
1293 #endif /* NAMEDSTREAMS */
1294 
1295 
1296 #if CONFIG_APPLEDOUBLE
1297 /*
1298  * Default Implementation (Non-native EA)
1299  */
1300 
1301 
1302 /*
1303  *  Typical "._" AppleDouble Header File layout:
1304  * ------------------------------------------------------------
1305  *        MAGIC          0x00051607
1306  *        VERSION        0x00020000
1307  *        FILLER         0
1308  *        COUNT          2
1309  *    .-- AD ENTRY[0]    Finder Info Entry (must be first)
1310  * .--+-- AD ENTRY[1]    Resource Fork Entry (must be last)
1311  * |  '-> FINDER INFO
1312  * |      /////////////  Fixed Size Data (32 bytes)
1313  * |      EXT ATTR HDR
1314  * |      /////////////
1315  * |      ATTR ENTRY[0] --.
1316  * |      ATTR ENTRY[1] --+--.
1317  * |      ATTR ENTRY[2] --+--+--.
1318  * |         ...          |  |  |
1319  * |      ATTR ENTRY[N] --+--+--+--.
1320  * |      ATTR DATA 0   <-'  |  |  |
1321  * |      ////////////       |  |  |
1322  * |      ATTR DATA 1   <----'  |  |
1323  * |      /////////////         |  |
1324  * |      ATTR DATA 2   <-------'  |
1325  * |      /////////////            |
1326  * |         ...                   |
1327  * |      ATTR DATA N   <----------'
1328  * |      /////////////
1329  * |                      Attribute Free Space
1330  * |
1331  * '----> RESOURCE FORK
1332  *        /////////////   Variable Sized Data
1333  *        /////////////
1334  *        /////////////
1335  *        /////////////
1336  *        /////////////
1337  *        /////////////
1338  *           ...
1339  *        /////////////
1340  *
1341  * ------------------------------------------------------------
1342  *
1343  *  NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
1344  *  stored as part of the Finder Info.  The length in the Finder
1345  *  Info AppleDouble entry includes the length of the extended
1346  *  attribute header, attribute entries, and attribute data.
1347  */
1348 
1349 /*
1350  * On Disk Data Structures
1351  *
1352  * Note: Motorola 68K alignment and big-endian.
1353  *
1354  * See RFC 1740 for additional information about the AppleDouble file format.
1355  *
1356  */
1357 
1358 #define ADH_MAGIC     0x00051607
1359 #define ADH_VERSION   0x00020000
1360 #define ADH_MACOSX    "Mac OS X        "
1361 
1362 /*
1363  * AppleDouble Entry ID's
1364  */
1365 #define AD_DATA          1   /* Data fork */
1366 #define AD_RESOURCE      2   /* Resource fork */
1367 #define AD_REALNAME      3   /* File's name on home file system */
1368 #define AD_COMMENT       4   /* Standard Mac comment */
1369 #define AD_ICONBW        5   /* Mac black & white icon */
1370 #define AD_ICONCOLOR     6   /* Mac color icon */
1371 #define AD_UNUSED        7   /* Not used */
1372 #define AD_FILEDATES     8   /* File dates; create, modify, etc */
1373 #define AD_FINDERINFO    9   /* Mac Finder info & extended info */
1374 #define AD_MACINFO      10   /* Mac file info, attributes, etc */
1375 #define AD_PRODOSINFO   11   /* Pro-DOS file info, attrib., etc */
1376 #define AD_MSDOSINFO    12   /* MS-DOS file info, attributes, etc */
1377 #define AD_AFPNAME      13   /* Short name on AFP server */
1378 #define AD_AFPINFO      14   /* AFP file info, attrib., etc */
1379 #define AD_AFPDIRID     15   /* AFP directory ID */
1380 #define AD_ATTRIBUTES   AD_FINDERINFO
1381 
1382 
1383 #define ATTR_FILE_PREFIX   "._"
1384 #define ATTR_HDR_MAGIC     0x41545452   /* 'ATTR' */
1385 
1386 #define ATTR_BUF_SIZE      4096        /* default size of the attr file and how much we'll grow by */
1387 
1388 /* Implementation Limits */
1389 #define ATTR_MAX_SIZE      AD_XATTR_MAXSIZE
1390 #define ATTR_MAX_HDR_SIZE  65536
1391 /*
1392  * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
1393  * size supported (including the attribute entries). All of
1394  * the attribute entries must reside within this limit.  If
1395  * any of the attribute data crosses the ATTR_MAX_HDR_SIZE
1396  * boundry, then all of the attribute data I/O is performed
1397  * separately from the attribute header I/O.
1398  *
1399  * In particular, all of the attr_entry structures must lie
1400  * completely within the first ATTR_MAX_HDR_SIZE bytes of the
1401  * AppleDouble file.  However, the attribute data (i.e. the
1402  * contents of the extended attributes) may extend beyond the
1403  * first ATTR_MAX_HDR_SIZE bytes of the file.  Note that this
1404  * limit is to allow the implementation to optimize by reading
1405  * the first ATTR_MAX_HDR_SIZE bytes of the file.
1406  */
1407 
1408 
1409 #define FINDERINFOSIZE  32
1410 
1411 typedef struct apple_double_entry {
1412 	u_int32_t   type;     /* entry type: see list, 0 invalid */
1413 	u_int32_t   offset;   /* entry data offset from the beginning of the file. */
1414 	u_int32_t   length;   /* entry data length in bytes. */
1415 } __attribute__((aligned(2), packed)) apple_double_entry_t;
1416 
1417 
1418 typedef struct apple_double_header {
1419 	u_int32_t   magic;         /* == ADH_MAGIC */
1420 	u_int32_t   version;       /* format version: 2 = 0x00020000 */
1421 	u_int32_t   filler[4];
1422 	u_int16_t   numEntries;    /* number of entries which follow */
1423 	apple_double_entry_t   entries[2];  /* 'finfo' & 'rsrc' always exist */
1424 	u_int8_t    finfo[FINDERINFOSIZE];  /* Must start with Finder Info (32 bytes) */
1425 	u_int8_t    pad[2];        /* get better alignment inside attr_header */
1426 } __attribute__((aligned(2), packed)) apple_double_header_t;
1427 
1428 #define ADHDRSIZE  (4+4+16+2)
1429 
1430 /* Entries are aligned on 4 byte boundaries */
1431 typedef struct attr_entry {
1432 	u_int32_t   offset;     /* file offset to data */
1433 	u_int32_t   length;     /* size of attribute data */
1434 	u_int16_t   flags;
1435 	u_int8_t    namelen;
1436 	u_int8_t    name[1];    /* NULL-terminated UTF-8 name (up to 128 bytes max) */
1437 } __attribute__((aligned(2), packed)) attr_entry_t;
1438 
1439 
1440 /* Header + entries must fit into 64K.  Data may extend beyond 64K. */
1441 typedef struct attr_header {
1442 	apple_double_header_t  appledouble;
1443 	u_int32_t   magic;        /* == ATTR_HDR_MAGIC */
1444 	u_int32_t   debug_tag;    /* for debugging == file id of owning file */
1445 	u_int32_t   total_size;   /* file offset of end of attribute header + entries + data */
1446 	u_int32_t   data_start;   /* file offset to attribute data area */
1447 	u_int32_t   data_length;  /* length of attribute data area */
1448 	u_int32_t   reserved[3];
1449 	u_int16_t   flags;
1450 	u_int16_t   num_attrs;
1451 } __attribute__((aligned(2), packed)) attr_header_t;
1452 
1453 
1454 /* Empty Resource Fork Header */
1455 typedef struct rsrcfork_header {
1456 	u_int32_t    fh_DataOffset;
1457 	u_int32_t    fh_MapOffset;
1458 	u_int32_t    fh_DataLength;
1459 	u_int32_t    fh_MapLength;
1460 	u_int8_t     systemData[112];
1461 	u_int8_t     appData[128];
1462 	u_int32_t    mh_DataOffset;
1463 	u_int32_t    mh_MapOffset;
1464 	u_int32_t    mh_DataLength;
1465 	u_int32_t    mh_MapLength;
1466 	u_int32_t    mh_Next;
1467 	u_int16_t    mh_RefNum;
1468 	u_int8_t     mh_Attr;
1469 	u_int8_t     mh_InMemoryAttr;
1470 	u_int16_t    mh_Types;
1471 	u_int16_t    mh_Names;
1472 	u_int16_t    typeCount;
1473 } __attribute__((aligned(2), packed)) rsrcfork_header_t;
1474 
1475 #define RF_FIRST_RESOURCE    256
1476 #define RF_NULL_MAP_LENGTH    30
1477 #define RF_EMPTY_TAG  "This resource fork intentionally left blank   "
1478 
1479 /* Runtime information about the attribute file. */
1480 typedef struct attr_info {
1481 	vfs_context_t          context;
1482 	vnode_t                filevp;
1483 	size_t                 filesize;
1484 	size_t                 iosize;
1485 	u_int8_t               *rawdata;
1486 	size_t                 rawsize;  /* minimum of filesize or ATTR_MAX_HDR_SIZE */
1487 	apple_double_header_t  *filehdr;
1488 	apple_double_entry_t   *finderinfo;
1489 	apple_double_entry_t   *rsrcfork;
1490 	attr_header_t          *attrhdr;
1491 	attr_entry_t           *attr_entry;
1492 	u_int8_t               readonly;
1493 	u_int8_t               emptyfinderinfo;
1494 } attr_info_t;
1495 
1496 
1497 #define ATTR_SETTING  1
1498 
1499 #define ATTR_ALIGN 3L  /* Use four-byte alignment */
1500 
1501 #define ATTR_ENTRY_LENGTH(namelen)  \
1502 	((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
1503 
1504 #define ATTR_NEXT(ae)  \
1505 	 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
1506 
1507 #define ATTR_VALID(ae, ai)  \
1508 	((&(ae)->namelen < ((ai).rawdata + (ai).rawsize)) && \
1509 	 (u_int8_t *)ATTR_NEXT(ae) <= ((ai).rawdata + (ai).rawsize))
1510 
1511 #define SWAP16(x)  OSSwapBigToHostInt16((x))
1512 #define SWAP32(x)  OSSwapBigToHostInt32((x))
1513 #define SWAP64(x)  OSSwapBigToHostInt64((x))
1514 
1515 
1516 static int get_doubleagentd_port(mach_port_t *doubleagentd_port);
1517 
1518 /*
1519  * DoubleAgent default xattr functions
1520  */
1521 static int default_getxattr_doubleagent(vnode_t vp, const char *name,
1522     uio_t uio, size_t *size, int options, vfs_context_t context,
1523     mach_port_t);
1524 static int default_setxattr_doubleagent(vnode_t vp, const char *name,
1525     uio_t uio, int options, vfs_context_t context, mach_port_t);
1526 static int default_listxattr_doubleagent(vnode_t vp, uio_t uio, size_t *size,
1527     int options, vfs_context_t context, mach_port_t);
1528 static int default_removexattr_doubleagent(vnode_t vp, const char *name,
1529     int options, vfs_context_t context, mach_port_t);
1530 
1531 
1532 static u_int32_t emptyfinfo[8] = {0};
1533 
1534 
1535 /*
1536  * Local support routines
1537  */
1538 static void close_xattrfile(struct fileglob *xfg, bool have_iocount, bool drop_iocount, vfs_context_t context);
1539 
1540 static int  open_xattrfile(vnode_t vp, int fileflags, struct fileglob **xfgp,
1541     int64_t *file_sizep, bool *created_xattr_filep, vfs_context_t context);
1542 
1543 static void remove_xattrfile(struct fileglob *xfg, vnode_t xvp, vfs_context_t context);
1544 
1545 static int  make_xattrfile_port(struct fileglob *xfg, ipc_port_t *portp);
1546 
1547 
1548 /*
1549  * Retrieve the data of an extended attribute.
1550  */
1551 static int
default_getxattr(vnode_t vp,const char * name,uio_t uio,size_t * size,__unused int options,vfs_context_t context)1552 default_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size,
1553     __unused int options, vfs_context_t context)
1554 {
1555 	mach_port_t port;
1556 	int error;
1557 
1558 	if (get_doubleagentd_port(&port) == 0) {
1559 		error = default_getxattr_doubleagent(vp, name, uio, size,
1560 		    options, context, port);
1561 		ipc_port_release_send(port);
1562 	} else {
1563 		error = ENOATTR;
1564 	}
1565 	return error;
1566 }
1567 
1568 /*
1569  * Set the data of an extended attribute.
1570  */
1571 static int __attribute__((noinline))
default_setxattr(vnode_t vp,const char * name,uio_t uio,int options,vfs_context_t context)1572 default_setxattr(vnode_t vp, const char *name, uio_t uio, int options,
1573     vfs_context_t context)
1574 {
1575 	mach_port_t port;
1576 	int error;
1577 
1578 	if (get_doubleagentd_port(&port) == 0) {
1579 		error = default_setxattr_doubleagent(vp, name, uio, options,
1580 		    context, port);
1581 		ipc_port_release_send(port);
1582 	} else {
1583 		error = ENOATTR;
1584 	}
1585 	return error;
1586 }
1587 
1588 /*
1589  * Remove an extended attribute.
1590  */
1591 static int
default_removexattr(vnode_t vp,const char * name,__unused int options,vfs_context_t context)1592 default_removexattr(vnode_t vp, const char *name, __unused int options,
1593     vfs_context_t context)
1594 {
1595 	mach_port_t port;
1596 	int error;
1597 
1598 	if (get_doubleagentd_port(&port) == 0) {
1599 		error = default_removexattr_doubleagent(vp, name, options,
1600 		    context, port);
1601 		ipc_port_release_send(port);
1602 	} else {
1603 		error = ENOATTR;
1604 	}
1605 	return error;
1606 }
1607 
1608 /*
1609  * Retrieve the list of extended attribute names.
1610  */
1611 static int
default_listxattr(vnode_t vp,uio_t uio,size_t * size,__unused int options,vfs_context_t context)1612 default_listxattr(vnode_t vp, uio_t uio, size_t *size, __unused int options,
1613     vfs_context_t context)
1614 {
1615 	mach_port_t port;
1616 	int error;
1617 
1618 	if (get_doubleagentd_port(&port) == 0) {
1619 		error = default_listxattr_doubleagent(vp, uio, size, options,
1620 		    context, port);
1621 		ipc_port_release_send(port);
1622 	} else {
1623 		error = 0;
1624 	}
1625 	return error;
1626 }
1627 
1628 static int
get_doubleagentd_port(mach_port_t * doubleagentd_port)1629 get_doubleagentd_port(mach_port_t *doubleagentd_port)
1630 {
1631 	kern_return_t ret;
1632 
1633 	*doubleagentd_port = MACH_PORT_NULL;
1634 	ret = host_get_doubleagentd_port(host_priv_self(), doubleagentd_port);
1635 	if (ret != KERN_SUCCESS) {
1636 		printf("vfs_xattr: can't get doubleagentd port, status 0x%08x\n", ret);
1637 		return EIO;
1638 	}
1639 	if (!IPC_PORT_VALID(*doubleagentd_port)) {
1640 		printf("vfs_xattr: doubleagentd port not valid\n");
1641 		return EIO;
1642 	}
1643 	return 0;
1644 }
1645 
1646 /*
1647  * Retrieve the data of an extended attribute.
1648  * (Using DoubleAgent to parse the AD file).
1649  */
1650 static int
default_getxattr_doubleagent(vnode_t vp,const char * name,uio_t uio,size_t * size,__unused int options,vfs_context_t context,mach_port_t doubleagentd_port)1651 default_getxattr_doubleagent(vnode_t vp, const char *name, uio_t uio,
1652     size_t *size, __unused int options, vfs_context_t context,
1653     mach_port_t doubleagentd_port)
1654 {
1655 	vnode_t xvp = NULL;
1656 	struct fileglob *xfg = NULL;
1657 	mach_port_t fileport = MACH_PORT_NULL;
1658 	uint64_t value_offset = 0;
1659 	uint64_t value_length = 0;
1660 	int64_t fsize;
1661 	int isrsrcfork;
1662 	int fileflags;
1663 	int error;
1664 	kern_return_t kr;
1665 	char cName[XATTR_MAXNAMELEN] = {0};
1666 	bool have_iocount = true;
1667 
1668 	fileflags = FREAD | O_SHLOCK;
1669 	isrsrcfork = strncmp(name, XATTR_RESOURCEFORK_NAME,
1670 	    sizeof(XATTR_RESOURCEFORK_NAME)) == 0;
1671 
1672 	if ((error = open_xattrfile(vp, fileflags, &xfg, &fsize, NULL, context))) {
1673 		goto out;
1674 	}
1675 	xvp = fg_get_data(xfg);
1676 	if ((error = make_xattrfile_port(xfg, &fileport))) {
1677 		goto out;
1678 	}
1679 
1680 	/* Drop the iocount before upcalling to doubleagentd. */
1681 	vnode_put(xvp);
1682 	have_iocount = false;
1683 
1684 	strncpy(cName, name, XATTR_MAXNAMELEN);
1685 
1686 	/*
1687 	 * Call doubleagentd to look up the xattr.  The fileport argument
1688 	 * is declared move-send, so the Mig stub consumes it.
1689 	 */
1690 	kr = doubleagent_lookup_xattr(doubleagentd_port, fileport, fsize, cName,
1691 	    &error, &value_offset, &value_length);
1692 	if (kr != KERN_SUCCESS) {
1693 		error = EIO;
1694 	}
1695 	if (error == 0) {
1696 		error = vnode_getwithref(xvp);
1697 	}
1698 	if (error) {
1699 		goto out;
1700 	}
1701 	have_iocount = true;
1702 	if (uio != NULL) {
1703 		if (isrsrcfork) {
1704 			// Resource Fork case is a bit different,
1705 			// as we can have a non-zero uio offset.
1706 			uio_setoffset(uio, uio_offset(uio) + value_offset);
1707 			error = VNOP_READ(xvp, uio, 0, context);
1708 			if (error == 0) {
1709 				uio_setoffset(uio, uio_offset(uio) - value_offset);
1710 			}
1711 		} else {
1712 			if (uio_resid(uio) < value_length) {
1713 				error = ERANGE;
1714 				goto out;
1715 			}
1716 
1717 			// Read from the relevant offset in the AD file into the uio.
1718 			user_ssize_t orig_resid = uio_resid(uio);
1719 			uio_setoffset(uio, value_offset);
1720 			uio_setresid(uio, value_length);
1721 
1722 			error = VNOP_READ(xvp, uio, 0, context);
1723 
1724 			uio_setoffset(uio, 0);
1725 			uio_setresid(uio, orig_resid - value_length + uio_resid(uio));
1726 		}
1727 	}
1728 
1729 	*size = value_length;
1730 
1731 out:
1732 	if (xfg != NULL) {
1733 		close_xattrfile(xfg, have_iocount, true, context);
1734 	}
1735 	return error;
1736 }
1737 
1738 /*
1739  * Retrieve the list of extended attribute names.
1740  * (Using DoubleAgent to parse the AD file).
1741  */
1742 static int
default_listxattr_doubleagent(vnode_t vp,uio_t uio,size_t * size,__unused int options,vfs_context_t context,mach_port_t doubleagentd_port)1743 default_listxattr_doubleagent(vnode_t vp, uio_t uio, size_t *size,
1744     __unused int options, vfs_context_t context, mach_port_t doubleagentd_port)
1745 {
1746 	vnode_t xvp = NULL;
1747 	struct fileglob *xfg = NULL;
1748 	int64_t fsize;
1749 	int error;
1750 
1751 	mach_port_t fileport = MACH_PORT_NULL;
1752 	kern_return_t kr;
1753 	void *buf = NULL;
1754 	listxattrs_result_t *result;
1755 	bool have_iocount = true;
1756 
1757 	/*
1758 	 * We do not zero "*size" here as we don't want to stomp a size set
1759 	 * when VNOP_LISTXATTR() processed any native EAs.  That size is
1760 	 * initially zeroed by the system call layer, up in listxattr() or
1761 	 * flistxattr().
1762 	 */
1763 
1764 	if ((error = open_xattrfile(vp, FREAD | O_SHLOCK, &xfg, &fsize, NULL,
1765 	    context))) {
1766 		if (error == ENOATTR) {
1767 			error = 0;
1768 		}
1769 		goto out;
1770 	}
1771 	xvp = fg_get_data(xfg);
1772 	if ((error = make_xattrfile_port(xfg, &fileport))) {
1773 		goto out;
1774 	}
1775 
1776 	/* Drop the iocount before upcalling to doubleagentd. */
1777 	vnode_put(xvp);
1778 	have_iocount = false;
1779 
1780 	buf = kalloc_data(sizeof(listxattrs_result_t), Z_WAITOK);
1781 	result = (listxattrs_result_t *)buf;
1782 
1783 	/*
1784 	 * Call doubleagentd to list the xattrs.  The fileport argument
1785 	 * is declared move-send, so the Mig stub consumes it.
1786 	 */
1787 	kr = doubleagent_list_xattrs(doubleagentd_port, fileport, fsize, &error,
1788 	    result);
1789 	if (kr != KERN_SUCCESS) {
1790 		error = EIO;
1791 	}
1792 	if (error == 0) {
1793 		error = vnode_getwithref(xvp);
1794 	}
1795 	if (error) {
1796 		goto out;
1797 	}
1798 	have_iocount = true;
1799 
1800 	if (uio != NULL) {
1801 		if (uio_resid(uio) < result->namesLength) {
1802 			error = ERANGE;
1803 			goto out;
1804 		}
1805 		// copy the relevant part of the result into the uio.
1806 		error = uiomove((const char *)result->data, (int)result->namesLength, uio);
1807 		if (error) {
1808 			if (error != EFAULT) {
1809 				error = ERANGE;
1810 			}
1811 			goto out;
1812 		}
1813 	}
1814 
1815 	/*
1816 	 * Set *size, while preserving any previous value from
1817 	 * VNOP_LISTXATTR().
1818 	 */
1819 	*size += result->namesLength;
1820 
1821 out:
1822 	if (xfg != NULL) {
1823 		close_xattrfile(xfg, have_iocount, true, context);
1824 	}
1825 	if (buf != NULL) {
1826 		kfree_data(buf, sizeof(listxattrs_result_t));
1827 	}
1828 	return error;
1829 }
1830 
1831 /*
1832  * Set the data of an extended attribute.
1833  * (Using DoubleAgent to parse the AD file).
1834  */
1835 static int __attribute__((noinline))
default_setxattr_doubleagent(vnode_t vp,const char * name,uio_t uio,int options,vfs_context_t context,mach_port_t doubleagentd_port)1836 default_setxattr_doubleagent(vnode_t vp, const char *name, uio_t uio,
1837     int options, vfs_context_t context, mach_port_t doubleagentd_port)
1838 {
1839 	vnode_t xvp = NULL;
1840 	struct fileglob *xfg = NULL;
1841 	size_t datalen;
1842 	int namelen;
1843 	int fileflags;
1844 	int error;
1845 	char cName[XATTR_MAXNAMELEN] = {0};
1846 	char finfo[FINDERINFOSIZE];
1847 	uio_t finfo_uio = NULL;
1848 	mach_port_t fileport = MACH_PORT_NULL;
1849 	uint64_t value_offset = 0;
1850 	int64_t fsize;
1851 	kern_return_t kr;
1852 	bool have_iocount = true;
1853 	bool created_xattr_file = false;
1854 	bool removed_xattr_file = false;
1855 
1856 	datalen = uio_resid(uio);
1857 	if (datalen > XATTR_MAXSIZE) {
1858 		return E2BIG;
1859 	}
1860 	namelen = (int)strlen(name) + 1;
1861 	if (namelen > UINT8_MAX) {
1862 		return EINVAL;
1863 	}
1864 
1865 	/*
1866 	 * By convention, Finder Info that is all zeroes is equivalent to not
1867 	 * having a Finder Info EA.  So if we're trying to set the Finder Info
1868 	 * to all zeroes, then delete it instead.  If a file didn't have an
1869 	 * AppleDouble file before, this prevents creating an AppleDouble file
1870 	 * with no useful content.
1871 	 *
1872 	 * If neither XATTR_CREATE nor XATTR_REPLACE were specified, we check
1873 	 * for all zeroes Finder Info before opening the AppleDouble file.
1874 	 * But if either of those options were specified, we need to open the
1875 	 * AppleDouble file to see whether there was already Finder Info (so we
1876 	 * can return an error if needed); this case is handled in DoubleAgent.
1877 	 */
1878 	if (strncmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
1879 		if (uio_offset(uio) != 0) {
1880 			return EINVAL;
1881 		}
1882 
1883 		if (datalen != FINDERINFOSIZE) {
1884 			return ERANGE;
1885 		}
1886 
1887 		// Duplicate the uio to keep it as-is for later.
1888 		finfo_uio = uio_duplicate(uio);
1889 		// Get the finfo data from the duplicated uio.
1890 		error = uiomove(finfo, (int)datalen, finfo_uio);
1891 		uio_free(finfo_uio);
1892 		if (error) {
1893 			return error;
1894 		}
1895 		if ((options & (XATTR_CREATE | XATTR_REPLACE)) == 0 &&
1896 		    bcmp(finfo, emptyfinfo, FINDERINFOSIZE) == 0) {
1897 			error = default_removexattr(vp, name, 0, context);
1898 			if (error == ENOATTR) {
1899 				error = 0;
1900 			}
1901 			return error;
1902 		}
1903 	}
1904 
1905 	if (strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0) {
1906 		/*
1907 		 * For ResourceFork we allow offset to be != 0, so adjust datalen accordingly
1908 		 * so doubleagent will adjust the file length accordingly
1909 		 *
1910 		 */
1911 		if (__improbable(os_add_overflow(datalen, uio_offset(uio), &datalen))) {
1912 			return EINVAL;
1913 		}
1914 
1915 		if (datalen > UINT32_MAX) {
1916 			return EINVAL;
1917 		}
1918 	}
1919 
1920 	/*
1921 	 * Open the file locked since setting an attribute
1922 	 * can change the layout of the Apple Double file.
1923 	 */
1924 	fileflags = FREAD | FWRITE | O_EXLOCK;
1925 	if ((error = open_xattrfile(vp, O_CREAT | fileflags, &xfg, &fsize,
1926 	    &created_xattr_file, context))) {
1927 		goto out;
1928 	}
1929 	xvp = fg_get_data(xfg);
1930 	if ((error = make_xattrfile_port(xfg, &fileport))) {
1931 		goto out;
1932 	}
1933 
1934 	/* Drop the iocount before upcalling to doubleagentd. */
1935 	vnode_put(xvp);
1936 	have_iocount = false;
1937 
1938 	strncpy(cName, name, XATTR_MAXNAMELEN);
1939 
1940 	/*
1941 	 * Call doubleagentd to allocate space for the xattr.  The
1942 	 * fileport argument is declared move-send, so the Mig stub
1943 	 * consumes it.
1944 	 */
1945 	kr = doubleagent_allocate_xattr(doubleagentd_port, fileport, fsize,
1946 	    cName, datalen, options, &error, &value_offset);
1947 	if (kr != KERN_SUCCESS) {
1948 		error = EIO;
1949 	}
1950 	if (error == 0) {
1951 		error = vnode_getwithref(xvp);
1952 	}
1953 	if (error) {
1954 		goto out;
1955 	}
1956 	have_iocount = true;
1957 
1958 	/*
1959 	 * write the uio data into the offset we got from doubleagent,
1960 	 * while adding the given uio offset (could be non-zero only for
1961 	 * resource fork; it is being checked earlier).
1962 	 */
1963 	uio_setoffset(uio, uio_offset(uio) + value_offset);
1964 	error = VNOP_WRITE(xvp, uio, 0, context);
1965 	uio_setoffset(uio, 0);
1966 
1967 out:
1968 	if (xfg != NULL) {
1969 		/*
1970 		 * In case we have just created the AppleDouble file, and DoubleAgent
1971 		 * couldn't allocate space for the xattr, remove it so we won't leave
1972 		 * an uninitialized AppleDouble file.
1973 		 */
1974 		if (error && created_xattr_file) {
1975 			/* remove_xattrfile() assumes we have an iocount on the vnode */
1976 			if (vnode_getwithref(xvp) == 0) {
1977 				remove_xattrfile(xfg, xvp, context);
1978 				removed_xattr_file = true;
1979 			}
1980 		}
1981 		/* remove_xattrfile() would call close_xattrfile already */
1982 		if (!removed_xattr_file) {
1983 			close_xattrfile(xfg, have_iocount, true, context);
1984 		}
1985 	}
1986 
1987 	/* Touch the change time if we changed an attribute. */
1988 	if (error == 0) {
1989 		struct vnode_attr va;
1990 
1991 		/* Re-write the mtime to cause a ctime change. */
1992 		VATTR_INIT(&va);
1993 		VATTR_WANTED(&va, va_modify_time);
1994 		if (vnode_getattr(vp, &va, context) == 0) {
1995 			VATTR_INIT(&va);
1996 			VATTR_SET(&va, va_modify_time, va.va_modify_time);
1997 			(void) vnode_setattr(vp, &va, context);
1998 		}
1999 	}
2000 
2001 	post_event_if_success(vp, error, NOTE_ATTRIB);
2002 
2003 	return error;
2004 }
2005 
2006 /*
2007  * Remove an extended attribute.
2008  * (Using DoubleAgent to parse the AD file).
2009  */
2010 static int
default_removexattr_doubleagent(vnode_t vp,const char * name,__unused int options,vfs_context_t context,mach_port_t doubleagentd_port)2011 default_removexattr_doubleagent(vnode_t vp, const char *name,
2012     __unused int options, vfs_context_t context,
2013     mach_port_t doubleagentd_port)
2014 {
2015 	vnode_t xvp = NULL;
2016 	struct fileglob *xfg = NULL;
2017 	int isrsrcfork;
2018 	int fileflags;
2019 	int error;
2020 	int64_t fsize;
2021 	boolean_t is_empty = false;
2022 	char cName[XATTR_MAXNAMELEN] = {0};
2023 	mach_port_t fileport = MACH_PORT_NULL;
2024 	kern_return_t kr;
2025 	bool have_iocount = true;
2026 
2027 	fileflags = FREAD | FWRITE | O_EXLOCK;
2028 	isrsrcfork = strncmp(name, XATTR_RESOURCEFORK_NAME,
2029 	    sizeof(XATTR_RESOURCEFORK_NAME)) == 0;
2030 
2031 	if ((error = open_xattrfile(vp, fileflags, &xfg, &fsize, NULL, context))) {
2032 		goto out;
2033 	}
2034 	xvp = fg_get_data(xfg);
2035 	if ((error = make_xattrfile_port(xfg, &fileport))) {
2036 		goto out;
2037 	}
2038 
2039 	/* Drop the iocount before upcalling to doubleagentd. */
2040 	vnode_put(xvp);
2041 	have_iocount = false;
2042 
2043 	strncpy(cName, name, XATTR_MAXNAMELEN);
2044 
2045 	/*
2046 	 * Call doubleagentd to remove the xattr.  The fileport argument
2047 	 * is declared move-send, so the Mig stub consumes it.
2048 	 */
2049 	kr = doubleagent_remove_xattr(doubleagentd_port, fileport, fsize, cName,
2050 	    &error, &is_empty);
2051 	if (kr != KERN_SUCCESS) {
2052 		error = EIO;
2053 	}
2054 	if (error == 0) {
2055 		error = vnode_getwithref(xvp);
2056 	}
2057 	if (error) {
2058 		goto out;
2059 	}
2060 	have_iocount = true;
2061 
2062 out:
2063 	if (error == 0) {
2064 		/* When there are no more attributes remove the ._ file. */
2065 		if (is_empty) {
2066 			remove_xattrfile(xfg, xvp, context);
2067 		} else {
2068 			close_xattrfile(xfg, have_iocount, true, context);
2069 		}
2070 		xfg = NULL;
2071 
2072 		/* Touch the change time if we changed an attribute. */
2073 		struct vnode_attr va;
2074 		/* Re-write the mtime to cause a ctime change. */
2075 		VATTR_INIT(&va);
2076 		VATTR_WANTED(&va, va_modify_time);
2077 		if (vnode_getattr(vp, &va, context) == 0) {
2078 			VATTR_INIT(&va);
2079 			VATTR_SET(&va, va_modify_time, va.va_modify_time);
2080 			(void) vnode_setattr(vp, &va, context);
2081 		}
2082 	}
2083 
2084 	post_event_if_success(vp, error, NOTE_ATTRIB);
2085 
2086 	if (xfg != NULL) {
2087 		close_xattrfile(xfg, have_iocount, true, context);
2088 	}
2089 	return error;
2090 }
2091 
2092 static int
open_xattrfile(vnode_t vp,int fileflags,struct fileglob ** xfgp,int64_t * file_sizep,bool * created_xattr_filep,vfs_context_t context)2093 open_xattrfile(vnode_t vp, int fileflags, struct fileglob **xfgp,
2094     int64_t *file_sizep, bool *created_xattr_filep, vfs_context_t context)
2095 {
2096 	extern const struct fileops vnops;      /* XXX */
2097 	vnode_t xvp = NULLVP;
2098 	vnode_t dvp = NULLVP;
2099 	struct fileglob *fg = NULL;
2100 	struct vnode_attr *va = NULL;
2101 	struct nameidata *nd = NULL;
2102 	char smallname[64];
2103 	char *filename = NULL;
2104 	const char *basename = NULL;
2105 	size_t alloc_len = 0;
2106 	size_t copy_len;
2107 	errno_t error;
2108 	int opened = 0;
2109 	int referenced = 0;
2110 	bool created_xattr_file = false;
2111 
2112 	if (vnode_isvroot(vp) && vnode_isdir(vp)) {
2113 		/*
2114 		 * For the root directory use "._." to hold the attributes.
2115 		 */
2116 		filename = &smallname[0];
2117 		snprintf(filename, sizeof(smallname), "%s%s", ATTR_FILE_PREFIX, ".");
2118 		dvp = vp;  /* the "._." file resides in the root dir */
2119 		goto lookup;
2120 	}
2121 	if ((dvp = vnode_getparent(vp)) == NULLVP) {
2122 		error = ENOATTR;
2123 		goto out;
2124 	}
2125 	if ((basename = vnode_getname(vp)) == NULL) {
2126 		error = ENOATTR;
2127 		goto out;
2128 	}
2129 
2130 	/* "._" Attribute files cannot have attributes */
2131 	if (vp->v_type == VREG && strlen(basename) > 2 &&
2132 	    basename[0] == '.' && basename[1] == '_') {
2133 		error = EPERM;
2134 		goto out;
2135 	}
2136 	filename = &smallname[0];
2137 	alloc_len = snprintf(filename, sizeof(smallname), "%s%s", ATTR_FILE_PREFIX, basename);
2138 	if (alloc_len >= sizeof(smallname)) {
2139 		alloc_len++;  /* snprintf result doesn't include '\0' */
2140 		filename = kalloc_data(alloc_len, Z_WAITOK);
2141 		copy_len = snprintf(filename, alloc_len, "%s%s", ATTR_FILE_PREFIX, basename);
2142 	}
2143 	/*
2144 	 * Note that the lookup here does not authorize.  Since we are looking
2145 	 * up in the same directory that we already have the file vnode in,
2146 	 * we must have been given the file vnode legitimately.  Read/write
2147 	 * access has already been authorized in layers above for calls from
2148 	 * userspace, and the authorization code using this path to read
2149 	 * file security from the EA must always get access
2150 	 */
2151 lookup:
2152 	nd = kalloc_type(struct nameidata, Z_WAITOK);
2153 	NDINIT(nd, LOOKUP, OP_OPEN, LOCKLEAF | NOFOLLOW | USEDVP | DONOTAUTH,
2154 	    UIO_SYSSPACE, CAST_USER_ADDR_T(filename), context);
2155 	nd->ni_dvp = dvp;
2156 
2157 	va = kalloc_type(struct vnode_attr, Z_WAITOK);
2158 
2159 	if (fileflags & O_CREAT) {
2160 		nd->ni_cnd.cn_nameiop = CREATE;
2161 #if CONFIG_TRIGGERS
2162 		nd->ni_op = OP_LINK;
2163 #endif
2164 		if (dvp != vp) {
2165 			nd->ni_cnd.cn_flags |= LOCKPARENT;
2166 		}
2167 		if ((error = namei(nd))) {
2168 			nd->ni_dvp = NULLVP;
2169 			error = ENOATTR;
2170 			goto out;
2171 		}
2172 		if ((xvp = nd->ni_vp) == NULLVP) {
2173 			uid_t uid;
2174 			gid_t gid;
2175 			mode_t umode;
2176 
2177 			/*
2178 			 * Pick up uid/gid/mode from target file.
2179 			 */
2180 			VATTR_INIT(va);
2181 			VATTR_WANTED(va, va_uid);
2182 			VATTR_WANTED(va, va_gid);
2183 			VATTR_WANTED(va, va_mode);
2184 			if (VNOP_GETATTR(vp, va, context) == 0 &&
2185 			    VATTR_IS_SUPPORTED(va, va_uid) &&
2186 			    VATTR_IS_SUPPORTED(va, va_gid) &&
2187 			    VATTR_IS_SUPPORTED(va, va_mode)) {
2188 				uid = va->va_uid;
2189 				gid = va->va_gid;
2190 				umode = va->va_mode & (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
2191 			} else { /* fallback values */
2192 				uid = KAUTH_UID_NONE;
2193 				gid = KAUTH_GID_NONE;
2194 				umode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
2195 			}
2196 
2197 			VATTR_INIT(va);
2198 			VATTR_SET(va, va_type, VREG);
2199 			VATTR_SET(va, va_mode, umode);
2200 			if (uid != KAUTH_UID_NONE) {
2201 				VATTR_SET(va, va_uid, uid);
2202 			}
2203 			if (gid != KAUTH_GID_NONE) {
2204 				VATTR_SET(va, va_gid, gid);
2205 			}
2206 
2207 			error = vn_create(dvp, &nd->ni_vp, nd, va,
2208 			    VN_CREATE_NOAUTH | VN_CREATE_NOINHERIT | VN_CREATE_NOLABEL,
2209 			    0, NULL,
2210 			    context);
2211 			if (error) {
2212 				error = ENOATTR;
2213 			} else {
2214 				xvp = nd->ni_vp;
2215 				created_xattr_file = true;
2216 				if (created_xattr_filep) {
2217 					*created_xattr_filep = true;
2218 				}
2219 			}
2220 		}
2221 		nameidone(nd);
2222 		if (dvp != vp) {
2223 			vnode_put(dvp);  /* drop iocount from LOCKPARENT request above */
2224 		}
2225 		if (error) {
2226 			goto out;
2227 		}
2228 	} else {
2229 		if ((error = namei(nd))) {
2230 			nd->ni_dvp = NULLVP;
2231 			error = ENOATTR;
2232 			goto out;
2233 		}
2234 		xvp = nd->ni_vp;
2235 		nameidone(nd);
2236 	}
2237 	nd->ni_dvp = NULLVP;
2238 
2239 	if (xvp->v_type != VREG) {
2240 		error = ENOATTR;
2241 		goto out;
2242 	}
2243 	/*
2244 	 * Owners must match.
2245 	 */
2246 	VATTR_INIT(va);
2247 	VATTR_WANTED(va, va_uid);
2248 	if (VNOP_GETATTR(vp, va, context) == 0 && VATTR_IS_SUPPORTED(va, va_uid)) {
2249 		uid_t owner = va->va_uid;
2250 
2251 		VATTR_INIT(va);
2252 		VATTR_WANTED(va, va_uid);
2253 		if (VNOP_GETATTR(xvp, va, context) == 0 && (owner != va->va_uid)) {
2254 			error = ENOATTR;  /* don't use this "._" file */
2255 			goto out;
2256 		}
2257 	}
2258 
2259 	if ((error = VNOP_OPEN(xvp, fileflags & ~(O_EXLOCK | O_SHLOCK), context))) {
2260 		error = ENOATTR;
2261 		goto out;
2262 	}
2263 	opened = 1;
2264 
2265 	if ((error = vnode_ref_ext(xvp, fileflags, 0)) != 0) {
2266 		goto out;
2267 	}
2268 	referenced = 1;
2269 
2270 	/*
2271 	 * Allocate a file object for the referenced vnode.
2272 	 * This file object now owns the vnode reference,
2273 	 * and the caller owns the iocount, which will be
2274 	 * dropped in close_xattrfile().
2275 	 */
2276 	fg = fg_alloc_init(context);
2277 	fg->fg_flag = fileflags & FMASK;
2278 	fg->fg_ops = &vnops;
2279 	fg_set_data(fg, xvp);
2280 
2281 	/* Apply file locking if requested. */
2282 	if (fileflags & (O_EXLOCK | O_SHLOCK)) {
2283 		struct flock lf = {
2284 			.l_whence = SEEK_SET,
2285 		};
2286 
2287 		if (fileflags & O_EXLOCK) {
2288 			lf.l_type = F_WRLCK;
2289 		} else {
2290 			lf.l_type = F_RDLCK;
2291 		}
2292 		error = VNOP_ADVLOCK(xvp, (caddr_t)fg, F_SETLK, &lf, F_FLOCK | F_WAIT, context, NULL);
2293 		if (error == ENOTSUP) {
2294 			error = 0;
2295 		} else if (error) {
2296 			error = ENOATTR;
2297 			goto out;
2298 		} else { // error == 0
2299 			fg->fg_flag |= FWASLOCKED;
2300 		}
2301 	}
2302 
2303 	if (file_sizep != NULL) {
2304 		/*
2305 		 * Now that the file is locked, get the file's size.
2306 		 */
2307 		VATTR_INIT(va);
2308 		VATTR_WANTED(va, va_data_size);
2309 		if ((error = vnode_getattr(xvp, va, context)) != 0) {
2310 			error = ENOATTR;
2311 			goto out;
2312 		}
2313 		*file_sizep = va->va_data_size;
2314 	}
2315 out:
2316 	if (error) {
2317 		if (fg != NULL) {
2318 			/* Let the normal close path handle this. */
2319 			if (created_xattr_file) {
2320 				remove_xattrfile(fg, xvp, context);
2321 			} else {
2322 				close_xattrfile(fg, true, true, context);
2323 			}
2324 			fg = NULL;
2325 			xvp = NULLVP;
2326 		} else if (xvp != NULLVP) {
2327 			if (opened) {
2328 				(void) VNOP_CLOSE(xvp, fileflags, context);
2329 			}
2330 			if (created_xattr_file) {
2331 				remove_xattrfile(NULL, xvp, context);
2332 			}
2333 			if (referenced) {
2334 				(void) vnode_rele(xvp);
2335 			}
2336 			/* remove_xattrfile() would have dropped the iocount already */
2337 			if (!created_xattr_file) {
2338 				(void) vnode_put(xvp);
2339 			}
2340 			xvp = NULLVP;
2341 		}
2342 		if ((error == ENOATTR) && (fileflags & O_CREAT)) {
2343 			error = EPERM;
2344 		}
2345 	}
2346 
2347 	/* Release resources after error-handling */
2348 	kfree_type(struct nameidata, nd);
2349 	kfree_type(struct vnode_attr, va);
2350 	if (dvp && (dvp != vp)) {
2351 		vnode_put(dvp);
2352 	}
2353 	if (basename) {
2354 		vnode_putname(basename);
2355 	}
2356 	if (filename && filename != &smallname[0]) {
2357 		kfree_data(filename, alloc_len);
2358 	}
2359 
2360 	*xfgp = fg;
2361 	return error;
2362 }
2363 
2364 static void
close_xattrfile(struct fileglob * xfg,bool have_iocount,bool drop_iocount,vfs_context_t context)2365 close_xattrfile(struct fileglob *xfg, bool have_iocount, bool drop_iocount,
2366     vfs_context_t context)
2367 {
2368 	vnode_t xvp = fg_get_data(xfg);
2369 
2370 	/*
2371 	 * N.B. The only time have_iocount would be false would be when
2372 	 * a vnode_getwithref() calls fails after coming back from a
2373 	 * doubleagentd upcall.  If that happens, then it would mean
2374 	 * that the old vnode identity is gone, and our advisory lock
2375 	 * would have been garbage-collected when the vnode was reclaimed.
2376 	 */
2377 	if (have_iocount) {
2378 		/*
2379 		 * fg_drop() won't drop our advisory lock because we are not
2380 		 * following POSIX semantics.  Drop it here.
2381 		 */
2382 		struct flock lf = {
2383 			.l_whence = SEEK_SET,
2384 			.l_type = F_UNLCK,
2385 		};
2386 		(void)VNOP_ADVLOCK(xvp, (caddr_t)xfg, F_UNLCK, &lf, F_FLOCK,
2387 		    context, NULL);
2388 
2389 		/* (Maybe) drop the iocount we took in open_xattrfile(). */
2390 		if (drop_iocount) {
2391 			vnode_put(xvp);
2392 		}
2393 	}
2394 
2395 	(void) fg_drop(current_proc(), xfg);
2396 }
2397 
2398 static void
remove_xattrfile(struct fileglob * xfg,vnode_t xvp,vfs_context_t context)2399 remove_xattrfile(struct fileglob *xfg, vnode_t xvp, vfs_context_t context)
2400 {
2401 	vnode_t dvp = NULL, rvp = NULL;
2402 	struct nameidata nd;
2403 	char *path = NULL;
2404 	int pathlen;
2405 	int error;
2406 
2407 	if (xfg != NULL) {
2408 		/*
2409 		 * Close the xattr file but don't dispose of the
2410 		 * iocount acquired in open_xattrfile() while doing
2411 		 * so.  We'll do that below once we have performed
2412 		 * the unlink operation.
2413 		 */
2414 		close_xattrfile(xfg, true, false, context);
2415 	}
2416 
2417 	path = zalloc(ZV_NAMEI);
2418 	pathlen = MAXPATHLEN;
2419 	error = vn_getpath(xvp, path, &pathlen);
2420 	if (error) {
2421 		zfree(ZV_NAMEI, path);
2422 		goto out;
2423 	}
2424 
2425 	NDINIT(&nd, DELETE, OP_UNLINK, LOCKPARENT | NOFOLLOW | DONOTAUTH,
2426 	    UIO_SYSSPACE, CAST_USER_ADDR_T(path), context);
2427 	error = namei(&nd);
2428 	zfree(ZV_NAMEI, path);
2429 	if (error) {
2430 		goto out;
2431 	}
2432 	dvp = nd.ni_dvp;
2433 	rvp = nd.ni_vp;
2434 
2435 	/*
2436 	 * Only remove if the namei() returned to us the same vnode that
2437 	 * we think we are supposed to be removing.  If they're not the
2438 	 * same, we could have raced against something else trying to
2439 	 * unlink it, and we don't want to remove someone else's (possibly
2440 	 * very important) file.
2441 	 */
2442 	if (rvp == xvp) {
2443 		(void) VNOP_REMOVE(dvp, rvp, &nd.ni_cnd, 0, context);
2444 	}
2445 	nameidone(&nd);
2446 
2447 out:
2448 	vnode_put(xvp);
2449 	if (dvp != NULLVP) {
2450 		vnode_put(dvp);
2451 	}
2452 	if (rvp != NULLVP) {
2453 		vnode_put(rvp);
2454 	}
2455 }
2456 
2457 static int
make_xattrfile_port(struct fileglob * fg,ipc_port_t * portp)2458 make_xattrfile_port(struct fileglob *fg, ipc_port_t *portp)
2459 {
2460 	/*
2461 	 * This is essentially a stripped-down copy of
2462 	 * sys_fileport_makeport().
2463 	 */
2464 	ipc_port_t fileport;
2465 	int error = 0;
2466 
2467 	/* Dropped when port is deallocated. */
2468 	fg_ref(FG_NOPROC, fg);
2469 
2470 	fileport = fileport_alloc(fg);
2471 	if (fileport == IPC_PORT_NULL) {
2472 		fg_drop_live(fg);
2473 		error = EIO;
2474 	} else {
2475 		/* Tag the fileglob for debugging purposes */
2476 		lck_mtx_lock_spin(&fg->fg_lock);
2477 		fg->fg_lflags |= FG_PORTMADE;
2478 		lck_mtx_unlock(&fg->fg_lock);
2479 	}
2480 
2481 	/*
2482 	 * The Mig defs for doubleagentd declare the fileport argument
2483 	 * as move-send.  If we ever decide we want to cache the fileport
2484 	 * here in the kernel, we will either need to change the Mig
2485 	 * defs back to the default mach_port_t (which is a copy-send)
2486 	 * or explicitly ipc_port_copy_send_any() the right before
2487 	 * sending it in the Mig stub.
2488 	 */
2489 
2490 	*portp = fileport;
2491 	return error;
2492 }
2493 
2494 #else /* CONFIG_APPLEDOUBLE */
2495 
2496 
2497 static int
default_getxattr(__unused vnode_t vp,__unused const char * name,__unused uio_t uio,__unused size_t * size,__unused int options,__unused vfs_context_t context)2498 default_getxattr(__unused vnode_t vp, __unused const char *name,
2499     __unused uio_t uio, __unused size_t *size, __unused int options,
2500     __unused vfs_context_t context)
2501 {
2502 	return ENOTSUP;
2503 }
2504 
2505 static int
default_setxattr(__unused vnode_t vp,__unused const char * name,__unused uio_t uio,__unused int options,__unused vfs_context_t context)2506 default_setxattr(__unused vnode_t vp, __unused const char *name,
2507     __unused uio_t uio, __unused int options, __unused vfs_context_t context)
2508 {
2509 	return ENOTSUP;
2510 }
2511 
2512 static int
default_listxattr(__unused vnode_t vp,__unused uio_t uio,__unused size_t * size,__unused int options,__unused vfs_context_t context)2513 default_listxattr(__unused vnode_t vp,
2514     __unused uio_t uio, __unused size_t *size, __unused int options,
2515     __unused vfs_context_t context)
2516 {
2517 	return ENOTSUP;
2518 }
2519 
2520 static int
default_removexattr(__unused vnode_t vp,__unused const char * name,__unused int options,__unused vfs_context_t context)2521 default_removexattr(__unused vnode_t vp, __unused const char *name,
2522     __unused int options, __unused vfs_context_t context)
2523 {
2524 	return ENOTSUP;
2525 }
2526 
2527 #endif /* CONFIG_APPLEDOUBLE */
2528