このページを編集する際は、編集に関する方針に従ってください。

概要

引数

  • 変数名--説明

実装

/* Allocate and load the module: note that size of section 0 is always

  zero, and we rely on this for optional sections. */

static struct module *load_module(void __user *umod,

				  unsigned long len,
				  const char __user *uargs)

{

	Elf_Ehdr *hdr;
	Elf_Shdr *sechdrs;
	char *secstrings, *args, *modmagic, *strtab = NULL;
	unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
		exportindex, modindex, obsparmindex, infoindex, gplindex,
		crcindex, gplcrcindex, versindex, pcpuindex;
	long arglen;
	struct module *mod;
	long err = 0;
	void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
	struct exception_table_entry *extable;
  • 例外テーブルのエントリ
    • 例外テーブルのエントリは2つのアドレスから構成されている
      • 例外を発生したアドレス
      • 例外をハンドリングするアドレス
    • exception_table_entry/linux2.6を参照
	DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
	       umod, len, uargs);
	if (len < sizeof(*hdr))
		return ERR_PTR(-ENOEXEC);
  • エラーコード -ENOEXECをvoidへのポインタにして返す
    • これによりオブジェクトと比較することが可能になる
    • 詳細はERR_PTR()/linux2.6を参照
	/* Suck in entire file: we'll want most of it. */
	/* vmalloc barfs on "unusual" numbers.  Check here */
	if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)
		return ERR_PTR(-ENOMEM);
  • サイズlenのメモリ領域を非連続メモリ領域から獲得する
    • 獲得されたメモリ領域の先頭アドレスを返す
    • 詳細はvmalloc()/linux2.6を参照
  • エラーコード -ENOMEMをvoidへのポインタにして返す
    • これによりオブジェクトと比較することが可能になる
    • 詳細はERR_PTR()/linux2.6を参照
	if (copy_from_user(hdr, umod, len) != 0) {
  • ユーザアドレスumodからカーネルアドレスhdrへデータをコピーする
    • ただし、指定されたユーザアドレスが不正なアドレスである場合は、カーネルアドレスにはコピーされず、カーネルアドレスのコピー領域には0で埋められる
    • コピーできなかったサイズ(単位はbyte)を返す。正常にコピーできた場合は0を返す。
    • 詳細はcopy_from_user()/linux2.6を参照
		err = -EFAULT;
		goto free_hdr;
	}
	/* Sanity checks against insmoding binaries or wrong arch,
          weird elf version */
	if (memcmp(hdr->e_ident, ELFMAG, 4) != 0
	    || hdr->e_type != ET_REL
	    || !elf_check_arch(hdr)
	    || hdr->e_shentsize != sizeof(*sechdrs)) {
  • 2つのメモリhdr->e_ident, ELFMAGの範囲4byteを比較する
    • 等しければ0を返し、等しくなければ0以外の値を返す
    • 詳細はmemcmp()/linux2.6を参照
		err = -ENOEXEC;
		goto free_hdr;
	}
	if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr))
		goto truncated;
	/* Convenience variables */
	sechdrs = (void *)hdr + hdr->e_shoff;
	secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
	sechdrs[0].sh_addr = 0;
	for (i = 1; i < hdr->e_shnum; i++) {
		if (sechdrs[i].sh_type != SHT_NOBITS
		    && len < sechdrs[i].sh_offset + sechdrs[i].sh_size)
			goto truncated;
		/* Mark all sections sh_addr with their address in the
		   temporary image. */
		sechdrs[i].sh_addr = (size_t)hdr + sechdrs[i].sh_offset;
		/* Internal symbols and strings. */
		if (sechdrs[i].sh_type == SHT_SYMTAB) {
			symindex = i;
			strindex = sechdrs[i].sh_link;
			strtab = (char *)hdr + sechdrs[strindex].sh_offset;
		}

#ifndef CONFIG_MODULE_UNLOAD

		/* Don't load .exit sections */
		if (strncmp(secstrings+sechdrs[i].sh_name, ".exit", 5) == 0)
			sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
  • 文字列secstrings+sechdrs[i].sh_nameと".exit"を比較する
    • 比較の結果、一致する場合は0を、一致しない場合は1を返す
    • 詳細はstrncmp()/linux2.6を参照

#endif

	}
	modindex = find_sec(hdr, sechdrs, secstrings,
			    ".gnu.linkonce.this_module");
  • セクション名".gnu.linkonce.this_module"を、セクションsecstringsから見つける。
    • 見つかった場合は、セクションヘッダテーブルのインデックスを返す
    • 詳細はfind_sec()/linux2.6を参照
	if (!modindex) {
		printk(KERN_WARNING "No module found in object\n");
		err = -ENOEXEC;
		goto free_hdr;
	}
	mod = (void *)sechdrs[modindex].sh_addr;
	if (symindex == 0) {
		printk(KERN_WARNING "%s: module has no symbols (stripped?)\n",
		       mod->name);
		err = -ENOEXEC;
		goto free_hdr;
	}
	/* Optional sections */
	exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
  • セクション名"__ksymtab"を、セクションsecstringsから見つける。
    • 見つかった場合は、セクションヘッダテーブルのインデックスを返す
    • 詳細はfind_sec()/linux2.6を参照
	gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
  • セクション名"__ksymtab_gpl"を、セクションsecstringsから見つける。
    • 見つかった場合は、セクションヘッダテーブルのインデックスを返す
    • 詳細はfind_sec()/linux2.6を参照
	crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
  • セクション名"__kcrctab"を、セクションsecstringsから見つける。
    • 見つかった場合は、セクションヘッダテーブルのインデックスを返す
    • 詳細はfind_sec()/linux2.6を参照
	gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
  • セクション名"__kcrctab_gpl"を、セクションsecstringsから見つける。
    • 見つかった場合は、セクションヘッダテーブルのインデックスを返す
    • 詳細はfind_sec()/linux2.6を参照
	setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
  • セクション名"__param"を、セクションsecstringsから見つける。
    • 見つかった場合は、セクションヘッダテーブルのインデックスを返す
    • 詳細はfind_sec()/linux2.6を参照
	exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
  • セクション名"__ex_table"を、セクションsecstringsから見つける。
    • 見つかった場合は、セクションヘッダテーブルのインデックスを返す
    • 詳細はfind_sec()/linux2.6を参照
	obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
  • セクション名"__obsparm"を、セクションsecstringsから見つける。
    • 見つかった場合は、セクションヘッダテーブルのインデックスを返す
    • 詳細はfind_sec()/linux2.6を参照
	versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
  • セクション名"__versions"を、セクションsecstringsから見つける。
    • 見つかった場合は、セクションヘッダテーブルのインデックスを返す
    • 詳細はfind_sec()/linux2.6を参照
	infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");
  • セクション名".modinfo"を、セクションsecstringsから見つける。
    • 見つかった場合は、セクションヘッダテーブルのインデックスを返す
    • 詳細はfind_sec()/linux2.6を参照
	pcpuindex = find_pcpusec(hdr, sechdrs, secstrings);
  • セクションsecstringsからセクション名".data.percpu"を見つける。
    • 見つかった場合は、セクションヘッダテーブルのインデックスを返す
    • 詳細はfind_pcpusec()/linux2.6を参照
	/* Don't keep modinfo section */
	sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;

#ifdef CONFIG_KALLSYMS

	/* Keep symbol and string tables for decoding later. */
	sechdrs[symindex].sh_flags |= SHF_ALLOC;
	sechdrs[strindex].sh_flags |= SHF_ALLOC;

#endif

	/* Check module struct version now, before we try to use module. */
	if (!check_modstruct_version(sechdrs, versindex, mod)) {
    • 詳細はcheck_modstruct_version()/linux2.6?を参照
		err = -ENOEXEC;
		goto free_hdr;
	}
	modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
  • セクションテーブルインデックスinfoindexに対応するセクションの、タグ"vermagic"の値を返す
	/* This is allowed: modprobe --force will invalidate it. */
	if (!modmagic) {
		tainted |= TAINT_FORCED_MODULE;
		printk(KERN_WARNING "%s: no version magic, tainting kernel.\n",
		       mod->name);
	} else if (!same_magic(modmagic, vermagic)) {
    • 詳細はsame_magic()/linux2.6?を参照
		printk(KERN_ERR "%s: version magic '%s' should be '%s'\n",
		       mod->name, modmagic, vermagic);
		err = -ENOEXEC;
		goto free_hdr;
	}
	/* Now copy in args */
	arglen = strlen_user(uargs);
	if (!arglen) {
		err = -EFAULT;
		goto free_hdr;
	}
	args = kmalloc(arglen, GFP_KERNEL);
	if (!args) {
		err = -ENOMEM;
		goto free_hdr;
	}
	if (copy_from_user(args, uargs, arglen) != 0) {
  • ユーザアドレスuargsからカーネルアドレスargsへデータをコピーする
    • ただし、指定されたユーザアドレスが不正なアドレスである場合は、カーネルアドレスにはコピーされず、カーネルアドレスのコピー領域には0で埋められる
    • コピーできなかったサイズ(単位はbyte)を返す。正常にコピーできた場合は0を返す
    • 詳細はcopy_from_user()/linux2.6を参照
		err = -EFAULT;
		goto free_mod;
	}
	if (find_module(mod->name)) {
  • モジュール名mod->nameに対応するモジュールを見つけ、返す
		err = -EEXIST;
		goto free_mod;
	}
	mod->state = MODULE_STATE_COMING;
	/* Allow arches to frob section contents and sizes.  */
	err = module_frob_arch_sections(hdr, sechdrs, secstrings, mod);
    • 詳細はmodule_frob_arch_sections()/linux2.6?を参照
	if (err < 0)
		goto free_mod;
	if (pcpuindex) {
		/* We have a special allocation for this section. */
		percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size,
					 sechdrs[pcpuindex].sh_addralign);
		if (!percpu) {
			err = -ENOMEM;
			goto free_mod;
		}
		sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
		mod->percpu = percpu;
	}
	/* Determine total sizes, and put offsets in sh_entsize.  For now
	   this is done generically; there doesn't appear to be any
	   special cases for the architectures. */
	layout_sections(mod, hdr, sechdrs, secstrings);
    • 詳細はlayout_sections()/linux2.6?を参照
	/* Do the allocs. */
	ptr = module_alloc(mod->core_size);
  • サイズmod->core_sizeのメモリ領域をカーネル実行されるページとして非連続メモリ領域から獲得する
	if (!ptr) {
		err = -ENOMEM;
		goto free_percpu;
	}
	memset(ptr, 0, mod->core_size);
	mod->module_core = ptr;
	ptr = module_alloc(mod->init_size);
  • サイズmod->init_sizeのメモリ領域をカーネル実行されるページとして非連続メモリ領域から獲得する
	if (!ptr && mod->init_size) {
		err = -ENOMEM;
		goto free_core;
	}
	memset(ptr, 0, mod->init_size);
	mod->module_init = ptr;
	/* Transfer each section which specifies SHF_ALLOC */
	DEBUGP("final section addresses:\n");
	for (i = 0; i < hdr->e_shnum; i++) {
		void *dest;
		if (!(sechdrs[i].sh_flags & SHF_ALLOC))
			continue;
		if (sechdrs[i].sh_entsize & INIT_OFFSET_MASK)
			dest = mod->module_init
				+ (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK);
		else
			dest = mod->module_core + sechdrs[i].sh_entsize;
		if (sechdrs[i].sh_type != SHT_NOBITS)
			memcpy(dest, (void *)sechdrs[i].sh_addr,
			       sechdrs[i].sh_size);
  • sechdrs[i].sh_addrからdestへメモリ領域をコピーする
		/* Update sh_addr to point to copy in image. */
		sechdrs[i].sh_addr = (unsigned long)dest;
		DEBUGP("\t0x%lx %s\n", sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name);
	}
	/* Module has been moved. */
	mod = (void *)sechdrs[modindex].sh_addr;
	/* Now we've moved module, initialize linked lists, etc. */
	module_unload_init(mod);
	/* Set up license info based on the info section */
	set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
    • 詳細はset_license()/linux2.6?を参照
  • セクションテーブルインデックスinfoindexに対応するセクションの、タグ"license"の値を返す
	/* Fix up syms, so that st_value is a pointer to location. */
	err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
			       mod);
    • 詳細はsimplify_symbols()/linux2.6?を参照
	if (err < 0)
		goto cleanup;
	/* Set up EXPORTed & EXPORT_GPLed symbols (section 0 is 0 length) */
	mod->num_syms = sechdrs[exportindex].sh_size / sizeof(*mod->syms);
	mod->syms = (void *)sechdrs[exportindex].sh_addr;
	if (crcindex)
		mod->crcs = (void *)sechdrs[crcindex].sh_addr;
	mod->num_gpl_syms = sechdrs[gplindex].sh_size / sizeof(*mod->gpl_syms);
	mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr;
	if (gplcrcindex)
		mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;

#ifdef CONFIG_MODVERSIONS

	if ((mod->num_syms && !crcindex) || 
	    (mod->num_gpl_syms && !gplcrcindex)) {
		printk(KERN_WARNING "%s: No versions for exported symbols."
		       " Tainting kernel.\n", mod->name);
		tainted |= TAINT_FORCED_MODULE;
	}

#endif

	/* Now do relocations. */
	for (i = 1; i < hdr->e_shnum; i++) {
		const char *strtab = (char *)sechdrs[strindex].sh_addr;
		unsigned int info = sechdrs[i].sh_info;
		/* Not a valid relocation section? */
		if (info >= hdr->e_shnum)
			continue;
		/* Don't bother with non-allocated sections */
		if (!(sechdrs[info].sh_flags & SHF_ALLOC))
			continue;
		if (sechdrs[i].sh_type == SHT_REL)
			err = apply_relocate(sechdrs, strtab, symindex, i,mod);
		else if (sechdrs[i].sh_type == SHT_RELA)
			err = apply_relocate_add(sechdrs, strtab, symindex, i,
						 mod);
    • 詳細はapply_relocate_add()/linux2.6?を参照
		if (err < 0)
			goto cleanup;
	}
 	/* Set up and sort exception table */
	mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable);
	mod->extable = extable = (void *)sechdrs[exindex].sh_addr;
	sort_extable(extable, extable + mod->num_exentries);
	/* Finally, copy percpu area over. */
	percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr,
		       sechdrs[pcpuindex].sh_size);
    • 詳細はpercpu_modcopy()/linux2.6?を参照
	add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
    • 詳細はadd_kallsyms()/linux2.6?を参照
	err = module_finalize(hdr, sechdrs, mod);
	if (err < 0)
		goto cleanup;
	mod->args = args;
	if (obsparmindex) {
		err = obsolete_params(mod->name, mod->args,
				      (struct obsolete_modparm *)
				      sechdrs[obsparmindex].sh_addr,
				      sechdrs[obsparmindex].sh_size
				      / sizeof(struct obsolete_modparm),
				      sechdrs, symindex,
				      (char *)sechdrs[strindex].sh_addr);
    • 詳細はobsolete_params()/linux2.6?を参照
		if (setupindex)
			printk(KERN_WARNING "%s: Ignoring new-style "
			       "parameters in presence of obsolete ones\n",
			       mod->name);
	} else {
		/* Size of section 0 is 0, so this works well if no params */
		err = parse_args(mod->name, mod->args,
				 (struct kernel_param *)
				 sechdrs[setupindex].sh_addr,
				 sechdrs[setupindex].sh_size
				 / sizeof(struct kernel_param),
				 NULL);
  • コマンドラインmod->argsを解析し、カーネルに渡すパラメータを設定する
	}
	err = mod_sysfs_setup(mod, 
			      (struct kernel_param *)
			      sechdrs[setupindex].sh_addr,
			      sechdrs[setupindex].sh_size
			      / sizeof(struct kernel_param));
    • 詳細はmod_sysfs_setup()/linux2.6?を参照
	if (err < 0)
		goto arch_cleanup;
	add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
    • 詳細はadd_sect_attrs()/linux2.6?を参照
	/* Get rid of temporary copy */
	vfree(hdr);
	/* Done! */
	return mod;
arch_cleanup:
	module_arch_cleanup(mod);
cleanup:
	module_unload_free(mod);
	module_free(mod, mod->module_init);
  • アドレスmod->module_initに対応する非連続メモリ領域の(物理メモリとの)マッピングを解除する
    • マッピングを解除する非連続メモリ領域に属するページ群はページキャッシュによりキャッシュされる
    • 詳細はmodule_free()/linux2.6を参照
free_core:
	module_free(mod, mod->module_core);
  • アドレスmod->module_coreに対応する非連続メモリ領域の(物理メモリとの)マッピングを解除する
    • マッピングを解除する非連続メモリ領域に属するページ群はページキャッシュによりキャッシュされる
    • 詳細はmodule_free()/linux2.6を参照
free_percpu:
	if (percpu)
		percpu_modfree(percpu);
free_mod:
	kfree(args);
  • オブジェクトargsをスラブアロケータに解放する
free_hdr:
	vfree(hdr);
  • アドレスhdrに対応する非連続メモリ領域の(物理メモリとの)マッピングを解除する
    • マッピングを解除する非連続メモリ領域に属するページ群はページキャッシュによりキャッシュされる
    • 詳細はvfree()/linux2.6を参照
	if (err < 0) return ERR_PTR(err);
  • エラーコード errをvoidへのポインタにして返す
    • これによりオブジェクトと比較することが可能になる
    • 詳細はERR_PTR()/linux2.6を参照
	else return ptr;
truncated:
	printk(KERN_ERR "Module len %lu truncated\n", len);
	err = -ENOEXEC;
	goto free_hdr;

}

呼出元


  • 1 -- 2015-07-03 (金) 19:33:29
    • 1' -- 2015-07-03 (金) 19:33:27
  • 1 -- 2015-07-03 (金) 19:33:26
  • 1 -- 2015-07-03 (金) 19:33:24
  • 1 -- 2015-07-03 (金) 19:33:23
  • 1 -- 2015-07-03 (金) 19:33:15
  • 1 -- 2015-06-25 (木) 23:33:46
    • 1' -- 2015-06-25 (木) 23:33:45
  • 1 -- 2015-06-25 (木) 23:33:43
  • 1 -- 2015-06-25 (木) 23:33:42
  • 1 -- 2015-06-25 (木) 23:33:40
  • 1 -- 2015-06-24 (水) 15:12:06
    • 1' -- 2015-06-24 (水) 15:12:05
  • 1 -- 2015-06-24 (水) 15:12:03
  • 1 -- 2015-06-24 (水) 15:12:02
  • 1 -- 2015-06-24 (水) 15:12:00
  • 1 -- 2015-06-04 (木) 23:40:06
    • 1' -- 2015-06-04 (木) 23:40:04
  • 1 -- 2015-06-04 (木) 23:40:03
  • 1 -- 2015-06-04 (木) 23:40:01
  • 1 -- 2015-06-04 (木) 23:40:00

履歴

  • 作者:ひら
  • 日付:2007/3/2
  • 対象:2.6.10
    更新日更新者更新内容

コメント/タグ?


  • 1 -- 2015-06-25 (木) 23:34:06
    • 1' -- 2015-06-25 (木) 23:34:05
  • 1 -- 2015-06-25 (木) 23:34:03
  • 1 -- 2015-06-25 (木) 23:34:01
  • 1 -- 2015-06-25 (木) 23:34:00
  • 1 -- 2015-06-25 (木) 23:33:54
  • 1 -- 2015-06-24 (水) 15:12:32
    • 1' -- 2015-06-24 (水) 15:12:30
  • 1 -- 2015-06-24 (水) 15:12:29
  • 1 -- 2015-06-24 (水) 15:12:27
  • 1 -- 2015-06-24 (水) 15:12:26
  • 1 -- 2015-06-04 (木) 23:41:26
    • 1' -- 2015-06-04 (木) 23:41:23
  • 1 -- 2015-06-04 (木) 23:41:21
  • 1 -- 2015-06-04 (木) 23:41:20
  • 1 -- 2015-06-04 (木) 23:41:18
  • 1 -- 2015-06-04 (木) 23:40:22
  • 特徴的 -- 2007-03-05 (月) 16:39:22

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2015-07-03 (金) 19:33:29 (871d)