カーネルモジュールのマジック番号(その2)
カーネルモジュールのロードは、load_module()で行われ、モジュールがロード可能かどうかは、そこからcheck_modstruct_version()およびsame_magic()で行われています。
最初のfind_symbol()は、すでに動作している任意のカーネルモジュールから、struct_moduleと言うシンボル名を探し出し、そのCRCを取得します(たぶん)。そしてcheck_version()で、そのCRCと、ロードしようとしているモジュールのstruct_moduleシンボルのCRCが、同じかどうかチェックします。
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; } #endiftry_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 }
補足
カーネルのバージョンマジック番号は、動的に取得するのでなく、ソース内にstaticの変数として埋め込まれています。static const char vermagic[] = VERMAGIC_STRING;