I am trying to use IOUserBlockStorageDevice in DriverKit to simulate a fake device (Implementing a Ram Disk).
Currently I'm confused on how to use the dmaaddress in the following interface
virtual kern_return_t DoAsyncReadWrite (bool isRead, uint32_t requestID, uint64_t dmaAddr, uint64_t size, uint64_t lba, uint64_t numOfBlocks, IOUserStorageOptions options) = 0;
According to
https://github.com/briancabbott/macOS-system-projects/blob/19310aa5c7b7507408261a22a2e8f46f9d478a88/Resources/Code/apple-oss-distributions/IOStorageFamily/IOUserBlockStorageDevice_kext.cpp
Before calling "DoAsyncReadWrite", kernel allocate a segment of physical memory by using "IODMAcommand::genIOVMSegments".
This segment's physical address is pass to DoAsyncReadWrite as parameter "dmaAddr".
To implement a correct ram disk, we need to "transform" this physical address to virtual so that we can "Read" or "Write" on this physical address.
I tried to use "IOMemoryDescriptor" to access this dmaAddr.
In IOKit, I belive I can use interface such as "withPhysicalAddress" to access the memory.
However, such interface is not exist while using driverkit, all interface that I can use in DriverKit IOMemoryDescriptor is :
-kern_return_t GetLength(uint64_t * returnLength) LOCALONLY;
// apparently not this one
-virtual kern_return_t CreateMapping( uint64_t options, uint64_t address, uint64_t offset, uint64_t length, uint64_t alignment, IOMemoryMap ** map);
// Maybe this one with kIOMemoryFixedAddress option?
// But I get Segment Fault while calling this with CreateMapping( kIOMemoryFixedAddress , dmaaddr, 0, size, 0, &map);
// Or getting error return while calling CreateMapping with same paramters after IOBufferMemoryDescriptor::Create
// Also, output iomemorymap is not used here, which is quiet strange.
static kern_return_t
CreateSubMemoryDescriptor(uint64_t memoryDescriptorCreateOptions, uint64_t offset, uint64_t length, IOMemoryDescriptor * ofDescriptor, IOMemoryDescriptor ** memory) attribute((availability(driverkit,introduced=20.0)));
// Seems not this, it create “sub“ memory descriptor
static kern_return_t
CreateWithMemoryDescriptors(uint64_t memoryDescriptorCreateOptions,
uint32_t withDescriptorsCount, IOMemoryDescriptor * const withDescriptors[32], IOMemoryDescriptor ** memory) attribute((availability(driverkit,introduced=20.0)));
// Seems not this, it don’t take any dmaaddr as parameter.
and a private function
kern_return_t Map( uint64_t options, uint64_t address, uint64_t length, uint64_t alignment, uint64_t * returnAddress, uint64_t * returnLength) LOCALONLY;
// Maybe this one? But the header file don’t show any description on this function and we are not sure what parameters should we pass.
// Currently I've test Map( kIOMemoryFixedAddress , dmaaddr, size, 0, &returnAddress, &returnLength) but get error return.
It seems that I've made some mistake on using IOMemoryDescriptor? How to correct access a dmaaddress?
I've also tried class "IODMACommand", but also get unexpected behavior.
Another question is how to read / write buffer after I create correct mapping.
While implementing kext, IOMemoryDescriptor can use "readBytes" or "writeBytes" to read or write memory that IOMemoryDescriptor maps to.
However, DriverKit don’t have interface of "readBytes" or "writeBytes".
Maybe I can directly access buffer by casting the IOMemoryDescriptor::Map "returnAddress" to void?
(I haven't tried it yet cause "Map" always failed now QQ)
Thanks for everyone's help.
Post
Replies
Boosts
Views
Activity
I'm currently use IOUserBlockStorageDevice to simulate a ram disk.
To simulate a pluggable ramdisk that can commute, I would like to use a hierarcy architecture.
However, something strange happened while I'm using hierarcy architecture.
The hierarcy architecture might shows as following in ioreg
...
+-o IOUserResources <class IOUserResources, id 0x10000011b, registered, matched, active, busy 0 (571 ms), retain 9>
| +-o IOUserDockChannelSerial <class IOUserService, id 0x10000040c, registered, matched, active, busy 0 (0 ms), retain 8>
| +-o MyService <class IOUserService, id 0x10000040d, registered, matched, active, busy 0 (2 ms), retain 9>
| +-o MyUserClient <class IOUserUserClient, id 0x100000760, registered, matched, active, busy 0 (2 ms), retain 9>
| +-o MyDevice <class IOUserBlockStorageDevice, id 0x100000762, registered, matched, active, busy 0 (2 ms), retain 8>
| +-o IOBlockStorageDriver <class IOBlockStorageDriver, id 0x100000763, registered, matched, active, busy 0 (1 ms), retain 8>
| +-o Testing Media <class IOMedia, id 0x100000764, registered, matched, active, busy 0 (1 ms), retain 9>
| +-o IOMediaBSDClient <class IOMediaBSDClient, id 0x100000765, registered, matched, active, busy 0 (0 ms), retain 6>
+-o IOUserServer(com.apple.IOUserDockChannelSerial-0x10000040c) <class IOUserServer, id 0x100000472, registered, matched, active, busy 0 (0 ms), retain 11>
+-o IOUserServer(com.example.apple-samplecode.dext-to-user-client.driver-0x10000040d) <class IOUserServer, id 0x100000474, registered, matched, active, busy 0 (0 ms), retain 13>
MyService is the loaded dext, which create an UserClient while a client connect.
MyUserClient has two interface: adddevice / remove which will add or remove a
MyDevice instance.
MyDevice is the IOUserBlockStorageDevice create by MyuserClient.
I'm using the following plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>IOKitPersonalities</key>
<dict>
<key>testDevice</key>
<dict>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleIdentifierKernel</key>
<string>com.apple.kpi.iokit</string>
<key>IOClass</key>
<string>IOUserService</string>
<key>IOMatchCategory</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>IOProviderClass</key>
<string>IOUserResources</string>
<key>IOResourceMatch</key>
<string>IOKit</string>
<key>IOUserClass</key>
<string>MyService</string>
<key>IOUserServerName</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>UserClientProperties</key>
<dict>
<key>MyDeviceProperties</key>
<dict>
<key>CFBundleIdentifierKernel</key>
<string>com.apple.iokit.IOStorageFamily</string>
<key>IOClass</key>
<string>IOUserBlockStorageDevice</string>
<key>IOUserClass</key>
<string>MyDevice</string>
</dict>
<key>IOClass</key>
<string>IOUserUserClient</string>
<key>IOUserClass</key>
<string>MyUserClient</string>
</dict>
</dict>
</dict>
<key>OSBundleUsageDescription</key>
<string></string>
</dict>
</plist>
and MyDevice is create by "auto kr = Create(this, "MyDeviceProperties", &client);" in MyUserClient.
To make sure the flow of MyDevice, I add an simple log (inside *** function) while entering each function implement.
Following is the system log after adddevice:
=== ExternalMethod AddDevice ===
2022-10-21 12:08:20.424783+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) AAABBB MyUserClient ccc Inside ExternalMethod!!!!!
2022-10-21 12:08:20.424803+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) AAABBB MyUserClient ExternalMethodType_AddDevice
2022-10-21 12:08:20.424812+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) AAABBB MyUserClient NewDevice
2022-10-21 12:08:20.424847+0800 0xcd3cd Default 0x0 0 0 kernel: (IOStorageFamily) INFO virtual bool IOUserBlockStorageDevice::init(OSDictionary *): Allocate resources
2022-10-21 12:08:20.425059+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) AAABBB MyDevice init.....
2022-10-21 12:08:20.425145+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) AAABBB MyDevice init done
2022-10-21 12:08:20.425152+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) AAABBB MyDevice Start
2022-10-21 12:08:20.425158+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) IOUserBlockStorageDevice::Start()
2022-10-21 12:08:20.425201+0800 0xcd3cd Default 0x0 0 0 kernel: (IOStorageFamily) INFO kern_return_t IOUserBlockStorageDevice::RegisterDext_Impl(): Registering dext
2022-10-21 12:08:20.425212+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) AAABBB MyDevice Reg service
2022-10-21 12:08:20.425270+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) AAABBB MyDevice Start() - Finished.
2022-10-21 12:08:20.425281+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) AAABBB MyUserClient NewDevice done
2022-10-21 12:08:20.425598+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) AAABBB MyDevice inside ReportRemovability
2022-10-21 12:08:20.425852+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) AAABBB MyDevice inside ReportWriteProtection
2022-10-21 12:08:20.425916+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) AAABBB MyDevice inside GetVendorString
2022-10-21 12:08:20.426022+0800 0xcd3cd Default 0x0 0 0 kernel: (dext) AAABBB MyDevice inside GetProductString
<log end, device stuch here>
The IOUserBlockStorageDevice stuck after calling GetProductString, not called GetDeviceParam, and the device size remains be zero in this case.
I'm not sure why MyDevice stuck.
Could anyone help for this case? I'll post some detailed test in reply.
I try to using the module UserNotifications in swift project, to send notifications of my macos app.
I pack my app with nested bundle like:
/Application/MyApp.app
- Contents
- Resources
- Frameworks
- MacOS
- my_binary
- Notifier.app
- Resources
- Frameworks
- Contents
- MacOS
- notifier_binary
When I use cmdline to execute my notifier_binary, it's work fine.
But when I execute it form my_binary, it will failed sometimes in api requestAuthorization, and the auth setting result will be not authed.
But in current user's setting, it had been allowed.
The error message in log, I can't find anything useful in google result,
I have no idea what this error message means.
2022-10-27 16:32:11.297912+0800 0x3ded Error 0x0 1697 0 notifier_binary: (UserNotifications) [com.apple.UserNotifications:Connections] [com.my.notifier] Getting notification settings failed with error: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.usernotifications.usernotificationservice was invalidated: failed at lookup with error 3 - No such process." UserInfo={NSDebugDescription=The connection to service named com.apple.usernotifications.usernotificationservice was invalidated: failed at lookup with error 3 - No such process.}
Here it's my swift code:
class NotiSender {
let un = UNUserNotificationCenter.current()
func sendNoti(){
var waiting = true;
un.requestAuthorization(options: [.alert, .sound]) {(authorized, error) in
if authorized {
} else if !authorized {
Logger.error("user not authorized\n")
} else {
Logger.error("error: \(error?.localizedDescription)\n")
}
waiting = false;
}
while (waiting) {
sleep(1);
}
un.getNotificationSettings{ (settings) in
if settings.authorizationStatus == .authorized {
// send my notifications
.......
}
}
@main
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
UNUserNotificationCenter.current().delegate = self
let sender = NotiSender()
sender.sendNoti()
......
}
}
Did I miss some entitlements or app setting in Info.plist ? Or did I misuse the api?
Thanks for any help!!!
Recently we've been working on file-based backups on macOS 10.15.7. When I finish the system volume group backup, including
The system role volume, default volume name 'Untitled' usually
The data role volume, default volume name 'Untitled - Data' usually
Next step, I launch Migration Assistant and choose "From a Mac, Time Machine backup or startup disk" to restore volume data.
But when I select the backed-up system role volume, a warning message poped up and tell me "Volume contains a macOS or OS X installation which may be damaged".
I try to rebuild folder firmlink from /usr/share/firmlinks before backing up data role volume, like the following steps:
Add SF_FIRMLINK by chflags to folders on system role volume
Add extened attribute com.apple.fs.firmlink which value is target file name
Make sure other attributes(creation time, permission, owner, group, etc) are the same between source and destination
But it still doesn't work (I check inode number on backed-up system role volume by "is -ailO").
I search some informations and find this blog:
https://bombich.com/blog/2020/05/27/bug-in-macos-10.15.5-impacts-bootable-backups-weve-got-you-covered.
So my question is "How do I recover firmlink between backed-up system role volume and data role volume?"
Thanks a lot
I have an *.pkg installer, and it calls osascript in the postinstall script.
I double clicked the installer to install my App, and most of the time it succeeded, except for this one:
On the Mac mini (late 2012, macOS 10.15.7), this installer got stuck at the postinstall stage.
And I saw this in /var/log/system.log:
com.apple.xpc.launchd[1] (com.apple.xpc.launchd.domain.pid.osascript.6247): Failed to bootstrap path: path = /usr/bin/osascript, error = 2: No such file or directory
What does this mean? I'm pretty sure that /usr/bin/osascript does exist on the Mac.
I aborted the installation process and retried, the result was the same.
How to fix this?
Recently I tried to use mac asr command to backup my mac. However, I got different error on different mac devices.
While I tried to asr backup my "Intel Mac 10.15.7", following is the command i used:
asr restore --source {system role volume} --target {another container's volume} --toSnapshot "{snapshot I take on both system role and data role}" --erase.
After running asr, it shows "Volume replication failed - error 49157" while backing up data volume.
I tried another asr backup on my "M1 Mac 12", following is the command i used:
asr restore --source {system role volume} --target {another container's volume} --toSnapshot "com.apple... (the snapshot that system snapshot mount)" --erase.
After running asr, it shows "Couldn't embed the APFS EFI driver - error 49174" at the end of asr. (while it's 100% done)
Does anyone know any detail info / document / solution about the asr error code?
Currently I cannot find anything about 49157 / 49197 error code.
Hi,
I got my "installer" command hangs.
I have a self-built pkg and I'd like to install it via command line:
sudo installer -pkg XXXX.pkg -verbose -target /
But the above command hangs for 10+ mins.
Here's the ps aux | grep installer output:
root 4013 0.0 0.4 4341956 15700 s000 S+ 3:02AM 0:00.73 installer -pkg XXXX.pkg -verbose -target /
I found some logs related to the installer command in /var/log/install.log
2022-01-14 03:02:10-08 cats-Mac-4 installer[4013]: Product archive /Users/test/Downloads/client/XXXX.pkg trustLevel=350
2022-01-14 03:02:11-08 cats-Mac-4 installer[4013]: External component packages (2) trustLevel=350
2022-01-14 03:02:11-08 cats-Mac-4 installer[4013]: -[IFDInstallController(Private) _buildInstallPlanReturningError:]: location = file://localhost
2022-01-14 03:02:11-08 cats-Mac-4 installer[4013]: -[IFDInstallController(Private) _buildInstallPlanReturningError:]: file://localhost/Users/test/Downloads/client/XXXX.pkg#YYYY.pkg
2022-01-14 03:02:11-08 cats-Mac-4 installer[4013]: -[IFDInstallController(Private) _buildInstallPlanReturningError:]: file://localhost/Users/test/Downloads/client/XXXX.pkg#YYYY.pkg
2022-01-14 03:02:11-08 cats-Mac-4 installer[4013]: Set authorization level to root for session
2022-01-14 03:02:11-08 cats-Mac-4 installer[4013]: Administrator authorization granted.
The self-built pkg has been signed / notarized correctly.
How to dig out what cause the command hangs?
Thank you!
Is there any way to get me terminal in macOS Recovery when FileVault is enabled and fails to reset account’s password?
I have a 2014 Mac Mini running Big Sur 11.6. It has FileVault enabled and allows iCloud account to unlock the volume. My case is, I forget my password, and my local account (the only account) is disabled somehow. I rebooted with command + R,the screen titled “macOS Recovery” asked me to Sign In with my Apple ID, and I did. And the loading messages read “Recovery FileVault key…” and then “The recovery key was found matching the volume…” something like that. Next, I was asked to reset my account’s password but it failed with “Credential verification failed because account is disable”. There wasn’t any option or button to exit to get Recovery Utilities. If I get the terminal, I can fix my account. But I have no access to the terminal.
Why didn’t it just show me the utilities after I sign in with my Apple ID? I already unlocked the volume with my iCloud account.