首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用IOMemoryDescriptor::CreateMapping在DriverKit中映射内存?

如何使用IOMemoryDescriptor::CreateMapping在DriverKit中映射内存?
EN

Stack Overflow用户
提问于 2020-10-09 01:15:35
回答 2查看 496关注 0票数 2

我正在努力学习更多关于DriverKit和内存管理的知识,我读到了这个问题:

How to allocate memory in a DriverKit system extension and map it to another process?

我想了解一下如何使用IOMemoryDescriptor::CreateMapping

我写了一个小应用来测试我做的地方(非常简单的代码):

代码语言:javascript
复制
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用户客户机类中,我正在做(我正在简化):

代码语言:javascript
复制
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基础的地方。

还是说我以前做的事情是不可能的?

在我的驱动程序中,这是我不知道如何使用CreateMappingIOMemoryMap的地方,所以这个缓冲区可以映射到内存位置并使用不同的值进行更新。

我可以创建一个IOBufferMemoryDescriptor,但是如何从我的应用程序将它绑定到缓冲区呢?我也不理解CreateMapping的各种选项。

请注意,在另一个测试应用程序中,我已经成功地使用了IOConnectMapMemory64()/CopyClientMemoryForType(),但我想具体了解一下CreateMapping()。

(我希望我对这个问题编辑了很多次…对StackOverflow来说还是个新手)

EN

回答 2

Stack Overflow用户

发布于 2020-10-09 17:50:41

还是我以前做不到的事情?

简而言之,不是。

您正在尝试映射任意用户进程内存,客户端应用程序没有使用IOKit将其显式标记为可供驱动程序使用。这不符合苹果关于安全、保障和沙盒的想法,所以这类东西在DriverKit中是不可用的。

显然,kext是全能的,所以这在以前是可能的,事实上,我自己也在运输驱动程序中使用过这项技术,然后在将kext移植到DriverKit时遇到了麻烦。

据我所知,直接访问客户端进程内存的唯一方法是:

  • 通过将buffers >= 4097字节作为结构输入或输出参数传递给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.
  • Because是256字节长,它小于或等于sizeof(io_struct_inband_t),缓冲区的内容被带内发送到内核-换句话说,它在IOConnectCallStructMethod()调用时被复制。
  • 这意味着在您的kext的外部方法调度函数中,结构输入是通过传入的IOExternalMethodArguments结构中的structureInput/structureInputSize字段传递的。structureInput是内核上下文中的指针,可以直接解除引用。指针仅在方法分派的执行期间有效,一旦方法返回synchronously.
  • If,就不能使用它。如果需要使用设备I/O的缓冲区,则可能需要将其包装在IOMemoryDescriptor中。要做到这一点,一种方法确实是通过IOMemoryDescriptor::CreateMapping().
  • If缓冲区是4097字节或更大,它将通过structureInputDescriptor IOMemoryDescriptor传递,它可以直接传递到设备I/O,或者在内核中进行内存映射以取消引用。此内存描述符直接引用用户进程的内存。

DriverKit扩展在功能上受到很大的限制,但外部方法参数的到达方式几乎完全相同。

  • 小结构通过IOUserClientMethodArgumentsstructureInput字段到达,该字段指向一个OSData object。您可以通过getBytesNoCopy()/getLength()方法访问内容。
  • 如果您需要在IOMemoryDescriptor中使用此数据进行后续I/O,我所知道的唯一方法是使用IOUSBHostDevice::CreateIOBuffer()IOBufferMemoryDescriptor::Create创建一个IOBufferMemoryDescriptor,然后将数据从IOUSBHostDevice::CreateIOBuffer()对象复制到已通过IOMemoryDescriptor引用的缓冲区中。您可以将其传递给I/O函数,或者使用CreateMapping()

将其映射到驱动程序的地址空间

票数 3
EN

Stack Overflow用户

发布于 2021-04-09 15:07:38

代码语言:javascript
复制
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 */
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64267540

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档