Files and Storage

RSS for tag

Ask questions about file systems and block storage.

Posts under Files and Storage tag

200 Posts

Post

Replies

Boosts

Views

Activity

On File System Permissions
Modern versions of macOS use a file system permission model that’s far more complex than the traditional BSD rwx model, and this post is my attempt at explaining that model. If you have a question about this, post it here on DevForums. Put your thread in the App & System Services > Core OS topic area and tag it with Files and Storage. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" On File System Permissions Modern versions of macOS have five different file system permission mechanisms: Traditional BSD permissions Access control lists (ACLs) App Sandbox Mandatory access control (MAC) Endpoint Security (ES) The first two were introduced a long time ago and rarely trip folks up. The second two are newer, more complex, and specific to macOS, and thus are the source of some confusion. Finally, Endpoint Security allows third-party developers to deny file system operations based on their own criteria. This post offers explanations and advice about all of these mechanisms. Error Codes App Sandbox and the mandatory access control system are both implemented using macOS’s sandboxing infrastructure. When a file system operation fails, check the error to see whether it was blocked by this sandboxing infrastructure. If an operation was blocked by BSD permissions or ACLs, it fails with EACCES (Permission denied, 13). If it was blocked by something else, it’ll fail with EPERM (Operation not permitted, 1). If you’re using Foundation’s FileManager, these error are both reported as Foundation errors, for example, the NSFileReadNoPermissionError error. To recover the underlying error, get the NSUnderlyingErrorKey property from the info dictionary. App Sandbox File system access within the App Sandbox is controlled by two factors. The first is the entitlements on the main executable. There are three relevant groups of entitlements: The com.apple.security.app-sandbox entitlement enables the App Sandbox. This denies access to all file system locations except those on a built-in allowlist (things like /System) or within the app’s containers. The various “standard location” entitlements extend the sandbox to include their corresponding locations. The various “file access temporary exceptions” entitlements extend the sandbox to include the items listed in the entitlement. Collectively this is known as your static sandbox. The second factor is dynamic sandbox extensions. The system issues these extensions to your sandbox based on user behaviour. For example, if the user selects a file in the open panel, the system issues a sandbox extension to your process so that it can access that file. The type of extension is determined by the main executable’s entitlements: com.apple.security.files.user-selected.read-only results in an extension that grants read-only access. com.apple.security.files.user-selected.read-write results in an extension that grants read/write access. Note There’s currently no way to get a dynamic sandbox extension that grants executable access. For all the gory details, see this post. These dynamic sandbox extensions are tied to your process; they go away when your process terminates. To maintain persistent access to an item, use a security-scoped bookmark. See Accessing files from the macOS App Sandbox. To pass access between processes, use an implicit security scoped bookmark, that is, a bookmark that was created without an explicit security scope (no .withSecurityScope flag) and without disabling the implicit security scope (no .withoutImplicitSecurityScope flag)). If you have access to a directory — regardless of whether that’s via an entitlement or a dynamic sandbox extension — then, in general, you have access to all items in the hierarchy rooted at that directory. This does not overrule the MAC protection discussed below. For example, if the user grants you access to ~/Library, that does not give you access to ~/Library/Mail because the latter is protected by MAC. Finally, the discussion above is focused on a new sandbox, the thing you get when you launch a sandboxed app from the Finder. If a sandboxed process starts a child process, that child process inherits its sandbox from its parent. For information on what happens in that case, see the Note box in Enabling App Sandbox Inheritance. IMPORTANT The child process inherits its parent process’s sandbox regardless of whether it has the com.apple.security.inherit entitlement. That entitlement exists primarily to act as a marker for App Review. App Review requires that all main executables have the com.apple.security.app-sandbox entitlement, and that entitlements starts a new sandbox by default. Thus, any helper tool inside your app needs the com.apple.security.inherit entitlement to trigger inheritance. However, if you’re not shipping on the Mac App Store you can leave off both of these entitlement and the helper process will inherit its parent’s sandbox just fine. The same applies if you run a built-in executable, like /bin/sh, as a child process. When the App Sandbox blocks something, it might generates a sandbox violation report. For information on how to view these reports, see Discovering and diagnosing App Sandbox violations. To learn more about the App Sandbox, see the various links in App Sandbox Resources. For information about how to embed a helper tool in a sandboxed app, see Embedding a Command-Line Tool in a Sandboxed App. Mandatory Access Control Mandatory access control (MAC) has been a feature of macOS for many releases, but it’s become a lot more prominent since macOS 10.14. There are many flavours of MAC but the ones you’re most likely to encounter are: Full Disk Access (macOS 10.14 and later) Files and Folders (macOS 10.15 and later) App bundle protection (macOS 13 and later) App container protection (macOS 14 and later) App group container protection (macOS 15 and later) Data Vaults (see below) and other internal techniques used by various macOS subsystems Mandatory access control, as the name suggests, is mandatory; it’s not an opt-in like the App Sandbox. Rather, all processes on the system, including those running as root, as subject to MAC. Data Vaults are not a third-party developer opportunity. See this post if you’re curious. In the Full Disk Access and Files and Folders cases, users grant a program a MAC privilege using System Settings > Privacy & Security. Some MAC privileges are per user (Files and Folders) and some are system wide (Full Disk Access). If you’re not sure, run this simple test: On a Mac with two users, log in as user A and enable the MAC privilege for a program. Now log in as user B. Does the program have the privilege? If a process tries to access an item restricted by MAC, the system may prompt the user to grant it access there and then. For example, if an app tries to access the desktop, you’ll see an alert like this: “AAA” would like to access files in your Desktop folder. [Don’t Allow] [OK] To customise this message, set Files and Folders properties in your Info.plist. This system only displays this alert once. It remembers the user’s initial choice and returns the same result thereafter. This relies on your code having a stable code signing identity. If your code is unsigned, or signed ad hoc (Signed to Run Locally in Xcode parlance), the system can’t tell that version N+1 of your code is the same as version N, and thus you’ll encounter excessive prompts. Note For information about how that works, see TN3127 Inside Code Signing: Requirements. The Files and Folders prompts only show up if the process is running in a GUI login session. If not, the operation is allowed or denied based on existing information. If there’s no existing information, the operation is denied by default. For more information about app and app group container protection, see the links in Trusted Execution Resources. For more information about app groups in general, see App Groups: macOS vs iOS: Working Towards Harmony On managed systems the site admin can use the com.apple.TCC.configuration-profile-policy payload to assign MAC privileges. For testing purposes you can reset parts of TCC using the tccutil command-line tool. For general information about that tool, see its man page. For a list of TCC service names, see the posts on this thread. Note TCC stands for transparency, consent, and control. It’s the subsystem within macOS that manages most of the privileges visible in System Settings > Privacy & Security. TCC has no API surface, but you see its name in various places, including the above-mentioned configuration profile payload and command-line tool, and the name of its accompanying daemon, tccd. While tccutil is an easy way to do basic TCC testing, the most reliable way to test TCC is in a VM, restoring to a fresh snapshot between each test. If you want to try this out, crib ideas from Testing a Notarised Product. The MAC privilege mechanism is heavily dependent on the concept of responsible code. For example, if an app contains a helper tool and the helper tool triggers a MAC prompt, we want: The app’s name and usage description to appear in the alert. The user’s decision to be recorded for the whole app, not that specific helper tool. That decision to show up in System Settings under the app’s name. For this to work the system must be able to tell that the app is the responsible code for the helper tool. The system has various heuristics to determine this and it works reasonably well in most cases. However, it’s possible to break this link. I haven’t fully research this but my experience is that this most often breaks when the child process does something ‘odd’ to break the link, such as trying to daemonise itself. If you’re building a launchd daemon or agent and you find that it’s not correctly attributed to your app, add the AssociatedBundleIdentifiers property to your launchd property list. See the launchd.plist man page for the details. Scripting MAC presents some serious challenges for scripting because scripts are run by interpreters and the system can’t distinguish file system operations done by the interpreter from those done by the script. For example, if you have a script that needs to manipulate files on your desktop, you wouldn’t want to give the interpreter that privilege because then any script could do that. The easiest solution to this problem is to package your script as a standalone program that MAC can use for its tracking. This may be easy or hard depending on the specific scripting environment. For example, AppleScript makes it easy to export a script as a signed app, but that’s not true for shell scripts. TCC and Main Executables TCC expects its bundled clients — apps, app extensions, and so on — to use a native main executable. That is, it expects the CFBundleExecutable property to be the name of a Mach-O executable. If your product uses a script as its main executable, you’re likely to encounter TCC problems. To resolve these, switch to using a Mach-O executable. For an example of how you might do that, see this post. Endpoint Security Endpoint Security (ES) is a general mechanism for third-party products to enforce custom security policies on the Mac. An ES client asks ES to send it events when specific security-relevant operations occur. These events can be notifications or authorisations. In the case of authorisation events, the ES client must either allow or deny the operation. As you might imagine, the set of security-relevant operations includes file system operations. For example, when you open a file using the open system call, ES delivers the ES_EVENT_TYPE_AUTH_OPEN event to any interested ES clients. If one of those ES client denies the operation, the open system call fails with EPERM. For more information about ES, see the Endpoint Security framework documentation. Revision History 2025-11-04 Added a discussion of Endpoint Security. Made numerous minor editorial changes. 2024-11-08 Added info about app group container protection. Clarified that Data Vaults are just one example of the techniques used internally by macOS. Made other editorial changes. 2023-06-13 Replaced two obsolete links with links to shiny new official documentation: Accessing files from the macOS App Sandbox and Discovering and diagnosing App Sandbox violations. Added a short discussion of app container protection and a link to WWDC 2023 Session 10053 What’s new in privacy. 2023-04-07 Added a link to my post about executable permissions. Fixed a broken link. 2023-02-10 In TCC and Main Executables, added a link to my native trampoline code. Introduced the concept of an implicit security scoped bookmark. Introduced AssociatedBundleIdentifiers. Made other minor editorial changes. 2022-04-26 Added an explanation of the TCC initialism. Added a link to Viewing Sandbox Violation Reports.  Added the TCC and Main Executables section. Made significant editorial changes. 2022-01-10 Added a discussion of the file system hierarchy. 2021-04-26 First posted.
0
0
13k
Nov ’25
Files and Storage Resources
General: Forums subtopic: App & System Services > Core OS Forums tags: Files and Storage, Foundation, FSKit, File Provider, Finder Sync, Disk Arbitration, APFS Foundation > Files and Data Persistence documentation Low-level file system APIs are documented in UNIX manual pages File System Programming Guide archived documentation About Apple File System documentation Apple File System Guide archived documentation File system changes introduced in iOS 17 forums post On File System Permissions forums post Extended Attributes and Zip Archives forums post Unpacking Apple Archives forums post Creating new file systems: FSKit framework documentation Building a passthrough file system sample code File Provider framework documentation Finder Sync framework documentation App Extension Programming Guide > App Extension Types > Finder Sync archived documentation Managing storage: Disk Arbitration framework documentation Disk Arbitration Programming Guide archived documentation Mass Storage Device Driver Programming Guide archived documentation Device File Access Guide for Storage Devices archived documentation BlockStorageDeviceDriverKit framework documentation Volume format references: Apple File System Reference TN1150 HFS Plus Volume Format Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
0
0
2.9k
Feb ’26
BlockStorageDeviceDriverKit grant confirmed by support but shows "No Requests" in the portal. How to resolve?
Hello! I am hoping a DTS engineer or someone who knows the Capability Requests portal can help, because I am stuck between a written support confirmation and what the portal actually shows. Background. We are building a native macOS iSCSI initiator for SOHO and home NAS use, developed over close to two years. A userspace daemon runs the iSCSI protocol and a DriverKit system extension presents the remote LUN as a block device. The code is essentially complete. Only the DriverKit extension cannot be signed, loaded and validated without the entitlement. We submitted request 32PC8MGU57 for two entitlements: com.apple.developer.driverkit.family.block-storage-device for the extension com.aviontex.iscsi.AviontexISCSI.AviontexInitiator com.apple.developer.driverkit.userclient-access for the app com.aviontex.iscsi.AviontexISCSI, scoped to the extension bundle id The problem. On June 25 Developer Support confirmed in writing that both entitlements were granted. The portal does not match that: Block Storage Device: No Requests: on both App IDs UserClient Access: Assigned: on the app SCSI Controller: Submitted: on the app So the one entitlement we actually need, Block Storage Device, shows as never requested, even though request 32PC8MGU57 covered it and support confirmed the grant. The case was escalated to the senior team on July 2 (case 102922935570). Follow-up emails since then have not received a response. Why Block Storage Device specifically Our initiator has no PCI or Thunderbolt bus and no DMA path, so SCSIControllerDriverKit does not fit. This is confirmed by DTS in thread 776020, where Kevin Elliott explains that SCSIControllerDriverKit passes data through fBufferIOVMAddr as a physical address with no mechanism to convert it into a VM address the dext can access. He also notes it cannot be used with any bus other than PCI or Thunderbolt. Block Storage Device is therefore the family we need. My questions: Am I reading the portal correctly: Block Storage Device not requested, UserClient Access assigned, SCSI Controller submitted? From here, what is the correct way to get Block Storage Device onto these two App IDs, with both the Development and the Distribution grant, since our public beta depends on Distribution? Should I submit a new request through the Capability Requests tab or does the escalated case handle it? Is there any way to get visibility on the escalated case, since email follow-ups are not being answered? A full technical justification is prepared and we are happy to share the source code. Any guidance would be appreciated. Thank you.
34
1
6.8k
16h
Drag and Drop stopped working after upgrading from macOS 15 to 26
When I drag and drop a file with flag "shouldAttemptToOpenInPlace: true", I was able to access the original file name in macOS 15. After upgrading to macOS 26, I can't access the original file name anymore. Instead, I got some useless file name such as ".com.apple.Foundation.NSItemProvider.gKZ91u.tmp". The app no longer works with these tmp filenames because it needs the orignal file name to do the file transfer. (Btw, this is a WinSCP like app on Mac platform) Could you please check and fix this issue? Thank you. FileRepresentation(contentType: .item, shouldAttemptToOpenInPlace: true)
5
0
968
16h
smbfs silently zero-fills already-written data after cached file size regresses on reopen
Hello everyone, I've been chasing a nasty silent data corruption bug in the macOS SMB client (smbfs.kext) and wanted to share what I found, in case someone else has hit it and in the hope that someone from the SMB team sees it. What happens Under concurrent writes with repeated reopens, the client can regress its cached file size (np->n_size) to an earlier, smaller value - behind data it has already written and flushed to the server. The next write then treats the already-written range as a hole, zero-fills it via IO_HEADZEROFILL, and sends the zeros to the server, right on top of the correct bytes it transmitted moments earlier. No write(2) fails and nothing is logged - the file just quietly comes back with a chunk-aligned run of zeros in the middle, at the correct overall length. Environment macOS 26.5 (Darwin 25.5.0), Apple silicon (16 KiB VM pages), SMB 2.1 Sources referenced: SMB client 538.121.1, xnu 12377.121.6 How to reproduce Mount an SMB 2.1(2.0.2 has the same issue as well) share. Have several threads write the same files in 8 KiB chunks, each chunk via its own open/lseek/write/close (so the file is reopened constantly as it fills), while the files are concurrently resolved by name (stat / directory enumeration). Read the files back through a cache-cold path (second mount, or F_NOCACHE) and compare. Roughly 1 file in several hundred came back corrupted for me. The core of the write pattern: CHUNK = 8192 # 2 chunks per 16 KiB page def write_chunk(path, data, offset): fd = os.open(path, os.O_CREAT | os.O_RDWR) # own handle per chunk try: os.lseek(fd, offset, os.SEEK_SET) os.write(fd, data) finally: os.close(fd) # per file: content = os.urandom(random.randint(265000, 300000)); # chunks written in batches of 8 threads, joined between batches; # each file written twice from the same buffer: NAME, then NAME.copy In my runs the corruption always landed on the second (.copy) write. One caveat: I reproduced this against a third-party SMB server, not against macOS File Sharing (smbd), and I don't expect it to reproduce against smbd directly. The stale size arrives via reopen-via-lookup (smbfs_update_size <- smbfs_nget <- smbfs_vnop_lookup) on a freshly instantiated vnode, whose n_sizetime lets the freshness guard pass. smbd instead reopens via vnop_compound_open -> smbfs_attr_cacheenter (warm vnode; the guard rejects it) - the same stale-size candidates occur, they just all get rejected. The server merely steers the client onto the vulnerable path; the bug itself is entirely client-side. What I observed I captured the kernel side with dtrace fbt probes on smbfs_setsize() / smbfs_update_size() (os_log drops events under this load). Timeline for one corrupted file, correlating pcap and dtrace (dtrace has whole-second resolution, marked ".x"): [pcap] = network packet capture of the SMB traffic between client and server [dtrace] = kernel-side trace of the smbfs size-update functions; timestamps only have whole-second resolution, so ".x" marks an unknown sub-second time :39.778 [pcap] — client sends WRITE off=32768 len=32768 with the correct data, covering [40960:65536). :39.777–.860 [pcap] — throughout, the server's CREATE/CLOSE responses report a strictly monotonic EOF: 0, 8192, 40960, 65536, ... 288255. :39.x [dtrace] — on a reopen, smbfs_update_size applies EOF 40960 (a superseded value), regressing n_size from 65536 to 40960. :39.x [dtrace] — the next write starts past the regressed size, so zero_head_off = 40960 and IO_HEADZEROFILL is set. :39.804 [pcap] — client sends WRITE off=32768 len=57344, ALL ZEROS over [40960:65536), on top of the correct data it sent 26 ms earlier. End result: the file is 288255 bytes (correct length) with 24 KiB of zeros at [40960:65536) - three consecutive 8 KiB chunks, i.e. 1.5 x 16 KiB VM pages. Worth stressing: the server's own responses reported a strictly monotonic EOF the whole time, so the regression to 40960 was purely the client applying a superseded value. Expected, obviously: the file reads back byte-for-byte identical to what was written. Where I think the bug is From reading the smbfs and xnu sources, three things combine: np->n_size isn't consistently synchronized - read under the node lock only (smbfs_vnops.c:7329/7387/7391) but written under f_clusterWriteLock (:7411) and by smbfs_vnop_strategy under the cluster lock, so the reader deciding the zero-fill has no ordering guarantee. Possible fix: read it once under f_clusterWriteLock in smbfs_vnop_write so the snapshot, extend, and zero_head_off stay consistent. The freshness guard checks the wrong thing - smbfs_update_size's reqtime <= n_sizetime guard validates the reply's request time, not whether the value is still current, so a superseded (smaller) size applied later still passes and calls smbfs_setsize(smaller). Possible fix: never shrink n_size from fa_size while the vnode has dirty pages or in-flight writes beyond that size. The zero-fill is destructive - zero_head_off = np->n_size (smbfs_vnops.c:7391) feeds IO_HEADZEROFILL, and cluster_write zeros [n_size, uio_offset) without checking whether the UBC already holds those pages as valid/dirty (vfs_cluster.c), then flushes the zeros to the server. A defensive check there would neutralize the corruption regardless of cause. Has anyone else seen silent zero-runs in files written over SMB under concurrent access? Thanks!
4
0
403
21h
Extremely long names in df output
I am not sure if it's from Xcode or macOS 27, but here is what I get after running df: /dev/disk3s3 228Gi 1.5Gi 15Gi 9% 112 161M 0% /Volumes/Recovery devices -- file:///Users/USER/Library/Containers/com.apple.CoreDevice.CoreDeviceService/Data/ 1.0Ti 0Bi 1.0Ti 0% 0 9.2E 0% /Users/USER/Library/Developer/CoreDevice/DeviceFS It's really annoying. Is there any way to remove this?
1
0
240
1d
Kernel Sandbox/System Policy intermittently denies ALL file access (not just mount syscall) on NFS mounts
I'm seeing a recurring issue on macOS 26.5.2 (build 25F84) where the kernel's Sandbox/System Policy layer intermittently denies file access on NFS mount points from local network servers. Posting here in case anyone recognizes this pattern or has a workaround, and flagging it since I've also filed a Feedback Assistant report (with a live-captured sysdiagnose) for the same issue. WHAT HAPPENS Two independent NFS mounts to two separate, unrelated servers on my LAN start failing simultaneously with "Operation not permitted." The kernel log shows: kernel: (Sandbox) System Policy: mount_nfs(PID) deny(1) file-mount /path/to/mount Critically, it's not limited to the mount syscall - within the same few-second window, System Policy also denies ls, perl, diskutil, and even umount -f on the exact same path, for otherwise unrelated processes. So it looks like a transient, path-scoped kernel decision rather than something specific to NFS or the mount syscall. It self-heals anywhere from seconds to ~30 minutes later, then recurs - documented 30-80+ occurrences/day via a background watchdog script. WHAT I'VE RULED OUT Server-side cause: two independent servers on different hardware fail identically at the same instant. Network issue: checked network logs in the same window, no correlated connectivity event. Third-party kext conflict: kextstat shows zero third-party kexts loaded. syspolicyd database corruption: no "ASP: Validation category" signature present. TCC/Full Disk Access: already granted; the denying layer is kernel Sandbox "System Policy," not TCC. QUESTION Has anyone else run into System Policy denying file-mount/file-read-data/file-unmount on network volume paths intermittently like this? Is there any userland way to inspect or reset whatever internal state drives this decision (I haven't found one - no spctl/tccutil/sysctl lever that touches it)? Happy to share more log excerpts if useful.
21
0
1.7k
1d
iOS restore ordering for an open Application Support SQLite file
I am trying to understand one supported iOS lifecycle guarantee. Consider a generic app that stores a single SQLite database in its private Library/Application Support directory and keeps one SQLite connection open while its process is alive. During a supported platform operation such as iCloud restore that continues after setup, Finder or Apple Devices restore, Quick Start direct transfer, Quick Start using iCloud, reinstall or offload recovery, or an app update, can the app become or remain running, background executing, or suspended while iOS restores, replaces, or rebinds its data container or a file within it? More specifically, can an existing open file descriptor or SQLite connection continue to reference an old filesystem object while a later lookup of the same Application Support path resolves to a restored or replacement object? If iOS does not permit that condition, what supported lifecycle invariant prevents it? For example, does iOS terminate the app before restored data becomes visible, gate launch until the complete per-app restored container is finalized, or keep the container binding stable for the lifetime of the process? If the behavior differs by mechanism, please distinguish iCloud restore after setup, Finder or Apple Devices restore, Quick Start direct transfer, Quick Start using iCloud, reinstall or offload recovery, and app update. • Does the platform's restore ordering depend on SQLite locks? • Does NSFileCoordinator participate when platform services restore private Application Support files? • Is there Apple documentation or an Apple-staff explanation that defines this ordering, including supported versions, conditions, or exceptions? The POSIX issue is that an open descriptor may continue to reference an old object after pathname replacement while a new lookup reaches a different object. SQLite also documents risks when an open database file is renamed or unlinked. I am not treating a raw rename or unlink test as equivalent to an Apple restore. I am explicitly excluding arbitrary unlink, rename, overwrite, or other direct same-container filesystem attacks. My question is only whether Apple's supported restore and container services can create an equivalent old-open-object versus newly-resolved-path condition while the same app process survives.
2
0
303
1d
MacPad Mobile – looking for TestFlight testers for Files and iCloud performance
Hello everyone, I’m a small/private developer working on MacPad Mobile, a native plain-text editor for iPhone and iPad. It edits files directly through Apple’s Files interface and requires no account or sign-in. I’m looking for a small number of TestFlight volunteers to help investigate an occasional performance issue. On some devices, the first folder transitions and the first opening of an iCloud Drive file can be noticeably slower than subsequent attempts. If you have approximately 5–10 minutes, I would particularly appreciate results from older iPhones, recent iPhones, and iPads. Suggested test: Leave the app unused for a while before beginning. Open a disposable plain-text file from iCloud Drive. Note whether navigating the first few folders feels slow. Note the delay between selecting the file and seeing its text. Repeat the same route and report whether it becomes faster. If possible, compare it with a file stored under “On My iPhone” or “On My iPad.” Please use disposable test files and avoid including private filenames, document contents, account details, or personal folder information in screenshots or feedback. Feedback can be submitted directly through TestFlight. Including the device model, iOS/iPadOS version, storage location, and whether the first and repeat attempts differed would be especially helpful. TestFlight link: https://testflight.apple.com/join/GhDzjNmj I know many people here have considerably more experience with Apple-platform development, so I’m also grateful for any advice about measuring Files-provider and iCloud latency correctly. I'm not very sure to do that everything correct. Thank you for your time and for any help you’re willing to provide. Best regards Frank
0
0
326
3d
Sanboxed Apps Reading Extended Security Information (ACL)
My custom filesystem kernel extension stores ACLs as an extended attribute, com.apple.system.Security. Sanboxed apps such as TextEdit, Pages, etc., running as a non-privileged process, fail to save modified contents when permissive ACLs are in use. Running them as a privileged process, does allow for file changes to be saved though. Non-sandboxed apps, such as VSCode, and command line programs are not susceptible to this behaviour. APFS, on the other hand, seems to handle ACLs as an ATTR_CMN_EXTENDED_SECURITY filesystem attribute, rather than as an EA. In this case, sandboxed apps have no trouble accessing the ACL data. I implemented a minimal PoC within my custom kext to verify this. I construct an ACL in memory allowing a given user to write,append,delete file contents, and return it that via vnop_getattr. This allows the file contents to be modified and saved by sandboxed apps. Can you please confirm if my findings are accurate and sandboxed apps fail to read the com.apple.system.Security EA by design? Also, Is it an accurate assumption, that ACLs should be handled either as an EA, or an ATTR_CMN_EXTENDED_SECURITY, but not both? Thanks.
10
0
758
4d
macOS Tahoe appears to ignore /etc/fstab ro and noauto — findings and workaround
macOS Tahoe appears to ignore /etc/fstab ro and noauto — findings and workaround I encountered what appears to be a regression in macOS Tahoe where Disk Arbitration no longer honors ro and noauto policies in /etc/fstab for external volumes. I am posting my findings here both to see whether others can reproduce the issue and to document a workaround, particularly for anyone using macOS for disk recovery or other workflows where preventing writes is important. The problem A configuration such as: UUID= none exfat noauto does not prevent the volume from automatically mounting. Similarly: UUID= none exfat ro does not result in a read-only mount. I also tested: UUID= none exfat ro,noauto with the same problem. This configuration worked for me before upgrading from macOS Sequoia to Tahoe. I initially suspected this might be related to Tahoe's newer exFAT/FSKit path, but testing APFS produced the same general behavior. It therefore appears to be broader than exFAT alone. /etc/fstab itself is being parsed correctly I tested the libc fstab interface using getfsent(). For example, an entry containing noauto is returned as: spec=UUID= | file=none | vfstype=exfat | mntops=noauto | type=rw So this does not appear to be a simple malformed-fstab problem. Tracing also shows diskarbitrationd accessing /etc/fstab. What Disk Arbitration is doing Unified logs from an affected exFAT mount show the filesystem being successfully probed, followed by Disk Arbitration mount approval callbacks. After approval, the reported mount options are: Mount options nodev,noowners,nosuid and the volume is then mounted successfully. The ro policy expected from /etc/fstab is notably absent from those mount options. Direct read-only mounting still works The filesystem itself is capable of being mounted read-only. For example, for exFAT: sudo mkdir -p /Volumes/Exchange sudo mount_exfat -o rdonly /dev/diskXsY /Volumes/Exchange This produces a genuinely read-only filesystem; a write test fails as expected. So at least in my testing, the problem appears to be associated with the normal Disk Arbitration mounting path rather than an inability of the filesystem to support read-only mounting. A working noauto workaround Disk Arbitration still supports mount approval callbacks. I tested a small client using: DAApprovalSessionCreate DARegisterDiskMountApprovalCallback DADissenterCreate The callback checks the volume UUID against /etc/fstab. If the corresponding entry contains noauto, it returns: kDAReturnNotPermitted This successfully prevents the volume from mounting. The test output looks like: [BLOCK] mount request: /dev/disk5s1 [BLOCK] mount request: /dev/disk5s2 The volume remains unmounted. Interestingly, this also blocks: diskutil mount /dev/diskXsY because diskutil mount goes through Disk Arbitration. A direct filesystem mount such as mount_exfat, however, bypasses that approval request and can still be used to deliberately mount the filesystem read-only. Why this matters For an ordinary external disk, an unexpected automount may only be annoying. For data recovery, forensic inspection, or a failing disk, the difference can be important. If /etc/fstab says: ro I expect that policy to protect the source filesystem from writes. Silently mounting the filesystem read-write instead means that the volume becomes available to Finder and other background services. That is exactly what I am trying to avoid when working with a recovery source. For this reason, I would recommend verifying the actual mount state rather than assuming that an existing /etc/fstab ro entry is still protecting a disk after upgrading to Tahoe. For example: mount or: diskutil info /dev/diskXsY should be used to confirm the resulting state. Current workaround design I am currently using a small compatibility helper that treats /etc/fstab as the source of truth: /etc/fstab ↓ compatibility helper ↓ Disk Arbitration mount approval The daemon side handles mount policy before Disk Arbitration can automatically mount the volume. An explicit mount helper can then perform a direct filesystem mount with the options specified in /etc/fstab, including read-only mounting where required. The intention is not to replace /etc/fstab, but to restore the behavior that was previously provided by the system. Reproduction request If anyone else is running macOS Tahoe, I would be interested to know whether you can reproduce this with either: UUID= none apfs noauto or: UUID= none exfat noauto and similarly with ro. Please be careful when testing ro: use a disposable/test volume rather than a disk whose contents actually depend on remaining read-only. I have also submitted this to Apple through Feedback Assistant. Feedback ID: 24677522 I will update this post if Apple provides additional information or if a later Tahoe update changes the behavior.
0
0
125
1w
Quick Look no longer invokes third-party Markdown preview extensions on iOS 27
Hi all! I am seeing the following problem while developing a Quick Look extension to preview Markdown files on iOS and macOS: On iOS 26, Quick Look invokes an installed data-based Quick Look preview extension for .md files resolved as net.daringfireball.markdown, and the extension renders the Markdown correctly. On iOS 27, the same document and the same installed extension no longer work. Quick Look still resolves the file as net.daringfireball.markdown, but it does not invoke the extension and instead displays the raw Markdown source using the generic plain-text preview. Also the same extension runs perfectly on macOS 26 and macOS 27. The extension subclasses QLPreviewProvider, has QLIsDataBasedPreview enabled, and includes net.daringfireball.markdown in QLSupportedContentTypes. As a control, the same installed extension correctly launches and renders equivalent document content when it is presented through a custom Uniform Type Identifier. This confirms that the extension is embedded, installed, and otherwise invocable; the failure is specific to Quick Look's provider selection for Markdown on iOS 27. Reproduction: Install an app containing the data-based preview extension described above. On iOS 26, open an .md document in Quick Look and observe that the extension is launched and renders the Markdown. On iOS 27, open the same document with the same extension installed. I reproduced this through Files, although the issue concerns Quick Look provider selection rather than Files-specific behavior. Observe that the extension is not launched and the raw Markdown source is shown. Open an equivalent document registered with a custom content type supported by the same extension. Observe that Quick Look launches the extension and displays the rendered preview. The attached screenshots show the same Markdown case rendered by QuickMark on iOS 26 and falling back to plain text on iOS 27. Is there a supported way for a third-party preview extension to handle net.daringfireball.markdown on iOS 27, or is this an unintended provider-selection regression? Tested with iOS 27.0 (24A5408d) on an iPhone 17 Pro Max Simulator using Xcode 27.0 (27A5237l). Feedback filed as FB24481377.
2
0
358
2w
Is there any way to reconstruct a corrupted APFS root tree?
Hi everyone. I've been at this for about 9 hours already but I just needed to ask this somewhere where somebody with experience might pop up. As usual, I left my iPhone backing up its photos and videos to a Photos library in an APFS 1TB Western Digital HDD drive. Today I woke up with an error window saying that the drive is corrupted in some way. Here are the steps that followed: 1- Tried to mount the drive in Disk Utility -> doesn't work 2- Ran first aid in Disk Utility -> doesn't work 3- fsck_apfs with multiple different options in Terminal -> doesn't work 4- Used ddrescue to clone the corrupted hard drive to a 2TB drive -> worked fine with no unreadable/corrupt sectors. 5- I downloaded the WD Drive Utilities and the quick drive test passed -> no error. 6- Called Apple Support (shout out to Imelda for being incredibly nice and experienced) but it seems the only solution is to erase the drive or contact WD. This is not an option for me since it's got my photos library from the last decade. I had a backup in another drive but it's very out of date. I just bought a NAS to transfer it all to a safer place, so the timing for this to happen is the worst case. 7- I noticed that in the Library folder in my Mac, I got a 1.3GB Photos library with many thumbnails of the pictures I was importing last night. The filename is Syndication.photoslibrary. Here's the log from fsck_apfs fsck_apfs Log After all the steps I took, it seems to me that: A- The hard drive is completely fine hardware-wise, evidenced by points 4 and 5. So I would assume that WD can't really help me recover my data. B- The "only" thing that's broken is the apfs_root. So my question is if there is some sort of way to reconstruct the root tree somehow. I would assume that this structure is only partially broken and that there are addresses that it should point to properly, that can support some sort of more involved recovery process. I tried reading the APFS documentation but I'm currently very emotionally distressed at the potential loss of my data that I can't parse that information right now. Does anybody have any clue if something can be done about this? Some sort of script? Literally anything. Many thanks in advance. Best, Andres PS: Please let me know if this forum is the appropriate place for this question. I'm mostly posting here since I feel this is a more advanced subject and I need all the help I can get.
1
0
206
2w
NFSv4.1: racing open/unlink/recreate of the same filename can leave processes unkillable
I've been building an SMB client and hoping to ship it as an FSKit module, but because of some blocking issues I decided to serve it over NFS instead. Unfortunately, I've run into another blocker, which I'll share in case others are seeing the same behavior. While testing against an NFSv4.1 server (stock Linux nfsd), I ran into a situation where processes on the Mac end up permanently blocked inside the NFS client, and I wanted to share it in case others hit the same thing. Filed as FB24538163. The trigger is several processes concurrently opening, unlinking and recreating the same filenames in one directory. Something like ten shell loops each doing cat, rm, and echo > over the same five names will do it. When it happens: The stuck processes ignore SIGKILL and sit in state U indefinitely (I have had them survive more than eight hours). umount -f on the mount blocks the same way, so the mount cannot be cleared either. Only a reboot recovers. The rest of the system stays responsive. Two details that may help narrow it down: It really is the name collision, not the load. The same loops using distinct filenames per process, at the same traffic volume and latency, ran clean for twenty minutes, while the same-name version wedged every time. Adding 8 ms of reply latency made it roughly ten times more frequent. It happens on a soft mount (timeo=100,retrycnt=3), where I would have expected EIO after the retry budget instead of an indefinite wait. Spindumps show the blocked threads inside nfs_vnop_open / nfs4_vnop_create, down through nfs4_open_rpc_internal into nfs_node_set_busy_helper, with one thread typically waiting on a write RPC reply (nfs_wait_reply) inside that same open path. A self-contained repro script is attached to the Feedback. The script only needs any NFSv4.1 server to point at, and its header has a one-line Docker command that produces one. This looks related to what the FUSE-T project has reported (macos-fuse-t/fuse-t issues 112 and 45), since FUSE-T rides the same client. If anyone knows a mount option or usage pattern that avoids the wait, or can confirm seeing this elsewhere, I would love to hear it.
0
1
137
2w
NSFileProviderReplicatedExtension triggering wrong fileproviderd behaviour?
TL;DR: looking for FileProvider Extension debugging suggestions... I am attempting to develop NSFileProviderReplicatedExtension. Against a real backing repository (~4TB), I've seen fileproviderd become heavily loaded, non-responsive (i.e. fileproviderctl dump has failed to complete within 60s on 8 tries) and (maybe?) re-enumerate the contents of the repository. The profiler says that it's spending most of its time doing sqlite work against the table for the domain from my extension. I hypothesize that my extension has telling fileproviderd occasionally inconsistent things and it is now making sure that the world is the way that it should be. So: is there a way to get it to log when it has received invalid info? (I did read its (terse 😊) man page. I'm running out of ideas of what more to check with responses from the extension.
1
0
337
3w
Can't get a scoped resource URL from drag and drop
Hi, My Mac app allows a customer to drag and drop a file package onto a SwiftUI view. I can't seem to find a way to successfully call .startAccessingSecurityScopedResource() with the file/dir that was dropped into the view. I put together a simple test app. Here is the code: struct ContentView: View { @State var isTargetedForDrop: Bool = false var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") Rectangle() .stroke(Color.gray) .onDrop(of: [UTType.fileURL], isTargeted: $isTargetedForDrop) { providers in guard let provider = providers.first(where: { $0.hasItemConformingToTypeIdentifier(UTType.fileURL.identifier) }) else { return false } provider.loadItem(forTypeIdentifier: UTType.fileURL.identifier, options: nil) { item, error in if let error = error { print("Drop load error: \(error)") return } if let url = item as? URL { print("Dropped file URL: \(url)") } else if let data = item as? Data, let url = URL(dataRepresentation: data, relativeTo: nil) { print("Dropped file URL (from data): \(url)") let access = url.startAccessingSecurityScopedResource() if access { print("Successfully accessed file at URL: \(url)") } else { print("Failed to access file at URL: \(url)") } url.stopAccessingSecurityScopedResource() } else { print("Unsupported dropped item: \(String(describing: item))") } } return true } } .padding() } } When I drop a file package into this view I see, "Failed to access file at URL: <the_full_file_path>" I'm running Xcode 26 on macOS 26.
3
1
766
4w
Pinpointing dandling pointers in 3rd party KEXTs
I'm debugging the following kernel panic to do with my custom filesystem KEXT: panic(cpu 0 caller 0xfffffe004cae3e24): [kalloc.type.var4.128]: element modified after free (off:96, val:0x00000000ffffffff, sz:128, ptr:0xfffffe2e7c639600) My reading of this is that somewhere in my KEXT I'm holding a reference 0xfffffe2e7c639600 to a 128 byte zone that wrote 0x00000000ffffffff at offset 96 after that particular chunk of memory had been released and zeroed out by the kernel. The panic itself is emitted when my KEXT requests the memory chunk that's been tempered with via the following set of calls. zalloc_uaf_panic() __abortlike static void zalloc_uaf_panic(zone_t z, uintptr_t elem, size_t size) { ... (panic)("[%s%s]: element modified after free " "(off:%d, val:0x%016lx, sz:%d, ptr:%p)%s", zone_heap_name(z), zone_name(z), first_offs, first_bits, esize, (void *)elem, buf); ... } zalloc_validate_element() static void zalloc_validate_element( zone_t zone, vm_offset_t elem, vm_size_t size, zalloc_flags_t flags) { ... if (memcmp_zero_ptr_aligned((void *)elem, size)) { zalloc_uaf_panic(zone, elem, size); } ... } The panic is triggered if memcmp_zero_ptr_aligned(), which is implemented in assembly, detects that an n-sized chunk of memory has been written after being free'd. /* memcmp_zero_ptr_aligned() checks string s of n bytes contains all zeros. * Address and size of the string s must be pointer-aligned. * Return 0 if true, 1 otherwise. Also return 0 if n is 0. */ extern int memcmp_zero_ptr_aligned(const void *s, size_t n); Normally, KASAN would be resorted to to aid with that. The KDK README states that KASAN kernels won't load on Apple Silicon. Attempting to follow the instructions given in the README for Intel-based machines does result in a failure for me on Apple Silicon. I stumbled on the Pishi project. But the custom boot kernel collection that gets created doesn't have any of the KEXTs that were specified to kmutil(8) via the --explicit-only flag, so it can't be instrumented in Ghidra. Which is confirmed as well by running: % kmutil inspect -B boot.kc.kasan boot kernel collection at /Users/user/boot.kc.kasan (AEB8F757-E770-8195-458D-B87CADCAB062): Extension Information: I'd appreciate any pointers on how to tackle UAFs in kernel space.
12
0
1.8k
Aug ’26
ShareLink with Collaboration in SwiftUI with a Document based app
Hello to anyone reading this. I am a bit lost as to what is the correct approach for enabling Collaboration for a Document based SwiftUI app. If I understand correctly, after setting up all the relevant entitlements and capabilities for enabling sharing, you only need to use ShareLink to begin a collaboration/send a copy by passing in the URL of the document. The collaboration is then handled with SWCollaborationView, which there have been NSViewRepresentable wrapper implementations posted around the web. My main question is; how do I know whether the document has been shared to create a collaboration? Do I have to have 2 sharing ToolbarItems? Basically, is there any documentation for implementing collaborations from a document based app, other than simply saying that starting a share is done by passing the url into a ShareLink? This seems to massively missing, or have I massively missed something?
0
0
390
Aug ’26
FSKit - Retrieve Process ID?
Does FSKit support the ability to get the process information, such as the pid, when a process accesses a resource? Being able have the process context is important for implementing certain access patterns and security logging in some contexts. For instance, we have a system that utilizes (pre-FSKit) a FUSE mount that, depending on the process has different "views" and "access" based on the process id.
3
0
842
Jul ’26
FSEvents vs Endpoint Security Framework for a macOS file-operation audit product
I'm developing a macOS product that generates verifiable audit records of media-asset movement on endpoints, for professional media-production companies. It is not an antivirus or Data Loss Prevention product; it collects operating-system file-system events and converts them into tamper-evident audit evidence and audit reports. Target users need comprehensive endpoint audit trails for compliance with industry security standards, including Motion Picture Association Trusted Partner Network assessments. The product must reliably distinguish these operations: file copy, move, rename, and volume mount and unmount — including on external volumes. I've reviewed existing forum guidance, including Quinn's explanation that FSEvents only signals that "something changed" rather than the exact operation, and that it is designed around Spotlight and Time Machine semantics. In my own testing I've also seen inconsistent flags across cp, Finder copy, and application saves, and frequent kFSEventStreamEventFlagMustScanSubDirs events on external drives even when nothing along the path changed. Questions: Given the above, for an audit product that must reliably distinguish copy vs. move vs. rename, should FSEvents be treated as structurally unsuitable, with the Endpoint Security Framework adopted instead as the primary source? For capturing volume mount and unmount operations, is the Endpoint Security Framework the recommended source, or should this be combined with Disk Arbitration? Are there long-term supported APIs recommended for this type of endpoint audit product, to ensure compatibility with future macOS releases? Any recommended documentation, WWDC sessions, or sample code for this use case would be appreciated. For context, I'm building toward a System Extension using the Endpoint Security Framework and will file the entitlement request separately; this post is to confirm the architectural direction before committing. Thank you.
7
0
641
Jul ’26
Accessing preferences in another app's sandbox - operation denied and NSAppDataUsageDescription never shows
macOS 27.0 beta 4 I have an installer app which needs to set a key/value inside a plist file during installation. This is for a screensaver that runs under the legacyScreensaver system, so the plist lives at: ~/Library/Containers/com.apple.ScreenSaver.Engine.legacyScreenSaver.x86-64/Data/Library/Preferences/com.foobar.plist Although I can see the plist file in the Finder, my installer app can't read or write it, and the NSAppDataUsageDescription string is not shown, nor does the OS ask the user for permission. Also, trying to do this via the Terminal app is also blocked (even using 'sudo'). I understand this is part of the new Golden Gate security system. In Golden Gate, is there a legitimate way to accomplish this so it works like it did in macOS 26 and earlier? I'd like my installer to request access, the NSAppDataUsageDescription string is shown, and the user can grant or deny permission.
5
0
893
Jul ’26
On File System Permissions
Modern versions of macOS use a file system permission model that’s far more complex than the traditional BSD rwx model, and this post is my attempt at explaining that model. If you have a question about this, post it here on DevForums. Put your thread in the App & System Services > Core OS topic area and tag it with Files and Storage. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" On File System Permissions Modern versions of macOS have five different file system permission mechanisms: Traditional BSD permissions Access control lists (ACLs) App Sandbox Mandatory access control (MAC) Endpoint Security (ES) The first two were introduced a long time ago and rarely trip folks up. The second two are newer, more complex, and specific to macOS, and thus are the source of some confusion. Finally, Endpoint Security allows third-party developers to deny file system operations based on their own criteria. This post offers explanations and advice about all of these mechanisms. Error Codes App Sandbox and the mandatory access control system are both implemented using macOS’s sandboxing infrastructure. When a file system operation fails, check the error to see whether it was blocked by this sandboxing infrastructure. If an operation was blocked by BSD permissions or ACLs, it fails with EACCES (Permission denied, 13). If it was blocked by something else, it’ll fail with EPERM (Operation not permitted, 1). If you’re using Foundation’s FileManager, these error are both reported as Foundation errors, for example, the NSFileReadNoPermissionError error. To recover the underlying error, get the NSUnderlyingErrorKey property from the info dictionary. App Sandbox File system access within the App Sandbox is controlled by two factors. The first is the entitlements on the main executable. There are three relevant groups of entitlements: The com.apple.security.app-sandbox entitlement enables the App Sandbox. This denies access to all file system locations except those on a built-in allowlist (things like /System) or within the app’s containers. The various “standard location” entitlements extend the sandbox to include their corresponding locations. The various “file access temporary exceptions” entitlements extend the sandbox to include the items listed in the entitlement. Collectively this is known as your static sandbox. The second factor is dynamic sandbox extensions. The system issues these extensions to your sandbox based on user behaviour. For example, if the user selects a file in the open panel, the system issues a sandbox extension to your process so that it can access that file. The type of extension is determined by the main executable’s entitlements: com.apple.security.files.user-selected.read-only results in an extension that grants read-only access. com.apple.security.files.user-selected.read-write results in an extension that grants read/write access. Note There’s currently no way to get a dynamic sandbox extension that grants executable access. For all the gory details, see this post. These dynamic sandbox extensions are tied to your process; they go away when your process terminates. To maintain persistent access to an item, use a security-scoped bookmark. See Accessing files from the macOS App Sandbox. To pass access between processes, use an implicit security scoped bookmark, that is, a bookmark that was created without an explicit security scope (no .withSecurityScope flag) and without disabling the implicit security scope (no .withoutImplicitSecurityScope flag)). If you have access to a directory — regardless of whether that’s via an entitlement or a dynamic sandbox extension — then, in general, you have access to all items in the hierarchy rooted at that directory. This does not overrule the MAC protection discussed below. For example, if the user grants you access to ~/Library, that does not give you access to ~/Library/Mail because the latter is protected by MAC. Finally, the discussion above is focused on a new sandbox, the thing you get when you launch a sandboxed app from the Finder. If a sandboxed process starts a child process, that child process inherits its sandbox from its parent. For information on what happens in that case, see the Note box in Enabling App Sandbox Inheritance. IMPORTANT The child process inherits its parent process’s sandbox regardless of whether it has the com.apple.security.inherit entitlement. That entitlement exists primarily to act as a marker for App Review. App Review requires that all main executables have the com.apple.security.app-sandbox entitlement, and that entitlements starts a new sandbox by default. Thus, any helper tool inside your app needs the com.apple.security.inherit entitlement to trigger inheritance. However, if you’re not shipping on the Mac App Store you can leave off both of these entitlement and the helper process will inherit its parent’s sandbox just fine. The same applies if you run a built-in executable, like /bin/sh, as a child process. When the App Sandbox blocks something, it might generates a sandbox violation report. For information on how to view these reports, see Discovering and diagnosing App Sandbox violations. To learn more about the App Sandbox, see the various links in App Sandbox Resources. For information about how to embed a helper tool in a sandboxed app, see Embedding a Command-Line Tool in a Sandboxed App. Mandatory Access Control Mandatory access control (MAC) has been a feature of macOS for many releases, but it’s become a lot more prominent since macOS 10.14. There are many flavours of MAC but the ones you’re most likely to encounter are: Full Disk Access (macOS 10.14 and later) Files and Folders (macOS 10.15 and later) App bundle protection (macOS 13 and later) App container protection (macOS 14 and later) App group container protection (macOS 15 and later) Data Vaults (see below) and other internal techniques used by various macOS subsystems Mandatory access control, as the name suggests, is mandatory; it’s not an opt-in like the App Sandbox. Rather, all processes on the system, including those running as root, as subject to MAC. Data Vaults are not a third-party developer opportunity. See this post if you’re curious. In the Full Disk Access and Files and Folders cases, users grant a program a MAC privilege using System Settings > Privacy & Security. Some MAC privileges are per user (Files and Folders) and some are system wide (Full Disk Access). If you’re not sure, run this simple test: On a Mac with two users, log in as user A and enable the MAC privilege for a program. Now log in as user B. Does the program have the privilege? If a process tries to access an item restricted by MAC, the system may prompt the user to grant it access there and then. For example, if an app tries to access the desktop, you’ll see an alert like this: “AAA” would like to access files in your Desktop folder. [Don’t Allow] [OK] To customise this message, set Files and Folders properties in your Info.plist. This system only displays this alert once. It remembers the user’s initial choice and returns the same result thereafter. This relies on your code having a stable code signing identity. If your code is unsigned, or signed ad hoc (Signed to Run Locally in Xcode parlance), the system can’t tell that version N+1 of your code is the same as version N, and thus you’ll encounter excessive prompts. Note For information about how that works, see TN3127 Inside Code Signing: Requirements. The Files and Folders prompts only show up if the process is running in a GUI login session. If not, the operation is allowed or denied based on existing information. If there’s no existing information, the operation is denied by default. For more information about app and app group container protection, see the links in Trusted Execution Resources. For more information about app groups in general, see App Groups: macOS vs iOS: Working Towards Harmony On managed systems the site admin can use the com.apple.TCC.configuration-profile-policy payload to assign MAC privileges. For testing purposes you can reset parts of TCC using the tccutil command-line tool. For general information about that tool, see its man page. For a list of TCC service names, see the posts on this thread. Note TCC stands for transparency, consent, and control. It’s the subsystem within macOS that manages most of the privileges visible in System Settings > Privacy & Security. TCC has no API surface, but you see its name in various places, including the above-mentioned configuration profile payload and command-line tool, and the name of its accompanying daemon, tccd. While tccutil is an easy way to do basic TCC testing, the most reliable way to test TCC is in a VM, restoring to a fresh snapshot between each test. If you want to try this out, crib ideas from Testing a Notarised Product. The MAC privilege mechanism is heavily dependent on the concept of responsible code. For example, if an app contains a helper tool and the helper tool triggers a MAC prompt, we want: The app’s name and usage description to appear in the alert. The user’s decision to be recorded for the whole app, not that specific helper tool. That decision to show up in System Settings under the app’s name. For this to work the system must be able to tell that the app is the responsible code for the helper tool. The system has various heuristics to determine this and it works reasonably well in most cases. However, it’s possible to break this link. I haven’t fully research this but my experience is that this most often breaks when the child process does something ‘odd’ to break the link, such as trying to daemonise itself. If you’re building a launchd daemon or agent and you find that it’s not correctly attributed to your app, add the AssociatedBundleIdentifiers property to your launchd property list. See the launchd.plist man page for the details. Scripting MAC presents some serious challenges for scripting because scripts are run by interpreters and the system can’t distinguish file system operations done by the interpreter from those done by the script. For example, if you have a script that needs to manipulate files on your desktop, you wouldn’t want to give the interpreter that privilege because then any script could do that. The easiest solution to this problem is to package your script as a standalone program that MAC can use for its tracking. This may be easy or hard depending on the specific scripting environment. For example, AppleScript makes it easy to export a script as a signed app, but that’s not true for shell scripts. TCC and Main Executables TCC expects its bundled clients — apps, app extensions, and so on — to use a native main executable. That is, it expects the CFBundleExecutable property to be the name of a Mach-O executable. If your product uses a script as its main executable, you’re likely to encounter TCC problems. To resolve these, switch to using a Mach-O executable. For an example of how you might do that, see this post. Endpoint Security Endpoint Security (ES) is a general mechanism for third-party products to enforce custom security policies on the Mac. An ES client asks ES to send it events when specific security-relevant operations occur. These events can be notifications or authorisations. In the case of authorisation events, the ES client must either allow or deny the operation. As you might imagine, the set of security-relevant operations includes file system operations. For example, when you open a file using the open system call, ES delivers the ES_EVENT_TYPE_AUTH_OPEN event to any interested ES clients. If one of those ES client denies the operation, the open system call fails with EPERM. For more information about ES, see the Endpoint Security framework documentation. Revision History 2025-11-04 Added a discussion of Endpoint Security. Made numerous minor editorial changes. 2024-11-08 Added info about app group container protection. Clarified that Data Vaults are just one example of the techniques used internally by macOS. Made other editorial changes. 2023-06-13 Replaced two obsolete links with links to shiny new official documentation: Accessing files from the macOS App Sandbox and Discovering and diagnosing App Sandbox violations. Added a short discussion of app container protection and a link to WWDC 2023 Session 10053 What’s new in privacy. 2023-04-07 Added a link to my post about executable permissions. Fixed a broken link. 2023-02-10 In TCC and Main Executables, added a link to my native trampoline code. Introduced the concept of an implicit security scoped bookmark. Introduced AssociatedBundleIdentifiers. Made other minor editorial changes. 2022-04-26 Added an explanation of the TCC initialism. Added a link to Viewing Sandbox Violation Reports.  Added the TCC and Main Executables section. Made significant editorial changes. 2022-01-10 Added a discussion of the file system hierarchy. 2021-04-26 First posted.
Replies
0
Boosts
0
Views
13k
Activity
Nov ’25
Files and Storage Resources
General: Forums subtopic: App & System Services > Core OS Forums tags: Files and Storage, Foundation, FSKit, File Provider, Finder Sync, Disk Arbitration, APFS Foundation > Files and Data Persistence documentation Low-level file system APIs are documented in UNIX manual pages File System Programming Guide archived documentation About Apple File System documentation Apple File System Guide archived documentation File system changes introduced in iOS 17 forums post On File System Permissions forums post Extended Attributes and Zip Archives forums post Unpacking Apple Archives forums post Creating new file systems: FSKit framework documentation Building a passthrough file system sample code File Provider framework documentation Finder Sync framework documentation App Extension Programming Guide > App Extension Types > Finder Sync archived documentation Managing storage: Disk Arbitration framework documentation Disk Arbitration Programming Guide archived documentation Mass Storage Device Driver Programming Guide archived documentation Device File Access Guide for Storage Devices archived documentation BlockStorageDeviceDriverKit framework documentation Volume format references: Apple File System Reference TN1150 HFS Plus Volume Format Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
Replies
0
Boosts
0
Views
2.9k
Activity
Feb ’26
BlockStorageDeviceDriverKit grant confirmed by support but shows "No Requests" in the portal. How to resolve?
Hello! I am hoping a DTS engineer or someone who knows the Capability Requests portal can help, because I am stuck between a written support confirmation and what the portal actually shows. Background. We are building a native macOS iSCSI initiator for SOHO and home NAS use, developed over close to two years. A userspace daemon runs the iSCSI protocol and a DriverKit system extension presents the remote LUN as a block device. The code is essentially complete. Only the DriverKit extension cannot be signed, loaded and validated without the entitlement. We submitted request 32PC8MGU57 for two entitlements: com.apple.developer.driverkit.family.block-storage-device for the extension com.aviontex.iscsi.AviontexISCSI.AviontexInitiator com.apple.developer.driverkit.userclient-access for the app com.aviontex.iscsi.AviontexISCSI, scoped to the extension bundle id The problem. On June 25 Developer Support confirmed in writing that both entitlements were granted. The portal does not match that: Block Storage Device: No Requests: on both App IDs UserClient Access: Assigned: on the app SCSI Controller: Submitted: on the app So the one entitlement we actually need, Block Storage Device, shows as never requested, even though request 32PC8MGU57 covered it and support confirmed the grant. The case was escalated to the senior team on July 2 (case 102922935570). Follow-up emails since then have not received a response. Why Block Storage Device specifically Our initiator has no PCI or Thunderbolt bus and no DMA path, so SCSIControllerDriverKit does not fit. This is confirmed by DTS in thread 776020, where Kevin Elliott explains that SCSIControllerDriverKit passes data through fBufferIOVMAddr as a physical address with no mechanism to convert it into a VM address the dext can access. He also notes it cannot be used with any bus other than PCI or Thunderbolt. Block Storage Device is therefore the family we need. My questions: Am I reading the portal correctly: Block Storage Device not requested, UserClient Access assigned, SCSI Controller submitted? From here, what is the correct way to get Block Storage Device onto these two App IDs, with both the Development and the Distribution grant, since our public beta depends on Distribution? Should I submit a new request through the Capability Requests tab or does the escalated case handle it? Is there any way to get visibility on the escalated case, since email follow-ups are not being answered? A full technical justification is prepared and we are happy to share the source code. Any guidance would be appreciated. Thank you.
Replies
34
Boosts
1
Views
6.8k
Activity
16h
Drag and Drop stopped working after upgrading from macOS 15 to 26
When I drag and drop a file with flag "shouldAttemptToOpenInPlace: true", I was able to access the original file name in macOS 15. After upgrading to macOS 26, I can't access the original file name anymore. Instead, I got some useless file name such as ".com.apple.Foundation.NSItemProvider.gKZ91u.tmp". The app no longer works with these tmp filenames because it needs the orignal file name to do the file transfer. (Btw, this is a WinSCP like app on Mac platform) Could you please check and fix this issue? Thank you. FileRepresentation(contentType: .item, shouldAttemptToOpenInPlace: true)
Replies
5
Boosts
0
Views
968
Activity
16h
smbfs silently zero-fills already-written data after cached file size regresses on reopen
Hello everyone, I've been chasing a nasty silent data corruption bug in the macOS SMB client (smbfs.kext) and wanted to share what I found, in case someone else has hit it and in the hope that someone from the SMB team sees it. What happens Under concurrent writes with repeated reopens, the client can regress its cached file size (np->n_size) to an earlier, smaller value - behind data it has already written and flushed to the server. The next write then treats the already-written range as a hole, zero-fills it via IO_HEADZEROFILL, and sends the zeros to the server, right on top of the correct bytes it transmitted moments earlier. No write(2) fails and nothing is logged - the file just quietly comes back with a chunk-aligned run of zeros in the middle, at the correct overall length. Environment macOS 26.5 (Darwin 25.5.0), Apple silicon (16 KiB VM pages), SMB 2.1 Sources referenced: SMB client 538.121.1, xnu 12377.121.6 How to reproduce Mount an SMB 2.1(2.0.2 has the same issue as well) share. Have several threads write the same files in 8 KiB chunks, each chunk via its own open/lseek/write/close (so the file is reopened constantly as it fills), while the files are concurrently resolved by name (stat / directory enumeration). Read the files back through a cache-cold path (second mount, or F_NOCACHE) and compare. Roughly 1 file in several hundred came back corrupted for me. The core of the write pattern: CHUNK = 8192 # 2 chunks per 16 KiB page def write_chunk(path, data, offset): fd = os.open(path, os.O_CREAT | os.O_RDWR) # own handle per chunk try: os.lseek(fd, offset, os.SEEK_SET) os.write(fd, data) finally: os.close(fd) # per file: content = os.urandom(random.randint(265000, 300000)); # chunks written in batches of 8 threads, joined between batches; # each file written twice from the same buffer: NAME, then NAME.copy In my runs the corruption always landed on the second (.copy) write. One caveat: I reproduced this against a third-party SMB server, not against macOS File Sharing (smbd), and I don't expect it to reproduce against smbd directly. The stale size arrives via reopen-via-lookup (smbfs_update_size <- smbfs_nget <- smbfs_vnop_lookup) on a freshly instantiated vnode, whose n_sizetime lets the freshness guard pass. smbd instead reopens via vnop_compound_open -> smbfs_attr_cacheenter (warm vnode; the guard rejects it) - the same stale-size candidates occur, they just all get rejected. The server merely steers the client onto the vulnerable path; the bug itself is entirely client-side. What I observed I captured the kernel side with dtrace fbt probes on smbfs_setsize() / smbfs_update_size() (os_log drops events under this load). Timeline for one corrupted file, correlating pcap and dtrace (dtrace has whole-second resolution, marked ".x"): [pcap] = network packet capture of the SMB traffic between client and server [dtrace] = kernel-side trace of the smbfs size-update functions; timestamps only have whole-second resolution, so ".x" marks an unknown sub-second time :39.778 [pcap] — client sends WRITE off=32768 len=32768 with the correct data, covering [40960:65536). :39.777–.860 [pcap] — throughout, the server's CREATE/CLOSE responses report a strictly monotonic EOF: 0, 8192, 40960, 65536, ... 288255. :39.x [dtrace] — on a reopen, smbfs_update_size applies EOF 40960 (a superseded value), regressing n_size from 65536 to 40960. :39.x [dtrace] — the next write starts past the regressed size, so zero_head_off = 40960 and IO_HEADZEROFILL is set. :39.804 [pcap] — client sends WRITE off=32768 len=57344, ALL ZEROS over [40960:65536), on top of the correct data it sent 26 ms earlier. End result: the file is 288255 bytes (correct length) with 24 KiB of zeros at [40960:65536) - three consecutive 8 KiB chunks, i.e. 1.5 x 16 KiB VM pages. Worth stressing: the server's own responses reported a strictly monotonic EOF the whole time, so the regression to 40960 was purely the client applying a superseded value. Expected, obviously: the file reads back byte-for-byte identical to what was written. Where I think the bug is From reading the smbfs and xnu sources, three things combine: np->n_size isn't consistently synchronized - read under the node lock only (smbfs_vnops.c:7329/7387/7391) but written under f_clusterWriteLock (:7411) and by smbfs_vnop_strategy under the cluster lock, so the reader deciding the zero-fill has no ordering guarantee. Possible fix: read it once under f_clusterWriteLock in smbfs_vnop_write so the snapshot, extend, and zero_head_off stay consistent. The freshness guard checks the wrong thing - smbfs_update_size's reqtime <= n_sizetime guard validates the reply's request time, not whether the value is still current, so a superseded (smaller) size applied later still passes and calls smbfs_setsize(smaller). Possible fix: never shrink n_size from fa_size while the vnode has dirty pages or in-flight writes beyond that size. The zero-fill is destructive - zero_head_off = np->n_size (smbfs_vnops.c:7391) feeds IO_HEADZEROFILL, and cluster_write zeros [n_size, uio_offset) without checking whether the UBC already holds those pages as valid/dirty (vfs_cluster.c), then flushes the zeros to the server. A defensive check there would neutralize the corruption regardless of cause. Has anyone else seen silent zero-runs in files written over SMB under concurrent access? Thanks!
Replies
4
Boosts
0
Views
403
Activity
21h
Extremely long names in df output
I am not sure if it's from Xcode or macOS 27, but here is what I get after running df: /dev/disk3s3 228Gi 1.5Gi 15Gi 9% 112 161M 0% /Volumes/Recovery devices -- file:///Users/USER/Library/Containers/com.apple.CoreDevice.CoreDeviceService/Data/ 1.0Ti 0Bi 1.0Ti 0% 0 9.2E 0% /Users/USER/Library/Developer/CoreDevice/DeviceFS It's really annoying. Is there any way to remove this?
Replies
1
Boosts
0
Views
240
Activity
1d
Kernel Sandbox/System Policy intermittently denies ALL file access (not just mount syscall) on NFS mounts
I'm seeing a recurring issue on macOS 26.5.2 (build 25F84) where the kernel's Sandbox/System Policy layer intermittently denies file access on NFS mount points from local network servers. Posting here in case anyone recognizes this pattern or has a workaround, and flagging it since I've also filed a Feedback Assistant report (with a live-captured sysdiagnose) for the same issue. WHAT HAPPENS Two independent NFS mounts to two separate, unrelated servers on my LAN start failing simultaneously with "Operation not permitted." The kernel log shows: kernel: (Sandbox) System Policy: mount_nfs(PID) deny(1) file-mount /path/to/mount Critically, it's not limited to the mount syscall - within the same few-second window, System Policy also denies ls, perl, diskutil, and even umount -f on the exact same path, for otherwise unrelated processes. So it looks like a transient, path-scoped kernel decision rather than something specific to NFS or the mount syscall. It self-heals anywhere from seconds to ~30 minutes later, then recurs - documented 30-80+ occurrences/day via a background watchdog script. WHAT I'VE RULED OUT Server-side cause: two independent servers on different hardware fail identically at the same instant. Network issue: checked network logs in the same window, no correlated connectivity event. Third-party kext conflict: kextstat shows zero third-party kexts loaded. syspolicyd database corruption: no "ASP: Validation category" signature present. TCC/Full Disk Access: already granted; the denying layer is kernel Sandbox "System Policy," not TCC. QUESTION Has anyone else run into System Policy denying file-mount/file-read-data/file-unmount on network volume paths intermittently like this? Is there any userland way to inspect or reset whatever internal state drives this decision (I haven't found one - no spctl/tccutil/sysctl lever that touches it)? Happy to share more log excerpts if useful.
Replies
21
Boosts
0
Views
1.7k
Activity
1d
My app seems to cause Time Machine errors
I've written an PDF viewing app, and there seems to be a correlation between files opened by the app and files that Time Machine says couldn't be backed up. The files can still "not be backed up", even after the app has closed them. Is there anything I specifically need to do to sever the link between the file and the app?
Replies
16
Boosts
0
Views
477
Activity
1d
iOS restore ordering for an open Application Support SQLite file
I am trying to understand one supported iOS lifecycle guarantee. Consider a generic app that stores a single SQLite database in its private Library/Application Support directory and keeps one SQLite connection open while its process is alive. During a supported platform operation such as iCloud restore that continues after setup, Finder or Apple Devices restore, Quick Start direct transfer, Quick Start using iCloud, reinstall or offload recovery, or an app update, can the app become or remain running, background executing, or suspended while iOS restores, replaces, or rebinds its data container or a file within it? More specifically, can an existing open file descriptor or SQLite connection continue to reference an old filesystem object while a later lookup of the same Application Support path resolves to a restored or replacement object? If iOS does not permit that condition, what supported lifecycle invariant prevents it? For example, does iOS terminate the app before restored data becomes visible, gate launch until the complete per-app restored container is finalized, or keep the container binding stable for the lifetime of the process? If the behavior differs by mechanism, please distinguish iCloud restore after setup, Finder or Apple Devices restore, Quick Start direct transfer, Quick Start using iCloud, reinstall or offload recovery, and app update. • Does the platform's restore ordering depend on SQLite locks? • Does NSFileCoordinator participate when platform services restore private Application Support files? • Is there Apple documentation or an Apple-staff explanation that defines this ordering, including supported versions, conditions, or exceptions? The POSIX issue is that an open descriptor may continue to reference an old object after pathname replacement while a new lookup reaches a different object. SQLite also documents risks when an open database file is renamed or unlinked. I am not treating a raw rename or unlink test as equivalent to an Apple restore. I am explicitly excluding arbitrary unlink, rename, overwrite, or other direct same-container filesystem attacks. My question is only whether Apple's supported restore and container services can create an equivalent old-open-object versus newly-resolved-path condition while the same app process survives.
Replies
2
Boosts
0
Views
303
Activity
1d
MacPad Mobile – looking for TestFlight testers for Files and iCloud performance
Hello everyone, I’m a small/private developer working on MacPad Mobile, a native plain-text editor for iPhone and iPad. It edits files directly through Apple’s Files interface and requires no account or sign-in. I’m looking for a small number of TestFlight volunteers to help investigate an occasional performance issue. On some devices, the first folder transitions and the first opening of an iCloud Drive file can be noticeably slower than subsequent attempts. If you have approximately 5–10 minutes, I would particularly appreciate results from older iPhones, recent iPhones, and iPads. Suggested test: Leave the app unused for a while before beginning. Open a disposable plain-text file from iCloud Drive. Note whether navigating the first few folders feels slow. Note the delay between selecting the file and seeing its text. Repeat the same route and report whether it becomes faster. If possible, compare it with a file stored under “On My iPhone” or “On My iPad.” Please use disposable test files and avoid including private filenames, document contents, account details, or personal folder information in screenshots or feedback. Feedback can be submitted directly through TestFlight. Including the device model, iOS/iPadOS version, storage location, and whether the first and repeat attempts differed would be especially helpful. TestFlight link: https://testflight.apple.com/join/GhDzjNmj I know many people here have considerably more experience with Apple-platform development, so I’m also grateful for any advice about measuring Files-provider and iCloud latency correctly. I'm not very sure to do that everything correct. Thank you for your time and for any help you’re willing to provide. Best regards Frank
Replies
0
Boosts
0
Views
326
Activity
3d
Sanboxed Apps Reading Extended Security Information (ACL)
My custom filesystem kernel extension stores ACLs as an extended attribute, com.apple.system.Security. Sanboxed apps such as TextEdit, Pages, etc., running as a non-privileged process, fail to save modified contents when permissive ACLs are in use. Running them as a privileged process, does allow for file changes to be saved though. Non-sandboxed apps, such as VSCode, and command line programs are not susceptible to this behaviour. APFS, on the other hand, seems to handle ACLs as an ATTR_CMN_EXTENDED_SECURITY filesystem attribute, rather than as an EA. In this case, sandboxed apps have no trouble accessing the ACL data. I implemented a minimal PoC within my custom kext to verify this. I construct an ACL in memory allowing a given user to write,append,delete file contents, and return it that via vnop_getattr. This allows the file contents to be modified and saved by sandboxed apps. Can you please confirm if my findings are accurate and sandboxed apps fail to read the com.apple.system.Security EA by design? Also, Is it an accurate assumption, that ACLs should be handled either as an EA, or an ATTR_CMN_EXTENDED_SECURITY, but not both? Thanks.
Replies
10
Boosts
0
Views
758
Activity
4d
macOS Tahoe appears to ignore /etc/fstab ro and noauto — findings and workaround
macOS Tahoe appears to ignore /etc/fstab ro and noauto — findings and workaround I encountered what appears to be a regression in macOS Tahoe where Disk Arbitration no longer honors ro and noauto policies in /etc/fstab for external volumes. I am posting my findings here both to see whether others can reproduce the issue and to document a workaround, particularly for anyone using macOS for disk recovery or other workflows where preventing writes is important. The problem A configuration such as: UUID= none exfat noauto does not prevent the volume from automatically mounting. Similarly: UUID= none exfat ro does not result in a read-only mount. I also tested: UUID= none exfat ro,noauto with the same problem. This configuration worked for me before upgrading from macOS Sequoia to Tahoe. I initially suspected this might be related to Tahoe's newer exFAT/FSKit path, but testing APFS produced the same general behavior. It therefore appears to be broader than exFAT alone. /etc/fstab itself is being parsed correctly I tested the libc fstab interface using getfsent(). For example, an entry containing noauto is returned as: spec=UUID= | file=none | vfstype=exfat | mntops=noauto | type=rw So this does not appear to be a simple malformed-fstab problem. Tracing also shows diskarbitrationd accessing /etc/fstab. What Disk Arbitration is doing Unified logs from an affected exFAT mount show the filesystem being successfully probed, followed by Disk Arbitration mount approval callbacks. After approval, the reported mount options are: Mount options nodev,noowners,nosuid and the volume is then mounted successfully. The ro policy expected from /etc/fstab is notably absent from those mount options. Direct read-only mounting still works The filesystem itself is capable of being mounted read-only. For example, for exFAT: sudo mkdir -p /Volumes/Exchange sudo mount_exfat -o rdonly /dev/diskXsY /Volumes/Exchange This produces a genuinely read-only filesystem; a write test fails as expected. So at least in my testing, the problem appears to be associated with the normal Disk Arbitration mounting path rather than an inability of the filesystem to support read-only mounting. A working noauto workaround Disk Arbitration still supports mount approval callbacks. I tested a small client using: DAApprovalSessionCreate DARegisterDiskMountApprovalCallback DADissenterCreate The callback checks the volume UUID against /etc/fstab. If the corresponding entry contains noauto, it returns: kDAReturnNotPermitted This successfully prevents the volume from mounting. The test output looks like: [BLOCK] mount request: /dev/disk5s1 [BLOCK] mount request: /dev/disk5s2 The volume remains unmounted. Interestingly, this also blocks: diskutil mount /dev/diskXsY because diskutil mount goes through Disk Arbitration. A direct filesystem mount such as mount_exfat, however, bypasses that approval request and can still be used to deliberately mount the filesystem read-only. Why this matters For an ordinary external disk, an unexpected automount may only be annoying. For data recovery, forensic inspection, or a failing disk, the difference can be important. If /etc/fstab says: ro I expect that policy to protect the source filesystem from writes. Silently mounting the filesystem read-write instead means that the volume becomes available to Finder and other background services. That is exactly what I am trying to avoid when working with a recovery source. For this reason, I would recommend verifying the actual mount state rather than assuming that an existing /etc/fstab ro entry is still protecting a disk after upgrading to Tahoe. For example: mount or: diskutil info /dev/diskXsY should be used to confirm the resulting state. Current workaround design I am currently using a small compatibility helper that treats /etc/fstab as the source of truth: /etc/fstab ↓ compatibility helper ↓ Disk Arbitration mount approval The daemon side handles mount policy before Disk Arbitration can automatically mount the volume. An explicit mount helper can then perform a direct filesystem mount with the options specified in /etc/fstab, including read-only mounting where required. The intention is not to replace /etc/fstab, but to restore the behavior that was previously provided by the system. Reproduction request If anyone else is running macOS Tahoe, I would be interested to know whether you can reproduce this with either: UUID= none apfs noauto or: UUID= none exfat noauto and similarly with ro. Please be careful when testing ro: use a disposable/test volume rather than a disk whose contents actually depend on remaining read-only. I have also submitted this to Apple through Feedback Assistant. Feedback ID: 24677522 I will update this post if Apple provides additional information or if a later Tahoe update changes the behavior.
Replies
0
Boosts
0
Views
125
Activity
1w
Quick Look no longer invokes third-party Markdown preview extensions on iOS 27
Hi all! I am seeing the following problem while developing a Quick Look extension to preview Markdown files on iOS and macOS: On iOS 26, Quick Look invokes an installed data-based Quick Look preview extension for .md files resolved as net.daringfireball.markdown, and the extension renders the Markdown correctly. On iOS 27, the same document and the same installed extension no longer work. Quick Look still resolves the file as net.daringfireball.markdown, but it does not invoke the extension and instead displays the raw Markdown source using the generic plain-text preview. Also the same extension runs perfectly on macOS 26 and macOS 27. The extension subclasses QLPreviewProvider, has QLIsDataBasedPreview enabled, and includes net.daringfireball.markdown in QLSupportedContentTypes. As a control, the same installed extension correctly launches and renders equivalent document content when it is presented through a custom Uniform Type Identifier. This confirms that the extension is embedded, installed, and otherwise invocable; the failure is specific to Quick Look's provider selection for Markdown on iOS 27. Reproduction: Install an app containing the data-based preview extension described above. On iOS 26, open an .md document in Quick Look and observe that the extension is launched and renders the Markdown. On iOS 27, open the same document with the same extension installed. I reproduced this through Files, although the issue concerns Quick Look provider selection rather than Files-specific behavior. Observe that the extension is not launched and the raw Markdown source is shown. Open an equivalent document registered with a custom content type supported by the same extension. Observe that Quick Look launches the extension and displays the rendered preview. The attached screenshots show the same Markdown case rendered by QuickMark on iOS 26 and falling back to plain text on iOS 27. Is there a supported way for a third-party preview extension to handle net.daringfireball.markdown on iOS 27, or is this an unintended provider-selection regression? Tested with iOS 27.0 (24A5408d) on an iPhone 17 Pro Max Simulator using Xcode 27.0 (27A5237l). Feedback filed as FB24481377.
Replies
2
Boosts
0
Views
358
Activity
2w
Is there any way to reconstruct a corrupted APFS root tree?
Hi everyone. I've been at this for about 9 hours already but I just needed to ask this somewhere where somebody with experience might pop up. As usual, I left my iPhone backing up its photos and videos to a Photos library in an APFS 1TB Western Digital HDD drive. Today I woke up with an error window saying that the drive is corrupted in some way. Here are the steps that followed: 1- Tried to mount the drive in Disk Utility -> doesn't work 2- Ran first aid in Disk Utility -> doesn't work 3- fsck_apfs with multiple different options in Terminal -> doesn't work 4- Used ddrescue to clone the corrupted hard drive to a 2TB drive -> worked fine with no unreadable/corrupt sectors. 5- I downloaded the WD Drive Utilities and the quick drive test passed -> no error. 6- Called Apple Support (shout out to Imelda for being incredibly nice and experienced) but it seems the only solution is to erase the drive or contact WD. This is not an option for me since it's got my photos library from the last decade. I had a backup in another drive but it's very out of date. I just bought a NAS to transfer it all to a safer place, so the timing for this to happen is the worst case. 7- I noticed that in the Library folder in my Mac, I got a 1.3GB Photos library with many thumbnails of the pictures I was importing last night. The filename is Syndication.photoslibrary. Here's the log from fsck_apfs fsck_apfs Log After all the steps I took, it seems to me that: A- The hard drive is completely fine hardware-wise, evidenced by points 4 and 5. So I would assume that WD can't really help me recover my data. B- The "only" thing that's broken is the apfs_root. So my question is if there is some sort of way to reconstruct the root tree somehow. I would assume that this structure is only partially broken and that there are addresses that it should point to properly, that can support some sort of more involved recovery process. I tried reading the APFS documentation but I'm currently very emotionally distressed at the potential loss of my data that I can't parse that information right now. Does anybody have any clue if something can be done about this? Some sort of script? Literally anything. Many thanks in advance. Best, Andres PS: Please let me know if this forum is the appropriate place for this question. I'm mostly posting here since I feel this is a more advanced subject and I need all the help I can get.
Replies
1
Boosts
0
Views
206
Activity
2w
NFSv4.1: racing open/unlink/recreate of the same filename can leave processes unkillable
I've been building an SMB client and hoping to ship it as an FSKit module, but because of some blocking issues I decided to serve it over NFS instead. Unfortunately, I've run into another blocker, which I'll share in case others are seeing the same behavior. While testing against an NFSv4.1 server (stock Linux nfsd), I ran into a situation where processes on the Mac end up permanently blocked inside the NFS client, and I wanted to share it in case others hit the same thing. Filed as FB24538163. The trigger is several processes concurrently opening, unlinking and recreating the same filenames in one directory. Something like ten shell loops each doing cat, rm, and echo > over the same five names will do it. When it happens: The stuck processes ignore SIGKILL and sit in state U indefinitely (I have had them survive more than eight hours). umount -f on the mount blocks the same way, so the mount cannot be cleared either. Only a reboot recovers. The rest of the system stays responsive. Two details that may help narrow it down: It really is the name collision, not the load. The same loops using distinct filenames per process, at the same traffic volume and latency, ran clean for twenty minutes, while the same-name version wedged every time. Adding 8 ms of reply latency made it roughly ten times more frequent. It happens on a soft mount (timeo=100,retrycnt=3), where I would have expected EIO after the retry budget instead of an indefinite wait. Spindumps show the blocked threads inside nfs_vnop_open / nfs4_vnop_create, down through nfs4_open_rpc_internal into nfs_node_set_busy_helper, with one thread typically waiting on a write RPC reply (nfs_wait_reply) inside that same open path. A self-contained repro script is attached to the Feedback. The script only needs any NFSv4.1 server to point at, and its header has a one-line Docker command that produces one. This looks related to what the FUSE-T project has reported (macos-fuse-t/fuse-t issues 112 and 45), since FUSE-T rides the same client. If anyone knows a mount option or usage pattern that avoids the wait, or can confirm seeing this elsewhere, I would love to hear it.
Replies
0
Boosts
1
Views
137
Activity
2w
NSFileProviderReplicatedExtension triggering wrong fileproviderd behaviour?
TL;DR: looking for FileProvider Extension debugging suggestions... I am attempting to develop NSFileProviderReplicatedExtension. Against a real backing repository (~4TB), I've seen fileproviderd become heavily loaded, non-responsive (i.e. fileproviderctl dump has failed to complete within 60s on 8 tries) and (maybe?) re-enumerate the contents of the repository. The profiler says that it's spending most of its time doing sqlite work against the table for the domain from my extension. I hypothesize that my extension has telling fileproviderd occasionally inconsistent things and it is now making sure that the world is the way that it should be. So: is there a way to get it to log when it has received invalid info? (I did read its (terse 😊) man page. I'm running out of ideas of what more to check with responses from the extension.
Replies
1
Boosts
0
Views
337
Activity
3w
Can't get a scoped resource URL from drag and drop
Hi, My Mac app allows a customer to drag and drop a file package onto a SwiftUI view. I can't seem to find a way to successfully call .startAccessingSecurityScopedResource() with the file/dir that was dropped into the view. I put together a simple test app. Here is the code: struct ContentView: View { @State var isTargetedForDrop: Bool = false var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") Rectangle() .stroke(Color.gray) .onDrop(of: [UTType.fileURL], isTargeted: $isTargetedForDrop) { providers in guard let provider = providers.first(where: { $0.hasItemConformingToTypeIdentifier(UTType.fileURL.identifier) }) else { return false } provider.loadItem(forTypeIdentifier: UTType.fileURL.identifier, options: nil) { item, error in if let error = error { print("Drop load error: \(error)") return } if let url = item as? URL { print("Dropped file URL: \(url)") } else if let data = item as? Data, let url = URL(dataRepresentation: data, relativeTo: nil) { print("Dropped file URL (from data): \(url)") let access = url.startAccessingSecurityScopedResource() if access { print("Successfully accessed file at URL: \(url)") } else { print("Failed to access file at URL: \(url)") } url.stopAccessingSecurityScopedResource() } else { print("Unsupported dropped item: \(String(describing: item))") } } return true } } .padding() } } When I drop a file package into this view I see, "Failed to access file at URL: <the_full_file_path>" I'm running Xcode 26 on macOS 26.
Replies
3
Boosts
1
Views
766
Activity
4w
Pinpointing dandling pointers in 3rd party KEXTs
I'm debugging the following kernel panic to do with my custom filesystem KEXT: panic(cpu 0 caller 0xfffffe004cae3e24): [kalloc.type.var4.128]: element modified after free (off:96, val:0x00000000ffffffff, sz:128, ptr:0xfffffe2e7c639600) My reading of this is that somewhere in my KEXT I'm holding a reference 0xfffffe2e7c639600 to a 128 byte zone that wrote 0x00000000ffffffff at offset 96 after that particular chunk of memory had been released and zeroed out by the kernel. The panic itself is emitted when my KEXT requests the memory chunk that's been tempered with via the following set of calls. zalloc_uaf_panic() __abortlike static void zalloc_uaf_panic(zone_t z, uintptr_t elem, size_t size) { ... (panic)("[%s%s]: element modified after free " "(off:%d, val:0x%016lx, sz:%d, ptr:%p)%s", zone_heap_name(z), zone_name(z), first_offs, first_bits, esize, (void *)elem, buf); ... } zalloc_validate_element() static void zalloc_validate_element( zone_t zone, vm_offset_t elem, vm_size_t size, zalloc_flags_t flags) { ... if (memcmp_zero_ptr_aligned((void *)elem, size)) { zalloc_uaf_panic(zone, elem, size); } ... } The panic is triggered if memcmp_zero_ptr_aligned(), which is implemented in assembly, detects that an n-sized chunk of memory has been written after being free'd. /* memcmp_zero_ptr_aligned() checks string s of n bytes contains all zeros. * Address and size of the string s must be pointer-aligned. * Return 0 if true, 1 otherwise. Also return 0 if n is 0. */ extern int memcmp_zero_ptr_aligned(const void *s, size_t n); Normally, KASAN would be resorted to to aid with that. The KDK README states that KASAN kernels won't load on Apple Silicon. Attempting to follow the instructions given in the README for Intel-based machines does result in a failure for me on Apple Silicon. I stumbled on the Pishi project. But the custom boot kernel collection that gets created doesn't have any of the KEXTs that were specified to kmutil(8) via the --explicit-only flag, so it can't be instrumented in Ghidra. Which is confirmed as well by running: % kmutil inspect -B boot.kc.kasan boot kernel collection at /Users/user/boot.kc.kasan (AEB8F757-E770-8195-458D-B87CADCAB062): Extension Information: I'd appreciate any pointers on how to tackle UAFs in kernel space.
Replies
12
Boosts
0
Views
1.8k
Activity
Aug ’26
ShareLink with Collaboration in SwiftUI with a Document based app
Hello to anyone reading this. I am a bit lost as to what is the correct approach for enabling Collaboration for a Document based SwiftUI app. If I understand correctly, after setting up all the relevant entitlements and capabilities for enabling sharing, you only need to use ShareLink to begin a collaboration/send a copy by passing in the URL of the document. The collaboration is then handled with SWCollaborationView, which there have been NSViewRepresentable wrapper implementations posted around the web. My main question is; how do I know whether the document has been shared to create a collaboration? Do I have to have 2 sharing ToolbarItems? Basically, is there any documentation for implementing collaborations from a document based app, other than simply saying that starting a share is done by passing the url into a ShareLink? This seems to massively missing, or have I massively missed something?
Replies
0
Boosts
0
Views
390
Activity
Aug ’26
FSKit - Retrieve Process ID?
Does FSKit support the ability to get the process information, such as the pid, when a process accesses a resource? Being able have the process context is important for implementing certain access patterns and security logging in some contexts. For instance, we have a system that utilizes (pre-FSKit) a FUSE mount that, depending on the process has different "views" and "access" based on the process id.
Replies
3
Boosts
0
Views
842
Activity
Jul ’26
FSEvents vs Endpoint Security Framework for a macOS file-operation audit product
I'm developing a macOS product that generates verifiable audit records of media-asset movement on endpoints, for professional media-production companies. It is not an antivirus or Data Loss Prevention product; it collects operating-system file-system events and converts them into tamper-evident audit evidence and audit reports. Target users need comprehensive endpoint audit trails for compliance with industry security standards, including Motion Picture Association Trusted Partner Network assessments. The product must reliably distinguish these operations: file copy, move, rename, and volume mount and unmount — including on external volumes. I've reviewed existing forum guidance, including Quinn's explanation that FSEvents only signals that "something changed" rather than the exact operation, and that it is designed around Spotlight and Time Machine semantics. In my own testing I've also seen inconsistent flags across cp, Finder copy, and application saves, and frequent kFSEventStreamEventFlagMustScanSubDirs events on external drives even when nothing along the path changed. Questions: Given the above, for an audit product that must reliably distinguish copy vs. move vs. rename, should FSEvents be treated as structurally unsuitable, with the Endpoint Security Framework adopted instead as the primary source? For capturing volume mount and unmount operations, is the Endpoint Security Framework the recommended source, or should this be combined with Disk Arbitration? Are there long-term supported APIs recommended for this type of endpoint audit product, to ensure compatibility with future macOS releases? Any recommended documentation, WWDC sessions, or sample code for this use case would be appreciated. For context, I'm building toward a System Extension using the Endpoint Security Framework and will file the entitlement request separately; this post is to confirm the architectural direction before committing. Thank you.
Replies
7
Boosts
0
Views
641
Activity
Jul ’26
Accessing preferences in another app's sandbox - operation denied and NSAppDataUsageDescription never shows
macOS 27.0 beta 4 I have an installer app which needs to set a key/value inside a plist file during installation. This is for a screensaver that runs under the legacyScreensaver system, so the plist lives at: ~/Library/Containers/com.apple.ScreenSaver.Engine.legacyScreenSaver.x86-64/Data/Library/Preferences/com.foobar.plist Although I can see the plist file in the Finder, my installer app can't read or write it, and the NSAppDataUsageDescription string is not shown, nor does the OS ask the user for permission. Also, trying to do this via the Terminal app is also blocked (even using 'sudo'). I understand this is part of the new Golden Gate security system. In Golden Gate, is there a legitimate way to accomplish this so it works like it did in macOS 26 and earlier? I'd like my installer to request access, the NSAppDataUsageDescription string is shown, and the user can grant or deny permission.
Replies
5
Boosts
0
Views
893
Activity
Jul ’26