FSKit External-Volume Mount Fails During Removable Volumes TCC Authorization

Summary

A minimal read-only FUSE-T filesystem cannot be mounted over a newly created, empty directory on an external APFS volume. FSKit reaches the LIFSv2 mount stage, but the final mount(2) returns EPERM. In the same timestamp window, sandboxd requests kTCCServiceSystemPolicyRemovableVolumes on behalf of root /usr/libexec/fskitd. The request is forwarded to com.apple.tccd.system, but TCC logs an invalid XPC connection and sends an empty reply with no auth_value. sandboxd then reports the missing authorization value and denies the request; fskitd immediately reports mount(2) error 1.

No user-facing consent prompt appears. This looks like an authorization handoff or policy-integration failure in the system FSKit mount path, rather than a denial returned by the filesystem implementation. The exact reason com.apple.tccd.system returns an invalid or empty reply is unknown.

Environment
ItemValue
Test date/time2026-11-06, approximately 18:47:31 CET
MacApple silicon (arm64)
macOS27.2, build 26B123
FUSE-T receiptsorg.fuse-t.core.1.2.9, org.fuse-t.fskit.1.2.9
Registered FSKit extensionorg.fuset.fskit-srv.module, version 0.1.3
FUSE-T library/Library/Application Support/fuse-t/lib/libfuse-t-1.2.9.dylib
Target volumeWDBlack4TB, /dev/disk8s1; case-sensitive APFS; owners enabled; read/write; diskutil reports Protocol: PCI-Express and Device Location: External
Mount pointNewly created, empty directory on the target volume; owned by logged-in user (UID 501), mode 0700
Minimal reproduction
  1. Enable/register the FUSE-T FSKit extension using its normal installation flow.

  2. Build or use a minimal read-only FUSE filesystem whose callbacks expose only the root directory and one static hello.txt file. The fixture used here was linked directly to FUSE-T 1.2.9 and did not read backing files or modify the target volume.

  3. As the logged-in user (UID 501; no sudo), create a new empty directory on an external APFS volume.

  4. Start a bounded unified-log capture for fskitd, sandboxd, and tccd, then run:

    ./hello -f -o backend=fskit <empty-directory-on-external-volume>
    
  5. Observe the mount failure and preserve the same-window logs.

Actual result
  • The FUSE process exits 1 and prints: fuse: mount failed with error: -1.
  • No mount is created at the test path.
  • fskitd finds/starts the FSKit extension instance and reaches “will mount over LIFSv2”.
  • The final mount(2) fails with errno 1 (EPERM / “Operation not permitted”).
  • The TCC events below occur at the same timestamp as the mount(2) error.
  • No permission prompt is shown to the logged-in user.
Timestamp-correlated attribution and authorization evidence

At 18:47:31.793, fskitd enters the LiveFS mount path. At 18:47:31.801, tccd records the relevant attribution chain:

accessing={TCCDProcess: identifier=com.apple.fskitd, pid=36573,
           auid=0, euid=0, binary_path=/usr/libexec/fskitd}
requesting={TCCDProcess: identifier=com.apple.sandboxd, pid=472,
            auid=0, euid=0, binary_path=/usr/libexec/sandboxd}

At 18:47:31.824, TCC logs a platform-binary prompting policy of Deny. In this trace that message is associated with a separate SystemPolicyAllFiles check; the All Files result is not being presented as the final Removable Volumes denial.

At 18:47:31.829, sandboxd checks kTCCServiceSystemPolicyRemovableVolumes for fskitd. Because the audit token has auid=-1, sandboxd routes the authorization request based on euid 0 to com.apple.tccd.system. The request includes fskitd’s audit token (pid 36573, auid -1, euid 0). The system tccd endpoint returns an invalid XPC connection / an empty reply without auth_value. The relevant messages are:

sandboxd: checking kTCCServiceSystemPolicyRemovableVolumes for fskitd
sandboxd: auid = -1; routing based on euid (0) instead
tccd: REQUEST ... tccd_uid=0 ... service=kTCCServiceSystemPolicyRemovableVolumes
sandboxd: RECV ... { count = 0 ... contents = }
sandboxd: Error ... Code=2 "missing 'auth_value' in reply message"
tccd: XPC forwardMessage error: Connection invalid
tccd: sending empty reply ... auth_value absent
sandboxd: kTCCServiceSystemPolicyRemovableVolumes denied by TCC for fskitd
fskitd: mount(2) error: 1
fskitd: mount launch failed with result "Operation not permitted"

The same EPERM/TCC failure was seen in earlier diagnostic attempts and again in this fresh invocation; this run provides the full timestamp-correlated attribution capture. It happens before a successful mount. The captured report contains the exact log lines selected from the bounded unified-log stream.

Expected behavior / questions for Apple
  1. Is kTCCServiceSystemPolicyRemovableVolumes expected to authorize the final LIFSv2 mount performed by fskitd when a client asks to mount over a directory on external APFS?
  2. For a root system daemon with auid=-1, should sandboxd route this request to com.apple.tccd.system? Why does that endpoint return an invalid connection / empty reply rather than an authorization result?
  3. What is the supported authorization flow for this case? Should a user-consent prompt be shown to the initiating application, or should the system broker authorize fskitd using the caller’s audit token or security-scoped destination access?
  4. If this mount operation is unsupported by design, could the documentation or returned error distinguish that policy from a generic EPERM?
Impact

FSKit-based user-space filesystems cannot mount into an existing folder on this external APFS volume, despite the empty mountpoint being owned by the user and despite the FSKit extension loading successfully. This blocks applications that must expose a virtual filesystem at the user-selected original folder. The failure is in the system mount / authorization path; the minimal filesystem does not implement writes or access external backing data.

Limitations

This reproduction establishes the behavior on one Apple-silicon Mac, macOS 27.2 (26B123), FUSE-T 1.2.9, and one external APFS volume. It does not establish whether this is a general macOS defect, a machine-specific TCC daemon condition, or an intentional policy with a broken authorization response. The cause of com.apple.tccd.system’s invalid XPC reply remains unknown.

SO, first a bit of a warning here:

For a root system daemon with auid=-1, should sandboxd route this request to com.apple.tccd.system? Why does that endpoint return an invalid connection / empty reply rather than an authorization result?

Unfortunately, interpreting the logging of this "cluster" of security daemon's can be very difficult. They're incredibly noisy and most of their messages sound important when they're just... not. For example, I think that particular message you’re seeing their is log noise that that’s been going on for years. In a similar vein, there are often cases where you're seeing logging from a check that's actually several checks away from the check that "should" have worked.

Moving into specifics:

What is the supported authorization flow for this case? Should a user-consent prompt be shown to the initiating application, or should the system broker authorize fskitd using the caller’s audit token or security-scoped destination access?

So, in general, our daemons rely on authorization of the calling process, not their "own" state. However, the complication here is that child processes inherit the sandbox of their parent instead of having their own. In the case of a command line tool, that means what matters is what authorization Terminal.app has been granted. That leads to:

Should a user-consent prompt be shown to the initiating application?

In theory... yes. However, in practice there are definitely cases where it doesn't, typically because it's not able to identify the controlling app or because the specifics of that particular case lead to a determination that it wasn't appropriate/correct.

That leads to my first suggestion, which is to grant Terminal FDA (Full Disk Access) and retest. If FDA works, then you can sort out what narrower grant it should use, but if it doesn't work then you can shift the focus to other options.

Is kTCCServiceSystemPolicyRemovableVolumes expected to authorize the final LIFSv2 mount performed by fskitd when a client asks to mount over a directory on external APFS?

I believe it will, however, my guess is that Terminal didn't have that authorization.

If this mount operation is unsupported by design, could the documentation or returned error distinguish that policy from a generic EPERM?

What are you actually planning to ship? You can't differentiate the error cases here; however, in the context of an app, you can generally set things up so this isn't really an issue.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware