xref: /xnu-11417.140.69/bsd/vfs/vfs_xattr.c (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
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;
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 /*
1517  * sysctl stuff
1518  */
1519 static int vfs_xattr_doubleagent_enabled = 1;
1520 SYSCTL_DECL(_vfs_generic);
1521 SYSCTL_INT(_vfs_generic, OID_AUTO, xattr_doubleagent_enabled, CTLFLAG_RW | CTLFLAG_LOCKED, &vfs_xattr_doubleagent_enabled, 0, "");
1522 
1523 static int get_doubleagentd_port(mach_port_t *doubleagentd_port);
1524 
1525 /*
1526  * VFS default xattr functions
1527  */
1528 static int default_getxattr_vfs(vnode_t vp, const char *name, uio_t uio, size_t *size, int options,
1529     vfs_context_t context);
1530 static int default_setxattr_vfs(vnode_t vp, const char *name, uio_t uio, int options,
1531     vfs_context_t context);
1532 static int default_listxattr_vfs(vnode_t vp, uio_t uio, size_t *size, int options,
1533     vfs_context_t context);
1534 static int default_removexattr_vfs(vnode_t vp, const char *name, int options,
1535     vfs_context_t context);
1536 
1537 /*
1538  * DoubleAgent default xattr functions
1539  */
1540 static int default_getxattr_doubleagent(vnode_t vp, const char *name,
1541     uio_t uio, size_t *size, int options, vfs_context_t context,
1542     mach_port_t);
1543 static int default_setxattr_doubleagent(vnode_t vp, const char *name,
1544     uio_t uio, int options, vfs_context_t context, mach_port_t);
1545 static int default_listxattr_doubleagent(vnode_t vp, uio_t uio, size_t *size,
1546     int options, vfs_context_t context, mach_port_t);
1547 static int default_removexattr_doubleagent(vnode_t vp, const char *name,
1548     int options, vfs_context_t context, mach_port_t);
1549 
1550 
1551 static u_int32_t emptyfinfo[8] = {0};
1552 
1553 
1554 /*
1555  * Local support routines
1556  */
1557 static void  close_xattrfile(struct fileglob *xfg, bool have_iocount, bool drop_iocount, vfs_context_t context);
1558 
1559 static int  open_xattrfile(vnode_t vp, int fileflags, struct fileglob **xfgp,
1560     int64_t *file_sizep, vfs_context_t context);
1561 
1562 static int  create_xattrfile(vnode_t xvp, u_int32_t fileid, vfs_context_t context);
1563 
1564 static void  remove_xattrfile(struct fileglob *xfg, vnode_t xvp, vfs_context_t context);
1565 
1566 static int  get_xattrinfo(vnode_t xvp, int setting, attr_info_t *ainfop, vfs_context_t context);
1567 
1568 static void  rel_xattrinfo(attr_info_t *ainfop);
1569 
1570 static int  write_xattrinfo(attr_info_t *ainfop);
1571 
1572 static void  init_empty_resource_fork(rsrcfork_header_t * rsrcforkhdr);
1573 
1574 static int make_xattrfile_port(struct fileglob *xfg, ipc_port_t *portp);
1575 
1576 #if BYTE_ORDER == LITTLE_ENDIAN
1577 static void  swap_adhdr(apple_double_header_t *adh);
1578 static void  swap_attrhdr(attr_header_t *ah, attr_info_t* info);
1579 
1580 #else
1581 #define swap_adhdr(x)
1582 #define swap_attrhdr(x, y)
1583 #endif
1584 
1585 static int  check_and_swap_attrhdr(attr_header_t *ah, attr_info_t* ainfop);
1586 static int  shift_data_down(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t context);
1587 static int  shift_data_up(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t context);
1588 
1589 
1590 /*
1591  * Sanity check and swap the header of an AppleDouble file.  Assumes the buffer
1592  * is in big endian (as it would exist on disk).  Verifies the following:
1593  * - magic field
1594  * - version field
1595  * - number of entries
1596  * - that each entry fits within the file size
1597  *
1598  * If the header is invalid, ENOATTR is returned.
1599  *
1600  * NOTE: Does not attempt to validate the extended attributes header that
1601  * may be embedded in the Finder Info entry.
1602  */
1603 static int
check_and_swap_apple_double_header(attr_info_t * ainfop)1604 check_and_swap_apple_double_header(attr_info_t *ainfop)
1605 {
1606 	int i, j;
1607 	u_int32_t header_end;
1608 	u_int32_t entry_end;
1609 	size_t rawsize;
1610 	apple_double_header_t *header;
1611 
1612 	rawsize = ainfop->rawsize;
1613 	header = (apple_double_header_t *) ainfop->rawdata;
1614 
1615 	/* Is the file big enough to contain an AppleDouble header? */
1616 	if (rawsize < offsetof(apple_double_header_t, entries)) {
1617 		return ENOATTR;
1618 	}
1619 
1620 	/* Swap the AppleDouble header fields to native order */
1621 	header->magic = SWAP32(header->magic);
1622 	header->version = SWAP32(header->version);
1623 	header->numEntries = SWAP16(header->numEntries);
1624 
1625 	/* Sanity check the AppleDouble header fields */
1626 	if (header->magic != ADH_MAGIC ||
1627 	    header->version != ADH_VERSION ||
1628 	    header->numEntries < 1 ||
1629 	    header->numEntries > 15) {
1630 		return ENOATTR;
1631 	}
1632 
1633 	/* Calculate where the entries[] array ends */
1634 	header_end = offsetof(apple_double_header_t, entries) +
1635 	    header->numEntries * sizeof(apple_double_entry_t);
1636 
1637 	/* Is the file big enough to contain the AppleDouble entries? */
1638 	if (rawsize < header_end) {
1639 		return ENOATTR;
1640 	}
1641 
1642 	/* Swap and sanity check each AppleDouble entry */
1643 	for (i = 0; i < header->numEntries; i++) {
1644 		/* Swap the per-entry fields to native order */
1645 		header->entries[i].type   = SWAP32(header->entries[i].type);
1646 		header->entries[i].offset = SWAP32(header->entries[i].offset);
1647 		header->entries[i].length = SWAP32(header->entries[i].length);
1648 
1649 		entry_end = header->entries[i].offset + header->entries[i].length;
1650 
1651 		/*
1652 		 * Does the entry's content start within the header itself,
1653 		 * did the addition overflow, or does the entry's content
1654 		 * extend past the end of the file?
1655 		 */
1656 		if (header->entries[i].offset < header_end ||
1657 		    entry_end < header->entries[i].offset ||
1658 		    entry_end > ainfop->filesize) {
1659 			return ENOATTR;
1660 		}
1661 
1662 		/*
1663 		 * Does the current entry's content overlap with a previous
1664 		 * entry's content?
1665 		 *
1666 		 * Yes, this is O(N**2), and there are more efficient algorithms
1667 		 * for testing pairwise overlap of N ranges when N is large.
1668 		 * But we have already ensured N < 16, and N is almost always 2.
1669 		 * So there's no point in using a more complex algorithm.
1670 		 */
1671 
1672 		for (j = 0; j < i; j++) {
1673 			if (entry_end > header->entries[j].offset &&
1674 			    header->entries[j].offset + header->entries[j].length > header->entries[i].offset) {
1675 				return ENOATTR;
1676 			}
1677 		}
1678 	}
1679 
1680 	return 0;
1681 }
1682 
1683 /*
1684  * Retrieve the data of an extended attribute.
1685  */
1686 static int
default_getxattr(vnode_t vp,const char * name,uio_t uio,size_t * size,__unused int options,vfs_context_t context)1687 default_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size,
1688     __unused int options, vfs_context_t context)
1689 {
1690 	mach_port_t port;
1691 	int error;
1692 
1693 	if (vfs_xattr_doubleagent_enabled &&
1694 	    get_doubleagentd_port(&port) == 0) {
1695 		error = default_getxattr_doubleagent(vp, name, uio, size,
1696 		    options, context, port);
1697 		ipc_port_release_send(port);
1698 	} else {
1699 		error = default_getxattr_vfs(vp, name, uio, size, options,
1700 		    context);
1701 	}
1702 	return error;
1703 }
1704 
1705 /*
1706  * Set the data of an extended attribute.
1707  */
1708 static int __attribute__((noinline))
default_setxattr(vnode_t vp,const char * name,uio_t uio,int options,vfs_context_t context)1709 default_setxattr(vnode_t vp, const char *name, uio_t uio, int options,
1710     vfs_context_t context)
1711 {
1712 	mach_port_t port;
1713 	int error;
1714 
1715 	if (vfs_xattr_doubleagent_enabled &&
1716 	    get_doubleagentd_port(&port) == 0) {
1717 		error = default_setxattr_doubleagent(vp, name, uio, options,
1718 		    context, port);
1719 		ipc_port_release_send(port);
1720 	} else {
1721 		error = default_setxattr_vfs(vp, name, uio, options, context);
1722 	}
1723 	return error;
1724 }
1725 
1726 /*
1727  * Remove an extended attribute.
1728  */
1729 static int
default_removexattr(vnode_t vp,const char * name,__unused int options,vfs_context_t context)1730 default_removexattr(vnode_t vp, const char *name, __unused int options,
1731     vfs_context_t context)
1732 {
1733 	mach_port_t port;
1734 	int error;
1735 
1736 	if (vfs_xattr_doubleagent_enabled &&
1737 	    get_doubleagentd_port(&port) == 0) {
1738 		error = default_removexattr_doubleagent(vp, name, options,
1739 		    context, port);
1740 		ipc_port_release_send(port);
1741 	} else {
1742 		error = default_removexattr_vfs(vp, name, options, context);
1743 	}
1744 	return error;
1745 }
1746 
1747 /*
1748  * Retrieve the list of extended attribute names.
1749  */
1750 static int
default_listxattr(vnode_t vp,uio_t uio,size_t * size,__unused int options,vfs_context_t context)1751 default_listxattr(vnode_t vp, uio_t uio, size_t *size, __unused int options,
1752     vfs_context_t context)
1753 {
1754 	mach_port_t port;
1755 	int error;
1756 
1757 	if (vfs_xattr_doubleagent_enabled &&
1758 	    get_doubleagentd_port(&port) == 0) {
1759 		error = default_listxattr_doubleagent(vp, uio, size, options,
1760 		    context, port);
1761 		ipc_port_release_send(port);
1762 	} else {
1763 		error = default_listxattr_vfs(vp, uio, size, options, context);
1764 	}
1765 	return error;
1766 }
1767 
1768 /*
1769  * Retrieve the data of an extended attribute.
1770  * (VFS implementation).
1771  */
1772 static int
default_getxattr_vfs(vnode_t vp,const char * name,uio_t uio,size_t * size,__unused int options,vfs_context_t context)1773 default_getxattr_vfs(vnode_t vp, const char *name, uio_t uio, size_t *size,
1774     __unused int options, vfs_context_t context)
1775 {
1776 	vnode_t xvp = NULL;
1777 	struct fileglob *xfg = NULL;
1778 	attr_info_t ainfo;
1779 	attr_header_t *header;
1780 	attr_entry_t *entry;
1781 	u_int8_t *attrdata;
1782 	u_int32_t datalen;
1783 	size_t namelen;
1784 	int isrsrcfork;
1785 	int fileflags;
1786 	int i;
1787 	int error;
1788 
1789 	fileflags = FREAD | O_SHLOCK;
1790 	isrsrcfork = strncmp(name, XATTR_RESOURCEFORK_NAME,
1791 	    sizeof(XATTR_RESOURCEFORK_NAME)) == 0;
1792 
1793 	if ((error = open_xattrfile(vp, fileflags, &xfg, NULL, context))) {
1794 		return error;
1795 	}
1796 	xvp = fg_get_data(xfg);
1797 
1798 	if ((error = get_xattrinfo(xvp, 0, &ainfo, context))) {
1799 		close_xattrfile(xfg, true, true, context);
1800 		return error;
1801 	}
1802 
1803 	/* Get the Finder Info. */
1804 	if (strncmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
1805 		if (ainfo.finderinfo == NULL || ainfo.emptyfinderinfo) {
1806 			error = ENOATTR;
1807 		} else if (uio == NULL) {
1808 			*size = FINDERINFOSIZE;
1809 			error = 0;
1810 		} else if (uio_offset(uio) != 0) {
1811 			error = EINVAL;
1812 		} else if (uio_resid(uio) < FINDERINFOSIZE) {
1813 			error = ERANGE;
1814 		} else {
1815 			attrdata = (u_int8_t*)ainfo.filehdr + ainfo.finderinfo->offset;
1816 			error = uiomove((caddr_t)attrdata, FINDERINFOSIZE, uio);
1817 		}
1818 		goto out;
1819 	}
1820 
1821 	/* Read the Resource Fork. */
1822 	if (isrsrcfork) {
1823 		if (!vnode_isreg(vp)) {
1824 			error = EPERM;
1825 		} else if (ainfo.rsrcfork == NULL) {
1826 			error = ENOATTR;
1827 		} else if (uio == NULL) {
1828 			*size = (size_t)ainfo.rsrcfork->length;
1829 		} else {
1830 			uio_setoffset(uio, uio_offset(uio) + ainfo.rsrcfork->offset);
1831 			error = VNOP_READ(xvp, uio, 0, context);
1832 			if (error == 0) {
1833 				uio_setoffset(uio, uio_offset(uio) - ainfo.rsrcfork->offset);
1834 			}
1835 		}
1836 		goto out;
1837 	}
1838 
1839 	if (ainfo.attrhdr == NULL || ainfo.attr_entry == NULL) {
1840 		error = ENOATTR;
1841 		goto out;
1842 	}
1843 	if (uio_offset(uio) != 0) {
1844 		error = EINVAL;
1845 		goto out;
1846 	}
1847 	error = ENOATTR;
1848 	namelen = strlen(name) + 1;
1849 	header = ainfo.attrhdr;
1850 	entry = ainfo.attr_entry;
1851 	/*
1852 	 * Search for attribute name in the header.
1853 	 */
1854 	for (i = 0; i < header->num_attrs && ATTR_VALID(entry, ainfo); i++) {
1855 		if (strncmp((const char *)entry->name, name, namelen) == 0) {
1856 			datalen = entry->length;
1857 			if (uio == NULL) {
1858 				*size = datalen;
1859 				error = 0;
1860 				break;
1861 			}
1862 			if (uio_resid(uio) < (user_ssize_t)datalen) {
1863 				error = ERANGE;
1864 				break;
1865 			}
1866 			if (entry->offset + datalen < ATTR_MAX_HDR_SIZE) {
1867 				attrdata = ((u_int8_t *)header + entry->offset);
1868 				error = uiomove((caddr_t)attrdata, datalen, uio);
1869 			} else {
1870 				uio_setoffset(uio, entry->offset);
1871 				error = VNOP_READ(xvp, uio, 0, context);
1872 				uio_setoffset(uio, 0);
1873 			}
1874 			break;
1875 		}
1876 		entry = ATTR_NEXT(entry);
1877 	}
1878 out:
1879 	rel_xattrinfo(&ainfo);
1880 	close_xattrfile(xfg, true, true, context);
1881 
1882 	return error;
1883 }
1884 
1885 /*
1886  * Set the data of an extended attribute.
1887  * (VFS implementation).
1888  */
1889 static int __attribute__((noinline))
default_setxattr_vfs(vnode_t vp,const char * name,uio_t uio,int options,vfs_context_t context)1890 default_setxattr_vfs(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t context)
1891 {
1892 	vnode_t xvp = NULL;
1893 	struct fileglob *xfg = NULL;
1894 	attr_info_t ainfo;
1895 	attr_header_t *header;
1896 	attr_entry_t *entry;
1897 	attr_entry_t *lastentry;
1898 	u_int8_t *attrdata;
1899 	size_t datalen;
1900 	size_t entrylen;
1901 	size_t datafreespace;
1902 	int namelen;
1903 	int found = 0;
1904 	int i;
1905 	int splitdata;
1906 	int fileflags;
1907 	int error;
1908 	char finfo[FINDERINFOSIZE];
1909 
1910 	datalen = uio_resid(uio);
1911 	if (datalen > XATTR_MAXSIZE) {
1912 		return E2BIG;
1913 	}
1914 	namelen = (int)strlen(name) + 1;
1915 	if (namelen > UINT8_MAX) {
1916 		return EINVAL;
1917 	}
1918 	entrylen = ATTR_ENTRY_LENGTH(namelen);
1919 
1920 	/*
1921 	 * By convention, Finder Info that is all zeroes is equivalent to not
1922 	 * having a Finder Info EA.  So if we're trying to set the Finder Info
1923 	 * to all zeroes, then delete it instead.  If a file didn't have an
1924 	 * AppleDouble file before, this prevents creating an AppleDouble file
1925 	 * with no useful content.
1926 	 *
1927 	 * If neither XATTR_CREATE nor XATTR_REPLACE were specified, we check
1928 	 * for all zeroes Finder Info before opening the AppleDouble file.
1929 	 * But if either of those options were specified, we need to open the
1930 	 * AppleDouble file to see whether there was already Finder Info (so we
1931 	 * can return an error if needed); this case is handled further below.
1932 	 *
1933 	 * NOTE: this copies the Finder Info data into the "finfo" local.
1934 	 */
1935 	if (strncmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
1936 		/*
1937 		 * TODO: check the XATTR_CREATE and XATTR_REPLACE flags.
1938 		 * That means we probably have to open_xattrfile and get_xattrinfo.
1939 		 */
1940 		if (uio_offset(uio) != 0) {
1941 			return EINVAL;
1942 		}
1943 
1944 		if (datalen != FINDERINFOSIZE) {
1945 			return ERANGE;
1946 		}
1947 
1948 		error = uiomove(finfo, (int)datalen, uio);
1949 		if (error) {
1950 			return error;
1951 		}
1952 		if ((options & (XATTR_CREATE | XATTR_REPLACE)) == 0 &&
1953 		    bcmp(finfo, emptyfinfo, FINDERINFOSIZE) == 0) {
1954 			error = default_removexattr(vp, name, 0, context);
1955 			if (error == ENOATTR) {
1956 				error = 0;
1957 			}
1958 			return error;
1959 		}
1960 	}
1961 
1962 start:
1963 	/*
1964 	 * Open the file locked since setting an attribute
1965 	 * can change the layout of the Apple Double file.
1966 	 */
1967 	fileflags = FREAD | FWRITE | O_EXLOCK;
1968 	if ((error = open_xattrfile(vp, O_CREAT | fileflags, &xfg, NULL, context))) {
1969 		return error;
1970 	}
1971 	xvp = fg_get_data(xfg);
1972 
1973 	if ((error = get_xattrinfo(xvp, ATTR_SETTING, &ainfo, context))) {
1974 		close_xattrfile(xfg, true, true, context);
1975 		return error;
1976 	}
1977 
1978 	/* Set the Finder Info. */
1979 	if (strncmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
1980 		if (ainfo.finderinfo && !ainfo.emptyfinderinfo) {
1981 			/* attr exists and "create" was specified? */
1982 			if (options & XATTR_CREATE) {
1983 				error = EEXIST;
1984 				goto out;
1985 			}
1986 		} else {
1987 			/* attr doesn't exists and "replace" was specified? */
1988 			if (options & XATTR_REPLACE) {
1989 				error = ENOATTR;
1990 				goto out;
1991 			}
1992 		}
1993 		if (options != 0 && bcmp(finfo, emptyfinfo, FINDERINFOSIZE) == 0) {
1994 			/*
1995 			 * Setting the Finder Info to all zeroes is equivalent to
1996 			 * removing it.  Close the xattr file and let
1997 			 * default_removexattr do the work (including deleting
1998 			 * the xattr file if there are no other xattrs).
1999 			 *
2000 			 * Note that we have to handle the case where the
2001 			 * Finder Info was already all zeroes, and we ignore
2002 			 * ENOATTR.
2003 			 *
2004 			 * The common case where options == 0 was handled above.
2005 			 */
2006 			rel_xattrinfo(&ainfo);
2007 			close_xattrfile(xfg, true, true, context);
2008 			error = default_removexattr(vp, name, 0, context);
2009 			if (error == ENOATTR) {
2010 				error = 0;
2011 			}
2012 			return error;
2013 		}
2014 		if (ainfo.finderinfo) {
2015 			attrdata = (u_int8_t *)ainfo.filehdr + ainfo.finderinfo->offset;
2016 			bcopy(finfo, attrdata, datalen);
2017 			ainfo.iosize = sizeof(attr_header_t);
2018 			error = write_xattrinfo(&ainfo);
2019 			goto out;
2020 		}
2021 		error = ENOATTR;
2022 		goto out;
2023 	}
2024 
2025 	/* Write the Resource Fork. */
2026 	if (strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0) {
2027 		off_t endoffset;
2028 
2029 		if (!vnode_isreg(vp)) {
2030 			error = EPERM;
2031 			goto out;
2032 		}
2033 		/* Make sure we have a rsrc fork pointer.. */
2034 		if (ainfo.rsrcfork == NULL) {
2035 			error = ENOATTR;
2036 			goto out;
2037 		}
2038 		if (ainfo.rsrcfork) {
2039 			if (ainfo.rsrcfork->length != 0) {
2040 				if (options & XATTR_CREATE) {
2041 					/* attr exists, and create specified ? */
2042 					error = EEXIST;
2043 					goto out;
2044 				}
2045 			} else {
2046 				/* Zero length AD rsrc fork */
2047 				if (options & XATTR_REPLACE) {
2048 					/* attr doesn't exist (0-length), but replace specified ? */
2049 					error = ENOATTR;
2050 					goto out;
2051 				}
2052 			}
2053 		} else {
2054 			/* We can't do much if we somehow didn't get an AD rsrc pointer */
2055 			error = ENOATTR;
2056 			goto out;
2057 		}
2058 
2059 		endoffset = uio_resid(uio) + uio_offset(uio); /* new size */
2060 		if (endoffset > UINT32_MAX || endoffset < 0) {
2061 			error = EINVAL;
2062 			goto out;
2063 		}
2064 		uio_setoffset(uio, uio_offset(uio) + ainfo.rsrcfork->offset);
2065 		error = VNOP_WRITE(xvp, uio, 0, context);
2066 		if (error) {
2067 			goto out;
2068 		}
2069 		uio_setoffset(uio, uio_offset(uio) - ainfo.rsrcfork->offset);
2070 		if (endoffset > ainfo.rsrcfork->length) {
2071 			ainfo.rsrcfork->length = (u_int32_t)endoffset;
2072 			ainfo.iosize = sizeof(attr_header_t);
2073 			error = write_xattrinfo(&ainfo);
2074 			goto out;
2075 		}
2076 		goto out;
2077 	}
2078 
2079 	if (datalen > ATTR_MAX_SIZE) {
2080 		return E2BIG;  /* EINVAL instead ? */
2081 	}
2082 
2083 	if (ainfo.attrhdr == NULL) {
2084 		error = ENOATTR;
2085 		goto out;
2086 	}
2087 	header = ainfo.attrhdr;
2088 	entry = ainfo.attr_entry;
2089 
2090 	/* Check if data area crosses the maximum header size. */
2091 	if ((header->data_start + header->data_length + entrylen + datalen) > ATTR_MAX_HDR_SIZE) {
2092 		splitdata = 1;  /* do data I/O separately */
2093 	} else {
2094 		splitdata = 0;
2095 	}
2096 
2097 	/*
2098 	 * See if attribute already exists.
2099 	 */
2100 	for (i = 0; i < header->num_attrs && ATTR_VALID(entry, ainfo); i++) {
2101 		if (strncmp((const char *)entry->name, name, namelen) == 0) {
2102 			found = 1;
2103 			break;
2104 		}
2105 		entry = ATTR_NEXT(entry);
2106 	}
2107 
2108 	if (found) {
2109 		if (options & XATTR_CREATE) {
2110 			error = EEXIST;
2111 			goto out;
2112 		}
2113 		if (datalen == entry->length) {
2114 			if (splitdata) {
2115 				uio_setoffset(uio, entry->offset);
2116 				error = VNOP_WRITE(xvp, uio, 0, context);
2117 				uio_setoffset(uio, 0);
2118 				if (error) {
2119 					printf("setxattr: VNOP_WRITE error %d\n", error);
2120 				}
2121 			} else {
2122 				attrdata = (u_int8_t *)header + entry->offset;
2123 				error = uiomove((caddr_t)attrdata, (int)datalen, uio);
2124 				if (error) {
2125 					goto out;
2126 				}
2127 				ainfo.iosize = ainfo.attrhdr->data_start + ainfo.attrhdr->data_length;
2128 				error = write_xattrinfo(&ainfo);
2129 				if (error) {
2130 					printf("setxattr: write_xattrinfo error %d\n", error);
2131 				}
2132 			}
2133 			goto out;
2134 		} else {
2135 			/*
2136 			 * Brute force approach - just remove old entry and set new entry.
2137 			 */
2138 			found = 0;
2139 			rel_xattrinfo(&ainfo);
2140 			close_xattrfile(xfg, true, true, context);
2141 			error = default_removexattr(vp, name, options, context);
2142 			if (error) {
2143 				return error;
2144 			}
2145 			/* Clear XATTR_REPLACE option since we just removed the attribute. */
2146 			options &= ~XATTR_REPLACE;
2147 			goto start; /* start over */
2148 		}
2149 	} else {
2150 		if (!ATTR_VALID(entry, ainfo)) {
2151 			error = ENOSPC;
2152 			goto out;
2153 		}
2154 	}
2155 
2156 	if (options & XATTR_REPLACE) {
2157 		error = ENOATTR;  /* nothing there to replace */
2158 		goto out;
2159 	}
2160 	/* Check if header size limit has been reached. */
2161 	if ((header->data_start + entrylen) > ATTR_MAX_HDR_SIZE) {
2162 		error = ENOSPC;
2163 		goto out;
2164 	}
2165 
2166 	datafreespace = header->total_size - (header->data_start + header->data_length);
2167 
2168 	/* Check if we need more space. */
2169 	if ((datalen + entrylen) > datafreespace) {
2170 		size_t growsize;
2171 
2172 		growsize = roundup((datalen + entrylen) - datafreespace, ATTR_BUF_SIZE);
2173 
2174 		/* Clip roundup size when we can still fit in ATTR_MAX_HDR_SIZE. */
2175 		if (!splitdata && (header->total_size + growsize) > ATTR_MAX_HDR_SIZE) {
2176 			growsize = ATTR_MAX_HDR_SIZE - header->total_size;
2177 		}
2178 
2179 		ainfo.filesize += growsize;
2180 		error = vnode_setsize(xvp, ainfo.filesize, 0, context);
2181 		if (error) {
2182 			printf("setxattr: VNOP_TRUNCATE error %d\n", error);
2183 		}
2184 		if (error) {
2185 			goto out;
2186 		}
2187 
2188 		/*
2189 		 * Move the resource fork out of the way.
2190 		 */
2191 		if (ainfo.rsrcfork) {
2192 			if (ainfo.rsrcfork->length != 0) {
2193 				shift_data_down(xvp,
2194 				    ainfo.rsrcfork->offset,
2195 				    ainfo.rsrcfork->length,
2196 				    growsize, context);
2197 			}
2198 			ainfo.rsrcfork->offset += growsize;
2199 		}
2200 		ainfo.finderinfo->length += growsize;
2201 		header->total_size += growsize;
2202 	}
2203 
2204 	/* Make space for a new entry. */
2205 	if (splitdata) {
2206 		shift_data_down(xvp,
2207 		    header->data_start,
2208 		    header->data_length,
2209 		    entrylen, context);
2210 	} else {
2211 		bcopy((u_int8_t *)header + header->data_start,
2212 		    (u_int8_t *)header + header->data_start + entrylen,
2213 		    header->data_length);
2214 	}
2215 	header->data_start += entrylen;
2216 
2217 	/* Fix up entry data offsets. */
2218 	lastentry = entry;
2219 	for (entry = ainfo.attr_entry; entry != lastentry && ATTR_VALID(entry, ainfo); entry = ATTR_NEXT(entry)) {
2220 		entry->offset += entrylen;
2221 	}
2222 
2223 	/*
2224 	 * If the attribute data area is entirely within
2225 	 * the header buffer, then just update the buffer,
2226 	 * otherwise we'll write it separately to the file.
2227 	 */
2228 	if (splitdata) {
2229 		off_t offset;
2230 
2231 		/* Write new attribute data after the end of existing data. */
2232 		offset = header->data_start + header->data_length;
2233 		uio_setoffset(uio, offset);
2234 		error = VNOP_WRITE(xvp, uio, 0, context);
2235 		uio_setoffset(uio, 0);
2236 		if (error) {
2237 			printf("setxattr: VNOP_WRITE error %d\n", error);
2238 			goto out;
2239 		}
2240 	} else {
2241 		attrdata = (u_int8_t *)header + header->data_start + header->data_length;
2242 
2243 		error = uiomove((caddr_t)attrdata, (int)datalen, uio);
2244 		if (error) {
2245 			printf("setxattr: uiomove error %d\n", error);
2246 			goto out;
2247 		}
2248 	}
2249 
2250 	/* Create the attribute entry. */
2251 	lastentry->length = (u_int32_t)datalen;
2252 	lastentry->offset = header->data_start + header->data_length;
2253 	lastentry->namelen = (u_int8_t)namelen;
2254 	lastentry->flags = 0;
2255 	bcopy(name, &lastentry->name[0], namelen);
2256 
2257 	/* Update the attributes header. */
2258 	header->num_attrs++;
2259 	header->data_length += datalen;
2260 
2261 	if (splitdata) {
2262 		/* Only write the entries, since the data was written separately. */
2263 		ainfo.iosize = ainfo.attrhdr->data_start;
2264 	} else {
2265 		/* The entry and data are both in the header; write them together. */
2266 		ainfo.iosize = ainfo.attrhdr->data_start + ainfo.attrhdr->data_length;
2267 	}
2268 	error = write_xattrinfo(&ainfo);
2269 	if (error) {
2270 		printf("setxattr: write_xattrinfo error %d\n", error);
2271 	}
2272 
2273 out:
2274 	rel_xattrinfo(&ainfo);
2275 	close_xattrfile(xfg, true, true, context);
2276 
2277 	/* Touch the change time if we changed an attribute. */
2278 	if (error == 0) {
2279 		struct vnode_attr va;
2280 
2281 		/* Re-write the mtime to cause a ctime change. */
2282 		VATTR_INIT(&va);
2283 		VATTR_WANTED(&va, va_modify_time);
2284 		if (vnode_getattr(vp, &va, context) == 0) {
2285 			VATTR_INIT(&va);
2286 			VATTR_SET(&va, va_modify_time, va.va_modify_time);
2287 			(void) vnode_setattr(vp, &va, context);
2288 		}
2289 	}
2290 
2291 	post_event_if_success(vp, error, NOTE_ATTRIB);
2292 
2293 	return error;
2294 }
2295 
2296 
2297 /*
2298  * Remove an extended attribute.
2299  * (VFS implementation).
2300  */
2301 static int
default_removexattr_vfs(vnode_t vp,const char * name,__unused int options,vfs_context_t context)2302 default_removexattr_vfs(vnode_t vp, const char *name, __unused int options, vfs_context_t context)
2303 {
2304 	vnode_t xvp = NULL;
2305 	struct fileglob *xfg = NULL;
2306 	attr_info_t ainfo;
2307 	attr_header_t *header;
2308 	attr_entry_t *entry;
2309 	attr_entry_t *oldslot;
2310 	u_int8_t *attrdata;
2311 	u_int32_t dataoff;
2312 	size_t datalen;
2313 	size_t entrylen;
2314 	int namelen;
2315 	int found = 0, lastone = 0;
2316 	int i;
2317 	int splitdata;
2318 	int attrcount = 0;
2319 	int isrsrcfork;
2320 	int fileflags;
2321 	int error;
2322 
2323 	fileflags = FREAD | FWRITE | O_EXLOCK;
2324 	isrsrcfork = strncmp(name, XATTR_RESOURCEFORK_NAME,
2325 	    sizeof(XATTR_RESOURCEFORK_NAME)) == 0;
2326 
2327 	if ((error = open_xattrfile(vp, fileflags, &xfg, NULL, context))) {
2328 		return error;
2329 	}
2330 	xvp = fg_get_data(xfg);
2331 
2332 	if ((error = get_xattrinfo(xvp, 0, &ainfo, context))) {
2333 		close_xattrfile(xfg, true, true, context);
2334 		return error;
2335 	}
2336 	if (ainfo.attrhdr) {
2337 		attrcount += ainfo.attrhdr->num_attrs;
2338 	}
2339 	if (ainfo.rsrcfork) {
2340 		++attrcount;
2341 	}
2342 	if (ainfo.finderinfo && !ainfo.emptyfinderinfo) {
2343 		++attrcount;
2344 	}
2345 
2346 	/* Clear the Finder Info. */
2347 	if (strncmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
2348 		if (ainfo.finderinfo == NULL || ainfo.emptyfinderinfo) {
2349 			error = ENOATTR;
2350 			goto out;
2351 		}
2352 		/* On removal of last attribute the ._ file is removed. */
2353 		if (--attrcount == 0) {
2354 			goto out;
2355 		}
2356 		attrdata = (u_int8_t *)ainfo.filehdr + ainfo.finderinfo->offset;
2357 		bzero((caddr_t)attrdata, FINDERINFOSIZE);
2358 		error = write_xattrinfo(&ainfo);
2359 		goto out;
2360 	}
2361 
2362 	/* Clear the Resource Fork. */
2363 	if (isrsrcfork) {
2364 		if (!vnode_isreg(vp)) {
2365 			error = EPERM;
2366 			goto out;
2367 		}
2368 		if (ainfo.rsrcfork == NULL || ainfo.rsrcfork->length == 0) {
2369 			error = ENOATTR;
2370 			goto out;
2371 		}
2372 		/* On removal of last attribute the ._ file is removed. */
2373 		if (--attrcount == 0) {
2374 			goto out;
2375 		}
2376 		/*
2377 		 * XXX
2378 		 * If the resource fork isn't the last AppleDouble
2379 		 * entry then the space needs to be reclaimed by
2380 		 * shifting the entries after the resource fork.
2381 		 */
2382 		if ((ainfo.rsrcfork->offset + ainfo.rsrcfork->length) == ainfo.filesize) {
2383 			ainfo.filesize -= ainfo.rsrcfork->length;
2384 			error = vnode_setsize(xvp, ainfo.filesize, 0, context);
2385 		}
2386 		if (error == 0) {
2387 			ainfo.rsrcfork->length = 0;
2388 			ainfo.iosize = sizeof(attr_header_t);
2389 			error = write_xattrinfo(&ainfo);
2390 		}
2391 		goto out;
2392 	}
2393 
2394 	if (ainfo.attrhdr == NULL) {
2395 		error = ENOATTR;
2396 		goto out;
2397 	}
2398 	namelen = (int)strlen(name) + 1;
2399 	header = ainfo.attrhdr;
2400 	entry = ainfo.attr_entry;
2401 
2402 	/*
2403 	 * See if this attribute exists.
2404 	 */
2405 	for (i = 0; i < header->num_attrs && ATTR_VALID(entry, ainfo); i++) {
2406 		if (strncmp((const char *)entry->name, name, namelen) == 0) {
2407 			found = 1;
2408 			if ((i + 1) == header->num_attrs) {
2409 				lastone = 1;
2410 			}
2411 			break;
2412 		}
2413 		entry = ATTR_NEXT(entry);
2414 	}
2415 	if (!found) {
2416 		error = ENOATTR;
2417 		goto out;
2418 	}
2419 	/* On removal of last attribute the ._ file is removed. */
2420 	if (--attrcount == 0) {
2421 		goto out;
2422 	}
2423 
2424 	datalen = entry->length;
2425 	dataoff = entry->offset;
2426 	entrylen = ATTR_ENTRY_LENGTH(namelen);
2427 	if ((header->data_start + header->data_length) > ATTR_MAX_HDR_SIZE) {
2428 		splitdata = 1;
2429 	} else {
2430 		splitdata = 0;
2431 	}
2432 
2433 	/* Remove the attribute entry. */
2434 	if (!lastone) {
2435 		bcopy((u_int8_t *)entry + entrylen, (u_int8_t *)entry,
2436 		    ((size_t)header + header->data_start) - ((size_t)entry + entrylen));
2437 	}
2438 
2439 	/* Adjust the attribute data. */
2440 	if (splitdata) {
2441 		shift_data_up(xvp,
2442 		    header->data_start,
2443 		    dataoff - header->data_start,
2444 		    entrylen,
2445 		    context);
2446 		if (!lastone) {
2447 			shift_data_up(xvp,
2448 			    dataoff + datalen,
2449 			    (header->data_start + header->data_length) - (dataoff + datalen),
2450 			    datalen + entrylen,
2451 			    context);
2452 		}
2453 		/* XXX write zeros to freed space ? */
2454 		ainfo.iosize = ainfo.attrhdr->data_start - entrylen;
2455 	} else {
2456 		bcopy((u_int8_t *)header + header->data_start,
2457 		    (u_int8_t *)header + header->data_start - entrylen,
2458 		    dataoff - header->data_start);
2459 		if (!lastone) {
2460 			bcopy((u_int8_t *)header + dataoff + datalen,
2461 			    (u_int8_t *)header + dataoff - entrylen,
2462 			    (header->data_start + header->data_length) - (dataoff + datalen));
2463 		}
2464 		bzero(((u_int8_t *)header + header->data_start + header->data_length) - (datalen + entrylen), (datalen + entrylen));
2465 		ainfo.iosize = ainfo.attrhdr->data_start + ainfo.attrhdr->data_length;
2466 	}
2467 
2468 	/* Adjust the header values and entry offsets. */
2469 	header->num_attrs--;
2470 	header->data_start -= entrylen;
2471 	header->data_length -= datalen;
2472 
2473 	oldslot = entry;
2474 	entry = ainfo.attr_entry;
2475 	for (i = 0; i < header->num_attrs && ATTR_VALID(entry, ainfo); i++) {
2476 		entry->offset -= entrylen;
2477 		if (entry >= oldslot) {
2478 			entry->offset -= datalen;
2479 		}
2480 		entry = ATTR_NEXT(entry);
2481 	}
2482 	error = write_xattrinfo(&ainfo);
2483 	if (error) {
2484 		printf("removexattr: write_xattrinfo error %d\n", error);
2485 	}
2486 out:
2487 	rel_xattrinfo(&ainfo);
2488 
2489 	/* When there are no more attributes remove the ._ file. */
2490 	if (attrcount == 0) {
2491 		remove_xattrfile(xfg, xvp, context);
2492 	} else {
2493 		close_xattrfile(xfg, true, true, context);
2494 	}
2495 	/* Touch the change time if we changed an attribute. */
2496 	if (error == 0) {
2497 		struct vnode_attr va;
2498 
2499 		/* Re-write the mtime to cause a ctime change. */
2500 		VATTR_INIT(&va);
2501 		VATTR_WANTED(&va, va_modify_time);
2502 		if (vnode_getattr(vp, &va, context) == 0) {
2503 			VATTR_INIT(&va);
2504 			VATTR_SET(&va, va_modify_time, va.va_modify_time);
2505 			(void) vnode_setattr(vp, &va, context);
2506 		}
2507 	}
2508 
2509 	post_event_if_success(vp, error, NOTE_ATTRIB);
2510 
2511 	return error;
2512 }
2513 
2514 
2515 /*
2516  * Retrieve the list of extended attribute names.
2517  * (VFS implementation).
2518  */
2519 static int
default_listxattr_vfs(vnode_t vp,uio_t uio,size_t * size,__unused int options,vfs_context_t context)2520 default_listxattr_vfs(vnode_t vp, uio_t uio, size_t *size, __unused int options, vfs_context_t context)
2521 {
2522 	vnode_t xvp = NULL;
2523 	struct fileglob *xfg = NULL;
2524 	attr_info_t ainfo;
2525 	attr_entry_t *entry;
2526 	int i, count;
2527 	int error;
2528 
2529 	/*
2530 	 * We do not zero "*size" here as we don't want to stomp a size set when
2531 	 * VNOP_LISTXATTR processed any native EAs.  That size is initially zeroed by the
2532 	 * system call layer, up in listxattr or flistxattr.
2533 	 */
2534 
2535 	if ((error = open_xattrfile(vp, FREAD | O_SHLOCK, &xfg, NULL, context))) {
2536 		if (error == ENOATTR) {
2537 			error = 0;
2538 		}
2539 		return error;
2540 	}
2541 	xvp = fg_get_data(xfg);
2542 
2543 	if ((error = get_xattrinfo(xvp, 0, &ainfo, context))) {
2544 		if (error == ENOATTR) {
2545 			error = 0;
2546 		}
2547 		close_xattrfile(xfg, true, true, context);
2548 		return error;
2549 	}
2550 
2551 	/* Check for Finder Info. */
2552 	if (ainfo.finderinfo && !ainfo.emptyfinderinfo) {
2553 		if (uio == NULL) {
2554 			*size += sizeof(XATTR_FINDERINFO_NAME);
2555 		} else if (uio_resid(uio) < (user_ssize_t)sizeof(XATTR_FINDERINFO_NAME)) {
2556 			error = ERANGE;
2557 			goto out;
2558 		} else {
2559 			error = uiomove(XATTR_FINDERINFO_NAME,
2560 			    sizeof(XATTR_FINDERINFO_NAME), uio);
2561 			if (error) {
2562 				error = ERANGE;
2563 				goto out;
2564 			}
2565 		}
2566 	}
2567 
2568 	/* Check for Resource Fork. */
2569 	if (vnode_isreg(vp) && ainfo.rsrcfork) {
2570 		if (uio == NULL) {
2571 			*size += sizeof(XATTR_RESOURCEFORK_NAME);
2572 		} else if (uio_resid(uio) < (user_ssize_t)sizeof(XATTR_RESOURCEFORK_NAME)) {
2573 			error = ERANGE;
2574 			goto out;
2575 		} else {
2576 			error = uiomove(XATTR_RESOURCEFORK_NAME,
2577 			    sizeof(XATTR_RESOURCEFORK_NAME), uio);
2578 			if (error) {
2579 				error = ERANGE;
2580 				goto out;
2581 			}
2582 		}
2583 	}
2584 
2585 	/* Check for attributes. */
2586 	if (ainfo.attrhdr) {
2587 		count = ainfo.attrhdr->num_attrs;
2588 		for (i = 0, entry = ainfo.attr_entry; i < count && ATTR_VALID(entry, ainfo); i++) {
2589 			if (xattr_protected((const char *)entry->name) ||
2590 			    ((entry->namelen < XATTR_MAXNAMELEN) &&
2591 			    (entry->name[entry->namelen] == '\0') &&
2592 			    (xattr_validatename((const char *)entry->name) != 0))) {
2593 				entry = ATTR_NEXT(entry);
2594 				continue;
2595 			}
2596 			if (uio == NULL) {
2597 				*size += entry->namelen;
2598 				entry = ATTR_NEXT(entry);
2599 				continue;
2600 			}
2601 			if (uio_resid(uio) < entry->namelen) {
2602 				error = ERANGE;
2603 				break;
2604 			}
2605 			error = uiomove((caddr_t) entry->name, entry->namelen, uio);
2606 			if (error) {
2607 				if (error != EFAULT) {
2608 					error = ERANGE;
2609 				}
2610 				break;
2611 			}
2612 			entry = ATTR_NEXT(entry);
2613 		}
2614 	}
2615 out:
2616 	rel_xattrinfo(&ainfo);
2617 	close_xattrfile(xfg, true, true, context);
2618 
2619 	return error;
2620 }
2621 
2622 static int
get_doubleagentd_port(mach_port_t * doubleagentd_port)2623 get_doubleagentd_port(mach_port_t *doubleagentd_port)
2624 {
2625 	kern_return_t ret;
2626 
2627 	*doubleagentd_port = MACH_PORT_NULL;
2628 	ret = host_get_doubleagentd_port(host_priv_self(), doubleagentd_port);
2629 	if (ret != KERN_SUCCESS) {
2630 		printf("vfs_xattr: can't get doubleagentd port, status 0x%08x\n", ret);
2631 		return EIO;
2632 	}
2633 	if (!IPC_PORT_VALID(*doubleagentd_port)) {
2634 		printf("vfs_xattr: doubleagentd port not valid\n");
2635 		return EIO;
2636 	}
2637 	return 0;
2638 }
2639 
2640 /*
2641  * Retrieve the data of an extended attribute.
2642  * (Using DoubleAgent to parse the AD file).
2643  */
2644 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)2645 default_getxattr_doubleagent(vnode_t vp, const char *name, uio_t uio,
2646     size_t *size, __unused int options, vfs_context_t context,
2647     mach_port_t doubleagentd_port)
2648 {
2649 	vnode_t xvp = NULL;
2650 	struct fileglob *xfg = NULL;
2651 	mach_port_t fileport = MACH_PORT_NULL;
2652 	uint64_t value_offset = 0;
2653 	uint64_t value_length = 0;
2654 	int64_t fsize;
2655 	int isrsrcfork;
2656 	int fileflags;
2657 	int error;
2658 	kern_return_t kr;
2659 	char cName[XATTR_MAXNAMELEN] = {0};
2660 	bool have_iocount = true;
2661 
2662 	fileflags = FREAD | O_SHLOCK;
2663 	isrsrcfork = strncmp(name, XATTR_RESOURCEFORK_NAME,
2664 	    sizeof(XATTR_RESOURCEFORK_NAME)) == 0;
2665 
2666 	if ((error = open_xattrfile(vp, fileflags, &xfg, &fsize, context))) {
2667 		goto out;
2668 	}
2669 	xvp = fg_get_data(xfg);
2670 	if ((error = make_xattrfile_port(xfg, &fileport))) {
2671 		goto out;
2672 	}
2673 
2674 	/* Drop the iocount before upcalling to doubleagentd. */
2675 	vnode_put(xvp);
2676 	have_iocount = false;
2677 
2678 	strncpy(cName, name, XATTR_MAXNAMELEN);
2679 
2680 	/*
2681 	 * Call doubleagentd to look up the xattr.  The fileport argument
2682 	 * is declared move-send, so the Mig stub consumes it.
2683 	 */
2684 	kr = doubleagent_lookup_xattr(doubleagentd_port, fileport, fsize, cName,
2685 	    &error, &value_offset, &value_length);
2686 	if (kr != KERN_SUCCESS) {
2687 		error = EIO;
2688 	}
2689 	if (error == 0) {
2690 		error = vnode_getwithref(xvp);
2691 	}
2692 	if (error) {
2693 		goto out;
2694 	}
2695 	have_iocount = true;
2696 	if (uio != NULL) {
2697 		if (isrsrcfork) {
2698 			// Resource Fork case is a bit different,
2699 			// as we can have a non-zero uio offset.
2700 			uio_setoffset(uio, uio_offset(uio) + value_offset);
2701 			error = VNOP_READ(xvp, uio, 0, context);
2702 			if (error == 0) {
2703 				uio_setoffset(uio, uio_offset(uio) - value_offset);
2704 			}
2705 		} else {
2706 			if (uio_resid(uio) < value_length) {
2707 				error = ERANGE;
2708 				goto out;
2709 			}
2710 
2711 			// Read from the relevant offset in the AD file into the uio.
2712 			user_ssize_t orig_resid = uio_resid(uio);
2713 			uio_setoffset(uio, value_offset);
2714 			uio_setresid(uio, value_length);
2715 
2716 			error = VNOP_READ(xvp, uio, 0, context);
2717 
2718 			uio_setoffset(uio, 0);
2719 			uio_setresid(uio, orig_resid - value_length + uio_resid(uio));
2720 		}
2721 	}
2722 
2723 	*size = value_length;
2724 
2725 out:
2726 	if (xfg != NULL) {
2727 		close_xattrfile(xfg, have_iocount, true, context);
2728 	}
2729 	return error;
2730 }
2731 
2732 /*
2733  * Retrieve the list of extended attribute names.
2734  * (Using DoubleAgent to parse the AD file).
2735  */
2736 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)2737 default_listxattr_doubleagent(vnode_t vp, uio_t uio, size_t *size,
2738     __unused int options, vfs_context_t context, mach_port_t doubleagentd_port)
2739 {
2740 	vnode_t xvp = NULL;
2741 	struct fileglob *xfg = NULL;
2742 	int64_t fsize;
2743 	int error;
2744 
2745 	mach_port_t fileport = MACH_PORT_NULL;
2746 	kern_return_t kr;
2747 	void *buf = NULL;
2748 	listxattrs_result_t *result;
2749 	bool have_iocount = true;
2750 
2751 	/*
2752 	 * We do not zero "*size" here as we don't want to stomp a size set
2753 	 * when VNOP_LISTXATTR() processed any native EAs.  That size is
2754 	 * initially zeroed by the system call layer, up in listxattr() or
2755 	 * flistxattr().
2756 	 */
2757 
2758 	if ((error = open_xattrfile(vp, FREAD | O_SHLOCK, &xfg, &fsize,
2759 	    context))) {
2760 		if (error == ENOATTR) {
2761 			error = 0;
2762 		}
2763 		goto out;
2764 	}
2765 	xvp = fg_get_data(xfg);
2766 	if ((error = make_xattrfile_port(xfg, &fileport))) {
2767 		goto out;
2768 	}
2769 
2770 	/* Drop the iocount before upcalling to doubleagentd. */
2771 	vnode_put(xvp);
2772 	have_iocount = false;
2773 
2774 	buf = kalloc_data(sizeof(listxattrs_result_t), Z_WAITOK);
2775 	result = (listxattrs_result_t *)buf;
2776 
2777 	/*
2778 	 * Call doubleagentd to list the xattrs.  The fileport argument
2779 	 * is declared move-send, so the Mig stub consumes it.
2780 	 */
2781 	kr = doubleagent_list_xattrs(doubleagentd_port, fileport, fsize, &error,
2782 	    result);
2783 	if (kr != KERN_SUCCESS) {
2784 		error = EIO;
2785 	}
2786 	if (error == 0) {
2787 		error = vnode_getwithref(xvp);
2788 	}
2789 	if (error) {
2790 		goto out;
2791 	}
2792 	have_iocount = true;
2793 
2794 	if (uio != NULL) {
2795 		if (uio_resid(uio) < result->namesLength) {
2796 			error = ERANGE;
2797 			goto out;
2798 		}
2799 		// copy the relevant part of the result into the uio.
2800 		error = uiomove((const char *)result->data, (int)result->namesLength, uio);
2801 		if (error) {
2802 			if (error != EFAULT) {
2803 				error = ERANGE;
2804 			}
2805 			goto out;
2806 		}
2807 	}
2808 
2809 	/*
2810 	 * Set *size, while preserving any previous value from
2811 	 * VNOP_LISTXATTR().
2812 	 */
2813 	*size += result->namesLength;
2814 
2815 out:
2816 	if (xfg != NULL) {
2817 		close_xattrfile(xfg, have_iocount, true, context);
2818 	}
2819 	if (buf != NULL) {
2820 		kfree_data(buf, sizeof(listxattrs_result_t));
2821 	}
2822 	return error;
2823 }
2824 
2825 /*
2826  * Set the data of an extended attribute.
2827  * (Using DoubleAgent to parse the AD file).
2828  */
2829 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)2830 default_setxattr_doubleagent(vnode_t vp, const char *name, uio_t uio,
2831     int options, vfs_context_t context, mach_port_t doubleagentd_port)
2832 {
2833 	vnode_t xvp = NULL;
2834 	struct fileglob *xfg = NULL;
2835 	size_t datalen;
2836 	int namelen;
2837 	int fileflags;
2838 	int error;
2839 	char cName[XATTR_MAXNAMELEN] = {0};
2840 	char finfo[FINDERINFOSIZE];
2841 	uio_t finfo_uio = NULL;
2842 	mach_port_t fileport = MACH_PORT_NULL;
2843 	uint64_t value_offset = 0;
2844 	int64_t fsize;
2845 	kern_return_t kr;
2846 	bool have_iocount = true;
2847 
2848 	datalen = uio_resid(uio);
2849 	if (datalen > XATTR_MAXSIZE) {
2850 		return E2BIG;
2851 	}
2852 	namelen = (int)strlen(name) + 1;
2853 	if (namelen > UINT8_MAX) {
2854 		return EINVAL;
2855 	}
2856 
2857 	/*
2858 	 * By convention, Finder Info that is all zeroes is equivalent to not
2859 	 * having a Finder Info EA.  So if we're trying to set the Finder Info
2860 	 * to all zeroes, then delete it instead.  If a file didn't have an
2861 	 * AppleDouble file before, this prevents creating an AppleDouble file
2862 	 * with no useful content.
2863 	 *
2864 	 * If neither XATTR_CREATE nor XATTR_REPLACE were specified, we check
2865 	 * for all zeroes Finder Info before opening the AppleDouble file.
2866 	 * But if either of those options were specified, we need to open the
2867 	 * AppleDouble file to see whether there was already Finder Info (so we
2868 	 * can return an error if needed); this case is handled in DoubleAgent.
2869 	 */
2870 	if (strncmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
2871 		if (uio_offset(uio) != 0) {
2872 			return EINVAL;
2873 		}
2874 
2875 		if (datalen != FINDERINFOSIZE) {
2876 			return ERANGE;
2877 		}
2878 
2879 		// Duplicate the uio to keep it as-is for later.
2880 		finfo_uio = uio_duplicate(uio);
2881 		// Get the finfo data from the duplicated uio.
2882 		error = uiomove(finfo, (int)datalen, finfo_uio);
2883 		uio_free(finfo_uio);
2884 		if (error) {
2885 			return error;
2886 		}
2887 		if ((options & (XATTR_CREATE | XATTR_REPLACE)) == 0 &&
2888 		    bcmp(finfo, emptyfinfo, FINDERINFOSIZE) == 0) {
2889 			error = default_removexattr(vp, name, 0, context);
2890 			if (error == ENOATTR) {
2891 				error = 0;
2892 			}
2893 			return error;
2894 		}
2895 	}
2896 
2897 	if (strncmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0) {
2898 		/*
2899 		 * For ResourceFork we allow offset to be != 0, so adjust datalen accordingly
2900 		 * so doubleagent will adjust the file length accordingly
2901 		 *
2902 		 */
2903 		if (__improbable(os_add_overflow(datalen, uio_offset(uio), &datalen))) {
2904 			return EINVAL;
2905 		}
2906 
2907 		if (datalen > UINT32_MAX) {
2908 			return EINVAL;
2909 		}
2910 	}
2911 
2912 	/*
2913 	 * Open the file locked since setting an attribute
2914 	 * can change the layout of the Apple Double file.
2915 	 */
2916 	fileflags = FREAD | FWRITE | O_EXLOCK;
2917 	if ((error = open_xattrfile(vp, O_CREAT | fileflags, &xfg,
2918 	    &fsize, context))) {
2919 		goto out;
2920 	}
2921 	xvp = fg_get_data(xfg);
2922 	if ((error = make_xattrfile_port(xfg, &fileport))) {
2923 		goto out;
2924 	}
2925 
2926 	/* Drop the iocount before upcalling to doubleagentd. */
2927 	vnode_put(xvp);
2928 	have_iocount = false;
2929 
2930 	strncpy(cName, name, XATTR_MAXNAMELEN);
2931 
2932 	/*
2933 	 * Call doubleagentd to allocate space for the xattr.  The
2934 	 * fileport argument is declared move-send, so the Mig stub
2935 	 * consumes it.
2936 	 */
2937 	kr = doubleagent_allocate_xattr(doubleagentd_port, fileport, fsize,
2938 	    cName, datalen, options, &error, &value_offset);
2939 	if (kr != KERN_SUCCESS) {
2940 		error = EIO;
2941 	}
2942 	if (error == 0) {
2943 		error = vnode_getwithref(xvp);
2944 	}
2945 	if (error) {
2946 		goto out;
2947 	}
2948 	have_iocount = true;
2949 
2950 	/*
2951 	 * write the uio data into the offset we got from doubleagent,
2952 	 * while adding the given uio offset (could be non-zero only for
2953 	 * resource fork; it is being checked earlier).
2954 	 */
2955 	uio_setoffset(uio, uio_offset(uio) + value_offset);
2956 	error = VNOP_WRITE(xvp, uio, 0, context);
2957 	uio_setoffset(uio, 0);
2958 
2959 out:
2960 	if (xfg != NULL) {
2961 		close_xattrfile(xfg, have_iocount, true, context);
2962 	}
2963 
2964 	/* Touch the change time if we changed an attribute. */
2965 	if (error == 0) {
2966 		struct vnode_attr va;
2967 
2968 		/* Re-write the mtime to cause a ctime change. */
2969 		VATTR_INIT(&va);
2970 		VATTR_WANTED(&va, va_modify_time);
2971 		if (vnode_getattr(vp, &va, context) == 0) {
2972 			VATTR_INIT(&va);
2973 			VATTR_SET(&va, va_modify_time, va.va_modify_time);
2974 			(void) vnode_setattr(vp, &va, context);
2975 		}
2976 	}
2977 
2978 	post_event_if_success(vp, error, NOTE_ATTRIB);
2979 
2980 	return error;
2981 }
2982 
2983 /*
2984  * Remove an extended attribute.
2985  * (Using DoubleAgent to parse the AD file).
2986  */
2987 static int
default_removexattr_doubleagent(vnode_t vp,const char * name,__unused int options,vfs_context_t context,mach_port_t doubleagentd_port)2988 default_removexattr_doubleagent(vnode_t vp, const char *name,
2989     __unused int options, vfs_context_t context,
2990     mach_port_t doubleagentd_port)
2991 {
2992 	vnode_t xvp = NULL;
2993 	struct fileglob *xfg = NULL;
2994 	int isrsrcfork;
2995 	int fileflags;
2996 	int error;
2997 	int64_t fsize;
2998 	boolean_t is_empty = false;
2999 	char cName[XATTR_MAXNAMELEN] = {0};
3000 	mach_port_t fileport = MACH_PORT_NULL;
3001 	kern_return_t kr;
3002 	bool have_iocount = true;
3003 
3004 	fileflags = FREAD | FWRITE | O_EXLOCK;
3005 	isrsrcfork = strncmp(name, XATTR_RESOURCEFORK_NAME,
3006 	    sizeof(XATTR_RESOURCEFORK_NAME)) == 0;
3007 
3008 	if ((error = open_xattrfile(vp, fileflags, &xfg, &fsize, context))) {
3009 		goto out;
3010 	}
3011 	xvp = fg_get_data(xfg);
3012 	if ((error = make_xattrfile_port(xfg, &fileport))) {
3013 		goto out;
3014 	}
3015 
3016 	/* Drop the iocount before upcalling to doubleagentd. */
3017 	vnode_put(xvp);
3018 	have_iocount = false;
3019 
3020 	strncpy(cName, name, XATTR_MAXNAMELEN);
3021 
3022 	/*
3023 	 * Call doubleagentd to remove the xattr.  The fileport argument
3024 	 * is declared move-send, so the Mig stub consumes it.
3025 	 */
3026 	kr = doubleagent_remove_xattr(doubleagentd_port, fileport, fsize, cName,
3027 	    &error, &is_empty);
3028 	if (kr != KERN_SUCCESS) {
3029 		error = EIO;
3030 	}
3031 	if (error == 0) {
3032 		error = vnode_getwithref(xvp);
3033 	}
3034 	if (error) {
3035 		goto out;
3036 	}
3037 	have_iocount = true;
3038 
3039 out:
3040 	if (error == 0) {
3041 		/* When there are no more attributes remove the ._ file. */
3042 		if (is_empty) {
3043 			remove_xattrfile(xfg, xvp, context);
3044 		} else {
3045 			close_xattrfile(xfg, have_iocount, true, context);
3046 		}
3047 		xfg = NULL;
3048 
3049 		/* Touch the change time if we changed an attribute. */
3050 		struct vnode_attr va;
3051 		/* Re-write the mtime to cause a ctime change. */
3052 		VATTR_INIT(&va);
3053 		VATTR_WANTED(&va, va_modify_time);
3054 		if (vnode_getattr(vp, &va, context) == 0) {
3055 			VATTR_INIT(&va);
3056 			VATTR_SET(&va, va_modify_time, va.va_modify_time);
3057 			(void) vnode_setattr(vp, &va, context);
3058 		}
3059 	}
3060 
3061 	post_event_if_success(vp, error, NOTE_ATTRIB);
3062 
3063 	if (xfg != NULL) {
3064 		close_xattrfile(xfg, have_iocount, true, context);
3065 	}
3066 	return error;
3067 }
3068 
3069 static int
open_xattrfile(vnode_t vp,int fileflags,struct fileglob ** xfgp,int64_t * file_sizep,vfs_context_t context)3070 open_xattrfile(vnode_t vp, int fileflags, struct fileglob **xfgp,
3071     int64_t *file_sizep, vfs_context_t context)
3072 {
3073 	extern const struct fileops vnops;      /* XXX */
3074 	vnode_t xvp = NULLVP;
3075 	vnode_t dvp = NULLVP;
3076 	struct fileglob *fg = NULL;
3077 	struct vnode_attr *va = NULL;
3078 	struct nameidata *nd = NULL;
3079 	char smallname[64];
3080 	char *filename = NULL;
3081 	const char *basename = NULL;
3082 	size_t alloc_len = 0;
3083 	size_t copy_len;
3084 	errno_t error;
3085 	int opened = 0;
3086 	int referenced = 0;
3087 	bool created_xattr_file = false;
3088 
3089 	if (vnode_isvroot(vp) && vnode_isdir(vp)) {
3090 		/*
3091 		 * For the root directory use "._." to hold the attributes.
3092 		 */
3093 		filename = &smallname[0];
3094 		snprintf(filename, sizeof(smallname), "%s%s", ATTR_FILE_PREFIX, ".");
3095 		dvp = vp;  /* the "._." file resides in the root dir */
3096 		goto lookup;
3097 	}
3098 	if ((dvp = vnode_getparent(vp)) == NULLVP) {
3099 		error = ENOATTR;
3100 		goto out;
3101 	}
3102 	if ((basename = vnode_getname(vp)) == NULL) {
3103 		error = ENOATTR;
3104 		goto out;
3105 	}
3106 
3107 	/* "._" Attribute files cannot have attributes */
3108 	if (vp->v_type == VREG && strlen(basename) > 2 &&
3109 	    basename[0] == '.' && basename[1] == '_') {
3110 		error = EPERM;
3111 		goto out;
3112 	}
3113 	filename = &smallname[0];
3114 	alloc_len = snprintf(filename, sizeof(smallname), "%s%s", ATTR_FILE_PREFIX, basename);
3115 	if (alloc_len >= sizeof(smallname)) {
3116 		alloc_len++;  /* snprintf result doesn't include '\0' */
3117 		filename = kalloc_data(alloc_len, Z_WAITOK);
3118 		copy_len = snprintf(filename, alloc_len, "%s%s", ATTR_FILE_PREFIX, basename);
3119 	}
3120 	/*
3121 	 * Note that the lookup here does not authorize.  Since we are looking
3122 	 * up in the same directory that we already have the file vnode in,
3123 	 * we must have been given the file vnode legitimately.  Read/write
3124 	 * access has already been authorized in layers above for calls from
3125 	 * userspace, and the authorization code using this path to read
3126 	 * file security from the EA must always get access
3127 	 */
3128 lookup:
3129 	nd = kalloc_type(struct nameidata, Z_WAITOK);
3130 	NDINIT(nd, LOOKUP, OP_OPEN, LOCKLEAF | NOFOLLOW | USEDVP | DONOTAUTH,
3131 	    UIO_SYSSPACE, CAST_USER_ADDR_T(filename), context);
3132 	nd->ni_dvp = dvp;
3133 
3134 	va = kalloc_type(struct vnode_attr, Z_WAITOK);
3135 
3136 	if (fileflags & O_CREAT) {
3137 		nd->ni_cnd.cn_nameiop = CREATE;
3138 #if CONFIG_TRIGGERS
3139 		nd->ni_op = OP_LINK;
3140 #endif
3141 		if (dvp != vp) {
3142 			nd->ni_cnd.cn_flags |= LOCKPARENT;
3143 		}
3144 		if ((error = namei(nd))) {
3145 			nd->ni_dvp = NULLVP;
3146 			error = ENOATTR;
3147 			goto out;
3148 		}
3149 		if ((xvp = nd->ni_vp) == NULLVP) {
3150 			uid_t uid;
3151 			gid_t gid;
3152 			mode_t umode;
3153 
3154 			/*
3155 			 * Pick up uid/gid/mode from target file.
3156 			 */
3157 			VATTR_INIT(va);
3158 			VATTR_WANTED(va, va_uid);
3159 			VATTR_WANTED(va, va_gid);
3160 			VATTR_WANTED(va, va_mode);
3161 			if (VNOP_GETATTR(vp, va, context) == 0 &&
3162 			    VATTR_IS_SUPPORTED(va, va_uid) &&
3163 			    VATTR_IS_SUPPORTED(va, va_gid) &&
3164 			    VATTR_IS_SUPPORTED(va, va_mode)) {
3165 				uid = va->va_uid;
3166 				gid = va->va_gid;
3167 				umode = va->va_mode & (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
3168 			} else { /* fallback values */
3169 				uid = KAUTH_UID_NONE;
3170 				gid = KAUTH_GID_NONE;
3171 				umode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
3172 			}
3173 
3174 			VATTR_INIT(va);
3175 			VATTR_SET(va, va_type, VREG);
3176 			VATTR_SET(va, va_mode, umode);
3177 			if (uid != KAUTH_UID_NONE) {
3178 				VATTR_SET(va, va_uid, uid);
3179 			}
3180 			if (gid != KAUTH_GID_NONE) {
3181 				VATTR_SET(va, va_gid, gid);
3182 			}
3183 
3184 			error = vn_create(dvp, &nd->ni_vp, nd, va,
3185 			    VN_CREATE_NOAUTH | VN_CREATE_NOINHERIT | VN_CREATE_NOLABEL,
3186 			    0, NULL,
3187 			    context);
3188 			if (error) {
3189 				error = ENOATTR;
3190 			} else {
3191 				xvp = nd->ni_vp;
3192 				created_xattr_file = true;
3193 			}
3194 		}
3195 		nameidone(nd);
3196 		if (dvp != vp) {
3197 			vnode_put(dvp);  /* drop iocount from LOCKPARENT request above */
3198 		}
3199 		if (error) {
3200 			goto out;
3201 		}
3202 	} else {
3203 		if ((error = namei(nd))) {
3204 			nd->ni_dvp = NULLVP;
3205 			error = ENOATTR;
3206 			goto out;
3207 		}
3208 		xvp = nd->ni_vp;
3209 		nameidone(nd);
3210 	}
3211 	nd->ni_dvp = NULLVP;
3212 
3213 	if (xvp->v_type != VREG) {
3214 		error = ENOATTR;
3215 		goto out;
3216 	}
3217 	/*
3218 	 * Owners must match.
3219 	 */
3220 	VATTR_INIT(va);
3221 	VATTR_WANTED(va, va_uid);
3222 	if (VNOP_GETATTR(vp, va, context) == 0 && VATTR_IS_SUPPORTED(va, va_uid)) {
3223 		uid_t owner = va->va_uid;
3224 
3225 		VATTR_INIT(va);
3226 		VATTR_WANTED(va, va_uid);
3227 		if (VNOP_GETATTR(xvp, va, context) == 0 && (owner != va->va_uid)) {
3228 			error = ENOATTR;  /* don't use this "._" file */
3229 			goto out;
3230 		}
3231 	}
3232 
3233 	if ((error = VNOP_OPEN(xvp, fileflags & ~(O_EXLOCK | O_SHLOCK), context))) {
3234 		error = ENOATTR;
3235 		goto out;
3236 	}
3237 	opened = 1;
3238 
3239 	if ((error = vnode_ref_ext(xvp, fileflags, 0)) != 0) {
3240 		goto out;
3241 	}
3242 	referenced = 1;
3243 
3244 	/*
3245 	 * If create was requested, make sure file header exists.
3246 	 * This is only done in the non-DoubleAgent case.
3247 	 * XXX And will be garbage-collected in due time.
3248 	 */
3249 	if (!vfs_xattr_doubleagent_enabled && (fileflags & O_CREAT) != 0) {
3250 		VATTR_INIT(va);
3251 		VATTR_WANTED(va, va_data_size);
3252 		VATTR_WANTED(va, va_fileid);
3253 		VATTR_WANTED(va, va_nlink);
3254 		if ((error = vnode_getattr(xvp, va, context)) != 0) {
3255 			error = EPERM;
3256 			goto out;
3257 		}
3258 
3259 		/* If the file is empty then add a default header. */
3260 		if (va->va_data_size == 0) {
3261 			/* Don't adopt hard-linked "._" files. */
3262 			if (VATTR_IS_SUPPORTED(va, va_nlink) && va->va_nlink > 1) {
3263 				error = EPERM;
3264 				goto out;
3265 			}
3266 			if ((error = create_xattrfile(xvp, (u_int32_t)va->va_fileid, context))) {
3267 				goto out;
3268 			}
3269 		}
3270 	}
3271 
3272 	/*
3273 	 * Allocate a file object for the referenced vnode.
3274 	 * This file object now owns the vnode reference,
3275 	 * and the caller owns the iocount, which will be
3276 	 * dropped in close_xattrfile().
3277 	 */
3278 	fg = fg_alloc_init(context);
3279 	fg->fg_flag = fileflags & FMASK;
3280 	fg->fg_ops = &vnops;
3281 	fg_set_data(fg, xvp);
3282 
3283 	/* Apply file locking if requested. */
3284 	if (fileflags & (O_EXLOCK | O_SHLOCK)) {
3285 		struct flock lf = {
3286 			.l_whence = SEEK_SET,
3287 		};
3288 
3289 		if (fileflags & O_EXLOCK) {
3290 			lf.l_type = F_WRLCK;
3291 		} else {
3292 			lf.l_type = F_RDLCK;
3293 		}
3294 		error = VNOP_ADVLOCK(xvp, (caddr_t)fg, F_SETLK, &lf, F_FLOCK | F_WAIT, context, NULL);
3295 		if (error == ENOTSUP) {
3296 			error = 0;
3297 		} else if (error) {
3298 			error = ENOATTR;
3299 			goto out;
3300 		} else { // error == 0
3301 			fg->fg_flag |= FWASLOCKED;
3302 		}
3303 	}
3304 
3305 	if (file_sizep != NULL) {
3306 		/*
3307 		 * Now that the file is locked, get the file's size.
3308 		 */
3309 		VATTR_INIT(va);
3310 		VATTR_WANTED(va, va_data_size);
3311 		if ((error = vnode_getattr(xvp, va, context)) != 0) {
3312 			error = ENOATTR;
3313 			goto out;
3314 		}
3315 		*file_sizep = va->va_data_size;
3316 	}
3317 out:
3318 	if (error) {
3319 		if (fg != NULL) {
3320 			/* Let the normal close path handle this. */
3321 			if (created_xattr_file) {
3322 				remove_xattrfile(fg, xvp, context);
3323 			} else {
3324 				close_xattrfile(fg, true, true, context);
3325 			}
3326 			fg = NULL;
3327 			xvp = NULLVP;
3328 		} else if (xvp != NULLVP) {
3329 			if (opened) {
3330 				(void) VNOP_CLOSE(xvp, fileflags, context);
3331 			}
3332 			if (created_xattr_file) {
3333 				remove_xattrfile(NULL, xvp, context);
3334 			}
3335 			if (referenced) {
3336 				(void) vnode_rele(xvp);
3337 			}
3338 			/* remove_xattrfile() would have dropped the iocount already */
3339 			if (!created_xattr_file) {
3340 				(void) vnode_put(xvp);
3341 			}
3342 			xvp = NULLVP;
3343 		}
3344 		if ((error == ENOATTR) && (fileflags & O_CREAT)) {
3345 			error = EPERM;
3346 		}
3347 	}
3348 
3349 	/* Release resources after error-handling */
3350 	kfree_type(struct nameidata, nd);
3351 	kfree_type(struct vnode_attr, va);
3352 	if (dvp && (dvp != vp)) {
3353 		vnode_put(dvp);
3354 	}
3355 	if (basename) {
3356 		vnode_putname(basename);
3357 	}
3358 	if (filename && filename != &smallname[0]) {
3359 		kfree_data(filename, alloc_len);
3360 	}
3361 
3362 	*xfgp = fg;
3363 	return error;
3364 }
3365 
3366 static void
close_xattrfile(struct fileglob * xfg,bool have_iocount,bool drop_iocount,vfs_context_t context)3367 close_xattrfile(struct fileglob *xfg, bool have_iocount, bool drop_iocount,
3368     vfs_context_t context)
3369 {
3370 	vnode_t xvp = fg_get_data(xfg);
3371 
3372 	/*
3373 	 * N.B. The only time have_iocount would be false would be when
3374 	 * a vnode_getwithref() calls fails after coming back from a
3375 	 * doubleagentd upcall.  If that happens, then it would mean
3376 	 * that the old vnode identity is gone, and our advisory lock
3377 	 * would have been garbage-collected when the vnode was reclaimed.
3378 	 */
3379 	if (have_iocount) {
3380 		/*
3381 		 * fg_drop() won't drop our advisory lock because we are not
3382 		 * following POSIX semantics.  Drop it here.
3383 		 */
3384 		struct flock lf = {
3385 			.l_whence = SEEK_SET,
3386 			.l_type = F_UNLCK,
3387 		};
3388 		(void)VNOP_ADVLOCK(xvp, (caddr_t)xfg, F_UNLCK, &lf, F_FLOCK,
3389 		    context, NULL);
3390 
3391 		/* (Maybe) drop the iocount we took in open_xattrfile(). */
3392 		if (drop_iocount) {
3393 			vnode_put(xvp);
3394 		}
3395 	}
3396 
3397 	(void) fg_drop(current_proc(), xfg);
3398 }
3399 
3400 static void
remove_xattrfile(struct fileglob * xfg,vnode_t xvp,vfs_context_t context)3401 remove_xattrfile(struct fileglob *xfg, vnode_t xvp, vfs_context_t context)
3402 {
3403 	vnode_t dvp = NULL, rvp = NULL;
3404 	struct nameidata nd;
3405 	char *path = NULL;
3406 	int pathlen;
3407 	int error;
3408 
3409 	if (xfg != NULL) {
3410 		/*
3411 		 * Close the xattr file but don't dispose of the
3412 		 * iocount acquired in open_xattrfile() while doing
3413 		 * so.  We'll do that below once we have performed
3414 		 * the unlink operation.
3415 		 */
3416 		close_xattrfile(xfg, true, false, context);
3417 	}
3418 
3419 	path = zalloc(ZV_NAMEI);
3420 	pathlen = MAXPATHLEN;
3421 	error = vn_getpath(xvp, path, &pathlen);
3422 	if (error) {
3423 		zfree(ZV_NAMEI, path);
3424 		goto out;
3425 	}
3426 
3427 	NDINIT(&nd, DELETE, OP_UNLINK, LOCKPARENT | NOFOLLOW | DONOTAUTH,
3428 	    UIO_SYSSPACE, CAST_USER_ADDR_T(path), context);
3429 	error = namei(&nd);
3430 	zfree(ZV_NAMEI, path);
3431 	if (error) {
3432 		goto out;
3433 	}
3434 	dvp = nd.ni_dvp;
3435 	rvp = nd.ni_vp;
3436 
3437 	/*
3438 	 * Only remove if the namei() returned to us the same vnode that
3439 	 * we think we are supposed to be removing.  If they're not the
3440 	 * same, we could have raced against something else trying to
3441 	 * unlink it, and we don't want to remove someone else's (possibly
3442 	 * very important) file.
3443 	 */
3444 	if (rvp == xvp) {
3445 		(void) VNOP_REMOVE(dvp, rvp, &nd.ni_cnd, 0, context);
3446 	}
3447 	nameidone(&nd);
3448 
3449 out:
3450 	vnode_put(xvp);
3451 	if (dvp != NULLVP) {
3452 		vnode_put(dvp);
3453 	}
3454 	if (rvp != NULLVP) {
3455 		vnode_put(rvp);
3456 	}
3457 }
3458 
3459 /*
3460  * Read in and parse the AppleDouble header and entries, and the extended
3461  * attribute header and entries if any.  Populates the fields of ainfop
3462  * based on the headers and entries found.
3463  *
3464  * The basic idea is to:
3465  * - Read in up to ATTR_MAX_HDR_SIZE bytes of the start of the file.  All
3466  *   AppleDouble entries, the extended attribute header, and extended
3467  *   attribute entries must lie within this part of the file; the rest of
3468  *   the AppleDouble handling code assumes this.  Plus it allows us to
3469  *   somewhat optimize by doing a smaller number of larger I/Os.
3470  * - Swap and sanity check the AppleDouble header (including the AppleDouble
3471  *   entries).
3472  * - Find the Finder Info and Resource Fork entries, if any.
3473  * - If we're going to be writing, try to make sure the Finder Info entry has
3474  *   room to store the extended attribute header, plus some space for extended
3475  *   attributes.
3476  * - Swap and sanity check the extended attribute header and entries (if any).
3477  */
3478 static int
get_xattrinfo(vnode_t xvp,int setting,attr_info_t * ainfop,vfs_context_t context)3479 get_xattrinfo(vnode_t xvp, int setting, attr_info_t *ainfop, vfs_context_t context)
3480 {
3481 	uio_t auio = NULL;
3482 	void * buffer = NULL;
3483 	apple_double_header_t  *filehdr;
3484 	struct vnode_attr va;
3485 	size_t iosize = 0;
3486 	int i;
3487 	int error;
3488 
3489 	bzero(ainfop, sizeof(attr_info_t));
3490 	ainfop->filevp = xvp;
3491 	ainfop->context = context;
3492 	VATTR_INIT(&va);
3493 	VATTR_WANTED(&va, va_data_size);
3494 	VATTR_WANTED(&va, va_fileid);
3495 	if ((error = vnode_getattr(xvp, &va, context))) {
3496 		goto bail;
3497 	}
3498 	ainfop->filesize = va.va_data_size;
3499 
3500 	/* When setting attributes, allow room for the header to grow. */
3501 	if (setting) {
3502 		iosize = ATTR_MAX_HDR_SIZE;
3503 	} else {
3504 		iosize = MIN(ATTR_MAX_HDR_SIZE, ainfop->filesize);
3505 	}
3506 
3507 	if (iosize == 0 || iosize < sizeof(apple_double_header_t)) {
3508 		error = ENOATTR;
3509 		goto bail;
3510 	}
3511 
3512 	ainfop->iosize = iosize;
3513 	buffer = kalloc_data(iosize, Z_WAITOK | Z_ZERO);
3514 	if (buffer == NULL) {
3515 		error = ENOMEM;
3516 		goto bail;
3517 	}
3518 
3519 	auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
3520 	uio_addiov(auio, (uintptr_t)buffer, iosize);
3521 
3522 	/* Read the file header. */
3523 	error = VNOP_READ(xvp, auio, 0, context);
3524 	if (error) {
3525 		goto bail;
3526 	}
3527 	ainfop->rawsize = iosize - uio_resid(auio);
3528 	ainfop->rawdata = (u_int8_t *)buffer;
3529 
3530 	filehdr = (apple_double_header_t *)buffer;
3531 
3532 	error = check_and_swap_apple_double_header(ainfop);
3533 	if (error) {
3534 		goto bail;
3535 	}
3536 
3537 	ainfop->filehdr = filehdr;  /* valid AppleDouble header */
3538 
3539 	/* rel_xattrinfo is responsible for freeing the header buffer */
3540 	buffer = NULL;
3541 
3542 	/* Find the Finder Info and Resource Fork entries, if any */
3543 	for (i = 0; i < filehdr->numEntries; ++i) {
3544 		if (filehdr->entries[i].type == AD_FINDERINFO &&
3545 		    filehdr->entries[i].length >= FINDERINFOSIZE) {
3546 			/* We found the Finder Info entry. */
3547 			ainfop->finderinfo = &filehdr->entries[i];
3548 
3549 			/* At this point check_and_swap_apple_double_header() call above
3550 			 * verified that all apple double entires are valid:
3551 			 * they point somewhere within the file.
3552 			 *
3553 			 * Now for finderinfo make sure that the fixed portion
3554 			 * is within the buffer we read in.
3555 			 */
3556 			if (((ainfop->finderinfo->offset + FINDERINFOSIZE) > ainfop->finderinfo->offset) &&
3557 			    ((ainfop->finderinfo->offset + FINDERINFOSIZE) <= ainfop->rawsize)) {
3558 				/*
3559 				 * Is the Finder Info "empty" (all zeroes)?  If so,
3560 				 * we'll pretend like the Finder Info extended attribute
3561 				 * does not exist.
3562 				 */
3563 				if (bcmp((u_int8_t*)ainfop->filehdr + ainfop->finderinfo->offset, emptyfinfo, sizeof(emptyfinfo)) == 0) {
3564 					ainfop->emptyfinderinfo = 1;
3565 				}
3566 			} else {
3567 				error = ENOATTR;
3568 				goto bail;
3569 			}
3570 		}
3571 		if (filehdr->entries[i].type == AD_RESOURCE) {
3572 			/*
3573 			 * Ignore zero-length resource forks when getting.  If setting,
3574 			 * we need to remember the resource fork entry so it can be
3575 			 * updated once the new content has been written.
3576 			 */
3577 			if (filehdr->entries[i].length == 0 && !setting) {
3578 				continue;
3579 			}
3580 
3581 			/*
3582 			 * Check to see if any "empty" resource fork is ours (i.e. is ignorable).
3583 			 *
3584 			 * The "empty" resource headers we created have a system data tag of:
3585 			 * "This resource fork intentionally left blank   "
3586 			 */
3587 			if (filehdr->entries[i].length == sizeof(rsrcfork_header_t) && !setting) {
3588 				uio_t  rf_uio;
3589 				u_int8_t  systemData[64];
3590 				int  rf_err;
3591 
3592 
3593 				/* Read the system data which starts at byte 16 */
3594 				rf_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
3595 				uio_addiov(rf_uio, (uintptr_t)systemData, sizeof(systemData));
3596 				uio_setoffset(rf_uio, filehdr->entries[i].offset + 16);
3597 				rf_err = VNOP_READ(xvp, rf_uio, 0, context);
3598 				uio_free(rf_uio);
3599 
3600 				if (rf_err != 0 ||
3601 				    bcmp(systemData, RF_EMPTY_TAG, sizeof(RF_EMPTY_TAG)) == 0) {
3602 					continue;  /* skip this resource fork */
3603 				}
3604 			}
3605 			ainfop->rsrcfork = &filehdr->entries[i];
3606 			if (i != (filehdr->numEntries - 1)) {
3607 				printf("get_xattrinfo: resource fork not last entry\n");
3608 				ainfop->readonly = 1;
3609 			}
3610 			continue;
3611 		}
3612 	}
3613 
3614 	/*
3615 	 * See if this file looks like it is laid out correctly to contain
3616 	 * extended attributes.  If so, then do the following:
3617 	 *
3618 	 * - If we're going to be writing, try to make sure the Finder Info
3619 	 *   entry has room to store the extended attribute header, plus some
3620 	 *   space for extended attributes.
3621 	 *
3622 	 * - Swap and sanity check the extended attribute header and entries
3623 	 *   (if any).
3624 	 */
3625 	if (filehdr->numEntries == 2 &&
3626 	    ainfop->finderinfo == &filehdr->entries[0] &&
3627 	    ainfop->rsrcfork == &filehdr->entries[1] &&
3628 	    ainfop->finderinfo->offset == offsetof(apple_double_header_t, finfo)) {
3629 		attr_header_t *attrhdr;
3630 		attrhdr = (attr_header_t *)filehdr;
3631 		/*
3632 		 * If we're going to be writing, try to make sure the Finder
3633 		 * Info entry has room to store the extended attribute header,
3634 		 * plus some space for extended attributes.
3635 		 */
3636 		if (setting && ainfop->finderinfo->length == FINDERINFOSIZE) {
3637 			size_t delta;
3638 			size_t writesize;
3639 
3640 			delta = ATTR_BUF_SIZE - (filehdr->entries[0].offset + FINDERINFOSIZE);
3641 			if (ainfop->rsrcfork && filehdr->entries[1].length) {
3642 				/* Make some room before existing resource fork. */
3643 				shift_data_down(xvp,
3644 				    filehdr->entries[1].offset,
3645 				    filehdr->entries[1].length,
3646 				    delta, context);
3647 				writesize = sizeof(attr_header_t);
3648 			} else {
3649 				/* We are in case where existing resource fork of length 0, try to create a new, empty resource fork. */
3650 				rsrcfork_header_t *rsrcforkhdr;
3651 
3652 				/* Do we have enough space in the header buffer for empty resource fork */
3653 				if (filehdr->entries[1].offset + delta + sizeof(rsrcfork_header_t) > ainfop->iosize) {
3654 					/* we do not have space, bail for now */
3655 					error = ENOATTR;
3656 					goto bail;
3657 				}
3658 
3659 				vnode_setsize(xvp, filehdr->entries[1].offset + delta, 0, context);
3660 
3661 				/* Steal some space for an empty RF header. */
3662 				delta -= sizeof(rsrcfork_header_t);
3663 
3664 				bzero(&attrhdr->appledouble.pad[0], delta);
3665 				rsrcforkhdr = (rsrcfork_header_t *)((char *)filehdr + filehdr->entries[1].offset + delta);
3666 
3667 				/* Fill in Empty Resource Fork Header. */
3668 				init_empty_resource_fork(rsrcforkhdr);
3669 
3670 				filehdr->entries[1].length = sizeof(rsrcfork_header_t);
3671 				writesize = ATTR_BUF_SIZE;
3672 			}
3673 			filehdr->entries[0].length += delta;
3674 			filehdr->entries[1].offset += delta;
3675 
3676 			/* Fill in Attribute Header. */
3677 			attrhdr->magic       = ATTR_HDR_MAGIC;
3678 			attrhdr->debug_tag   = (u_int32_t)va.va_fileid;
3679 			attrhdr->total_size  = filehdr->entries[1].offset;
3680 			attrhdr->data_start  = sizeof(attr_header_t);
3681 			attrhdr->data_length = 0;
3682 			attrhdr->reserved[0] = 0;
3683 			attrhdr->reserved[1] = 0;
3684 			attrhdr->reserved[2] = 0;
3685 			attrhdr->flags       = 0;
3686 			attrhdr->num_attrs   = 0;
3687 
3688 			/* Push out new header */
3689 			uio_reset(auio, 0, UIO_SYSSPACE, UIO_WRITE);
3690 			uio_addiov(auio, (uintptr_t)filehdr, writesize);
3691 
3692 			swap_adhdr(filehdr);    /* to big endian */
3693 			swap_attrhdr(attrhdr, ainfop);  /* to big endian */
3694 			error = VNOP_WRITE(xvp, auio, 0, context);
3695 			swap_adhdr(filehdr);    /* back to native */
3696 			/* The attribute header gets swapped below. */
3697 		}
3698 	}
3699 	/*
3700 	 * Swap and sanity check the extended attribute header and
3701 	 * entries (if any).  The Finder Info content must be big enough
3702 	 * to include the extended attribute header; if not, we just
3703 	 * ignore it.
3704 	 *
3705 	 * Note that we're passing the offset + length (i.e. the end)
3706 	 * of the Finder Info instead of rawsize to validate_attrhdr.
3707 	 * This ensures that all extended attributes lie within the
3708 	 * Finder Info content according to the AppleDouble entry.
3709 	 *
3710 	 * Sets ainfop->attrhdr and ainfop->attr_entry if a valid
3711 	 * header was found.
3712 	 */
3713 	if (ainfop->finderinfo &&
3714 	    ainfop->finderinfo == &filehdr->entries[0] &&
3715 	    ainfop->finderinfo->length >= (sizeof(attr_header_t) - sizeof(apple_double_header_t))) {
3716 		attr_header_t *attrhdr = (attr_header_t*)filehdr;
3717 
3718 		if (ainfop->finderinfo->offset != offsetof(apple_double_header_t, finfo)) {
3719 			error = ENOATTR;
3720 			goto bail;
3721 		}
3722 
3723 		if ((error = check_and_swap_attrhdr(attrhdr, ainfop)) == 0) {
3724 			ainfop->attrhdr = attrhdr;  /* valid attribute header */
3725 			/* First attr_entry starts immediately following attribute header */
3726 			ainfop->attr_entry = (attr_entry_t *)&attrhdr[1];
3727 		}
3728 	}
3729 
3730 	error = 0;
3731 bail:
3732 	if (auio != NULL) {
3733 		uio_free(auio);
3734 	}
3735 	kfree_data(buffer, iosize);
3736 	return error;
3737 }
3738 
3739 
3740 static int
create_xattrfile(vnode_t xvp,u_int32_t fileid,vfs_context_t context)3741 create_xattrfile(vnode_t xvp, u_int32_t fileid, vfs_context_t context)
3742 {
3743 	attr_header_t *xah;
3744 	rsrcfork_header_t *rsrcforkhdr;
3745 	void * buffer;
3746 	uio_t auio;
3747 	int rsrcforksize;
3748 	int error;
3749 
3750 	buffer = kalloc_data(ATTR_BUF_SIZE, Z_WAITOK | Z_ZERO);
3751 
3752 	xah = (attr_header_t *)buffer;
3753 	auio = uio_create(1, 0, UIO_SYSSPACE, UIO_WRITE);
3754 	uio_addiov(auio, (uintptr_t)buffer, ATTR_BUF_SIZE);
3755 	rsrcforksize = sizeof(rsrcfork_header_t);
3756 	rsrcforkhdr = (rsrcfork_header_t *) ((char *)buffer + ATTR_BUF_SIZE - rsrcforksize);
3757 
3758 	/* Fill in Apple Double Header. */
3759 	xah->appledouble.magic             = SWAP32(ADH_MAGIC);
3760 	xah->appledouble.version           = SWAP32(ADH_VERSION);
3761 	xah->appledouble.numEntries        = SWAP16(2);
3762 	xah->appledouble.entries[0].type   = SWAP32(AD_FINDERINFO);
3763 	xah->appledouble.entries[0].offset = SWAP32(offsetof(apple_double_header_t, finfo));
3764 	xah->appledouble.entries[0].length = SWAP32(ATTR_BUF_SIZE - offsetof(apple_double_header_t, finfo) - rsrcforksize);
3765 	xah->appledouble.entries[1].type   = SWAP32(AD_RESOURCE);
3766 	xah->appledouble.entries[1].offset = SWAP32(ATTR_BUF_SIZE - rsrcforksize);
3767 	xah->appledouble.entries[1].length = SWAP32(rsrcforksize);
3768 	bcopy(ADH_MACOSX, xah->appledouble.filler, sizeof(xah->appledouble.filler));
3769 
3770 	/* Fill in Attribute Header. */
3771 	xah->magic       = SWAP32(ATTR_HDR_MAGIC);
3772 	xah->debug_tag   = SWAP32(fileid);
3773 	xah->total_size  = SWAP32(ATTR_BUF_SIZE - rsrcforksize);
3774 	xah->data_start  = SWAP32(sizeof(attr_header_t));
3775 
3776 	/* Fill in Empty Resource Fork Header. */
3777 	init_empty_resource_fork(rsrcforkhdr);
3778 
3779 	/* Push it out. */
3780 	error = VNOP_WRITE(xvp, auio, IO_UNIT, context);
3781 
3782 	/* Did we write out the full uio? */
3783 	if (uio_resid(auio) > 0) {
3784 		error = ENOSPC;
3785 	}
3786 
3787 	uio_free(auio);
3788 	kfree_data(buffer, ATTR_BUF_SIZE);
3789 
3790 	return error;
3791 }
3792 
3793 static void
init_empty_resource_fork(rsrcfork_header_t * rsrcforkhdr)3794 init_empty_resource_fork(rsrcfork_header_t * rsrcforkhdr)
3795 {
3796 	bzero(rsrcforkhdr, sizeof(rsrcfork_header_t));
3797 	rsrcforkhdr->fh_DataOffset = SWAP32(RF_FIRST_RESOURCE);
3798 	rsrcforkhdr->fh_MapOffset  = SWAP32(RF_FIRST_RESOURCE);
3799 	rsrcforkhdr->fh_MapLength  = SWAP32(RF_NULL_MAP_LENGTH);
3800 	rsrcforkhdr->mh_DataOffset = SWAP32(RF_FIRST_RESOURCE);
3801 	rsrcforkhdr->mh_MapOffset  = SWAP32(RF_FIRST_RESOURCE);
3802 	rsrcforkhdr->mh_MapLength  = SWAP32(RF_NULL_MAP_LENGTH);
3803 	rsrcforkhdr->mh_Types      = SWAP16(RF_NULL_MAP_LENGTH - 2 );
3804 	rsrcforkhdr->mh_Names      = SWAP16(RF_NULL_MAP_LENGTH);
3805 	rsrcforkhdr->typeCount     = SWAP16(-1);
3806 	bcopy(RF_EMPTY_TAG, rsrcforkhdr->systemData, sizeof(RF_EMPTY_TAG));
3807 }
3808 
3809 static void
rel_xattrinfo(attr_info_t * ainfop)3810 rel_xattrinfo(attr_info_t *ainfop)
3811 {
3812 	kfree_data_addr(ainfop->filehdr);
3813 	bzero(ainfop, sizeof(attr_info_t));
3814 }
3815 
3816 static int
write_xattrinfo(attr_info_t * ainfop)3817 write_xattrinfo(attr_info_t *ainfop)
3818 {
3819 	uio_t auio;
3820 	int error;
3821 
3822 	auio = uio_create(1, 0, UIO_SYSSPACE, UIO_WRITE);
3823 	uio_addiov(auio, (uintptr_t)ainfop->filehdr, ainfop->iosize);
3824 
3825 	swap_adhdr(ainfop->filehdr);
3826 	if (ainfop->attrhdr != NULL) {
3827 		swap_attrhdr(ainfop->attrhdr, ainfop);
3828 	}
3829 
3830 	error = VNOP_WRITE(ainfop->filevp, auio, 0, ainfop->context);
3831 
3832 	swap_adhdr(ainfop->filehdr);
3833 	if (ainfop->attrhdr != NULL) {
3834 		swap_attrhdr(ainfop->attrhdr, ainfop);
3835 	}
3836 	uio_free(auio);
3837 
3838 	return error;
3839 }
3840 
3841 #if BYTE_ORDER == LITTLE_ENDIAN
3842 /*
3843  * Endian swap apple double header
3844  */
3845 static void
swap_adhdr(apple_double_header_t * adh)3846 swap_adhdr(apple_double_header_t *adh)
3847 {
3848 	int count;
3849 	int i;
3850 
3851 	count = (adh->magic == ADH_MAGIC) ? adh->numEntries : SWAP16(adh->numEntries);
3852 
3853 	adh->magic      = SWAP32(adh->magic);
3854 	adh->version    = SWAP32(adh->version);
3855 	adh->numEntries = SWAP16(adh->numEntries);
3856 
3857 	for (i = 0; i < count; i++) {
3858 		adh->entries[i].type   = SWAP32(adh->entries[i].type);
3859 		adh->entries[i].offset = SWAP32(adh->entries[i].offset);
3860 		adh->entries[i].length = SWAP32(adh->entries[i].length);
3861 	}
3862 }
3863 
3864 /*
3865  * Endian swap extended attributes header
3866  */
3867 static void
swap_attrhdr(attr_header_t * ah,attr_info_t * info)3868 swap_attrhdr(attr_header_t *ah, attr_info_t* info)
3869 {
3870 	attr_entry_t *ae;
3871 	int count;
3872 	int i;
3873 
3874 	count = (ah->magic == ATTR_HDR_MAGIC) ? ah->num_attrs : SWAP16(ah->num_attrs);
3875 
3876 	ah->magic       = SWAP32(ah->magic);
3877 	ah->debug_tag   = SWAP32(ah->debug_tag);
3878 	ah->total_size  = SWAP32(ah->total_size);
3879 	ah->data_start  = SWAP32(ah->data_start);
3880 	ah->data_length = SWAP32(ah->data_length);
3881 	ah->flags       = SWAP16(ah->flags);
3882 	ah->num_attrs   = SWAP16(ah->num_attrs);
3883 
3884 	ae = (attr_entry_t *)(&ah[1]);
3885 	for (i = 0; i < count && ATTR_VALID(ae, *info); i++, ae = ATTR_NEXT(ae)) {
3886 		ae->offset = SWAP32(ae->offset);
3887 		ae->length = SWAP32(ae->length);
3888 		ae->flags  = SWAP16(ae->flags);
3889 	}
3890 }
3891 #endif
3892 
3893 /*
3894  * Validate and swap the attributes header contents, and each attribute's
3895  * attr_entry_t.
3896  *
3897  * Note: Assumes the caller has verified that the Finder Info content is large
3898  * enough to contain the attr_header structure itself.  Therefore, we can
3899  * swap the header fields before sanity checking them.
3900  */
3901 static int
check_and_swap_attrhdr(attr_header_t * ah,attr_info_t * ainfop)3902 check_and_swap_attrhdr(attr_header_t *ah, attr_info_t *ainfop)
3903 {
3904 	attr_entry_t *ae;
3905 	u_int8_t *buf_end;
3906 	u_int32_t end;
3907 	int count;
3908 	int i;
3909 	uint32_t total_header_size;
3910 	uint32_t total_data_size;
3911 
3912 	if (ah == NULL) {
3913 		return EINVAL;
3914 	}
3915 
3916 	if (SWAP32(ah->magic) != ATTR_HDR_MAGIC) {
3917 		return EINVAL;
3918 	}
3919 
3920 	/* Swap the basic header fields */
3921 	ah->magic       = SWAP32(ah->magic);
3922 	ah->debug_tag   = SWAP32(ah->debug_tag);
3923 	ah->total_size  = SWAP32(ah->total_size);
3924 	ah->data_start  = SWAP32(ah->data_start);
3925 	ah->data_length = SWAP32(ah->data_length);
3926 	ah->flags       = SWAP16(ah->flags);
3927 	ah->num_attrs   = SWAP16(ah->num_attrs);
3928 
3929 	/*
3930 	 * Make sure the total_size fits within the Finder Info area, and the
3931 	 * extended attribute data area fits within total_size.
3932 	 */
3933 	end = ah->data_start + ah->data_length;
3934 	if (ah->total_size > ainfop->finderinfo->offset + ainfop->finderinfo->length ||
3935 	    ah->data_start < sizeof(attr_header_t) ||
3936 	    end < ah->data_start ||
3937 	    end > ah->total_size) {
3938 		return EINVAL;
3939 	}
3940 
3941 	/*
3942 	 * Make sure each of the attr_entry_t's fits within total_size.
3943 	 */
3944 	buf_end = ainfop->rawdata + ah->data_start;
3945 	if (buf_end > ainfop->rawdata + ainfop->rawsize) {
3946 		return EINVAL;
3947 	}
3948 	count = ah->num_attrs;
3949 	if (count > 256) {
3950 		return EINVAL;
3951 	}
3952 	ae = (attr_entry_t *)(&ah[1]);
3953 
3954 	total_header_size = sizeof(attr_header_t);
3955 	total_data_size = 0;
3956 	for (i = 0; i < count; i++) {
3957 		/* Make sure the fixed-size part of this attr_entry_t fits. */
3958 		if ((u_int8_t *) &ae[1] > buf_end) {
3959 			return EINVAL;
3960 		}
3961 
3962 		/* Make sure the variable-length name fits */
3963 		if (&ae->name[ae->namelen] > buf_end) {
3964 			return EINVAL;
3965 		}
3966 
3967 		/* Make sure that namelen is matching name's real length, namelen included NUL */
3968 		if (strnlen((const char *)ae->name, ae->namelen) != ae->namelen - 1) {
3969 			return EINVAL;
3970 		}
3971 
3972 		/* Swap the attribute entry fields */
3973 		ae->offset      = SWAP32(ae->offset);
3974 		ae->length      = SWAP32(ae->length);
3975 		ae->flags       = SWAP16(ae->flags);
3976 
3977 		/* Make sure the attribute content fits and points to the data part */
3978 		end = ae->offset + ae->length;
3979 		if (end < ae->offset || end > ah->total_size) {
3980 			return EINVAL;
3981 		}
3982 
3983 		/* Make sure entry points to data section and not header */
3984 		if (ae->offset < ah->data_start || end > ah->data_start + ah->data_length) {
3985 			return EINVAL;
3986 		}
3987 
3988 		/* We verified namelen is ok above, so add this entry's size to a total */
3989 		if (os_add_overflow(total_header_size, ATTR_ENTRY_LENGTH(ae->namelen), &total_header_size)) {
3990 			return EINVAL;
3991 		}
3992 
3993 		/* We verified that entry's length is within data section, so add it to running size total */
3994 		if (os_add_overflow(total_data_size, ae->length, &total_data_size)) {
3995 			return EINVAL;
3996 		}
3997 
3998 		ae = ATTR_NEXT(ae);
3999 	}
4000 
4001 
4002 	/* make sure data_start is actually after all the xattr key entries */
4003 	if (ah->data_start < total_header_size) {
4004 		return EINVAL;
4005 	}
4006 
4007 	/* make sure all entries' data  length add to header's idea of data length */
4008 	if (total_data_size != ah->data_length) {
4009 		return EINVAL;
4010 	}
4011 
4012 	return 0;
4013 }
4014 
4015 //
4016 // "start" & "end" are byte offsets in the file.
4017 // "to" is the byte offset we want to move the
4018 // data to.  "to" should be > "start".
4019 //
4020 // we do the copy backwards to avoid problems if
4021 // there's an overlap.
4022 //
4023 static int
shift_data_down(vnode_t xvp,off_t start,size_t len,off_t delta,vfs_context_t context)4024 shift_data_down(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t context)
4025 {
4026 	int ret, iolen;
4027 	size_t chunk, orig_chunk;
4028 	char *buff;
4029 	off_t pos;
4030 	kauth_cred_t ucred = vfs_context_ucred(context);
4031 	proc_t p = vfs_context_proc(context);
4032 
4033 	if (delta == 0 || len == 0) {
4034 		return 0;
4035 	}
4036 
4037 	chunk = 4096;
4038 	if (len < chunk) {
4039 		chunk = len;
4040 	}
4041 	orig_chunk = chunk;
4042 
4043 	buff = kalloc_data(chunk, Z_WAITOK);
4044 	if (buff == NULL) {
4045 		return ENOMEM;
4046 	}
4047 
4048 	for (pos = start + len - chunk; pos >= start; pos -= chunk) {
4049 		ret = vn_rdwr(UIO_READ, xvp, buff, (int)chunk, pos, UIO_SYSSPACE, IO_NODELOCKED | IO_NOAUTH, ucred, &iolen, p);
4050 		if (iolen != 0) {
4051 			printf("xattr:shift_data: error reading data @ %lld (read %d of %lu) (%d)\n",
4052 			    pos, ret, chunk, ret);
4053 			break;
4054 		}
4055 
4056 		ret = vn_rdwr(UIO_WRITE, xvp, buff, (int)chunk, pos + delta, UIO_SYSSPACE, IO_NODELOCKED | IO_NOAUTH, ucred, &iolen, p);
4057 		if (iolen != 0) {
4058 			printf("xattr:shift_data: error writing data @ %lld (wrote %d of %lu) (%d)\n",
4059 			    pos + delta, ret, chunk, ret);
4060 			break;
4061 		}
4062 
4063 		if ((pos - (off_t)chunk) < start) {
4064 			chunk = pos - start;
4065 
4066 			if (chunk == 0) {   // we're all done
4067 				break;
4068 			}
4069 		}
4070 	}
4071 
4072 	kfree_data(buff, orig_chunk);
4073 	return 0;
4074 }
4075 
4076 
4077 static int
shift_data_up(vnode_t xvp,off_t start,size_t len,off_t delta,vfs_context_t context)4078 shift_data_up(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t context)
4079 {
4080 	int ret, iolen;
4081 	size_t chunk, orig_chunk;
4082 	char *buff;
4083 	off_t pos;
4084 	off_t end;
4085 	kauth_cred_t ucred = vfs_context_ucred(context);
4086 	proc_t p = vfs_context_proc(context);
4087 
4088 	if (delta == 0 || len == 0) {
4089 		return 0;
4090 	}
4091 
4092 	chunk = 4096;
4093 	if (len < chunk) {
4094 		chunk = len;
4095 	}
4096 	orig_chunk = chunk;
4097 	end = start + len;
4098 
4099 	buff = kalloc_data(chunk, Z_WAITOK);
4100 	if (buff == NULL) {
4101 		return ENOMEM;
4102 	}
4103 
4104 	for (pos = start; pos < end; pos += chunk) {
4105 		ret = vn_rdwr(UIO_READ, xvp, buff, (int)chunk, pos, UIO_SYSSPACE, IO_NODELOCKED | IO_NOAUTH, ucred, &iolen, p);
4106 		if (iolen != 0) {
4107 			printf("xattr:shift_data: error reading data @ %lld (read %d of %lu) (%d)\n",
4108 			    pos, ret, chunk, ret);
4109 			break;
4110 		}
4111 
4112 		ret = vn_rdwr(UIO_WRITE, xvp, buff, (int)chunk, pos - delta, UIO_SYSSPACE, IO_NODELOCKED | IO_NOAUTH, ucred, &iolen, p);
4113 		if (iolen != 0) {
4114 			printf("xattr:shift_data: error writing data @ %lld (wrote %d of %lu) (%d)\n",
4115 			    pos + delta, ret, chunk, ret);
4116 			break;
4117 		}
4118 
4119 		if ((pos + (off_t)chunk) > end) {
4120 			chunk = end - pos;
4121 
4122 			if (chunk == 0) {   // we're all done
4123 				break;
4124 			}
4125 		}
4126 	}
4127 
4128 	kfree_data(buff, orig_chunk);
4129 	return 0;
4130 }
4131 
4132 static int
make_xattrfile_port(struct fileglob * fg,ipc_port_t * portp)4133 make_xattrfile_port(struct fileglob *fg, ipc_port_t *portp)
4134 {
4135 	/*
4136 	 * This is essentially a stripped-down copy of
4137 	 * sys_fileport_makeport().
4138 	 */
4139 	ipc_port_t fileport;
4140 	int error = 0;
4141 
4142 	/* Dropped when port is deallocated. */
4143 	fg_ref(FG_NOPROC, fg);
4144 
4145 	fileport = fileport_alloc(fg);
4146 	if (fileport == IPC_PORT_NULL) {
4147 		fg_drop_live(fg);
4148 		error = EIO;
4149 	} else {
4150 		/* Tag the fileglob for debugging purposes */
4151 		lck_mtx_lock_spin(&fg->fg_lock);
4152 		fg->fg_lflags |= FG_PORTMADE;
4153 		lck_mtx_unlock(&fg->fg_lock);
4154 	}
4155 
4156 	/*
4157 	 * The Mig defs for doubleagentd declare the fileport argument
4158 	 * as move-send.  If we ever decide we want to cache the fileport
4159 	 * here in the kernel, we will either need to change the Mig
4160 	 * defs back to the default mach_port_t (which is a copy-send)
4161 	 * or explicitly ipc_port_copy_send_any() the right before
4162 	 * sending it in the Mig stub.
4163 	 */
4164 
4165 	*portp = fileport;
4166 	return error;
4167 }
4168 
4169 #else /* CONFIG_APPLEDOUBLE */
4170 
4171 
4172 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)4173 default_getxattr(__unused vnode_t vp, __unused const char *name,
4174     __unused uio_t uio, __unused size_t *size, __unused int options,
4175     __unused vfs_context_t context)
4176 {
4177 	return ENOTSUP;
4178 }
4179 
4180 static int
default_setxattr(__unused vnode_t vp,__unused const char * name,__unused uio_t uio,__unused int options,__unused vfs_context_t context)4181 default_setxattr(__unused vnode_t vp, __unused const char *name,
4182     __unused uio_t uio, __unused int options, __unused vfs_context_t context)
4183 {
4184 	return ENOTSUP;
4185 }
4186 
4187 static int
default_listxattr(__unused vnode_t vp,__unused uio_t uio,__unused size_t * size,__unused int options,__unused vfs_context_t context)4188 default_listxattr(__unused vnode_t vp,
4189     __unused uio_t uio, __unused size_t *size, __unused int options,
4190     __unused vfs_context_t context)
4191 {
4192 	return ENOTSUP;
4193 }
4194 
4195 static int
default_removexattr(__unused vnode_t vp,__unused const char * name,__unused int options,__unused vfs_context_t context)4196 default_removexattr(__unused vnode_t vp, __unused const char *name,
4197     __unused int options, __unused vfs_context_t context)
4198 {
4199 	return ENOTSUP;
4200 }
4201 
4202 #endif /* CONFIG_APPLEDOUBLE */
4203