LoginSignup
3
1

More than 1 year has passed since last update.

linux kernelにおけるinsmodの裏側を確認

Last updated at Posted at 2021-08-02

ちょっと早い夏休みだ自由研究をしよう(3日目)

TL;DR

  • kernel objectのinsmod処理は、kernel/module.cの中で行われる。
  • syscall(init_module)が起点となる。
  • 最終的にはkernelへのnotifierが呼ばれる。

はじめに

insmodってよく使いますよね! でも、その裏側は見た記憶があまりない… ここでは順番にその流れを確認していきたい。

busybox

組込エンジニアなので、busyboxのinsmodを起点とする。

Kernel

kernel側のソースコードは、大部分がkernel/module.cにまとまっている。

point

Q. moduleの未定義シンボルはどこで解決されるの?

A. simplify_symbols()から呼ばれた、resolve_symbol()で。

Q. moduleのアドレス再割り当てはどこで行われる?

A. apply_relocations() で補正される。

static int apply_relocations(struct module *mod, const struct load_info *info)
{
    unsigned int i;
    int err = 0;

    /* Now do relocations. */
    for (i = 1; i < info->hdr->e_shnum; i++) {
        unsigned int infosec = info->sechdrs[i].sh_info;

        /* Not a valid relocation section? */
        if (infosec >= info->hdr->e_shnum)
            continue;

        /* Don't bother with non-allocated sections */
        if (!(info->sechdrs[infosec].sh_flags & SHF_ALLOC))
            continue;

        if (info->sechdrs[i].sh_flags & SHF_RELA_LIVEPATCH)
            err = klp_apply_section_relocs(mod, info->sechdrs,
                               info->secstrings,
                               info->strtab,
                               info->index.sym, i,
                               NULL);
        else if (info->sechdrs[i].sh_type == SHT_REL)
            err = apply_relocate(info->sechdrs, info->strtab,
                         info->index.sym, i, mod);
        else if (info->sechdrs[i].sh_type == SHT_RELA)
            err = apply_relocate_add(info->sechdrs, info->strtab,
                         info->index.sym, i, mod);
        if (err < 0)
            break;
    }
    return err;
}

この関数内の、apply_relocate()は、例えば、ARMの場合ならば、arm/kernel/modules.c内に定義されている。

Q. kernelはどうやってinsmodされたことを知覚するの?

A. do_init_module()内の関数が、kernelへの通知処理。

/*
 * This is where the real work happens.
 *
 * Keep it uninlined to provide a reliable breakpoint target, e.g. for the gdb
 * helper command 'lx-symbols'.
 */
static noinline int do_init_module(struct module *mod)
{
    int ret = 0;
    struct mod_initfree *freeinit;

    freeinit = kmalloc(sizeof(*freeinit), GFP_KERNEL);
    if (!freeinit) {
        ret = -ENOMEM;
        goto fail;
    }
    freeinit->module_init = mod->init_layout.base;

    /*
     * We want to find out whether @mod uses async during init.  Clear
     * PF_USED_ASYNC.  async_schedule*() will set it.
     */
    current->flags &= ~PF_USED_ASYNC;

    do_mod_ctors(mod);
    /* Start the module */
    if (mod->init != NULL)
        ret = do_one_initcall(mod->init);
    if (ret < 0) {
        goto fail_free_freeinit;
    }
    if (ret > 0) {
        pr_warn("%s: '%s'->init suspiciously returned %d, it should "
            "follow 0/-E convention\n"
            "%s: loading module anyway...\n",
            __func__, mod->name, ret, __func__);
        dump_stack();
    }

    /* Now it's a first class citizen! */
    mod->state = MODULE_STATE_LIVE;
    blocking_notifier_call_chain(&module_notify_list,
                     MODULE_STATE_LIVE, mod);

    /* Delay uevent until module has finished its init routine */
    kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);


まとめ

  • kernel objectのinsmod処理は、kernel/module.cの中で行われる。
  • syscall(init_module)が起点となる。
  • 最終的にはkernelへのnotifierが呼ばれる。
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1