FSKit volume mount fails with "Permission denied"

I'm trying to use FSKit to create a File System Extension that can read MFS-formatted disk images, following the old MFSLives sample project for reference.

I have a well-formed MFS formatted img file that I'm trying to mount, but I'm having trouble getting the system to actually use my FSModule.

DiskImageMounter fails to mount the img file, but I'm able to use it to attach the image as a device by clicking "Ignore" when it prompts me that it isn't able to read the disk. This is effectively the same as using the hdiutil command in Terminal.

hdiutil attach -imagekey diskimage-class=CRawDiskImage -nomount Sample.img

I've read that FSKit isn't fully integrated with Disk Arbitration yet, so I decided to see if I could force the system to use my extension by using the mount command.

mkdir /tmp/Sample
mount -F -t MFS disk54 /tmp/Sample

Watching the logs in Console, I can see that fskit_agent sees my extension in its "New Modules List", and I see an MFS process gets launched and logs messages from com.apple.running and com.apple.xpc. However, the logs from the MFS process end there, and don't include any of my debug logs, which should be posted when my FSFileSystem subclass is created or when probeResource is called.

Ultimately the mount command fails with exit code 69 and prints the following error message:

mount: Probing resource: The operation couldn’t be completed. Permission denied
mount: Unable to invoke task

I've checked everything I could think of:

  • The extension is enabled in System Settings.
  • The extension has the FSKit Module capability added in Xcode.
  • The Info.plist sets the FSSupportsBlockResources key to YES.
  • The Info.plist sets both the FSName and FSShortName keys to MFS.
  • The extension has its Team set to my developer account, with Xcode setting the Provisioning Profile and Signing Certificate automatically.
  • The hosting app has its Team set to my developer account with the "Development" signing certificate.

I wanted to see if it was something with my project configuration or implementation, so I downloaded the KhaosT/FSKitSample project from GitHub. Once I got that building, I tried mounting a disk image using the MyFS extesnion, but my system wouldn't run that either.

Is there something about the system configuration I should be aware of to enable File System Extensions? I have my MFS extension showing up and enabled, but I'm not sure if there's something I'm missing that I still have to do.

Is there a capability or signing requirement I didn't list that's required for the extension to run? The documentation doesn't specify anything about the entitlements, signing capabilities, or Info.plist keys, so I'm not sure what I should be looking for.

I'm running macOS Sequoia 15.6.1 on an M2 Max MacBook Pro, and I'm building my project with Xcode 26 beta 6.

A random guess: your command in your post doesn't have this, but if you're actually running the hdiutil command with sudo, the dev node of the disk ends up being owned by root which might lead to you seeing the issue at https://developer.apple.com/forums/thread/788609.

I would think the solution then would be to use sudo mount but in my experience that hasn't worked which I think is a bug (FB18436584). If you run all commands like hdiutil and mount without sudo though, then it should work (at least it does on my machine).

Accepted Answer

I'm trying to use FSKit to create a File System Extension that can read MFS-formatted disk images, following the old MFSLives sample project for reference.

I think this is a lovely idea and greatly enjoy the idea that macOS might someday regain full read/write support for MFS.

DiskImageMounter fails to mount the img file, but I'm able to use it to attach the image as a device by clicking "Ignore" when it prompts me that it isn't able to read the disk. This is effectively the same as using the hdiutil command in Terminal.

So, looking over what you wrote, this is what immediately jumped out at me:

"diskimage-class=CRawDiskImage"

That shouldn't be necessary. Any DiskImage we shipped would have been in one of our standard DiskImage formats, so hdiutil should have attached the image without any additional argument. You're using it because without that argument, hdiutil fails because it doesn't recognize the image, and that's because it's using an old format we dropped support for at some point in the now distant past.

However, the problem here is that what "CRawDiskImage" is doing is treating the data file as raw disk data, which means it's ALSO including the original header data for the old disk image format, which throws off the offsets of the entire volume.

In any case, the solution here is to delete the first 0x54 (84d) bytes*.

*Thank you to Quinn for doing the legwork on this.

That makes the first bytes of the file:

0x4C4B6000 00860012

And, more importantly, it means that the data starting at byte 1024 is:

0xD2D79A4E FFC8C125

...so that the first two bytes of logical block 2 are the MFS volume signature:

enum {
    kMFSSigWord = 0xD2D7
};

You'll also note that this makes the file 419,200 bytes, which is exactly 818 (512-byte) blocks, just like a real block storage device would be.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thank you to Quinn for doing the legwork on this.

Hey, it’s not just altruism. As someone with a large array of MFS formatted disks [1], I have a vested interest in modern support for the MFS file system (-:

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Well, disk images. I discard the actual floppy disks just over 30 years ago!

...with a large array of MFS formatted disks

Dozens and dozens of megabytes...

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

As a quick admin note, the "comment" feature in our forums doesn't really work very well, so I'd always recommend just posting your reply.

These log message from com.apple.FSKit, category default, seem relevant.

Looking at our code, I think something went wrong in your probeResource. Breaking down the log messages, these three messages are logged before calling probeResource and validates "basic" I/O:

Successful dynamic cast of resource to bd. Got fd 3
readFirstSectorAndLog reading from 3 got rv 512 error (null)
Successful read, first characters 4c4b:6000

This is logged by the reply block we pass to probeResource. The "null" here indicates that the FSProbeResult you returned was "NULL":

Returning (null)

And this is logged shortly after in the same block, logging the Error probeResource returned:

FSModule dev.steve.MFSLives.MFS probe: returned Error Domain=NSPOSIXErrorDomain Code=22 "Invalid argument"

Notably, I don't see any logs from my code, so although it claims that the probe failed, it's not because of my code.

So, a few things I'd verify here:

  1. I'd zero pad the image file so it's "much" bigger (10-20mb). While all of this should work fine with a tiny file, 400kb is infinitesimal by modern standards and bugs happen. It's easy enough to zero pad the file JUST incase "something" is going wrong and you can remove the padding once you've got something working.

  2. Make sure you have logging in place that will ALWAYS log EVERY possible entry point. From long (and slightly bitter...) experience, one of the easiest ways to waste ENORMOUS amounts of time is to misunderstand what's actually happening because you didn't actually log "every" case. I've wasted HOURS investigating what I thought the problem was because I wasn't careful about what and where I was logging.

  3. You're actually able to see that logging. It's an easy thing to overlook but, again, it's easy to end up wasting lots of time because your infrastructure doesn't work the way you thought it did.

One easy trick I've used to validate my own expectations is by adding a "brute force" failure like this:

print(...)
sleep(10)
abort()

The sleep is long enough that you'll be able to watch your extension "stall" in activity monitor if/when it hits that code. The abort() means you'll then crash and you can use the crash log to confirm that exactly where you were in your code. Then you just have to go find whatever you printed to confirm that "print" does in fact "work".

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thanks for your help! You were right. My code is being called. It turns out I didn't see my log messages because I had them at the debug and info levels, and those apparently don't show up in the Console app. I was able to figure out what's going on wrong in my probe implementation, and now I've got that working! Now I just need to figure out how to get the rest of my module working right, lol.

those apparently don't show up in the Console app.

Yeah, that’s an annoying pitfall. You have to explicitly enable those via the commands on the Action menu.

If you’re working at this level, it’s worth spending the time to learn more about the system log. There are lots of hints, tips, and references to docs in Your Friend the System Log.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

FSKit volume mount fails with "Permission denied"
 
 
Q