1/* 2 * Copyright (c) 1995-2014 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#include <sys/systm.h> 37#include <sys/namei.h> 38#include <sys/kernel.h> 39#include <sys/stat.h> 40#include <sys/vnode_internal.h> 41#include <sys/mount_internal.h> 42#include <sys/proc_internal.h> 43#include <sys/kauth.h> 44#include <sys/uio_internal.h> 45#include <sys/malloc.h> 46#include <sys/attr.h> 47#include <sys/sysproto.h> 48#include <sys/xattr.h> 49#include <sys/fsevents.h> 50#include <kern/kalloc.h> 51#include <miscfs/specfs/specdev.h> 52#include <hfs/hfs.h> 53 54#if CONFIG_MACF 55#include <security/mac_framework.h> 56#endif 57 58#define ATTR_TIME_SIZE -1 59 60/* 61 * SPI. 62 */ 63#define FSOPT_ATTRLIST_EXTENDED 0x00000020 64 65/* Valid only if FSOPT_ATTRLIST_EXTENDED is set */ 66#define ATTR_CMN_GEN_COUNT 0x00080000 /* same as ATTR_CMN_NAMEDATTRCOUNT */ 67#define ATTR_CMN_DOCUMENT_ID 0x00100000 /* same as ATTR_CMN_NAMEDATTRLIST */ 68 69#define ATTR_CMN_ERROR 0x20000000 70 71/* 72 * Structure describing the state of an in-progress attrlist operation. 73 */ 74struct _attrlist_buf { 75 char *base; 76 char *fixedcursor; 77 char *varcursor; 78 ssize_t allocated; 79 ssize_t needed; 80 attribute_set_t actual; 81 attribute_set_t valid; 82}; 83 84 85/* 86 * Attempt to pack a fixed width attribute of size (count) bytes from 87 * source to our attrlist buffer. 88 */ 89static void 90attrlist_pack_fixed(struct _attrlist_buf *ab, void *source, ssize_t count) 91{ 92 /* 93 * Use ssize_t for pointer math purposes, 94 * since a ssize_t is a signed long 95 */ 96 ssize_t fit; 97 98 /* 99 * Compute the amount of remaining space in the attrlist buffer 100 * based on how much we've used for fixed width fields vs. the 101 * start of the attributes. 102 * 103 * If we've still got room, then 'fit' will contain the amount of 104 * remaining space. 105 * 106 * Note that this math is safe because, in the event that the 107 * fixed-width cursor has moved beyond the end of the buffer, 108 * then, the second input into lmin() below will be negative, and 109 * we will fail the (fit > 0) check below. 110 */ 111 fit = lmin(count, ab->allocated - (ab->fixedcursor - ab->base)); 112 if (fit > 0) { 113 /* Copy in as much as we can */ 114 bcopy(source, ab->fixedcursor, fit); 115 } 116 117 /* always move in increments of 4, even if we didn't pack an attribute. */ 118 ab->fixedcursor += roundup(count, 4); 119} 120 121/* 122 * Attempt to pack one (or two) variable width attributes into the attrlist 123 * buffer. If we are trying to pack two variable width attributes, they are treated 124 * as a single variable-width attribute from the POV of the system call caller. 125 * 126 * Recall that a variable-width attribute has two components: the fixed-width 127 * attribute that tells the caller where to look, and the actual variable width data. 128 */ 129static void 130attrlist_pack_variable2(struct _attrlist_buf *ab, const void *source, ssize_t count, 131 const void *ext, ssize_t extcount) 132{ 133 134 /* Use ssize_t's for pointer math ease */ 135 struct attrreference ar; 136 ssize_t fit; 137 138 /* 139 * Pack the fixed-width component to the variable object. 140 * Note that we may be able to pack the fixed width attref, but not 141 * the variable (if there's no room). 142 */ 143 ar.attr_dataoffset = ab->varcursor - ab->fixedcursor; 144 ar.attr_length = count + extcount; 145 attrlist_pack_fixed(ab, &ar, sizeof(ar)); 146 147 /* 148 * Use an lmin() to do a signed comparison. We use a signed comparison 149 * to detect the 'out of memory' conditions as described above in the 150 * fixed width check above. 151 * 152 * Then pack the first variable attribute as space allows. Note that we advance 153 * the variable cursor only if we we had some available space. 154 */ 155 fit = lmin(count, ab->allocated - (ab->varcursor - ab->base)); 156 if (fit > 0) { 157 if (source != NULL) { 158 bcopy(source, ab->varcursor, fit); 159 } 160 ab->varcursor += fit; 161 } 162 163 /* Compute the available space for the second attribute */ 164 fit = lmin(extcount, ab->allocated - (ab->varcursor - ab->base)); 165 if (fit > 0) { 166 /* Copy in data for the second attribute (if needed) if there is room */ 167 if (ext != NULL) { 168 bcopy(ext, ab->varcursor, fit); 169 } 170 ab->varcursor += fit; 171 } 172 /* always move in increments of 4 */ 173 ab->varcursor = (char *)roundup((uintptr_t)ab->varcursor, 4); 174} 175 176/* 177 * Packing a single variable-width attribute is the same as calling the two, but with 178 * an invalid 2nd attribute. 179 */ 180static void 181attrlist_pack_variable(struct _attrlist_buf *ab, const void *source, ssize_t count) 182{ 183 attrlist_pack_variable2(ab, source, count, NULL, 0); 184} 185 186/* 187 * Attempt to pack a string. This is a special case of a variable width attribute. 188 * 189 * If "source" is NULL, then an empty string ("") will be packed. If "source" is 190 * not NULL, but "count" is zero, then "source" is assumed to be a NUL-terminated 191 * C-string. If "source" is not NULL and "count" is not zero, then only the first 192 * "count" bytes of "source" will be copied, and a NUL terminator will be added. 193 * 194 * If the attrlist buffer doesn't have enough room to hold the entire string (including 195 * NUL terminator), then copy as much as will fit. The attrlist buffer's "varcursor" 196 * will always be updated based on the entire length of the string (including NUL 197 * terminator); this means "varcursor" may end up pointing beyond the end of the 198 * allocated buffer space. 199 */ 200static void 201attrlist_pack_string(struct _attrlist_buf *ab, const char *source, ssize_t count) 202{ 203 struct attrreference ar; 204 ssize_t fit, space; 205 206 /* 207 * Supplied count is character count of string text, excluding trailing nul 208 * which we always supply here. 209 */ 210 if (source == NULL) { 211 count = 0; 212 } else if (count == 0) { 213 count = strlen(source); 214 } 215 216 /* 217 * Construct the fixed-width attribute that refers to this string. 218 */ 219 ar.attr_dataoffset = ab->varcursor - ab->fixedcursor; 220 ar.attr_length = count + 1; 221 attrlist_pack_fixed(ab, &ar, sizeof(ar)); 222 223 /* 224 * Now compute how much available memory we have to copy the string text. 225 * 226 * space = the number of bytes available in the attribute buffer to hold the 227 * string's value. 228 * 229 * fit = the number of bytes to copy from the start of the string into the 230 * attribute buffer, NOT including the NUL terminator. If the attribute 231 * buffer is large enough, this will be the string's length; otherwise, it 232 * will be equal to "space". 233 */ 234 space = ab->allocated - (ab->varcursor - ab->base); 235 fit = lmin(count, space); 236 if (space > 0) { 237 /* 238 * If there is space remaining, copy data in, and 239 * accommodate the trailing NUL terminator. 240 * 241 * NOTE: if "space" is too small to hold the string and its NUL 242 * terminator (space < fit + 1), then the string value in the attribute 243 * buffer will NOT be NUL terminated! 244 * 245 * NOTE 2: bcopy() will do nothing if the length ("fit") is zero. 246 * Therefore, we don't bother checking for that here. 247 */ 248 bcopy(source, ab->varcursor, fit); 249 /* is there room for our trailing nul? */ 250 if (space > fit) { 251 ab->varcursor[fit++] = '\0'; 252 /* 'fit' now the number of bytes AFTER adding in the NUL */ 253 } 254 } 255 /* 256 * always move in increments of 4 (including the trailing NUL) 257 */ 258 ab->varcursor += roundup((count+1), 4); 259 260} 261 262#define ATTR_PACK4(AB, V) \ 263 do { \ 264 if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 4) { \ 265 *(uint32_t *)AB.fixedcursor = V; \ 266 AB.fixedcursor += 4; \ 267 } \ 268 } while (0) 269 270#define ATTR_PACK8(AB, V) \ 271 do { \ 272 if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 8) { \ 273 *(uint64_t *)AB.fixedcursor = *(uint64_t *)&V; \ 274 AB.fixedcursor += 8; \ 275 } \ 276 } while (0) 277 278#define ATTR_PACK(b, v) attrlist_pack_fixed(b, &v, sizeof(v)) 279#define ATTR_PACK_CAST(b, t, v) \ 280 do { \ 281 t _f = (t)v; \ 282 ATTR_PACK(b, _f); \ 283 } while (0) 284 285#define ATTR_PACK_TIME(b, v, is64) \ 286 do { \ 287 if (is64) { \ 288 struct user64_timespec us = {v.tv_sec, v.tv_nsec}; \ 289 ATTR_PACK(&b, us); \ 290 } else { \ 291 struct user32_timespec us = {v.tv_sec, v.tv_nsec}; \ 292 ATTR_PACK(&b, us); \ 293 } \ 294 } while(0) 295 296 297/* 298 * Table-driven setup for all valid common/volume attributes. 299 */ 300struct getvolattrlist_attrtab { 301 attrgroup_t attr; 302 uint64_t bits; 303#define VFSATTR_BIT(b) (VFSATTR_ ## b) 304 ssize_t size; 305}; 306static struct getvolattrlist_attrtab getvolattrlist_common_tab[] = { 307 {ATTR_CMN_NAME, 0, sizeof(struct attrreference)}, 308 {ATTR_CMN_DEVID, 0, sizeof(dev_t)}, 309 {ATTR_CMN_FSID, 0, sizeof(fsid_t)}, 310 {ATTR_CMN_OBJTYPE, 0, sizeof(fsobj_type_t)}, 311 {ATTR_CMN_OBJTAG, 0, sizeof(fsobj_tag_t)}, 312 {ATTR_CMN_OBJID, 0, sizeof(fsobj_id_t)}, 313 {ATTR_CMN_OBJPERMANENTID, 0, sizeof(fsobj_id_t)}, 314 {ATTR_CMN_PAROBJID, 0, sizeof(fsobj_id_t)}, 315 {ATTR_CMN_SCRIPT, 0, sizeof(text_encoding_t)}, 316 {ATTR_CMN_CRTIME, VFSATTR_BIT(f_create_time), ATTR_TIME_SIZE}, 317 {ATTR_CMN_MODTIME, VFSATTR_BIT(f_modify_time), ATTR_TIME_SIZE}, 318 {ATTR_CMN_CHGTIME, VFSATTR_BIT(f_modify_time), ATTR_TIME_SIZE}, 319 {ATTR_CMN_ACCTIME, VFSATTR_BIT(f_access_time), ATTR_TIME_SIZE}, 320 {ATTR_CMN_BKUPTIME, VFSATTR_BIT(f_backup_time), ATTR_TIME_SIZE}, 321 {ATTR_CMN_FNDRINFO, 0, 32}, 322 {ATTR_CMN_OWNERID, 0, sizeof(uid_t)}, 323 {ATTR_CMN_GRPID, 0, sizeof(gid_t)}, 324 {ATTR_CMN_ACCESSMASK, 0, sizeof(uint32_t)}, 325 {ATTR_CMN_FLAGS, 0, sizeof(uint32_t)}, 326 {ATTR_CMN_USERACCESS, 0, sizeof(uint32_t)}, 327 {ATTR_CMN_EXTENDED_SECURITY, 0, sizeof(struct attrreference)}, 328 {ATTR_CMN_UUID, 0, sizeof(guid_t)}, 329 {ATTR_CMN_GRPUUID, 0, sizeof(guid_t)}, 330 {ATTR_CMN_FILEID, 0, sizeof(uint64_t)}, 331 {ATTR_CMN_PARENTID, 0, sizeof(uint64_t)}, 332 {ATTR_CMN_RETURNED_ATTRS, 0, sizeof(attribute_set_t)}, 333 {ATTR_CMN_ERROR, 0, sizeof(uint32_t)}, 334 {0, 0, 0} 335}; 336#define ATTR_CMN_VOL_INVALID \ 337 (ATTR_CMN_EXTENDED_SECURITY | ATTR_CMN_UUID | ATTR_CMN_GRPUUID | \ 338 ATTR_CMN_FILEID | ATTR_CMN_PARENTID) 339 340static struct getvolattrlist_attrtab getvolattrlist_vol_tab[] = { 341 {ATTR_VOL_FSTYPE, 0, sizeof(uint32_t)}, 342 {ATTR_VOL_SIGNATURE, VFSATTR_BIT(f_signature), sizeof(uint32_t)}, 343 {ATTR_VOL_SIZE, VFSATTR_BIT(f_blocks), sizeof(off_t)}, 344 {ATTR_VOL_SPACEFREE, VFSATTR_BIT(f_bfree) | VFSATTR_BIT(f_bsize), sizeof(off_t)}, 345 {ATTR_VOL_SPACEAVAIL, VFSATTR_BIT(f_bavail) | VFSATTR_BIT(f_bsize), sizeof(off_t)}, 346 {ATTR_VOL_MINALLOCATION, VFSATTR_BIT(f_bsize), sizeof(off_t)}, 347 {ATTR_VOL_ALLOCATIONCLUMP, VFSATTR_BIT(f_bsize), sizeof(off_t)}, 348 {ATTR_VOL_IOBLOCKSIZE, VFSATTR_BIT(f_iosize), sizeof(uint32_t)}, 349 {ATTR_VOL_OBJCOUNT, VFSATTR_BIT(f_objcount), sizeof(uint32_t)}, 350 {ATTR_VOL_FILECOUNT, VFSATTR_BIT(f_filecount), sizeof(uint32_t)}, 351 {ATTR_VOL_DIRCOUNT, VFSATTR_BIT(f_dircount), sizeof(uint32_t)}, 352 {ATTR_VOL_MAXOBJCOUNT, VFSATTR_BIT(f_maxobjcount), sizeof(uint32_t)}, 353 {ATTR_VOL_MOUNTPOINT, 0, sizeof(struct attrreference)}, 354 {ATTR_VOL_NAME, VFSATTR_BIT(f_vol_name), sizeof(struct attrreference)}, 355 {ATTR_VOL_MOUNTFLAGS, 0, sizeof(uint32_t)}, 356 {ATTR_VOL_MOUNTEDDEVICE, 0, sizeof(struct attrreference)}, 357 {ATTR_VOL_ENCODINGSUSED, 0, sizeof(uint64_t)}, 358 {ATTR_VOL_CAPABILITIES, VFSATTR_BIT(f_capabilities), sizeof(vol_capabilities_attr_t)}, 359 {ATTR_VOL_UUID, VFSATTR_BIT(f_uuid), sizeof(uuid_t)}, 360 {ATTR_VOL_ATTRIBUTES, VFSATTR_BIT(f_attributes), sizeof(vol_attributes_attr_t)}, 361 {ATTR_VOL_INFO, 0, 0}, 362 {0, 0, 0} 363}; 364 365static int 366getvolattrlist_parsetab(struct getvolattrlist_attrtab *tab, attrgroup_t attrs, struct vfs_attr *vsp, 367 ssize_t *sizep, int is_64bit) 368{ 369 attrgroup_t recognised; 370 371 recognised = 0; 372 do { 373 /* is this attribute set? */ 374 if (tab->attr & attrs) { 375 recognised |= tab->attr; 376 vsp->f_active |= tab->bits; 377 if (tab->size == ATTR_TIME_SIZE) { 378 if (is_64bit) { 379 *sizep += sizeof(struct user64_timespec); 380 } else { 381 *sizep += sizeof(struct user32_timespec); 382 } 383 } else { 384 *sizep += tab->size; 385 } 386 } 387 } while ((++tab)->attr != 0); 388 389 /* check to make sure that we recognised all of the passed-in attributes */ 390 if (attrs & ~recognised) 391 return(EINVAL); 392 return(0); 393} 394 395/* 396 * Given the attributes listed in alp, configure vap to request 397 * the data from a filesystem. 398 */ 399static int 400getvolattrlist_setupvfsattr(struct attrlist *alp, struct vfs_attr *vsp, ssize_t *sizep, int is_64bit) 401{ 402 int error; 403 404 /* 405 * Parse the above tables. 406 */ 407 *sizep = sizeof(uint32_t); /* length count */ 408 if (alp->commonattr) { 409 if ((alp->commonattr & ATTR_CMN_VOL_INVALID) && 410 (alp->commonattr & ATTR_CMN_RETURNED_ATTRS) == 0) { 411 return (EINVAL); 412 } 413 if ((error = getvolattrlist_parsetab(getvolattrlist_common_tab, 414 alp->commonattr, vsp, sizep, 415 is_64bit)) != 0) { 416 return(error); 417 } 418 } 419 if (alp->volattr && 420 (error = getvolattrlist_parsetab(getvolattrlist_vol_tab, alp->volattr, vsp, sizep, is_64bit)) != 0) 421 return(error); 422 423 return(0); 424} 425 426/* 427 * Given the attributes listed in asp and those supported 428 * in the vsp, fixup the asp attributes to reflect any 429 * missing attributes from the file system 430 */ 431static void 432getvolattrlist_fixupattrs(attribute_set_t *asp, struct vfs_attr *vsp) 433{ 434 struct getvolattrlist_attrtab *tab; 435 436 if (asp->commonattr) { 437 tab = getvolattrlist_common_tab; 438 do { 439 if ((tab->attr & asp->commonattr) && 440 (tab->bits != 0) && 441 ((tab->bits & vsp->f_supported) == 0)) { 442 asp->commonattr &= ~tab->attr; 443 } 444 } while ((++tab)->attr != 0); 445 } 446 if (asp->volattr) { 447 tab = getvolattrlist_vol_tab; 448 do { 449 if ((tab->attr & asp->volattr) && 450 (tab->bits != 0) && 451 ((tab->bits & vsp->f_supported) == 0)) { 452 asp->volattr &= ~tab->attr; 453 } 454 } while ((++tab)->attr != 0); 455 } 456} 457 458/* 459 * Table-driven setup for all valid common/dir/file/fork attributes against files. 460 */ 461struct getattrlist_attrtab { 462 attrgroup_t attr; 463 uint64_t bits; 464#define VATTR_BIT(b) (VNODE_ATTR_ ## b) 465 ssize_t size; 466 kauth_action_t action; 467}; 468 469/* 470 * A zero after the ATTR_ bit indicates that we don't expect the underlying FS to report back with this 471 * information, and we will synthesize it at the VFS level. 472 */ 473static struct getattrlist_attrtab getattrlist_common_tab[] = { 474 {ATTR_CMN_NAME, VATTR_BIT(va_name), sizeof(struct attrreference), KAUTH_VNODE_READ_ATTRIBUTES}, 475 {ATTR_CMN_DEVID, 0, sizeof(dev_t), KAUTH_VNODE_READ_ATTRIBUTES}, 476 {ATTR_CMN_FSID, VATTR_BIT(va_fsid), sizeof(fsid_t), KAUTH_VNODE_READ_ATTRIBUTES}, 477 {ATTR_CMN_OBJTYPE, 0, sizeof(fsobj_type_t), KAUTH_VNODE_READ_ATTRIBUTES}, 478 {ATTR_CMN_OBJTAG, 0, sizeof(fsobj_tag_t), KAUTH_VNODE_READ_ATTRIBUTES}, 479 {ATTR_CMN_OBJID, VATTR_BIT(va_fileid) | VATTR_BIT(va_linkid), sizeof(fsobj_id_t), KAUTH_VNODE_READ_ATTRIBUTES}, 480 {ATTR_CMN_OBJPERMANENTID, VATTR_BIT(va_fileid) | VATTR_BIT(va_linkid), sizeof(fsobj_id_t), KAUTH_VNODE_READ_ATTRIBUTES}, 481 {ATTR_CMN_PAROBJID, VATTR_BIT(va_parentid), sizeof(fsobj_id_t), KAUTH_VNODE_READ_ATTRIBUTES}, 482 {ATTR_CMN_SCRIPT, VATTR_BIT(va_encoding), sizeof(text_encoding_t), KAUTH_VNODE_READ_ATTRIBUTES}, 483 {ATTR_CMN_CRTIME, VATTR_BIT(va_create_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES}, 484 {ATTR_CMN_MODTIME, VATTR_BIT(va_modify_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES}, 485 {ATTR_CMN_CHGTIME, VATTR_BIT(va_change_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES}, 486 {ATTR_CMN_ACCTIME, VATTR_BIT(va_access_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES}, 487 {ATTR_CMN_BKUPTIME, VATTR_BIT(va_backup_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES}, 488 {ATTR_CMN_FNDRINFO, 0, 32, KAUTH_VNODE_READ_ATTRIBUTES}, 489 {ATTR_CMN_OWNERID, VATTR_BIT(va_uid), sizeof(uid_t), KAUTH_VNODE_READ_ATTRIBUTES}, 490 {ATTR_CMN_GRPID, VATTR_BIT(va_gid), sizeof(gid_t), KAUTH_VNODE_READ_ATTRIBUTES}, 491 {ATTR_CMN_ACCESSMASK, VATTR_BIT(va_mode), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES}, 492 {ATTR_CMN_FLAGS, VATTR_BIT(va_flags), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES}, 493 {ATTR_CMN_USERACCESS, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES}, 494 {ATTR_CMN_EXTENDED_SECURITY, VATTR_BIT(va_acl), sizeof(struct attrreference), KAUTH_VNODE_READ_SECURITY}, 495 {ATTR_CMN_UUID, VATTR_BIT(va_uuuid), sizeof(guid_t), KAUTH_VNODE_READ_ATTRIBUTES}, 496 {ATTR_CMN_GRPUUID, VATTR_BIT(va_guuid), sizeof(guid_t), KAUTH_VNODE_READ_ATTRIBUTES}, 497 {ATTR_CMN_FILEID, VATTR_BIT(va_fileid), sizeof(uint64_t), KAUTH_VNODE_READ_ATTRIBUTES}, 498 {ATTR_CMN_PARENTID, VATTR_BIT(va_parentid), sizeof(uint64_t), KAUTH_VNODE_READ_ATTRIBUTES}, 499 {ATTR_CMN_FULLPATH, 0, sizeof(struct attrreference), KAUTH_VNODE_READ_ATTRIBUTES}, 500 {ATTR_CMN_ADDEDTIME, VATTR_BIT(va_addedtime), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES}, 501 {ATTR_CMN_RETURNED_ATTRS, 0, sizeof(attribute_set_t), 0}, 502 {ATTR_CMN_ERROR, 0, sizeof(uint32_t), 0}, 503 {0, 0, 0, 0} 504}; 505 506static struct getattrlist_attrtab getattrlist_common_tab_extended[] = { 507 {ATTR_CMN_NAME, VATTR_BIT(va_name), sizeof(struct attrreference), KAUTH_VNODE_READ_ATTRIBUTES}, 508 {ATTR_CMN_DEVID, 0, sizeof(dev_t), KAUTH_VNODE_READ_ATTRIBUTES}, 509 {ATTR_CMN_FSID, VATTR_BIT(va_fsid), sizeof(fsid_t), KAUTH_VNODE_READ_ATTRIBUTES}, 510 {ATTR_CMN_OBJTYPE, 0, sizeof(fsobj_type_t), KAUTH_VNODE_READ_ATTRIBUTES}, 511 {ATTR_CMN_OBJTAG, 0, sizeof(fsobj_tag_t), KAUTH_VNODE_READ_ATTRIBUTES}, 512 {ATTR_CMN_OBJID, VATTR_BIT(va_fileid) | VATTR_BIT(va_linkid), sizeof(fsobj_id_t), KAUTH_VNODE_READ_ATTRIBUTES}, 513 {ATTR_CMN_OBJPERMANENTID, VATTR_BIT(va_fileid) | VATTR_BIT(va_linkid), sizeof(fsobj_id_t), KAUTH_VNODE_READ_ATTRIBUTES}, 514 {ATTR_CMN_PAROBJID, VATTR_BIT(va_parentid), sizeof(fsobj_id_t), KAUTH_VNODE_READ_ATTRIBUTES}, 515 {ATTR_CMN_SCRIPT, VATTR_BIT(va_encoding), sizeof(text_encoding_t), KAUTH_VNODE_READ_ATTRIBUTES}, 516 {ATTR_CMN_CRTIME, VATTR_BIT(va_create_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES}, 517 {ATTR_CMN_MODTIME, VATTR_BIT(va_modify_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES}, 518 {ATTR_CMN_CHGTIME, VATTR_BIT(va_change_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES}, 519 {ATTR_CMN_ACCTIME, VATTR_BIT(va_access_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES}, 520 {ATTR_CMN_BKUPTIME, VATTR_BIT(va_backup_time), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES}, 521 {ATTR_CMN_FNDRINFO, 0, 32, KAUTH_VNODE_READ_ATTRIBUTES}, 522 {ATTR_CMN_OWNERID, VATTR_BIT(va_uid), sizeof(uid_t), KAUTH_VNODE_READ_ATTRIBUTES}, 523 {ATTR_CMN_GRPID, VATTR_BIT(va_gid), sizeof(gid_t), KAUTH_VNODE_READ_ATTRIBUTES}, 524 {ATTR_CMN_ACCESSMASK, VATTR_BIT(va_mode), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES}, 525 {ATTR_CMN_FLAGS, VATTR_BIT(va_flags), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES}, 526 {ATTR_CMN_GEN_COUNT, VATTR_BIT(va_gen), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES}, 527 {ATTR_CMN_DOCUMENT_ID, VATTR_BIT(va_document_id), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES}, 528 {ATTR_CMN_USERACCESS, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES}, 529 {ATTR_CMN_EXTENDED_SECURITY, VATTR_BIT(va_acl), sizeof(struct attrreference), KAUTH_VNODE_READ_SECURITY}, 530 {ATTR_CMN_UUID, VATTR_BIT(va_uuuid), sizeof(guid_t), KAUTH_VNODE_READ_ATTRIBUTES}, 531 {ATTR_CMN_GRPUUID, VATTR_BIT(va_guuid), sizeof(guid_t), KAUTH_VNODE_READ_ATTRIBUTES}, 532 {ATTR_CMN_FILEID, VATTR_BIT(va_fileid), sizeof(uint64_t), KAUTH_VNODE_READ_ATTRIBUTES}, 533 {ATTR_CMN_PARENTID, VATTR_BIT(va_parentid), sizeof(uint64_t), KAUTH_VNODE_READ_ATTRIBUTES}, 534 {ATTR_CMN_FULLPATH, 0, sizeof(struct attrreference), KAUTH_VNODE_READ_ATTRIBUTES}, 535 {ATTR_CMN_ADDEDTIME, VATTR_BIT(va_addedtime), ATTR_TIME_SIZE, KAUTH_VNODE_READ_ATTRIBUTES}, 536 {ATTR_CMN_RETURNED_ATTRS, 0, sizeof(attribute_set_t), 0}, 537 {ATTR_CMN_ERROR, 0, sizeof(uint32_t), 0}, 538 {0, 0, 0, 0} 539}; 540 541static struct getattrlist_attrtab getattrlist_dir_tab[] = { 542 {ATTR_DIR_LINKCOUNT, VATTR_BIT(va_dirlinkcount), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES}, 543 {ATTR_DIR_ENTRYCOUNT, VATTR_BIT(va_nchildren), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES}, 544 {ATTR_DIR_MOUNTSTATUS, 0, sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES}, 545 {0, 0, 0, 0} 546}; 547static struct getattrlist_attrtab getattrlist_file_tab[] = { 548 {ATTR_FILE_LINKCOUNT, VATTR_BIT(va_nlink), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES}, 549 {ATTR_FILE_TOTALSIZE, VATTR_BIT(va_total_size), sizeof(off_t), KAUTH_VNODE_READ_ATTRIBUTES}, 550 {ATTR_FILE_ALLOCSIZE, VATTR_BIT(va_total_alloc) | VATTR_BIT(va_total_size), sizeof(off_t), KAUTH_VNODE_READ_ATTRIBUTES}, 551 {ATTR_FILE_IOBLOCKSIZE, VATTR_BIT(va_iosize), sizeof(uint32_t), KAUTH_VNODE_READ_ATTRIBUTES}, 552 {ATTR_FILE_DEVTYPE, VATTR_BIT(va_rdev), sizeof(dev_t), KAUTH_VNODE_READ_ATTRIBUTES}, 553 {ATTR_FILE_DATALENGTH, VATTR_BIT(va_total_size) | VATTR_BIT(va_data_size), sizeof(off_t), KAUTH_VNODE_READ_ATTRIBUTES}, 554 {ATTR_FILE_DATAALLOCSIZE, VATTR_BIT(va_total_alloc)| VATTR_BIT(va_data_alloc), sizeof(off_t), KAUTH_VNODE_READ_ATTRIBUTES}, 555 {ATTR_FILE_RSRCLENGTH, 0, sizeof(off_t), KAUTH_VNODE_READ_ATTRIBUTES}, 556 {ATTR_FILE_RSRCALLOCSIZE, 0, sizeof(off_t), KAUTH_VNODE_READ_ATTRIBUTES}, 557 {0, 0, 0, 0} 558}; 559 560/* 561 * The following are attributes that VFS can derive. 562 * 563 * A majority of them are the same attributes that are required for stat(2) and statfs(2). 564 */ 565#define VFS_DFLT_ATTR_VOL (ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | \ 566 ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \ 567 ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \ 568 ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \ 569 ATTR_VOL_MOUNTPOINT | ATTR_VOL_MOUNTFLAGS | \ 570 ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_CAPABILITIES | \ 571 ATTR_VOL_ATTRIBUTES | ATTR_VOL_ENCODINGSUSED) 572 573#define VFS_DFLT_ATTR_CMN (ATTR_CMN_NAME | ATTR_CMN_DEVID | \ 574 ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \ 575 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | \ 576 ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | \ 577 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \ 578 ATTR_CMN_FNDRINFO | \ 579 ATTR_CMN_OWNERID | ATTR_CMN_GRPID | \ 580 ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS | \ 581 ATTR_CMN_USERACCESS | ATTR_CMN_FILEID | \ 582 ATTR_CMN_PARENTID | ATTR_CMN_RETURNED_ATTRS | \ 583 ATTR_CMN_DOCUMENT_ID | ATTR_CMN_GEN_COUNT) 584 585#define VFS_DFLT_ATTR_CMN_EXT (ATTR_CMN_EXT_GEN_COUNT | ATTR_CMN_EXT_DOCUMENT_ID) 586 587#define VFS_DFLT_ATTR_DIR (ATTR_DIR_LINKCOUNT | ATTR_DIR_MOUNTSTATUS) 588 589#define VFS_DFLT_ATTR_FILE (ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | \ 590 ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \ 591 ATTR_FILE_DEVTYPE | ATTR_FILE_DATALENGTH | \ 592 ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_RSRCLENGTH | \ 593 ATTR_FILE_RSRCALLOCSIZE) 594 595static int 596getattrlist_parsetab(struct getattrlist_attrtab *tab, attrgroup_t attrs, struct vnode_attr *vap, 597 ssize_t *sizep, kauth_action_t *actionp, int is_64bit) 598{ 599 attrgroup_t recognised; 600 601 recognised = 0; 602 do { 603 /* is this attribute set? */ 604 if (tab->attr & attrs) { 605 recognised |= tab->attr; 606 vap->va_active |= tab->bits; 607 if (tab->size == ATTR_TIME_SIZE) { 608 if (is_64bit) { 609 *sizep += sizeof(struct user64_timespec); 610 } else { 611 *sizep += sizeof(struct user32_timespec); 612 } 613 } else { 614 *sizep += tab->size; 615 } 616 *actionp |= tab->action; 617 if (attrs == recognised) 618 break; /* all done, get out */ 619 } 620 } while ((++tab)->attr != 0); 621 622 /* check to make sure that we recognised all of the passed-in attributes */ 623 if (attrs & ~recognised) 624 return(EINVAL); 625 return(0); 626} 627 628/* 629 * Given the attributes listed in alp, configure vap to request 630 * the data from a filesystem. 631 */ 632static int 633getattrlist_setupvattr(struct attrlist *alp, int attr_cmn_extended, struct vnode_attr *vap, ssize_t *sizep, kauth_action_t *actionp, int is_64bit, int isdir) 634{ 635 int error; 636 struct getattrlist_attrtab *cmn_tab; 637 638 639 if (attr_cmn_extended) 640 cmn_tab = getattrlist_common_tab_extended; 641 else 642 cmn_tab = getattrlist_common_tab; 643 /* 644 * Parse the above tables. 645 */ 646 *sizep = sizeof(uint32_t); /* length count */ 647 *actionp = 0; 648 if (alp->commonattr && 649 (error = getattrlist_parsetab(cmn_tab, alp->commonattr, vap, sizep, actionp, is_64bit)) != 0) 650 return(error); 651 if (isdir && alp->dirattr && 652 (error = getattrlist_parsetab(getattrlist_dir_tab, alp->dirattr, vap, sizep, actionp, is_64bit)) != 0) 653 return(error); 654 if (!isdir && alp->fileattr && 655 (error = getattrlist_parsetab(getattrlist_file_tab, alp->fileattr, vap, sizep, actionp, is_64bit)) != 0) 656 return(error); 657 658 return(0); 659} 660 661/* 662 * Given the attributes listed in asp and those supported 663 * in the vap, fixup the asp attributes to reflect any 664 * missing attributes from the file system 665 */ 666static void 667getattrlist_fixupattrs(attribute_set_t *asp, struct vnode_attr *vap) 668{ 669 struct getattrlist_attrtab *tab; 670 671 if (asp->commonattr) { 672 tab = getattrlist_common_tab; 673 do { 674 /* 675 * This if() statement is slightly confusing. We're trying to 676 * iterate through all of the bits listed in the array 677 * getattr_common_tab, and see if the filesystem was expected 678 * to support it, and whether or not we need to do anything about this. 679 * 680 * This array is full of structs that have 4 fields (attr, bits, size, action). 681 * The first is used to store the ATTR_CMN_* bit that was being requested 682 * from userland. The second stores the VATTR_BIT corresponding to the field 683 * filled in vnode_attr struct. If it is 0, then we don't typically expect 684 * the filesystem to fill in this field. The third is the size of the field, 685 * and the fourth is the type of kauth actions needed. 686 * 687 * So, for all of the ATTR_CMN bits listed in this array, we iterate through 688 * them, and check to see if it was both passed down to the filesystem via the 689 * va_active bitfield, and whether or not we expect it to be emitted from 690 * the filesystem. If it wasn't supported, then we un-twiddle the bit and move 691 * on. This is done so that we can uncheck those bits and re-request 692 * a vnode_getattr from the filesystem again. 693 */ 694 if ((tab->attr & asp->commonattr) && 695 (tab->bits & vap->va_active) && 696 (tab->bits & vap->va_supported) == 0) { 697 asp->commonattr &= ~tab->attr; 698 } 699 } while ((++tab)->attr != 0); 700 } 701 if (asp->dirattr) { 702 tab = getattrlist_dir_tab; 703 do { 704 if ((tab->attr & asp->dirattr) && 705 (tab->bits & vap->va_active) && 706 (vap->va_supported & tab->bits) == 0) { 707 asp->dirattr &= ~tab->attr; 708 } 709 } while ((++tab)->attr != 0); 710 } 711 if (asp->fileattr) { 712 tab = getattrlist_file_tab; 713 do { 714 if ((tab->attr & asp->fileattr) && 715 (tab->bits & vap->va_active) && 716 (vap->va_supported & tab->bits) == 0) { 717 asp->fileattr &= ~tab->attr; 718 } 719 } while ((++tab)->attr != 0); 720 } 721} 722 723static int 724setattrlist_setfinderinfo(vnode_t vp, char *fndrinfo, struct vfs_context *ctx) 725{ 726 uio_t auio; 727 char uio_buf[UIO_SIZEOF(1)]; 728 int error; 729 730 if ((auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_WRITE, uio_buf, sizeof(uio_buf))) == NULL) { 731 error = ENOMEM; 732 } else { 733 uio_addiov(auio, CAST_USER_ADDR_T(fndrinfo), 32); 734 error = vn_setxattr(vp, XATTR_FINDERINFO_NAME, auio, XATTR_NOSECURITY, ctx); 735 uio_free(auio); 736 } 737 738#if CONFIG_FSE 739 if (error == 0 && need_fsevent(FSE_FINDER_INFO_CHANGED, vp)) { 740 add_fsevent(FSE_FINDER_INFO_CHANGED, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE); 741 } 742#endif 743 return (error); 744} 745 746 747/* 748 * Find something resembling a terminal component name in the mountedonname for vp 749 * 750 */ 751static void 752getattrlist_findnamecomp(const char *mn, const char **np, ssize_t *nl) 753{ 754 int counting; 755 const char *cp; 756 757 /* 758 * We're looking for the last sequence of non / characters, but 759 * not including any trailing / characters. 760 */ 761 *np = NULL; 762 *nl = 0; 763 counting = 0; 764 for (cp = mn; *cp != 0; cp++) { 765 if (!counting) { 766 /* start of run of chars */ 767 if (*cp != '/') { 768 *np = cp; 769 counting = 1; 770 } 771 } else { 772 /* end of run of chars */ 773 if (*cp == '/') { 774 *nl = cp - *np; 775 counting = 0; 776 } 777 } 778 } 779 /* need to close run? */ 780 if (counting) 781 *nl = cp - *np; 782} 783 784 785static int 786getvolattrlist(vnode_t vp, struct getattrlist_args *uap, struct attrlist *alp, 787 vfs_context_t ctx, int is_64bit) 788{ 789 struct vfs_attr vs; 790 struct vnode_attr va; 791 struct _attrlist_buf ab; 792 int error; 793 ssize_t fixedsize, varsize; 794 const char *cnp = NULL; /* protected by ATTR_CMN_NAME */ 795 ssize_t cnl = 0; /* protected by ATTR_CMN_NAME */ 796 int release_str = 0; 797 mount_t mnt; 798 int return_valid; 799 int pack_invalid; 800 801 ab.base = NULL; 802 VATTR_INIT(&va); 803 VFSATTR_INIT(&vs); 804 vs.f_vol_name = NULL; 805 mnt = vp->v_mount; 806 807 /* Check for special packing semantics */ 808 return_valid = (alp->commonattr & ATTR_CMN_RETURNED_ATTRS); 809 pack_invalid = (uap->options & FSOPT_PACK_INVAL_ATTRS); 810 if (pack_invalid) { 811 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */ 812 if (!return_valid) { 813 error = EINVAL; 814 goto out; 815 } 816 /* Keep invalid attrs from being uninitialized */ 817 bzero(&vs, sizeof (vs)); 818 /* Generate a valid mask for post processing */ 819 bcopy(&alp->commonattr, &ab.valid, sizeof (attribute_set_t)); 820 } 821 822 /* 823 * For now, the vnode must be the root of its filesystem. 824 * To relax this, we need to be able to find the root vnode of a filesystem 825 * from any vnode in the filesystem. 826 */ 827 if (!vnode_isvroot(vp)) { 828 error = EINVAL; 829 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: volume attributes requested but not the root of a filesystem"); 830 goto out; 831 } 832 833 /* 834 * Set up the vfs_attr structure and call the filesystem. 835 */ 836 if ((error = getvolattrlist_setupvfsattr(alp, &vs, &fixedsize, is_64bit)) != 0) { 837 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: setup for request failed"); 838 goto out; 839 } 840 if (vs.f_active != 0) { 841 /* If we're going to ask for f_vol_name, allocate a buffer to point it at */ 842 if (VFSATTR_IS_ACTIVE(&vs, f_vol_name)) { 843 vs.f_vol_name = (char *) kalloc(MAXPATHLEN); 844 if (vs.f_vol_name == NULL) { 845 error = ENOMEM; 846 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: could not allocate f_vol_name buffer"); 847 goto out; 848 } 849 } 850 851#if CONFIG_MACF 852 error = mac_mount_check_getattr(ctx, mnt, &vs); 853 if (error != 0) 854 goto out; 855#endif 856 VFS_DEBUG(ctx, vp, "ATTRLIST - calling to get %016llx with supported %016llx", vs.f_active, vs.f_supported); 857 if ((error = vfs_getattr(mnt, &vs, ctx)) != 0) { 858 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: filesystem returned %d", error); 859 goto out; 860 } 861 862 /* 863 * Did we ask for something the filesystem doesn't support? 864 */ 865 if (!VFSATTR_ALL_SUPPORTED(&vs)) { 866 /* default value for volume subtype */ 867 if (VFSATTR_IS_ACTIVE(&vs, f_fssubtype) 868 && !VFSATTR_IS_SUPPORTED(&vs, f_fssubtype)) 869 VFSATTR_RETURN(&vs, f_fssubtype, 0); 870 871 /* 872 * If the file system didn't supply f_signature, then 873 * default it to 'BD', which is the generic signature 874 * that most Carbon file systems should return. 875 */ 876 if (VFSATTR_IS_ACTIVE(&vs, f_signature) 877 && !VFSATTR_IS_SUPPORTED(&vs, f_signature)) 878 VFSATTR_RETURN(&vs, f_signature, 0x4244); 879 880 /* default for block size */ 881 if (VFSATTR_IS_ACTIVE(&vs, f_bsize) 882 && !VFSATTR_IS_SUPPORTED(&vs, f_bsize)) 883 VFSATTR_RETURN(&vs, f_bsize, mnt->mnt_devblocksize); 884 885 /* default value for volume f_attributes */ 886 if (VFSATTR_IS_ACTIVE(&vs, f_attributes) 887 && !VFSATTR_IS_SUPPORTED(&vs, f_attributes)) { 888 vol_attributes_attr_t *attrp = &vs.f_attributes; 889 890 attrp->validattr.commonattr = VFS_DFLT_ATTR_CMN; 891 attrp->validattr.volattr = VFS_DFLT_ATTR_VOL; 892 attrp->validattr.dirattr = VFS_DFLT_ATTR_DIR; 893 attrp->validattr.fileattr = VFS_DFLT_ATTR_FILE; 894 attrp->validattr.forkattr = 0; 895 896 attrp->nativeattr.commonattr = 0; 897 attrp->nativeattr.volattr = 0; 898 attrp->nativeattr.dirattr = 0; 899 attrp->nativeattr.fileattr = 0; 900 attrp->nativeattr.forkattr = 0; 901 VFSATTR_SET_SUPPORTED(&vs, f_attributes); 902 } 903 904 /* default value for volume f_capabilities */ 905 if (VFSATTR_IS_ACTIVE(&vs, f_capabilities)) { 906 /* getattrlist is always supported now. */ 907 if (!VFSATTR_IS_SUPPORTED(&vs, f_capabilities)) { 908 vs.f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] = 0; 909 vs.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] = VOL_CAP_INT_ATTRLIST; 910 vs.f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED1] = 0; 911 vs.f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED2] = 0; 912 913 vs.f_capabilities.valid[VOL_CAPABILITIES_FORMAT] = 0; 914 vs.f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] = VOL_CAP_INT_ATTRLIST; 915 vs.f_capabilities.valid[VOL_CAPABILITIES_RESERVED1] = 0; 916 vs.f_capabilities.valid[VOL_CAPABILITIES_RESERVED2] = 0; 917 VFSATTR_SET_SUPPORTED(&vs, f_capabilities); 918 } 919 else { 920 /* OR in VOL_CAP_INT_ATTRLIST if f_capabilities is supported */ 921 vs.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_ATTRLIST; 922 vs.f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_ATTRLIST; 923 } 924 } 925 926 /* check to see if our fixups were enough */ 927 if (!VFSATTR_ALL_SUPPORTED(&vs)) { 928 if (return_valid) { 929 if (pack_invalid) { 930 /* Fix up valid mask for post processing */ 931 getvolattrlist_fixupattrs(&ab.valid, &vs); 932 933 /* Force packing of everything asked for */ 934 vs.f_supported = vs.f_active; 935 } else { 936 /* Adjust the requested attributes */ 937 getvolattrlist_fixupattrs((attribute_set_t *)&alp->commonattr, &vs); 938 } 939 } else { 940 error = EINVAL; 941 goto out; 942 } 943 } 944 } 945 } 946 947 /* 948 * Some fields require data from the root vp 949 */ 950 if (alp->commonattr & (ATTR_CMN_OWNERID | ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS | ATTR_CMN_SCRIPT)) { 951 VATTR_WANTED(&va, va_uid); 952 VATTR_WANTED(&va, va_gid); 953 VATTR_WANTED(&va, va_mode); 954 VATTR_WANTED(&va, va_flags); 955 VATTR_WANTED(&va, va_encoding); 956 957 if ((error = vnode_getattr(vp, &va, ctx)) != 0) { 958 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: could not fetch attributes from root vnode", vp); 959 goto out; 960 } 961 962 if (VATTR_IS_ACTIVE(&va, va_encoding) && 963 !VATTR_IS_SUPPORTED(&va, va_encoding)) { 964 if (!return_valid || pack_invalid) 965 /* use kTextEncodingMacUnicode */ 966 VATTR_RETURN(&va, va_encoding, 0x7e); 967 else 968 /* don't use a default */ 969 alp->commonattr &= ~ATTR_CMN_SCRIPT; 970 } 971 } 972 973 /* 974 * Compute variable-size buffer requirements. 975 */ 976 varsize = 0; 977 if (alp->commonattr & ATTR_CMN_NAME) { 978 if (vp->v_mount->mnt_vfsstat.f_mntonname[1] == 0x00 && 979 vp->v_mount->mnt_vfsstat.f_mntonname[0] == '/') { 980 /* special case for boot volume. Use root name when it's 981 * available (which is the volume name) or just the mount on 982 * name of "/". we must do this for binary compatibility with 983 * pre Tiger code. returning nothing for the boot volume name 984 * breaks installers - 3961058 985 */ 986 cnp = vnode_getname(vp); 987 if (cnp == NULL) { 988 /* just use "/" as name */ 989 cnp = &vp->v_mount->mnt_vfsstat.f_mntonname[0]; 990 } 991 else { 992 release_str = 1; 993 } 994 cnl = strlen(cnp); 995 } 996 else { 997 getattrlist_findnamecomp(vp->v_mount->mnt_vfsstat.f_mntonname, &cnp, &cnl); 998 } 999 if (alp->commonattr & ATTR_CMN_NAME) 1000 varsize += roundup(cnl + 1, 4); 1001 } 1002 if (alp->volattr & ATTR_VOL_MOUNTPOINT) 1003 varsize += roundup(strlen(mnt->mnt_vfsstat.f_mntonname) + 1, 4); 1004 if (alp->volattr & ATTR_VOL_NAME) { 1005 vs.f_vol_name[MAXPATHLEN-1] = '\0'; /* Ensure nul-termination */ 1006 varsize += roundup(strlen(vs.f_vol_name) + 1, 4); 1007 } 1008 if (alp->volattr & ATTR_VOL_MOUNTEDDEVICE) 1009 varsize += roundup(strlen(mnt->mnt_vfsstat.f_mntfromname) + 1, 4); 1010 1011 /* 1012 * Allocate a target buffer for attribute results. 1013 * Note that since we won't ever copy out more than the caller requested, 1014 * we never need to allocate more than they offer. 1015 */ 1016 ab.allocated = ulmin(uap->bufferSize, fixedsize + varsize); 1017 if (ab.allocated > ATTR_MAX_BUFFER) { 1018 error = ENOMEM; 1019 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab.allocated, ATTR_MAX_BUFFER); 1020 goto out; 1021 } 1022 MALLOC(ab.base, char *, ab.allocated, M_TEMP, M_WAITOK); 1023 if (ab.base == NULL) { 1024 error = ENOMEM; 1025 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab.allocated); 1026 goto out; 1027 } 1028 1029 /* 1030 * Pack results into the destination buffer. 1031 */ 1032 ab.fixedcursor = ab.base + sizeof(uint32_t); 1033 if (return_valid) { 1034 ab.fixedcursor += sizeof (attribute_set_t); 1035 bzero(&ab.actual, sizeof (ab.actual)); 1036 } 1037 ab.varcursor = ab.base + fixedsize; 1038 ab.needed = fixedsize + varsize; 1039 1040 /* common attributes **************************************************/ 1041 if (alp->commonattr & ATTR_CMN_NAME) { 1042 attrlist_pack_string(&ab, cnp, cnl); 1043 ab.actual.commonattr |= ATTR_CMN_NAME; 1044 } 1045 if ((alp->commonattr & ATTR_CMN_ERROR) && 1046 (!return_valid || pack_invalid)) { 1047 ATTR_PACK4(ab, 0); 1048 ab.actual.commonattr |= ATTR_CMN_ERROR; 1049 } 1050 if (alp->commonattr & ATTR_CMN_DEVID) { 1051 ATTR_PACK4(ab, mnt->mnt_vfsstat.f_fsid.val[0]); 1052 ab.actual.commonattr |= ATTR_CMN_DEVID; 1053 } 1054 if (alp->commonattr & ATTR_CMN_FSID) { 1055 ATTR_PACK8(ab, mnt->mnt_vfsstat.f_fsid); 1056 ab.actual.commonattr |= ATTR_CMN_FSID; 1057 } 1058 if (alp->commonattr & ATTR_CMN_OBJTYPE) { 1059 if (!return_valid || pack_invalid) 1060 ATTR_PACK4(ab, 0); 1061 } 1062 if (alp->commonattr & ATTR_CMN_OBJTAG) { 1063 ATTR_PACK4(ab, vp->v_tag); 1064 ab.actual.commonattr |= ATTR_CMN_OBJTAG; 1065 } 1066 if (alp->commonattr & ATTR_CMN_OBJID) { 1067 if (!return_valid || pack_invalid) { 1068 fsobj_id_t f = {0, 0}; 1069 ATTR_PACK8(ab, f); 1070 } 1071 } 1072 if (alp->commonattr & ATTR_CMN_OBJPERMANENTID) { 1073 if (!return_valid || pack_invalid) { 1074 fsobj_id_t f = {0, 0}; 1075 ATTR_PACK8(ab, f); 1076 } 1077 } 1078 if (alp->commonattr & ATTR_CMN_PAROBJID) { 1079 if (!return_valid || pack_invalid) { 1080 fsobj_id_t f = {0, 0}; 1081 ATTR_PACK8(ab, f); 1082 } 1083 } 1084 /* note that this returns the encoding for the volume name, not the node name */ 1085 if (alp->commonattr & ATTR_CMN_SCRIPT) { 1086 ATTR_PACK4(ab, va.va_encoding); 1087 ab.actual.commonattr |= ATTR_CMN_SCRIPT; 1088 } 1089 if (alp->commonattr & ATTR_CMN_CRTIME) { 1090 ATTR_PACK_TIME(ab, vs.f_create_time, is_64bit); 1091 ab.actual.commonattr |= ATTR_CMN_CRTIME; 1092 } 1093 if (alp->commonattr & ATTR_CMN_MODTIME) { 1094 ATTR_PACK_TIME(ab, vs.f_modify_time, is_64bit); 1095 ab.actual.commonattr |= ATTR_CMN_MODTIME; 1096 } 1097 if (alp->commonattr & ATTR_CMN_CHGTIME) { 1098 if (!return_valid || pack_invalid) 1099 ATTR_PACK_TIME(ab, vs.f_modify_time, is_64bit); 1100 } 1101 if (alp->commonattr & ATTR_CMN_ACCTIME) { 1102 ATTR_PACK_TIME(ab, vs.f_access_time, is_64bit); 1103 ab.actual.commonattr |= ATTR_CMN_ACCTIME; 1104 } 1105 if (alp->commonattr & ATTR_CMN_BKUPTIME) { 1106 ATTR_PACK_TIME(ab, vs.f_backup_time, is_64bit); 1107 ab.actual.commonattr |= ATTR_CMN_BKUPTIME; 1108 } 1109 if (alp->commonattr & ATTR_CMN_FNDRINFO) { 1110 char f[32]; 1111 /* 1112 * This attribute isn't really Finder Info, at least for HFS. 1113 */ 1114 if (vp->v_tag == VT_HFS) { 1115 error = VNOP_IOCTL(vp, HFS_GET_BOOT_INFO, (caddr_t)&f, 0, ctx); 1116 if (error == 0) { 1117 attrlist_pack_fixed(&ab, f, sizeof(f)); 1118 ab.actual.commonattr |= ATTR_CMN_FNDRINFO; 1119 } else if (!return_valid) { 1120 goto out; 1121 } 1122 } else if (!return_valid || pack_invalid) { 1123 /* XXX we could at least pass out the volume UUID here */ 1124 bzero(&f, sizeof(f)); 1125 attrlist_pack_fixed(&ab, f, sizeof(f)); 1126 } 1127 } 1128 if (alp->commonattr & ATTR_CMN_OWNERID) { 1129 ATTR_PACK4(ab, va.va_uid); 1130 ab.actual.commonattr |= ATTR_CMN_OWNERID; 1131 } 1132 if (alp->commonattr & ATTR_CMN_GRPID) { 1133 ATTR_PACK4(ab, va.va_gid); 1134 ab.actual.commonattr |= ATTR_CMN_GRPID; 1135 } 1136 if (alp->commonattr & ATTR_CMN_ACCESSMASK) { 1137 ATTR_PACK_CAST(&ab, uint32_t, va.va_mode); 1138 ab.actual.commonattr |= ATTR_CMN_ACCESSMASK; 1139 } 1140 if (alp->commonattr & ATTR_CMN_FLAGS) { 1141 ATTR_PACK4(ab, va.va_flags); 1142 ab.actual.commonattr |= ATTR_CMN_FLAGS; 1143 } 1144 if (alp->commonattr & ATTR_CMN_USERACCESS) { /* XXX this is expensive and also duplicate work */ 1145 uint32_t perms = 0; 1146 if (vnode_isdir(vp)) { 1147 if (vnode_authorize(vp, NULL, 1148 KAUTH_VNODE_ACCESS | KAUTH_VNODE_ADD_FILE | KAUTH_VNODE_ADD_SUBDIRECTORY | KAUTH_VNODE_DELETE_CHILD, ctx) == 0) 1149 perms |= W_OK; 1150 if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_LIST_DIRECTORY, ctx) == 0) 1151 perms |= R_OK; 1152 if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_SEARCH, ctx) == 0) 1153 perms |= X_OK; 1154 } else { 1155 if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA, ctx) == 0) 1156 perms |= W_OK; 1157 if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_READ_DATA, ctx) == 0) 1158 perms |= R_OK; 1159 if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_EXECUTE, ctx) == 0) 1160 perms |= X_OK; 1161 } 1162#if CONFIG_MACF 1163 /* 1164 * Rather than MAC preceding DAC, in this case we want 1165 * the smallest set of permissions granted by both MAC & DAC 1166 * checks. We won't add back any permissions. 1167 */ 1168 if (perms & W_OK) 1169 if (mac_vnode_check_access(ctx, vp, W_OK) != 0) 1170 perms &= ~W_OK; 1171 if (perms & R_OK) 1172 if (mac_vnode_check_access(ctx, vp, R_OK) != 0) 1173 perms &= ~R_OK; 1174 if (perms & X_OK) 1175 if (mac_vnode_check_access(ctx, vp, X_OK) != 0) 1176 perms &= ~X_OK; 1177#endif /* MAC */ 1178 KAUTH_DEBUG("ATTRLIST - returning user access %x", perms); 1179 ATTR_PACK4(ab, perms); 1180 ab.actual.commonattr |= ATTR_CMN_USERACCESS; 1181 } 1182 /* 1183 * The following common volume attributes are only 1184 * packed when the pack_invalid mode is enabled. 1185 */ 1186 if (pack_invalid) { 1187 uint64_t fid = 0; 1188 1189 if (alp->commonattr & ATTR_CMN_EXTENDED_SECURITY) 1190 attrlist_pack_variable(&ab, NULL, 0); 1191 if (alp->commonattr & ATTR_CMN_UUID) 1192 ATTR_PACK(&ab, kauth_null_guid); 1193 if (alp->commonattr & ATTR_CMN_GRPUUID) 1194 ATTR_PACK(&ab, kauth_null_guid); 1195 if (alp->commonattr & ATTR_CMN_FILEID) 1196 ATTR_PACK8(ab, fid); 1197 if (alp->commonattr & ATTR_CMN_PARENTID) 1198 ATTR_PACK8(ab, fid); 1199 } 1200 1201 /* volume attributes **************************************************/ 1202 1203 if (alp->volattr & ATTR_VOL_FSTYPE) { 1204 ATTR_PACK_CAST(&ab, uint32_t, vfs_typenum(mnt)); 1205 ab.actual.volattr |= ATTR_VOL_FSTYPE; 1206 } 1207 if (alp->volattr & ATTR_VOL_SIGNATURE) { 1208 ATTR_PACK_CAST(&ab, uint32_t, vs.f_signature); 1209 ab.actual.volattr |= ATTR_VOL_SIGNATURE; 1210 } 1211 if (alp->volattr & ATTR_VOL_SIZE) { 1212 ATTR_PACK_CAST(&ab, off_t, vs.f_bsize * vs.f_blocks); 1213 ab.actual.volattr |= ATTR_VOL_SIZE; 1214 } 1215 if (alp->volattr & ATTR_VOL_SPACEFREE) { 1216 ATTR_PACK_CAST(&ab, off_t, vs.f_bsize * vs.f_bfree); 1217 ab.actual.volattr |= ATTR_VOL_SPACEFREE; 1218 } 1219 if (alp->volattr & ATTR_VOL_SPACEAVAIL) { 1220 ATTR_PACK_CAST(&ab, off_t, vs.f_bsize * vs.f_bavail); 1221 ab.actual.volattr |= ATTR_VOL_SPACEAVAIL; 1222 } 1223 if (alp->volattr & ATTR_VOL_MINALLOCATION) { 1224 ATTR_PACK_CAST(&ab, off_t, vs.f_bsize); 1225 ab.actual.volattr |= ATTR_VOL_MINALLOCATION; 1226 } 1227 if (alp->volattr & ATTR_VOL_ALLOCATIONCLUMP) { 1228 ATTR_PACK_CAST(&ab, off_t, vs.f_bsize); /* not strictly true */ 1229 ab.actual.volattr |= ATTR_VOL_ALLOCATIONCLUMP; 1230 } 1231 if (alp->volattr & ATTR_VOL_IOBLOCKSIZE) { 1232 ATTR_PACK_CAST(&ab, uint32_t, vs.f_iosize); 1233 ab.actual.volattr |= ATTR_VOL_IOBLOCKSIZE; 1234 } 1235 if (alp->volattr & ATTR_VOL_OBJCOUNT) { 1236 ATTR_PACK_CAST(&ab, uint32_t, vs.f_objcount); 1237 ab.actual.volattr |= ATTR_VOL_OBJCOUNT; 1238 } 1239 if (alp->volattr & ATTR_VOL_FILECOUNT) { 1240 ATTR_PACK_CAST(&ab, uint32_t, vs.f_filecount); 1241 ab.actual.volattr |= ATTR_VOL_FILECOUNT; 1242 } 1243 if (alp->volattr & ATTR_VOL_DIRCOUNT) { 1244 ATTR_PACK_CAST(&ab, uint32_t, vs.f_dircount); 1245 ab.actual.volattr |= ATTR_VOL_DIRCOUNT; 1246 } 1247 if (alp->volattr & ATTR_VOL_MAXOBJCOUNT) { 1248 ATTR_PACK_CAST(&ab, uint32_t, vs.f_maxobjcount); 1249 ab.actual.volattr |= ATTR_VOL_MAXOBJCOUNT; 1250 } 1251 if (alp->volattr & ATTR_VOL_MOUNTPOINT) { 1252 attrlist_pack_string(&ab, mnt->mnt_vfsstat.f_mntonname, 0); 1253 ab.actual.volattr |= ATTR_VOL_MOUNTPOINT; 1254 } 1255 if (alp->volattr & ATTR_VOL_NAME) { 1256 attrlist_pack_string(&ab, vs.f_vol_name, 0); 1257 ab.actual.volattr |= ATTR_VOL_NAME; 1258 } 1259 if (alp->volattr & ATTR_VOL_MOUNTFLAGS) { 1260 ATTR_PACK_CAST(&ab, uint32_t, mnt->mnt_flag); 1261 ab.actual.volattr |= ATTR_VOL_MOUNTFLAGS; 1262 } 1263 if (alp->volattr & ATTR_VOL_MOUNTEDDEVICE) { 1264 attrlist_pack_string(&ab, mnt->mnt_vfsstat.f_mntfromname, 0); 1265 ab.actual.volattr |= ATTR_VOL_MOUNTEDDEVICE; 1266 } 1267 if (alp->volattr & ATTR_VOL_ENCODINGSUSED) { 1268 if (!return_valid || pack_invalid) 1269 ATTR_PACK_CAST(&ab, uint64_t, ~0LL); /* return all encodings */ 1270 } 1271 if (alp->volattr & ATTR_VOL_CAPABILITIES) { 1272 /* fix up volume capabilities */ 1273 if (vfs_extendedsecurity(mnt)) { 1274 vs.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_EXTENDED_SECURITY; 1275 } else { 1276 vs.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] &= ~VOL_CAP_INT_EXTENDED_SECURITY; 1277 } 1278 vs.f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_EXTENDED_SECURITY; 1279 ATTR_PACK(&ab, vs.f_capabilities); 1280 ab.actual.volattr |= ATTR_VOL_CAPABILITIES; 1281 } 1282 if (alp->volattr & ATTR_VOL_UUID) { 1283 ATTR_PACK(&ab, vs.f_uuid); 1284 ab.actual.volattr |= ATTR_VOL_UUID; 1285 } 1286 if (alp->volattr & ATTR_VOL_ATTRIBUTES) { 1287 /* fix up volume attribute information */ 1288 1289 vs.f_attributes.validattr.commonattr |= VFS_DFLT_ATTR_CMN; 1290 vs.f_attributes.validattr.volattr |= VFS_DFLT_ATTR_VOL; 1291 vs.f_attributes.validattr.dirattr |= VFS_DFLT_ATTR_DIR; 1292 vs.f_attributes.validattr.fileattr |= VFS_DFLT_ATTR_FILE; 1293 1294 if (vfs_extendedsecurity(mnt)) { 1295 vs.f_attributes.validattr.commonattr |= (ATTR_CMN_EXTENDED_SECURITY | ATTR_CMN_UUID | ATTR_CMN_GRPUUID); 1296 } else { 1297 vs.f_attributes.validattr.commonattr &= ~(ATTR_CMN_EXTENDED_SECURITY | ATTR_CMN_UUID | ATTR_CMN_GRPUUID); 1298 vs.f_attributes.nativeattr.commonattr &= ~(ATTR_CMN_EXTENDED_SECURITY | ATTR_CMN_UUID | ATTR_CMN_GRPUUID); 1299 } 1300 ATTR_PACK(&ab, vs.f_attributes); 1301 ab.actual.volattr |= ATTR_VOL_ATTRIBUTES; 1302 } 1303 1304 /* diagnostic */ 1305 if (!return_valid && (ab.fixedcursor - ab.base) != fixedsize) 1306 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x", 1307 fixedsize, (long) (ab.fixedcursor - ab.base), alp->commonattr, alp->volattr); 1308 if (!return_valid && ab.varcursor != (ab.base + ab.needed)) 1309 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab.varcursor - ab.base), ab.needed); 1310 1311 /* 1312 * In the compatible case, we report the smaller of the required and returned sizes. 1313 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size 1314 * of the result buffer, even if we copied less out. The caller knows how big a buffer 1315 * they gave us, so they can always check for truncation themselves. 1316 */ 1317 *(uint32_t *)ab.base = (uap->options & FSOPT_REPORT_FULLSIZE) ? ab.needed : imin(ab.allocated, ab.needed); 1318 1319 /* Return attribute set output if requested. */ 1320 if (return_valid) { 1321 ab.actual.commonattr |= ATTR_CMN_RETURNED_ATTRS; 1322 if (pack_invalid) { 1323 /* Only report the attributes that are valid */ 1324 ab.actual.commonattr &= ab.valid.commonattr; 1325 ab.actual.volattr &= ab.valid.volattr; 1326 } 1327 bcopy(&ab.actual, ab.base + sizeof(uint32_t), sizeof (ab.actual)); 1328 } 1329 error = copyout(ab.base, uap->attributeBuffer, ab.allocated); 1330 1331out: 1332 if (vs.f_vol_name != NULL) 1333 kfree(vs.f_vol_name, MAXPATHLEN); 1334 if (release_str) { 1335 vnode_putname(cnp); 1336 } 1337 if (ab.base != NULL) 1338 FREE(ab.base, M_TEMP); 1339 VFS_DEBUG(ctx, vp, "ATTRLIST - returning %d", error); 1340 return(error); 1341} 1342 1343/* 1344 * Obtain attribute information about a filesystem object. 1345 */ 1346 1347static int 1348getattrlist_internal(vnode_t vp, struct getattrlist_args *uap, 1349 __unused struct componentname *getattr_name, proc_t p, vfs_context_t ctx) 1350{ 1351 struct attrlist al; 1352 struct vnode_attr va; 1353 struct _attrlist_buf ab; 1354 kauth_action_t action; 1355 ssize_t fixedsize, varsize; 1356 const char *cnp; 1357 const char *vname = NULL; 1358 char *fullpathptr; 1359 ssize_t fullpathlen; 1360 ssize_t cnl; 1361 int proc_is64; 1362 int error; 1363 int return_valid; 1364 int pack_invalid; 1365 int attr_extended; 1366 int vtype = 0; 1367 uint32_t perms = 0; 1368 1369 proc_is64 = proc_is64bit(p); 1370 VATTR_INIT(&va); 1371 va.va_name = NULL; 1372 ab.base = NULL; 1373 cnp = "unknown"; 1374 cnl = 0; 1375 fullpathptr = NULL; 1376 fullpathlen = 0; 1377 1378 /* 1379 * Fetch the attribute request. 1380 */ 1381 if ((error = copyin(uap->alist, &al, sizeof(al))) != 0) 1382 goto out; 1383 if (al.bitmapcount != ATTR_BIT_MAP_COUNT) { 1384 error = EINVAL; 1385 goto out; 1386 } 1387 1388 VFS_DEBUG(ctx, vp, "%p ATTRLIST - %s request common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'", 1389 vp, p->p_comm, al.commonattr, al.volattr, al.fileattr, al.dirattr, al.forkattr, 1390 (uap->options & FSOPT_NOFOLLOW) ? "no":"", vp->v_name); 1391 1392#if CONFIG_MACF 1393 error = mac_vnode_check_getattrlist(ctx, vp, &al); 1394 if (error) 1395 goto out; 1396#endif /* MAC */ 1397 1398 /* 1399 * It is legal to request volume or file attributes, 1400 * but not both. 1401 */ 1402 if (al.volattr) { 1403 if (al.fileattr || al.dirattr || al.forkattr) { 1404 error = EINVAL; 1405 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: mixed volume/file/directory/fork attributes"); 1406 goto out; 1407 } 1408 /* handle volume attribute request */ 1409 error = getvolattrlist(vp, uap, &al, ctx, proc_is64); 1410 goto out; 1411 } 1412 1413 /* Check for special packing semantics */ 1414 return_valid = (al.commonattr & ATTR_CMN_RETURNED_ATTRS) ? 1 : 0; 1415 pack_invalid = (uap->options & FSOPT_PACK_INVAL_ATTRS) ? 1 : 0; 1416 attr_extended = (uap->options & FSOPT_ATTRLIST_EXTENDED) ? 1 : 0; 1417 if (pack_invalid) { 1418 /* FSOPT_PACK_INVAL_ATTRS requires ATTR_CMN_RETURNED_ATTRS */ 1419 if (!return_valid || al.forkattr) { 1420 error = EINVAL; 1421 goto out; 1422 } 1423 /* Keep invalid attrs from being uninitialized */ 1424 bzero(&va, sizeof (va)); 1425 /* Generate a valid mask for post processing */ 1426 bcopy(&al.commonattr, &ab.valid, sizeof (attribute_set_t)); 1427 } 1428 1429 /* Pick up the vnode type. If the FS is bad and changes vnode types on us, we 1430 * will have a valid snapshot that we can work from here. 1431 */ 1432 vtype = vp->v_type; 1433 1434 1435 /* 1436 * Set up the vnode_attr structure and authorise. 1437 */ 1438 if ((error = getattrlist_setupvattr(&al, attr_extended, &va, &fixedsize, &action, proc_is64, (vtype == VDIR))) != 0) { 1439 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: setup for request failed"); 1440 goto out; 1441 } 1442 if ((error = vnode_authorize(vp, NULL, action, ctx)) != 0) { 1443 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: authorisation failed/denied"); 1444 goto out; 1445 } 1446 1447 /* 1448 * If we're asking for the full path, allocate a buffer for that. 1449 */ 1450 if (al.commonattr & (ATTR_CMN_FULLPATH)) { 1451 fullpathptr = (char*) kalloc(MAXPATHLEN); 1452 if (fullpathptr == NULL) { 1453 error = ENOMEM; 1454 VFS_DEBUG(ctx,vp, "ATTRLIST - ERROR: cannot allocate fullpath buffer"); 1455 goto out; 1456 } 1457 } 1458 1459 1460 if (va.va_active != 0) { 1461 /* 1462 * If we're going to ask for va_name, allocate a buffer to point it at 1463 */ 1464 if (VATTR_IS_ACTIVE(&va, va_name)) { 1465 va.va_name = (char *) kalloc(MAXPATHLEN); 1466 if (va.va_name == NULL) { 1467 error = ENOMEM; 1468 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: cannot allocate va_name buffer"); 1469 goto out; 1470 } 1471 } 1472 1473 /* 1474 * Call the filesystem. 1475 */ 1476 if ((error = vnode_getattr(vp, &va, ctx)) != 0) { 1477 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: filesystem returned %d", error); 1478 goto out; 1479 } 1480 1481 /* did we ask for something the filesystem doesn't support? */ 1482 if (!VATTR_ALL_SUPPORTED(&va)) { 1483 1484 /* 1485 * There are a couple of special cases. If we are after object IDs, 1486 * we can make do with va_fileid. 1487 */ 1488 if ((al.commonattr & (ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | ATTR_CMN_FILEID)) && !VATTR_IS_SUPPORTED(&va, va_linkid)) 1489 VATTR_CLEAR_ACTIVE(&va, va_linkid); /* forget we wanted this */ 1490 1491 /* 1492 * Many filesystems don't know their parent object id. 1493 * If necessary, attempt to derive it from the vnode. 1494 */ 1495 if ((al.commonattr & (ATTR_CMN_PAROBJID | ATTR_CMN_PARENTID)) && 1496 !VATTR_IS_SUPPORTED(&va, va_parentid)) { 1497 vnode_t dvp; 1498 1499 if ((dvp = vnode_getparent(vp)) != NULLVP) { 1500 struct vnode_attr lva; 1501 1502 VATTR_INIT(&lva); 1503 VATTR_WANTED(&lva, va_fileid); 1504 if (vnode_getattr(dvp, &lva, ctx) == 0 && 1505 VATTR_IS_SUPPORTED(&va, va_fileid)) { 1506 va.va_parentid = lva.va_fileid; 1507 VATTR_SET_SUPPORTED(&va, va_parentid); 1508 } 1509 vnode_put(dvp); 1510 } 1511 } 1512 /* 1513 * And we can report datasize/alloc from total. 1514 */ 1515 if ((al.fileattr & ATTR_FILE_DATALENGTH) && !VATTR_IS_SUPPORTED(&va, va_data_size)) 1516 VATTR_CLEAR_ACTIVE(&va, va_data_size); 1517 if ((al.fileattr & ATTR_FILE_DATAALLOCSIZE) && !VATTR_IS_SUPPORTED(&va, va_data_alloc)) 1518 VATTR_CLEAR_ACTIVE(&va, va_data_alloc); 1519 1520 /* 1521 * If we don't have an encoding, go with UTF-8 1522 */ 1523 if ((al.commonattr & ATTR_CMN_SCRIPT) && 1524 !VATTR_IS_SUPPORTED(&va, va_encoding) && !return_valid) 1525 VATTR_RETURN(&va, va_encoding, 0x7e /* kTextEncodingMacUnicode */); 1526 1527 /* 1528 * If we don't have a name, we'll get one from the vnode or mount point. 1529 */ 1530 if ((al.commonattr & ATTR_CMN_NAME) && !VATTR_IS_SUPPORTED(&va, va_name)) { 1531 VATTR_CLEAR_ACTIVE(&va, va_name); 1532 } 1533 1534 /* If va_dirlinkcount isn't supported use a default of 1. */ 1535 if ((al.dirattr & ATTR_DIR_LINKCOUNT) && !VATTR_IS_SUPPORTED(&va, va_dirlinkcount)) { 1536 VATTR_RETURN(&va, va_dirlinkcount, 1); 1537 } 1538 1539 /* check again */ 1540 if (!VATTR_ALL_SUPPORTED(&va)) { 1541 if (return_valid) { 1542 if (pack_invalid) { 1543 /* Fix up valid mask for post processing */ 1544 getattrlist_fixupattrs(&ab.valid, &va); 1545 1546 /* Force packing of everything asked for */ 1547 va.va_supported = va.va_active; 1548 } else { 1549 /* Adjust the requested attributes */ 1550 getattrlist_fixupattrs((attribute_set_t *)&al.commonattr, &va); 1551 } 1552 } else { 1553 error = EINVAL; 1554 goto out; 1555 } 1556 } 1557 } 1558 } 1559 1560 /* 1561 * Compute variable-space requirements. 1562 */ 1563 varsize = 0; /* length count */ 1564 1565 /* We may need to fix up the name attribute if requested */ 1566 if (al.commonattr & ATTR_CMN_NAME) { 1567 if (VATTR_IS_SUPPORTED(&va, va_name)) { 1568 va.va_name[MAXPATHLEN-1] = '\0'; /* Ensure nul-termination */ 1569 cnp = va.va_name; 1570 cnl = strlen(cnp); 1571 } 1572 else { 1573 /* Filesystem did not support getting the name */ 1574 if (vnode_isvroot(vp)) { 1575 if (vp->v_mount->mnt_vfsstat.f_mntonname[1] == 0x00 && 1576 vp->v_mount->mnt_vfsstat.f_mntonname[0] == '/') { 1577 /* special case for boot volume. Use root name when it's 1578 * available (which is the volume name) or just the mount on 1579 * name of "/". we must do this for binary compatibility with 1580 * pre Tiger code. returning nothing for the boot volume name 1581 * breaks installers - 3961058 1582 */ 1583 cnp = vname = vnode_getname(vp); 1584 if (cnp == NULL) { 1585 /* just use "/" as name */ 1586 cnp = &vp->v_mount->mnt_vfsstat.f_mntonname[0]; 1587 } 1588 cnl = strlen(cnp); 1589 } 1590 else { 1591 getattrlist_findnamecomp(vp->v_mount->mnt_vfsstat.f_mntonname, &cnp, &cnl); 1592 } 1593 } 1594 else { 1595 cnp = vname = vnode_getname(vp); 1596 cnl = 0; 1597 if (cnp != NULL) { 1598 cnl = strlen(cnp); 1599 } 1600 } 1601 } 1602 varsize += roundup(cnl + 1, 4); 1603 } 1604 1605 /* 1606 * Compute the full path to this vnode, if necessary. This attribute is almost certainly 1607 * not supported by any filesystem, so build the path to this vnode at this time. 1608 */ 1609 if (al.commonattr & ATTR_CMN_FULLPATH) { 1610 int len = MAXPATHLEN; 1611 int err; 1612 /* call build_path making sure NOT to use the cache-only behavior */ 1613 err = build_path(vp, fullpathptr, len, &len, 0, vfs_context_current()); 1614 if (err) { 1615 error = err; 1616 goto out; 1617 } 1618 fullpathlen = 0; 1619 if (fullpathptr){ 1620 fullpathlen = strlen(fullpathptr); 1621 } 1622 varsize += roundup(fullpathlen+1, 4); 1623 } 1624 1625 /* 1626 * We have a kauth_acl_t but we will be returning a kauth_filesec_t. 1627 * 1628 * XXX This needs to change at some point; since the blob is opaque in 1629 * user-space this is OK. 1630 */ 1631 if ((al.commonattr & ATTR_CMN_EXTENDED_SECURITY) && 1632 VATTR_IS_SUPPORTED(&va, va_acl) && 1633 (va.va_acl != NULL)) { 1634 1635 /* 1636 * Since we have a kauth_acl_t (not a kauth_filesec_t), we have to check against 1637 * KAUTH_FILESEC_NOACL ourselves 1638 */ 1639 if (va.va_acl->acl_entrycount == KAUTH_FILESEC_NOACL) { 1640 varsize += roundup((KAUTH_FILESEC_SIZE(0)), 4); 1641 } 1642 else { 1643 varsize += roundup ((KAUTH_FILESEC_SIZE(va.va_acl->acl_entrycount)), 4); 1644 } 1645 } 1646 1647 /* 1648 * Allocate a target buffer for attribute results. 1649 * 1650 * Note that we won't ever copy out more than the caller requested, even though 1651 * we might have to allocate more than they offer so that the diagnostic checks 1652 * don't result in a panic if the caller's buffer is too small.. 1653 */ 1654 ab.allocated = fixedsize + varsize; 1655 /* Cast 'allocated' to an unsigned to verify allocation size */ 1656 if ( ((size_t)ab.allocated) > ATTR_MAX_BUFFER) { 1657 error = ENOMEM; 1658 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab.allocated, ATTR_MAX_BUFFER); 1659 goto out; 1660 } 1661 MALLOC(ab.base, char *, ab.allocated, M_TEMP, M_WAITOK); 1662 if (ab.base == NULL) { 1663 error = ENOMEM; 1664 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab.allocated); 1665 goto out; 1666 } 1667 1668 /* set the S_IFMT bits for the mode */ 1669 if (al.commonattr & ATTR_CMN_ACCESSMASK) { 1670 switch (vp->v_type) { 1671 case VREG: 1672 va.va_mode |= S_IFREG; 1673 break; 1674 case VDIR: 1675 va.va_mode |= S_IFDIR; 1676 break; 1677 case VBLK: 1678 va.va_mode |= S_IFBLK; 1679 break; 1680 case VCHR: 1681 va.va_mode |= S_IFCHR; 1682 break; 1683 case VLNK: 1684 va.va_mode |= S_IFLNK; 1685 break; 1686 case VSOCK: 1687 va.va_mode |= S_IFSOCK; 1688 break; 1689 case VFIFO: 1690 va.va_mode |= S_IFIFO; 1691 break; 1692 default: 1693 error = EBADF; 1694 goto out; 1695 } 1696 } 1697 1698 /* 1699 * Pack results into the destination buffer. 1700 */ 1701 ab.fixedcursor = ab.base + sizeof(uint32_t); 1702 if (return_valid) { 1703 ab.fixedcursor += sizeof (attribute_set_t); 1704 bzero(&ab.actual, sizeof (ab.actual)); 1705 } 1706 ab.varcursor = ab.base + fixedsize; 1707 ab.needed = ab.allocated; 1708 1709 /* common attributes **************************************************/ 1710 if (al.commonattr & ATTR_CMN_NAME) { 1711 attrlist_pack_string(&ab, cnp, cnl); 1712 ab.actual.commonattr |= ATTR_CMN_NAME; 1713 } 1714 if ((al.commonattr & ATTR_CMN_ERROR) && 1715 (!return_valid || pack_invalid)) { 1716 ATTR_PACK4(ab, 0); 1717 ab.actual.commonattr |= ATTR_CMN_ERROR; 1718 } 1719 if (al.commonattr & ATTR_CMN_DEVID) { 1720 ATTR_PACK4(ab, vp->v_mount->mnt_vfsstat.f_fsid.val[0]); 1721 ab.actual.commonattr |= ATTR_CMN_DEVID; 1722 } 1723 if (al.commonattr & ATTR_CMN_FSID) { 1724 ATTR_PACK8(ab, vp->v_mount->mnt_vfsstat.f_fsid); 1725 ab.actual.commonattr |= ATTR_CMN_FSID; 1726 } 1727 if (al.commonattr & ATTR_CMN_OBJTYPE) { 1728 ATTR_PACK4(ab, vtype); 1729 ab.actual.commonattr |= ATTR_CMN_OBJTYPE; 1730 } 1731 if (al.commonattr & ATTR_CMN_OBJTAG) { 1732 ATTR_PACK4(ab, vp->v_tag); 1733 ab.actual.commonattr |= ATTR_CMN_OBJTAG; 1734 } 1735 if (al.commonattr & ATTR_CMN_OBJID) { 1736 fsobj_id_t f; 1737 /* 1738 * Carbon can't deal with us reporting the target ID 1739 * for links. So we ask the filesystem to give us the 1740 * source ID as well, and if it gives us one, we use 1741 * it instead. 1742 */ 1743 if (VATTR_IS_SUPPORTED(&va, va_linkid)) { 1744 f.fid_objno = va.va_linkid; 1745 } else { 1746 f.fid_objno = va.va_fileid; 1747 } 1748 f.fid_generation = 0; 1749 ATTR_PACK8(ab, f); 1750 ab.actual.commonattr |= ATTR_CMN_OBJID; 1751 } 1752 if (al.commonattr & ATTR_CMN_OBJPERMANENTID) { 1753 fsobj_id_t f; 1754 /* 1755 * Carbon can't deal with us reporting the target ID 1756 * for links. So we ask the filesystem to give us the 1757 * source ID as well, and if it gives us one, we use 1758 * it instead. 1759 */ 1760 if (VATTR_IS_SUPPORTED(&va, va_linkid)) { 1761 f.fid_objno = va.va_linkid; 1762 } else { 1763 f.fid_objno = va.va_fileid; 1764 } 1765 f.fid_generation = 0; 1766 ATTR_PACK8(ab, f); 1767 ab.actual.commonattr |= ATTR_CMN_OBJPERMANENTID; 1768 } 1769 if (al.commonattr & ATTR_CMN_PAROBJID) { 1770 fsobj_id_t f; 1771 1772 f.fid_objno = va.va_parentid; /* could be lossy here! */ 1773 f.fid_generation = 0; 1774 ATTR_PACK8(ab, f); 1775 ab.actual.commonattr |= ATTR_CMN_PAROBJID; 1776 } 1777 if (al.commonattr & ATTR_CMN_SCRIPT) { 1778 if (VATTR_IS_SUPPORTED(&va, va_encoding)) { 1779 ATTR_PACK4(ab, va.va_encoding); 1780 ab.actual.commonattr |= ATTR_CMN_SCRIPT; 1781 } else if (!return_valid || pack_invalid) { 1782 ATTR_PACK4(ab, 0x7e); 1783 } 1784 } 1785 if (al.commonattr & ATTR_CMN_CRTIME) { 1786 ATTR_PACK_TIME(ab, va.va_create_time, proc_is64); 1787 ab.actual.commonattr |= ATTR_CMN_CRTIME; 1788 } 1789 if (al.commonattr & ATTR_CMN_MODTIME) { 1790 ATTR_PACK_TIME(ab, va.va_modify_time, proc_is64); 1791 ab.actual.commonattr |= ATTR_CMN_MODTIME; 1792 } 1793 if (al.commonattr & ATTR_CMN_CHGTIME) { 1794 ATTR_PACK_TIME(ab, va.va_change_time, proc_is64); 1795 ab.actual.commonattr |= ATTR_CMN_CHGTIME; 1796 } 1797 if (al.commonattr & ATTR_CMN_ACCTIME) { 1798 ATTR_PACK_TIME(ab, va.va_access_time, proc_is64); 1799 ab.actual.commonattr |= ATTR_CMN_ACCTIME; 1800 } 1801 if (al.commonattr & ATTR_CMN_BKUPTIME) { 1802 ATTR_PACK_TIME(ab, va.va_backup_time, proc_is64); 1803 ab.actual.commonattr |= ATTR_CMN_BKUPTIME; 1804 } 1805 /* 1806 * They are requesting user access, we should obtain this before getting 1807 * the finder info. For some network file systems this is a performance 1808 * improvement. 1809 */ 1810 if (al.commonattr & ATTR_CMN_USERACCESS) { /* this is expensive */ 1811 if (vtype == VDIR) { 1812 if (vnode_authorize(vp, NULL, 1813 KAUTH_VNODE_ACCESS | KAUTH_VNODE_ADD_FILE | KAUTH_VNODE_ADD_SUBDIRECTORY | KAUTH_VNODE_DELETE_CHILD, ctx) == 0) 1814 perms |= W_OK; 1815 if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_LIST_DIRECTORY, ctx) == 0) 1816 perms |= R_OK; 1817 if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_SEARCH, ctx) == 0) 1818 perms |= X_OK; 1819 } else { 1820 if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA, ctx) == 0) 1821 perms |= W_OK; 1822 if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_READ_DATA, ctx) == 0) 1823 perms |= R_OK; 1824 if (vnode_authorize(vp, NULL, KAUTH_VNODE_ACCESS | KAUTH_VNODE_EXECUTE, ctx) == 0) 1825 perms |= X_OK; 1826 } 1827 } 1828 1829 if (al.commonattr & ATTR_CMN_FNDRINFO) { 1830 uio_t auio; 1831 size_t fisize = 32; 1832 char uio_buf[UIO_SIZEOF(1)]; 1833 1834 if ((auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ, 1835 uio_buf, sizeof(uio_buf))) == NULL) { 1836 error = ENOMEM; 1837 goto out; 1838 } 1839 uio_addiov(auio, CAST_USER_ADDR_T(ab.fixedcursor), fisize); 1840 error = vn_getxattr(vp, XATTR_FINDERINFO_NAME, auio, 1841 &fisize, XATTR_NOSECURITY, ctx); 1842 uio_free(auio); 1843 /* 1844 * Default to zeros if its not available, 1845 * unless ATTR_CMN_RETURNED_ATTRS was requested. 1846 */ 1847 if (error && 1848 (!return_valid || pack_invalid) && 1849 ((error == ENOATTR) || (error == ENOENT) || 1850 (error == ENOTSUP) || (error == EPERM))) { 1851 VFS_DEBUG(ctx, vp, "ATTRLIST - No system.finderinfo attribute, returning zeroes"); 1852 bzero(ab.fixedcursor, 32); 1853 error = 0; 1854 } 1855 if (error == 0) { 1856 ab.fixedcursor += 32; 1857 ab.actual.commonattr |= ATTR_CMN_FNDRINFO; 1858 } else if (!return_valid) { 1859 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: reading system.finderinfo attribute"); 1860 goto out; 1861 } 1862 } 1863 if (al.commonattr & ATTR_CMN_OWNERID) { 1864 ATTR_PACK4(ab, va.va_uid); 1865 ab.actual.commonattr |= ATTR_CMN_OWNERID; 1866 } 1867 if (al.commonattr & ATTR_CMN_GRPID) { 1868 ATTR_PACK4(ab, va.va_gid); 1869 ab.actual.commonattr |= ATTR_CMN_GRPID; 1870 } 1871 if (al.commonattr & ATTR_CMN_ACCESSMASK) { 1872 ATTR_PACK4(ab, va.va_mode); 1873 ab.actual.commonattr |= ATTR_CMN_ACCESSMASK; 1874 } 1875 if (al.commonattr & ATTR_CMN_FLAGS) { 1876 ATTR_PACK4(ab, va.va_flags); 1877 ab.actual.commonattr |= ATTR_CMN_FLAGS; 1878 } 1879 if (attr_extended) { 1880 if (al.commonattr & ATTR_CMN_GEN_COUNT) { 1881 if (VATTR_IS_SUPPORTED(&va, va_gen)) { 1882 ATTR_PACK4(ab, va.va_gen); 1883 ab.actual.commonattr |= ATTR_CMN_GEN_COUNT; 1884 } else if (!return_valid || pack_invalid) { 1885 ATTR_PACK4(ab, 0); 1886 } 1887 } 1888 1889 if (al.commonattr & ATTR_CMN_DOCUMENT_ID) { 1890 if (VATTR_IS_SUPPORTED(&va, va_document_id)) { 1891 ATTR_PACK4(ab, va.va_document_id); 1892 ab.actual.commonattr |= ATTR_CMN_DOCUMENT_ID; 1893 } else if (!return_valid || pack_invalid) { 1894 ATTR_PACK4(ab, 0); 1895 } 1896 } 1897 } 1898 /* We already obtain the user access, so just fill in the buffer here */ 1899 if (al.commonattr & ATTR_CMN_USERACCESS) { 1900#if CONFIG_MACF 1901 /* 1902 * Rather than MAC preceding DAC, in this case we want 1903 * the smallest set of permissions granted by both MAC & DAC 1904 * checks. We won't add back any permissions. 1905 */ 1906 if (perms & W_OK) 1907 if (mac_vnode_check_access(ctx, vp, W_OK) != 0) 1908 perms &= ~W_OK; 1909 if (perms & R_OK) 1910 if (mac_vnode_check_access(ctx, vp, R_OK) != 0) 1911 perms &= ~R_OK; 1912 if (perms & X_OK) 1913 if (mac_vnode_check_access(ctx, vp, X_OK) != 0) 1914 perms &= ~X_OK; 1915#endif /* MAC */ 1916 VFS_DEBUG(ctx, vp, "ATTRLIST - granting perms %d", perms); 1917 ATTR_PACK4(ab, perms); 1918 ab.actual.commonattr |= ATTR_CMN_USERACCESS; 1919 } 1920 if (al.commonattr & ATTR_CMN_EXTENDED_SECURITY) { 1921 if (VATTR_IS_SUPPORTED(&va, va_acl) && (va.va_acl != NULL)) { 1922 struct kauth_filesec fsec; 1923 /* 1924 * We want to return a kauth_filesec (for now), but all we have is a kauth_acl. 1925 */ 1926 fsec.fsec_magic = KAUTH_FILESEC_MAGIC; 1927 fsec.fsec_owner = kauth_null_guid; 1928 fsec.fsec_group = kauth_null_guid; 1929 attrlist_pack_variable2(&ab, &fsec, __offsetof(struct kauth_filesec, fsec_acl), va.va_acl, KAUTH_ACL_COPYSIZE(va.va_acl)); 1930 ab.actual.commonattr |= ATTR_CMN_EXTENDED_SECURITY; 1931 } else if (!return_valid || pack_invalid) { 1932 attrlist_pack_variable(&ab, NULL, 0); 1933 } 1934 } 1935 if (al.commonattr & ATTR_CMN_UUID) { 1936 if (VATTR_IS_SUPPORTED(&va, va_uuuid)) { 1937 ATTR_PACK(&ab, va.va_uuuid); 1938 ab.actual.commonattr |= ATTR_CMN_UUID; 1939 } else if (!return_valid || pack_invalid) { 1940 ATTR_PACK(&ab, kauth_null_guid); 1941 } 1942 } 1943 if (al.commonattr & ATTR_CMN_GRPUUID) { 1944 if (VATTR_IS_SUPPORTED(&va, va_guuid)) { 1945 ATTR_PACK(&ab, va.va_guuid); 1946 ab.actual.commonattr |= ATTR_CMN_GRPUUID; 1947 } else if (!return_valid || pack_invalid) { 1948 ATTR_PACK(&ab, kauth_null_guid); 1949 } 1950 } 1951 if (al.commonattr & ATTR_CMN_FILEID) { 1952 ATTR_PACK8(ab, va.va_fileid); 1953 ab.actual.commonattr |= ATTR_CMN_FILEID; 1954 } 1955 if (al.commonattr & ATTR_CMN_PARENTID) { 1956 ATTR_PACK8(ab, va.va_parentid); 1957 ab.actual.commonattr |= ATTR_CMN_PARENTID; 1958 } 1959 1960 if (al.commonattr & ATTR_CMN_FULLPATH) { 1961 attrlist_pack_string (&ab, fullpathptr, fullpathlen); 1962 ab.actual.commonattr |= ATTR_CMN_FULLPATH; 1963 } 1964 1965 if (al.commonattr & ATTR_CMN_ADDEDTIME) { 1966 ATTR_PACK_TIME(ab, va.va_addedtime, proc_is64); 1967 ab.actual.commonattr |= ATTR_CMN_ADDEDTIME; 1968 } 1969 1970 /* directory attributes *********************************************/ 1971 if (al.dirattr && (vtype == VDIR)) { 1972 if (al.dirattr & ATTR_DIR_LINKCOUNT) { /* full count of entries */ 1973 ATTR_PACK4(ab, (uint32_t)va.va_dirlinkcount); 1974 ab.actual.dirattr |= ATTR_DIR_LINKCOUNT; 1975 } 1976 if (al.dirattr & ATTR_DIR_ENTRYCOUNT) { 1977 ATTR_PACK4(ab, (uint32_t)va.va_nchildren); 1978 ab.actual.dirattr |= ATTR_DIR_ENTRYCOUNT; 1979 } 1980 if (al.dirattr & ATTR_DIR_MOUNTSTATUS) { 1981 uint32_t mntstat; 1982 1983 mntstat = (vp->v_flag & VROOT) ? DIR_MNTSTATUS_MNTPOINT : 0; 1984#if CONFIG_TRIGGERS 1985 /* 1986 * Report back on active vnode triggers 1987 * that can directly trigger a mount 1988 */ 1989 if (vp->v_resolve && 1990 !(vp->v_resolve->vr_flags & VNT_NO_DIRECT_MOUNT)) { 1991 mntstat |= DIR_MNTSTATUS_TRIGGER; 1992 } 1993#endif 1994 ATTR_PACK4(ab, mntstat); 1995 ab.actual.dirattr |= ATTR_DIR_MOUNTSTATUS; 1996 } 1997 } 1998 1999 /* file attributes **************************************************/ 2000 if (al.fileattr && (vtype != VDIR)) { 2001 2002 size_t rsize = 0; 2003 uint64_t rlength = 0; 2004 uint64_t ralloc = 0; 2005 /* 2006 * Pre-fetch the rsrc attributes now so we only get them once. 2007 * Fetch the resource fork size/allocation via xattr interface 2008 */ 2009 if (al.fileattr & (ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE)) { 2010 if ((error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, NULL, &rsize, XATTR_NOSECURITY, ctx)) != 0) { 2011 if ((error == ENOENT) || (error == ENOATTR) || (error == ENOTSUP) || (error == EPERM)|| (error == EACCES)) { 2012 rsize = 0; 2013 error = 0; 2014 } else { 2015 goto out; 2016 } 2017 } 2018 rlength = rsize; 2019 2020 if (al.fileattr & (ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_ALLOCSIZE)) { 2021 uint32_t blksize = vp->v_mount->mnt_vfsstat.f_bsize; 2022 if (blksize == 0) { 2023 blksize = 512; 2024 } 2025 ralloc = roundup(rsize, blksize); 2026 } 2027 } 2028 2029 if (al.fileattr & ATTR_FILE_LINKCOUNT) { 2030 ATTR_PACK4(ab, (uint32_t)va.va_nlink); 2031 ab.actual.fileattr |= ATTR_FILE_LINKCOUNT; 2032 } 2033 /* 2034 * Note the following caveats for the TOTALSIZE and ALLOCSIZE attributes: 2035 * We infer that if the filesystem does not support va_data_size or va_data_alloc 2036 * it must not know about alternate forks. So when we need to gather 2037 * the total size or total alloc, it's OK to substitute the total size for 2038 * the data size below. This is because it is likely a flat filesystem and we must 2039 * be using AD files to store the rsrc fork and EAs. 2040 * 2041 * Additionally, note that getattrlist is barred from being called on 2042 * resource fork paths. (Search for CN_ALLOWRSRCFORK). So if the filesystem does 2043 * support va_data_size, it is guaranteed to represent the data fork's size. This 2044 * is an important distinction to make because when we call vnode_getattr on 2045 * an HFS resource fork vnode, to get the size, it will vend out the resource 2046 * fork's size (it only gets the size of the passed-in vnode). 2047 */ 2048 if (al.fileattr & ATTR_FILE_TOTALSIZE) { 2049 uint64_t totalsize = rlength; 2050 2051 if (VATTR_IS_SUPPORTED(&va, va_data_size)) { 2052 totalsize += va.va_data_size; 2053 } else { 2054 totalsize += va.va_total_size; 2055 } 2056 2057 ATTR_PACK8(ab, totalsize); 2058 ab.actual.fileattr |= ATTR_FILE_TOTALSIZE; 2059 } 2060 if (al.fileattr & ATTR_FILE_ALLOCSIZE) { 2061 uint64_t totalalloc = ralloc; 2062 2063 /* 2064 * If data_alloc is supported, then it must represent the 2065 * data fork size. 2066 */ 2067 if (VATTR_IS_SUPPORTED(&va, va_data_alloc)) { 2068 totalalloc += va.va_data_alloc; 2069 } 2070 else { 2071 totalalloc += va.va_total_alloc; 2072 } 2073 2074 ATTR_PACK8(ab, totalalloc); 2075 ab.actual.fileattr |= ATTR_FILE_ALLOCSIZE; 2076 } 2077 if (al.fileattr & ATTR_FILE_IOBLOCKSIZE) { 2078 ATTR_PACK4(ab, va.va_iosize); 2079 ab.actual.fileattr |= ATTR_FILE_IOBLOCKSIZE; 2080 } 2081 if (al.fileattr & ATTR_FILE_CLUMPSIZE) { 2082 if (!return_valid || pack_invalid) { 2083 ATTR_PACK4(ab, 0); /* this value is deprecated */ 2084 ab.actual.fileattr |= ATTR_FILE_CLUMPSIZE; 2085 } 2086 } 2087 if (al.fileattr & ATTR_FILE_DEVTYPE) { 2088 uint32_t dev; 2089 2090 if ((vp->v_type == VCHR) || (vp->v_type == VBLK)) { 2091 if (vp->v_specinfo != NULL) 2092 dev = vp->v_specinfo->si_rdev; 2093 else 2094 dev = va.va_rdev; 2095 } else { 2096 dev = 0; 2097 } 2098 ATTR_PACK4(ab, dev); 2099 ab.actual.fileattr |= ATTR_FILE_DEVTYPE; 2100 } 2101 2102 /* 2103 * If the filesystem does not support datalength 2104 * or dataallocsize, then we infer that totalsize and 2105 * totalalloc are substitutes. 2106 */ 2107 if (al.fileattr & ATTR_FILE_DATALENGTH) { 2108 if (VATTR_IS_SUPPORTED(&va, va_data_size)) { 2109 ATTR_PACK8(ab, va.va_data_size); 2110 } else { 2111 ATTR_PACK8(ab, va.va_total_size); 2112 } 2113 ab.actual.fileattr |= ATTR_FILE_DATALENGTH; 2114 } 2115 if (al.fileattr & ATTR_FILE_DATAALLOCSIZE) { 2116 if (VATTR_IS_SUPPORTED(&va, va_data_alloc)) { 2117 ATTR_PACK8(ab, va.va_data_alloc); 2118 } else { 2119 ATTR_PACK8(ab, va.va_total_alloc); 2120 } 2121 ab.actual.fileattr |= ATTR_FILE_DATAALLOCSIZE; 2122 } 2123 /* already got the resource fork size/allocation above */ 2124 if (al.fileattr & ATTR_FILE_RSRCLENGTH) { 2125 ATTR_PACK8(ab, rlength); 2126 ab.actual.fileattr |= ATTR_FILE_RSRCLENGTH; 2127 } 2128 if (al.fileattr & ATTR_FILE_RSRCALLOCSIZE) { 2129 ATTR_PACK8(ab, ralloc); 2130 ab.actual.fileattr |= ATTR_FILE_RSRCALLOCSIZE; 2131 } 2132 } 2133 2134 /* diagnostic */ 2135 if (!return_valid && (ab.fixedcursor - ab.base) != fixedsize) 2136 panic("packed field size mismatch; allocated %ld but packed %ld for common %08x vol %08x", 2137 fixedsize, (long) (ab.fixedcursor - ab.base), al.commonattr, al.volattr); 2138 if (!return_valid && ab.varcursor != (ab.base + ab.needed)) 2139 panic("packed variable field size mismatch; used %ld but expected %ld", (long) (ab.varcursor - ab.base), ab.needed); 2140 2141 /* 2142 * In the compatible case, we report the smaller of the required and returned sizes. 2143 * If the FSOPT_REPORT_FULLSIZE option is supplied, we report the full (required) size 2144 * of the result buffer, even if we copied less out. The caller knows how big a buffer 2145 * they gave us, so they can always check for truncation themselves. 2146 */ 2147 *(uint32_t *)ab.base = (uap->options & FSOPT_REPORT_FULLSIZE) ? ab.needed : imin(ab.allocated, ab.needed); 2148 2149 /* Return attribute set output if requested. */ 2150 if (return_valid) { 2151 ab.actual.commonattr |= ATTR_CMN_RETURNED_ATTRS; 2152 if (pack_invalid) { 2153 /* Only report the attributes that are valid */ 2154 ab.actual.commonattr &= ab.valid.commonattr; 2155 ab.actual.dirattr &= ab.valid.dirattr; 2156 ab.actual.fileattr &= ab.valid.fileattr; 2157 } 2158 bcopy(&ab.actual, ab.base + sizeof(uint32_t), sizeof (ab.actual)); 2159 } 2160 2161 /* Only actually copyout as much out as the user buffer can hold */ 2162 error = copyout(ab.base, uap->attributeBuffer, imin(uap->bufferSize, ab.allocated)); 2163 2164out: 2165 if (va.va_name) 2166 kfree(va.va_name, MAXPATHLEN); 2167 if (fullpathptr) 2168 kfree(fullpathptr, MAXPATHLEN); 2169 if (vname) 2170 vnode_putname(vname); 2171 if (ab.base != NULL) 2172 FREE(ab.base, M_TEMP); 2173 if (VATTR_IS_SUPPORTED(&va, va_acl) && (va.va_acl != NULL)) 2174 kauth_acl_free(va.va_acl); 2175 2176 VFS_DEBUG(ctx, vp, "ATTRLIST - returning %d", error); 2177 return(error); 2178} 2179 2180int 2181fgetattrlist(proc_t p, struct fgetattrlist_args *uap, __unused int32_t *retval) 2182{ 2183 struct vfs_context *ctx; 2184 vnode_t vp = NULL; 2185 int error; 2186 struct getattrlist_args ap; 2187 2188 ctx = vfs_context_current(); 2189 error = 0; 2190 2191 if ((error = file_vnode(uap->fd, &vp)) != 0) 2192 return (error); 2193 2194 if ((error = vnode_getwithref(vp)) != 0) { 2195 file_drop(uap->fd); 2196 return(error); 2197 } 2198 2199 ap.path = 0; 2200 ap.alist = uap->alist; 2201 ap.attributeBuffer = uap->attributeBuffer; 2202 ap.bufferSize = uap->bufferSize; 2203 ap.options = uap->options; 2204 2205 /* Default to using the vnode's name. */ 2206 error = getattrlist_internal(vp, &ap, NULL, p, ctx); 2207 2208 file_drop(uap->fd); 2209 if (vp) 2210 vnode_put(vp); 2211 2212 return error; 2213} 2214 2215int 2216getattrlist(proc_t p, struct getattrlist_args *uap, __unused int32_t *retval) 2217{ 2218 struct vfs_context *ctx; 2219 struct nameidata nd; 2220 vnode_t vp = NULL; 2221 u_long nameiflags; 2222 int error; 2223 2224 ctx = vfs_context_current(); 2225 error = 0; 2226 2227 /* 2228 * Look up the file. 2229 */ 2230 nameiflags = NOTRIGGER | AUDITVNPATH1; 2231 if (!(uap->options & FSOPT_NOFOLLOW)) 2232 nameiflags |= FOLLOW; 2233 NDINIT(&nd, LOOKUP, OP_GETATTR, nameiflags, UIO_USERSPACE, uap->path, ctx); 2234 2235 if ((error = namei(&nd)) != 0) { 2236 /* vp is still uninitialized */ 2237 return error; 2238 } 2239 2240 vp = nd.ni_vp; 2241 /* Pass along our componentname to getattrlist_internal */ 2242 error = getattrlist_internal(vp, uap, &(nd.ni_cnd), p, ctx); 2243 2244 /* Retain the namei reference until the getattrlist completes. */ 2245 nameidone(&nd); 2246 if (vp) 2247 vnode_put(vp); 2248 2249 return error; 2250} 2251 2252static int 2253attrlist_unpack_fixed(char **cursor, char *end, void *buf, ssize_t size) 2254{ 2255 /* make sure we have enough source data */ 2256 if ((*cursor) + size > end) 2257 return(EINVAL); 2258 2259 bcopy(*cursor, buf, size); 2260 *cursor += size; 2261 return(0); 2262} 2263 2264#define ATTR_UNPACK(v) do {if ((error = attrlist_unpack_fixed(&cursor, bufend, &v, sizeof(v))) != 0) goto out;} while(0); 2265#define ATTR_UNPACK_CAST(t, v) do { t _f; ATTR_UNPACK(_f); v = _f;} while(0) 2266#define ATTR_UNPACK_TIME(v, is64) \ 2267 do { \ 2268 if (is64) { \ 2269 struct user64_timespec us; \ 2270 ATTR_UNPACK(us); \ 2271 v.tv_sec = us.tv_sec; \ 2272 v.tv_nsec = us.tv_nsec; \ 2273 } else { \ 2274 struct user32_timespec us; \ 2275 ATTR_UNPACK(us); \ 2276 v.tv_sec = us.tv_sec; \ 2277 v.tv_nsec = us.tv_nsec; \ 2278 } \ 2279 } while(0) 2280 2281 2282/* 2283 * Write attributes. 2284 */ 2285static int 2286setattrlist_internal(vnode_t vp, struct setattrlist_args *uap, proc_t p, vfs_context_t ctx) 2287{ 2288 struct attrlist al; 2289 struct vnode_attr va; 2290 struct attrreference ar; 2291 kauth_action_t action; 2292 char *user_buf, *cursor, *bufend, *fndrinfo, *cp, *volname; 2293 int proc_is64, error; 2294 uint32_t nace; 2295 kauth_filesec_t rfsec; 2296 2297 user_buf = NULL; 2298 fndrinfo = NULL; 2299 volname = NULL; 2300 error = 0; 2301 proc_is64 = proc_is64bit(p); 2302 VATTR_INIT(&va); 2303 2304 /* 2305 * Fetch the attribute set and validate. 2306 */ 2307 if ((error = copyin(uap->alist, (caddr_t) &al, sizeof (al)))) 2308 goto out; 2309 if (al.bitmapcount != ATTR_BIT_MAP_COUNT) { 2310 error = EINVAL; 2311 goto out; 2312 } 2313 2314 VFS_DEBUG(ctx, vp, "%p ATTRLIST - %s set common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'", 2315 vp, p->p_comm, al.commonattr, al.volattr, al.fileattr, al.dirattr, al.forkattr, 2316 (uap->options & FSOPT_NOFOLLOW) ? "no":"", vp->v_name); 2317 2318 if (al.volattr) { 2319 if ((al.volattr & ~ATTR_VOL_SETMASK) || 2320 (al.commonattr & ~ATTR_CMN_VOLSETMASK) || 2321 al.fileattr || 2322 al.forkattr) { 2323 error = EINVAL; 2324 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: attempt to set invalid volume attributes"); 2325 goto out; 2326 } 2327 } else { 2328 if ((al.commonattr & ~ATTR_CMN_SETMASK) || 2329 (al.fileattr & ~ATTR_FILE_SETMASK) || 2330 (al.dirattr & ~ATTR_DIR_SETMASK) || 2331 (al.forkattr & ~ATTR_FORK_SETMASK)) { 2332 error = EINVAL; 2333 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: attempt to set invalid file/folder attributes"); 2334 goto out; 2335 } 2336 } 2337 2338 /* 2339 * If the caller's bitmaps indicate that there are no attributes to set, 2340 * then exit early. In particular, we want to avoid the MALLOC below 2341 * since the caller's bufferSize could be zero, and MALLOC of zero bytes 2342 * returns a NULL pointer, which would cause setattrlist to return ENOMEM. 2343 */ 2344 if (al.commonattr == 0 && 2345 (al.volattr & ~ATTR_VOL_INFO) == 0 && 2346 al.dirattr == 0 && 2347 al.fileattr == 0 && 2348 al.forkattr == 0) { 2349 error = 0; 2350 goto out; 2351 } 2352 2353 /* 2354 * Make the naive assumption that the caller has supplied a reasonable buffer 2355 * size. We could be more careful by pulling in the fixed-size region, checking 2356 * the attrref structures, then pulling in the variable section. 2357 * We need to reconsider this for handling large ACLs, as they should probably be 2358 * brought directly into a buffer. Multiple copyins will make this slower though. 2359 * 2360 * We could also map the user buffer if it is larger than some sensible mimimum. 2361 */ 2362 if (uap->bufferSize > ATTR_MAX_BUFFER) { 2363 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: buffer size %d too large", uap->bufferSize); 2364 error = ENOMEM; 2365 goto out; 2366 } 2367 MALLOC(user_buf, char *, uap->bufferSize, M_TEMP, M_WAITOK); 2368 if (user_buf == NULL) { 2369 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: could not allocate %d bytes for buffer", uap->bufferSize); 2370 error = ENOMEM; 2371 goto out; 2372 } 2373 if ((error = copyin(uap->attributeBuffer, user_buf, uap->bufferSize)) != 0) { 2374 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: buffer copyin failed"); 2375 goto out; 2376 } 2377 VFS_DEBUG(ctx, vp, "ATTRLIST - copied in %d bytes of user attributes to %p", uap->bufferSize, user_buf); 2378 2379#if CONFIG_MACF 2380 error = mac_vnode_check_setattrlist(ctx, vp, &al); 2381 if (error) 2382 goto out; 2383#endif /* MAC */ 2384 2385 /* 2386 * Unpack the argument buffer. 2387 */ 2388 cursor = user_buf; 2389 bufend = cursor + uap->bufferSize; 2390 2391 /* common */ 2392 if (al.commonattr & ATTR_CMN_SCRIPT) { 2393 ATTR_UNPACK(va.va_encoding); 2394 VATTR_SET_ACTIVE(&va, va_encoding); 2395 } 2396 if (al.commonattr & ATTR_CMN_CRTIME) { 2397 ATTR_UNPACK_TIME(va.va_create_time, proc_is64); 2398 VATTR_SET_ACTIVE(&va, va_create_time); 2399 } 2400 if (al.commonattr & ATTR_CMN_MODTIME) { 2401 ATTR_UNPACK_TIME(va.va_modify_time, proc_is64); 2402 VATTR_SET_ACTIVE(&va, va_modify_time); 2403 } 2404 if (al.commonattr & ATTR_CMN_CHGTIME) { 2405 ATTR_UNPACK_TIME(va.va_change_time, proc_is64); 2406 VATTR_SET_ACTIVE(&va, va_change_time); 2407 } 2408 if (al.commonattr & ATTR_CMN_ACCTIME) { 2409 ATTR_UNPACK_TIME(va.va_access_time, proc_is64); 2410 VATTR_SET_ACTIVE(&va, va_access_time); 2411 } 2412 if (al.commonattr & ATTR_CMN_BKUPTIME) { 2413 ATTR_UNPACK_TIME(va.va_backup_time, proc_is64); 2414 VATTR_SET_ACTIVE(&va, va_backup_time); 2415 } 2416 if (al.commonattr & ATTR_CMN_FNDRINFO) { 2417 if ((cursor + 32) > bufend) { 2418 error = EINVAL; 2419 VFS_DEBUG(ctx, vp, "ATTRLIST - not enough data supplied for FINDERINFO"); 2420 goto out; 2421 } 2422 fndrinfo = cursor; 2423 cursor += 32; 2424 } 2425 if (al.commonattr & ATTR_CMN_OWNERID) { 2426 ATTR_UNPACK(va.va_uid); 2427 VATTR_SET_ACTIVE(&va, va_uid); 2428 } 2429 if (al.commonattr & ATTR_CMN_GRPID) { 2430 ATTR_UNPACK(va.va_gid); 2431 VATTR_SET_ACTIVE(&va, va_gid); 2432 } 2433 if (al.commonattr & ATTR_CMN_ACCESSMASK) { 2434 ATTR_UNPACK_CAST(uint32_t, va.va_mode); 2435 VATTR_SET_ACTIVE(&va, va_mode); 2436 } 2437 if (al.commonattr & ATTR_CMN_FLAGS) { 2438 ATTR_UNPACK(va.va_flags); 2439 VATTR_SET_ACTIVE(&va, va_flags); 2440 } 2441 if (al.commonattr & ATTR_CMN_EXTENDED_SECURITY) { 2442 2443 /* 2444 * We are (for now) passed a kauth_filesec_t, but all we want from 2445 * it is the ACL. 2446 */ 2447 cp = cursor; 2448 ATTR_UNPACK(ar); 2449 if (ar.attr_dataoffset < 0) { 2450 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: bad offset supplied", ar.attr_dataoffset); 2451 error = EINVAL; 2452 goto out; 2453 } 2454 2455 cp += ar.attr_dataoffset; 2456 rfsec = (kauth_filesec_t)cp; 2457 if (((((char *)rfsec) + KAUTH_FILESEC_SIZE(0)) > bufend) || /* no space for acl */ 2458 (rfsec->fsec_magic != KAUTH_FILESEC_MAGIC) || /* bad magic */ 2459 (KAUTH_FILESEC_COPYSIZE(rfsec) != ar.attr_length) || /* size does not match */ 2460 ((cp + KAUTH_FILESEC_COPYSIZE(rfsec)) > bufend)) { /* ACEs overrun buffer */ 2461 error = EINVAL; 2462 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: bad ACL supplied", ar.attr_length); 2463 goto out; 2464 } 2465 nace = rfsec->fsec_entrycount; 2466 if (nace == KAUTH_FILESEC_NOACL) 2467 nace = 0; 2468 if (nace > KAUTH_ACL_MAX_ENTRIES) { /* ACL size invalid */ 2469 error = EINVAL; 2470 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: bad ACL supplied"); 2471 goto out; 2472 } 2473 nace = rfsec->fsec_acl.acl_entrycount; 2474 if (nace == KAUTH_FILESEC_NOACL) { 2475 /* deleting ACL */ 2476 VATTR_SET(&va, va_acl, NULL); 2477 } else { 2478 2479 if (nace > KAUTH_ACL_MAX_ENTRIES) { /* ACL size invalid */ 2480 error = EINVAL; 2481 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: supplied ACL is too large"); 2482 goto out; 2483 } 2484 VATTR_SET(&va, va_acl, &rfsec->fsec_acl); 2485 } 2486 } 2487 if (al.commonattr & ATTR_CMN_UUID) { 2488 ATTR_UNPACK(va.va_uuuid); 2489 VATTR_SET_ACTIVE(&va, va_uuuid); 2490 } 2491 if (al.commonattr & ATTR_CMN_GRPUUID) { 2492 ATTR_UNPACK(va.va_guuid); 2493 VATTR_SET_ACTIVE(&va, va_guuid); 2494 } 2495 2496 /* volume */ 2497 if (al.volattr & ATTR_VOL_INFO) { 2498 if (al.volattr & ATTR_VOL_NAME) { 2499 volname = cursor; 2500 ATTR_UNPACK(ar); 2501 /* attr_length cannot be 0! */ 2502 if ((ar.attr_dataoffset < 0) || (ar.attr_length == 0)) { 2503 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: bad offset supplied (2) ", ar.attr_dataoffset); 2504 error = EINVAL; 2505 goto out; 2506 } 2507 2508 volname += ar.attr_dataoffset; 2509 if ((volname + ar.attr_length) > bufend) { 2510 error = EINVAL; 2511 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: volume name too big for caller buffer"); 2512 goto out; 2513 } 2514 /* guarantee NUL termination */ 2515 volname[ar.attr_length - 1] = 0; 2516 } 2517 } 2518 2519 /* file */ 2520 if (al.fileattr & ATTR_FILE_DEVTYPE) { 2521 /* XXX does it actually make any sense to change this? */ 2522 error = EINVAL; 2523 VFS_DEBUG(ctx, vp, "ATTRLIST - XXX device type change not implemented"); 2524 goto out; 2525 } 2526 2527 /* 2528 * Validate and authorize. 2529 */ 2530 action = 0; 2531 if ((va.va_active != 0LL) && ((error = vnode_authattr(vp, &va, &action, ctx)) != 0)) { 2532 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: attribute changes refused: %d", error); 2533 goto out; 2534 } 2535 /* 2536 * We can auth file Finder Info here. HFS volume FinderInfo is really boot data, 2537 * and will be auth'ed by the FS. 2538 */ 2539 if (fndrinfo != NULL) { 2540 if (al.volattr & ATTR_VOL_INFO) { 2541 if (vp->v_tag != VT_HFS) { 2542 error = EINVAL; 2543 goto out; 2544 } 2545 } else { 2546 action |= KAUTH_VNODE_WRITE_EXTATTRIBUTES; 2547 } 2548 } 2549 2550 if ((action != 0) && ((error = vnode_authorize(vp, NULL, action, ctx)) != 0)) { 2551 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: authorization failed"); 2552 goto out; 2553 } 2554 2555 /* 2556 * When we're setting both the access mask and the finder info, then 2557 * check if were about to remove write access for the owner. Since 2558 * vnode_setattr and vn_setxattr invoke two separate vnops, we need 2559 * to consider their ordering. 2560 * 2561 * If were about to remove write access for the owner we'll set the 2562 * Finder Info here before vnode_setattr. Otherwise we'll set it 2563 * after vnode_setattr since it may be adding owner write access. 2564 */ 2565 if ((fndrinfo != NULL) && !(al.volattr & ATTR_VOL_INFO) && 2566 (al.commonattr & ATTR_CMN_ACCESSMASK) && !(va.va_mode & S_IWUSR)) { 2567 if ((error = setattrlist_setfinderinfo(vp, fndrinfo, ctx)) != 0) { 2568 goto out; 2569 } 2570 fndrinfo = NULL; /* it was set here so skip setting below */ 2571 } 2572 2573 /* 2574 * Write the attributes if we have any. 2575 */ 2576 if ((va.va_active != 0LL) && ((error = vnode_setattr(vp, &va, ctx)) != 0)) { 2577 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: filesystem returned %d", error); 2578 goto out; 2579 } 2580 2581 /* 2582 * Write the Finder Info if we have any. 2583 */ 2584 if (fndrinfo != NULL) { 2585 if (al.volattr & ATTR_VOL_INFO) { 2586 if (vp->v_tag == VT_HFS) { 2587 error = VNOP_IOCTL(vp, HFS_SET_BOOT_INFO, (caddr_t)fndrinfo, 0, ctx); 2588 if (error != 0) 2589 goto out; 2590 } else { 2591 /* XXX should never get here */ 2592 } 2593 } else if ((error = setattrlist_setfinderinfo(vp, fndrinfo, ctx)) != 0) { 2594 goto out; 2595 } 2596 } 2597 2598 /* 2599 * Set the volume name, if we have one 2600 */ 2601 if (volname != NULL) 2602 { 2603 struct vfs_attr vs; 2604 2605 VFSATTR_INIT(&vs); 2606 2607 vs.f_vol_name = volname; /* References the setattrlist buffer directly */ 2608 VFSATTR_WANTED(&vs, f_vol_name); 2609 2610#if CONFIG_MACF 2611 error = mac_mount_check_setattr(ctx, vp->v_mount, &vs); 2612 if (error != 0) 2613 goto out; 2614#endif 2615 2616 if ((error = vfs_setattr(vp->v_mount, &vs, ctx)) != 0) { 2617 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: setting volume name failed"); 2618 goto out; 2619 } 2620 2621 if (!VFSATTR_ALL_SUPPORTED(&vs)) { 2622 error = EINVAL; 2623 VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: could not set volume name"); 2624 goto out; 2625 } 2626 } 2627 2628 /* all done and successful */ 2629 2630out: 2631 if (user_buf != NULL) 2632 FREE(user_buf, M_TEMP); 2633 VFS_DEBUG(ctx, vp, "ATTRLIST - set returning %d", error); 2634 return(error); 2635} 2636 2637int 2638setattrlist(proc_t p, struct setattrlist_args *uap, __unused int32_t *retval) 2639{ 2640 struct vfs_context *ctx; 2641 struct nameidata nd; 2642 vnode_t vp = NULL; 2643 u_long nameiflags; 2644 int error = 0; 2645 2646 ctx = vfs_context_current(); 2647 2648 /* 2649 * Look up the file. 2650 */ 2651 nameiflags = AUDITVNPATH1; 2652 if ((uap->options & FSOPT_NOFOLLOW) == 0) 2653 nameiflags |= FOLLOW; 2654 NDINIT(&nd, LOOKUP, OP_SETATTR, nameiflags, UIO_USERSPACE, uap->path, ctx); 2655 if ((error = namei(&nd)) != 0) 2656 goto out; 2657 vp = nd.ni_vp; 2658 nameidone(&nd); 2659 2660 error = setattrlist_internal(vp, uap, p, ctx); 2661out: 2662 if (vp != NULL) 2663 vnode_put(vp); 2664 return error; 2665} 2666 2667int 2668fsetattrlist(proc_t p, struct fsetattrlist_args *uap, __unused int32_t *retval) 2669{ 2670 struct vfs_context *ctx; 2671 vnode_t vp = NULL; 2672 int error; 2673 struct setattrlist_args ap; 2674 2675 ctx = vfs_context_current(); 2676 2677 if ((error = file_vnode(uap->fd, &vp)) != 0) 2678 return (error); 2679 2680 if ((error = vnode_getwithref(vp)) != 0) { 2681 file_drop(uap->fd); 2682 return(error); 2683 } 2684 2685 ap.path = 0; 2686 ap.alist = uap->alist; 2687 ap.attributeBuffer = uap->attributeBuffer; 2688 ap.bufferSize = uap->bufferSize; 2689 ap.options = uap->options; 2690 2691 error = setattrlist_internal(vp, &ap, p, ctx); 2692 file_drop(uap->fd); 2693 if (vp != NULL) 2694 vnode_put(vp); 2695 2696 return error; 2697} 2698 2699