カーネルモジュールのマジック番号(その2)
Rev.1を表示中。最新版はこちら。
カーネルモジュールのロードは、load_module()で行われ、モジュールがロード可能かどうかは、そこからcheck_modstruct_version()およびsame_magic()で行われています。
static noinline struct module *load_module(void __user *umod,
unsigned long len,
const char __user *uargs)
{
:
:
versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");
:
if (!check_modstruct_version(sechdrs, versindex, mod)) {
err = -ENOEXEC;
goto free_hdr;
}
modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
if (!modmagic) {
err = try_to_force_load(mod, "magic");
if (err)
goto free_hdr;
} else if (!same_magic(modmagic, vermagic, versindex)) {
printk(KERN_ERR "%s: version magic '%s' should be '%s'\n",
mod->name, modmagic, vermagic);
err = -ENOEXEC;
goto free_hdr;
}
:
:
}
check_modstruct_version()は、CONFIG_MODVERSIONSを設定しないでカーネルを構築した場合、常に1を返すようにコンパイルされます。本チェックは行わない事になります。以下はCONFIG_MODVERSIONSを設定した場合の処理になります。最初のfind_symbol()は、すでに動作している任意のカーネルモジュールから、struct_moduleと言うシンボル名を探し出し、そのCRCを取得します(たぶん)。そしてcheck_version()で、そのCRCと、ロードしようとしているモジュールのstruct_moduleシンボルのCRCが、同じかどうかチェックします。
static inline int check_modstruct_version(Elf_Shdr *sechdrs,
unsigned int versindex,
struct module *mod)
{
const unsigned long *crc;
if (IS_ERR_VALUE(find_symbol("struct_module", NULL, &crc, true, false)))
BUG();
return check_version(sechdrs, versindex, "struct_module", mod, crc);
}
same_magic()でマジック番号のチェックを行います。CONFIG_MODVERSIONSが設定されてのカーネルの場合、マジック番号の最初の項目だけのチェックとなります。そうでない場合マジック番号すべてのチェックとなります。引数のhas_crcsは、モジュールに__versionsがあるかどうかのフラグで、モジュールがCONFIG_MODVERSIONSを設定しないで作成された場合、この値は0となります。この場合マジック番号全文字列とのチェックとなります。CONFIG_MODVERSIONSでのカーネルでCONFIG_MODVERSIONSでないモジュールをロードする場合を想定しての事でしょうか?でもこの場合check_modstruct_version()で弾かれるのでは思うのですが・・・。よく解りません。
#ifdef CONFIG_MODVERSIONS
static inline int same_magic(const char *amagic, const char *bmagic,
bool has_crcs)
{
if (has_crcs) {
amagic += strcspn(amagic, " ");
bmagic += strcspn(bmagic, " ");
}
return strcmp(amagic, bmagic) == 0;
}
#else
static inline int same_magic(const char *amagic, const char *bmagic,
bool has_crcs)
{
return strcmp(amagic, bmagic) == 0;
}
#endif
try_to_force_load()はvermagicを設定してないモジュールの処理で、カーネルがCONFIG_MODULE_FORCE_LOADでコンパイルされている時に限り、ロード可能となります。
static int try_to_force_load(struct module *mod, const char *symname)
{
#ifdef CONFIG_MODULE_FORCE_LOAD
if (!(tainted & TAINT_FORCED_MODULE))
printk("%s: no version for \"%s\" found: kernel tainted.\n",
mod->name, symname);
add_taint_module(mod, TAINT_FORCED_MODULE);
return 0;
#else
return -ENOEXEC;
#endif
}






