我正在努力学习更多关于DriverKit和内存管理的知识,我读到了这个问题:
How to allocate memory in a DriverKit system extension and map it to another process?
我想了解一下如何使用IOMemoryDescriptor::CreateMapping。
我写了一个小应用来测试我做的地方(非常简单的代码):
uint8_t * buffer = new uint8_t[256];
for (int i = 0 ; i < 256 ; i++)
buffer[i] = 0xC6;
clientData in, out;
in.nbytes = 256;
in.pbuffer = buffer;
size_t sout = sizeof(out);
IOConnectCallStructMethod(connection, selector,&in,sizeof(in),&out,&sout);
// out.pbuffer now has new values in it在我的Kext用户客户机类中,我正在做(我正在简化):
IOReturn UserClient::MyExtFunction(clientData * in, clientData * out, IOByteCount inSize, IOByteCount * outSize)
{
MyFunction(in->nBytes, in->pbuffer);//this will change the content of pbuffer
*out = *in;
}
IOReturn UserClient::MyFunction(SInt32 nBytesToRead,void* pUserBuffer,SInt32* nBytesRead)
{
PrepareBuffer(nBytesToRead,&pBuffer);
...
(call function that will fill pBuffer)
}
IOReturn UserClient::PrepareBuffer(UInt32 nBytes,void** pBuffer);
{
IOMemoryDescriptor * desc = IOMemoryDescriptor::withAddressRange((mach_vm_address_t)*pBuffer,nBytes,direction, owner task);
desc->prepare();
IOMemoryMap * map = desc->map();
*pBuffer = (void*)map->getVirtualAddress();
return kIOReturnSuccess;
}这就是我不知道如何在DExt中重现的地方,也是我真的不理解CreateMapping基础的地方。
还是说我以前做的事情是不可能的?
在我的驱动程序中,这是我不知道如何使用CreateMapping和IOMemoryMap的地方,所以这个缓冲区可以映射到内存位置并使用不同的值进行更新。
我可以创建一个IOBufferMemoryDescriptor,但是如何从我的应用程序将它绑定到缓冲区呢?我也不理解CreateMapping的各种选项。
请注意,在另一个测试应用程序中,我已经成功地使用了IOConnectMapMemory64()/CopyClientMemoryForType(),但我想具体了解一下CreateMapping()。
(我希望我对这个问题编辑了很多次…对StackOverflow来说还是个新手)
发布于 2020-10-09 17:50:41
还是我以前做不到的事情?
简而言之,不是。
您正在尝试映射任意用户进程内存,客户端应用程序没有使用IOKit将其显式标记为可供驱动程序使用。这不符合苹果关于安全、保障和沙盒的想法,所以这类东西在DriverKit中是不可用的。
显然,kext是全能的,所以这在以前是可能的,事实上,我自己也在运输驱动程序中使用过这项技术,然后在将kext移植到DriverKit时遇到了麻烦。
据我所知,直接访问客户端进程内存的唯一方法是:
IOConnectCall…Method()s,以便它们在驱动程序中作为IOMemoryDescriptors到达。请注意,这些可以在驱动程序中保留更长时间,但至少对于输入结构,用户空间端的更新不会反映在驱动程序端,因为使用了写时复制映射。因此,它们应该仅用于在预期方向上发送数据。IOConnectMapMemory64()/CopyClientMemoryForType().将现有IOMemoryDescriptor映射到其空间
这确实意味着你不能使用像你正在使用的那样的间接数据结构。你必须使用“打包的”结构,或者将索引放入持久的共享缓冲区。
所谓“打包”结构,我指的是包含头结构的缓冲区,比如你的clientData,在连续的内存中,后面跟着其他的数据,比如你的buffer,通过偏移量引用它到这个连续的内存中。整个连续的内存块可以作为输入结构传递。
我已经向Apple提交了反馈,要求在用户客户端和do之间交换数据的更强大的机制;我不知道它是否会实现,但如果这样的工具有用,我建议你也这样做。(用例子解释你想用它做什么)我们中报告它的人越多,它发生的可能性就越大。(IOMemoryDescriptor::CreateSubMemoryDescriptor()是在我提交请求后添加的;我不会声称我是第一个这样做的人,也不会说苹果在我的建议之前不打算添加它,但他们正在积极改进DriverKit API。)
问题之前的原始答案被编辑得更加具体:
(之所以保留,是因为它概括地解释了如何处理外部方法的缓冲区参数,这可能对将来的读者有帮助。)
你的问题有点模糊,但让我看看我是否能计算出你在kext中做了什么,与你在你的dext中做了什么:
IOConnectCallStructMethod(connection, selector, buffer, 256, NULL, NULL);。这意味着buffer将作为“结构输入”参数传递给外部缓冲区您的method.sizeof(io_struct_inband_t),缓冲区的内容被带内发送到内核-换句话说,它在IOConnectCallStructMethod()调用时被复制。IOExternalMethodArguments结构中的structureInput/structureInputSize字段传递的。structureInput是内核上下文中的指针,可以直接解除引用。指针仅在方法分派的执行期间有效,一旦方法返回synchronously.IOMemoryDescriptor中。要做到这一点,一种方法确实是通过IOMemoryDescriptor::CreateMapping().structureInputDescriptor IOMemoryDescriptor传递,它可以直接传递到设备I/O,或者在内核中进行内存映射以取消引用。此内存描述符直接引用用户进程的内存。DriverKit扩展在功能上受到很大的限制,但外部方法参数的到达方式几乎完全相同。
IOUserClientMethodArguments的structureInput字段到达,该字段指向一个OSData object。您可以通过getBytesNoCopy()/getLength()方法访问内容。IOMemoryDescriptor中使用此数据进行后续I/O,我所知道的唯一方法是使用IOUSBHostDevice::CreateIOBuffer()或IOBufferMemoryDescriptor::Create创建一个IOBufferMemoryDescriptor,然后将数据从IOUSBHostDevice::CreateIOBuffer()对象复制到已通过IOMemoryDescriptor引用的缓冲区中。您可以将其传递给I/O函数,或者使用CreateMapping()将其映射到驱动程序的地址空间
发布于 2021-04-09 15:07:38
namespace
{
/*
**********************************************************************************
** create a memory descriptor and map its address
**********************************************************************************
*/
IOReturn arcmsr_userclient_create_memory_descriptor_and_map_address(const void* address, size_t length, IOMemoryDescriptor** memory_descriptor)
{
IOBufferMemoryDescriptor *buffer_memory_descriptor = nullptr;
uint64_t buffer_address;
uint64_t len;
#if ARCMSR_DEBUG_IO_USER_CLIENT
arcmsr_debug_print("ArcMSRUserClient: *******************************************************\n");
arcmsr_debug_print("ArcMSRUserClient: ** IOUserClient IOMemoryDescriptor create_with_bytes \n");
arcmsr_debug_print("ArcMSRUserClient: *******************************************************\n");
#endif
if (!address || !memory_descriptor)
{
return kIOReturnBadArgument;
}
if (IOBufferMemoryDescriptor::Create(kIOMemoryDirectionInOut, length, 0, &buffer_memory_descriptor) != kIOReturnSuccess)
{
if (buffer_memory_descriptor)
{
OSSafeReleaseNULL(buffer_memory_descriptor);
}
return kIOReturnError;
}
if (buffer_memory_descriptor->Map(0, 0, 0, 0, &buffer_address, &len) != kIOReturnSuccess)
{
if (buffer_memory_descriptor)
{
OSSafeReleaseNULL(buffer_memory_descriptor);
}
return kIOReturnError;
}
if (length != len)
{
if (buffer_memory_descriptor)
{
OSSafeReleaseNULL(buffer_memory_descriptor);
}
return kIOReturnNoMemory;
}
memcpy(reinterpret_cast<void*>(buffer_address), address, length);
*memory_descriptor = buffer_memory_descriptor;
return kIOReturnSuccess;
}
} /* namespace */https://stackoverflow.com/questions/64267540
复制相似问题