是否可以 vmap 内核模块的内存?

发布于 2024-11-16 11:49:32 字数 1986 浏览 0 评论 0原文

通过 vmap 映射内核模块的内存是否有任何限制?在我的系统上,我编写了一个简单的 KMOD,它映射内核函数 (printk) 和模块函数 (printx),并检查映射是否相等。结果表明映射模块的 printx 存在问题 - 映射和函数的代码不相等。有人可以解释我做错了什么吗?这是代码:

// vmap-test.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>

int printx(void)
{
    return 0;
}


void vmap_action(unsigned long address)
{
    void * mapping;
    struct page * page;

    page = virt_to_page(address);
    mapping = vmap(&page, 1, VM_MAP, PAGE_KERNEL);
    if (mapping) {
        int i = 0;
        void * data = mapping + offset_in_page(address);

        printk("VMAP: src %p -> dst %p\n", (void *)address, data);
        for (i=0; i<16; i++) {
            printk("%.02x %.02x\n", ((u8 *)address)[i], ((u8 *)data)[i]);
        }
        vunmap(mapping);
    }
}

int my_module_init(void)
{
    vmap_action((unsigned long)printk);
    vmap_action((unsigned long)printx);

    return 0;
}
module_init(my_module_init);

void my_module_exit(void)
{
}
module_exit(my_module_exit);

dmesg 的结果是:

vmap(printk)

[88107.398146] VMAP: src ffffffff813dfaef -> dst ffffc900117ddaef
[88107.398148] 55 55
[88107.398149] 48 48
[88107.398150] 89 89
[88107.398151] e5 e5
[88107.398152] 48 48
[88107.398153] 83 83
[88107.398154] ec ec
[88107.398155] 50 50
[88107.398156] 0f 0f
[88107.398156] 1f 1f
[88107.398157] 44 44
[88107.398158] 00 00
[88107.398159] 00 00
[88107.398160] 48 48
[88107.398161] 8d 8d
[88107.398162] 45 45

vmap(printx)

[88107.398164] VMAP: src ffffffffa009a010 -> dst ffffc900117fd010
[88107.398166] 55 35
[88107.398167] 48 fb
[88107.398168] 89 53
[88107.398169] e5 d5
[88107.398170] 0f f7
[88107.398171] 1f 97
[88107.398171] 44 ee
[88107.398172] 00 fd
[88107.398173] 00 d5
[88107.398174] 31 2d
[88107.398175] c0 bf
[88107.398176] 5d f6
[88107.398177] c3 2d
[88107.398178] 0f bd
[88107.398179] 1f b7
[88107.398180] 00 99

欢迎任何建议:) 谢谢。

Is there any constraint to the mapping kernel module's memory via the vmap? On my system I write a simple KMOD, that maps a kernel-function (printk) and a module-function (printx) and check if mappings are equals. The result shows me that there is a problem with mapping module's printx - the mapping and the function's code does not equals. Could someone explain me what I do wrong? And here is the code:

// vmap-test.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>

int printx(void)
{
    return 0;
}


void vmap_action(unsigned long address)
{
    void * mapping;
    struct page * page;

    page = virt_to_page(address);
    mapping = vmap(&page, 1, VM_MAP, PAGE_KERNEL);
    if (mapping) {
        int i = 0;
        void * data = mapping + offset_in_page(address);

        printk("VMAP: src %p -> dst %p\n", (void *)address, data);
        for (i=0; i<16; i++) {
            printk("%.02x %.02x\n", ((u8 *)address)[i], ((u8 *)data)[i]);
        }
        vunmap(mapping);
    }
}

int my_module_init(void)
{
    vmap_action((unsigned long)printk);
    vmap_action((unsigned long)printx);

    return 0;
}
module_init(my_module_init);

void my_module_exit(void)
{
}
module_exit(my_module_exit);

And the result with dmesg is:

vmap(printk)

[88107.398146] VMAP: src ffffffff813dfaef -> dst ffffc900117ddaef
[88107.398148] 55 55
[88107.398149] 48 48
[88107.398150] 89 89
[88107.398151] e5 e5
[88107.398152] 48 48
[88107.398153] 83 83
[88107.398154] ec ec
[88107.398155] 50 50
[88107.398156] 0f 0f
[88107.398156] 1f 1f
[88107.398157] 44 44
[88107.398158] 00 00
[88107.398159] 00 00
[88107.398160] 48 48
[88107.398161] 8d 8d
[88107.398162] 45 45

vmap(printx)

[88107.398164] VMAP: src ffffffffa009a010 -> dst ffffc900117fd010
[88107.398166] 55 35
[88107.398167] 48 fb
[88107.398168] 89 53
[88107.398169] e5 d5
[88107.398170] 0f f7
[88107.398171] 1f 97
[88107.398171] 44 ee
[88107.398172] 00 fd
[88107.398173] 00 d5
[88107.398174] 31 2d
[88107.398175] c0 bf
[88107.398176] 5d f6
[88107.398177] c3 2d
[88107.398178] 0f bd
[88107.398179] 1f b7
[88107.398180] 00 99

Any suggestions are welcome :) Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

心的憧憬 2024-11-23 11:49:32

好吧,我发现 KSplice 项目中实现了类似的功能,如下所示:

/*
 * map_writable creates a shadow page mapping of the range
 * [addr, addr + len) so that we can write to code mapped read-only.
 *
 * It is similar to a generalized version of x86's text_poke.  But
 * because one cannot use vmalloc/vfree() inside stop_machine, we use
 * map_writable to map the pages before stop_machine, then use the
 * mapping inside stop_machine, and unmap the pages afterwards.
 */
static void *map_writable(void *addr, size_t len)
{
    void *vaddr;
    int nr_pages = DIV_ROUND_UP(offset_in_page(addr) + len, PAGE_SIZE);
    struct page **pages = kmalloc(nr_pages * sizeof(*pages), GFP_KERNEL);
    void *page_addr = (void *)((unsigned long)addr & PAGE_MASK);
    int i;

    if (pages == NULL)
        return NULL;

    for (i = 0; i < nr_pages; i++) {
        if (__module_address((unsigned long)page_addr) == NULL) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) || !defined(CONFIG_X86_64)
            pages[i] = virt_to_page(page_addr);
#else /* LINUX_VERSION_CODE < && CONFIG_X86_64 */
/* e3ebadd95cb621e2c7436f3d3646447ac9d5c16d was after 2.6.21
 * This works around a broken virt_to_page() from the RHEL 5 backport
 * of x86-64 relocatable kernel support.
 */
            pages[i] =
                pfn_to_page(__pa_symbol(page_addr) >> PAGE_SHIFT);
#endif /* LINUX_VERSION_CODE || !CONFIG_X86_64 */
            WARN_ON(!PageReserved(pages[i]));
        } else {
            pages[i] = vmalloc_to_page(addr);
        }
        if (pages[i] == NULL) {
            kfree(pages);
            return NULL;
        }
        page_addr += PAGE_SIZE;
    }
    vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
    kfree(pages);
    if (vaddr == NULL)
        return NULL;
    return vaddr + offset_in_page(addr);
}

因此,它的出现对内核和模块的内存有不同的处理。如果页面不属于任何模块,则使用 vmalloc_to_page 而不是 virt_to_phys。我会检查是否有帮助并稍后发布结果。

Well, I found that similar function is implemented in KSplice project and here is it:

/*
 * map_writable creates a shadow page mapping of the range
 * [addr, addr + len) so that we can write to code mapped read-only.
 *
 * It is similar to a generalized version of x86's text_poke.  But
 * because one cannot use vmalloc/vfree() inside stop_machine, we use
 * map_writable to map the pages before stop_machine, then use the
 * mapping inside stop_machine, and unmap the pages afterwards.
 */
static void *map_writable(void *addr, size_t len)
{
    void *vaddr;
    int nr_pages = DIV_ROUND_UP(offset_in_page(addr) + len, PAGE_SIZE);
    struct page **pages = kmalloc(nr_pages * sizeof(*pages), GFP_KERNEL);
    void *page_addr = (void *)((unsigned long)addr & PAGE_MASK);
    int i;

    if (pages == NULL)
        return NULL;

    for (i = 0; i < nr_pages; i++) {
        if (__module_address((unsigned long)page_addr) == NULL) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) || !defined(CONFIG_X86_64)
            pages[i] = virt_to_page(page_addr);
#else /* LINUX_VERSION_CODE < && CONFIG_X86_64 */
/* e3ebadd95cb621e2c7436f3d3646447ac9d5c16d was after 2.6.21
 * This works around a broken virt_to_page() from the RHEL 5 backport
 * of x86-64 relocatable kernel support.
 */
            pages[i] =
                pfn_to_page(__pa_symbol(page_addr) >> PAGE_SHIFT);
#endif /* LINUX_VERSION_CODE || !CONFIG_X86_64 */
            WARN_ON(!PageReserved(pages[i]));
        } else {
            pages[i] = vmalloc_to_page(addr);
        }
        if (pages[i] == NULL) {
            kfree(pages);
            return NULL;
        }
        page_addr += PAGE_SIZE;
    }
    vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
    kfree(pages);
    if (vaddr == NULL)
        return NULL;
    return vaddr + offset_in_page(addr);
}

So, as it comes there is a different handling of kernel's and module's memory. If the page is not belongs to any module then vmalloc_to_page rather then virt_to_phys used. I'll check if it helps and post the result later.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文