Linux Kernel source code scenario analysis-insmod

Source: Internet
Author: User
Tags strcmp

Before looking at this article, I looked at the article, the Linux character device driver.

Insmod, there are a number of things that are generally done:

1. Open the module you want to install and read it into the user space. The so-called "module" is a compiled but not connected. o file.

2, the module must have some in the module can not be implemented within the symbol (function name or variable name), the reference to these symbols should be connected to the corresponding symbol in the kernel. For this purpose, you need to ask the kernel for the address of these symbols in the kernel through the system call Query_module . If the kernel allows the "move out" of the addresses of these symbols, the relevant "symbol table" is returned. Some symbols may not belong to the kernel itself, but to other modules that are already installed.

This completes the one-way connection module mirroring in the user space. In the following init_module parameter Mod_user, the first half is the module structure (the inside pointer points to the second half of the data), the second part is the name size + module image (which contains init_module and Cleanup_ Module) + other parameters (such as Deps) of the collection body .

3. Then, the system calls Create_module to create a module data structure in the kernel and "subscribe" to the required system (kernel) space.

4, finally, through the system call Init_module, the user space to complete the one-way connection module image into the kernel space, and then call the module named init_module function (in the Linux character device driver article is freg_init).


Next, we explain Query_module, the code is as follows:

Asmlinkage longsys_query_module (const char *name_user, int which, char *buf, size_t Bufsize,//name_user is the module name of the module in which the object is queried, The result of the query is returned through the buffer buf size_t *ret) {struct module *mod;int err;lock_kernel (); if (Name_user = = NULL) mod = &kernel_module; else {long Namelen;char *name;if ((Namelen = Get_mod_name (Name_user, &name)) < 0) {//Copy name from user space to system space Err = Namelen ; goto out;} Err =-enoent;if (Namelen = = 0)//If 0, point to the kernel itself mod = &kernel_module;else if (mod = find_module (name)) = = NULL) {//in Modu Le_list in search of the corresponding module structure put_mod_name (name); goto out;} Put_mod_name (name);} Switch (which) {case 0:err = 0;break;case Qm_modules:err = Qm_modules (buf, bufsize, ret); Break;case qm_deps:err = Qm_deps (M OD, buf, bufsize, ret);//The number of dependent modules, buf the module name of these modules break;case Qm_refs:err = qm_refs (mod, buf, bufsize, ret); Break;case qm_ Symbols:err = Qm_symbols (mod, buf, bufsize, ret); Break;case qm_info:err = Qm_info (mod, buf, bufsize, ret); break;default:e rr =-einval;break;} Out:unlock_kernel (); return err;}

struct Module *find_module (const char *name) {struct module *mod;for (mod = module_list; mod; mod = mod->next) {if (mod ->flags & mod_deleted) continue;if (!strcmp (mod->name, name)) break;} return mod;}
Static intqm_deps (struct module *mod, char *buf, size_t bufsize, size_t *ret) {size_t I, space, len;if (mod = = &kernel_ module) return-einval;if (! Mod_can_query (MoD)) if (Put_user (0, ret)) Return-efault;elsereturn 0;space = 0;for (i = 0; i < mod->ndeps; ++i) {cons t char *dep_name = The name of the module to which mod->deps[i].dep->name;//depends; Mod->deps[i] points to Module_reflen = strlen (dep_name) +1 , if (len > BufSize) goto calc_space_needed;if (Copy_to_user (buf, Dep_name, Len)) Return-efault;buf + = len;bufsize-= Len ; space + = Len;} if (Put_user (i, ret)) Return-efault;elsereturn 0;calc_space_needed:space + = Len;while (++i < mod->ndeps) space + = St Rlen (Mod->deps[i].dep->name) +1;if (Put_user (space, ret)) RETURN-EFAULT;ELSERETURN-ENOSPC;}

The various data structures are as follows:

struct module_symbol{unsigned long value;const char *name;}; struct Module_ref{struct module *dep;/* "parent" pointer */struct module *ref;/* "Child" pointer */struct module_ref *next _ref;};/  * TBD */struct module_persist;struct module{unsigned Long size_of_struct;/* = sizeof (module) */struct module *next;const Char *name;//module name unsigned long size;//module size union{atomic_t usecount;long pad;} uc;/* Needs to keep its size-so says Rth * /unsigned long flags;/* AutoClean et al */unsigned nsyms;//symbols unsigned ndeps;//the number of module dependencies that this module relies on. struct MODULE_SYMBOL *syms;//describes a symbol, including the symbol name and its address struct module_ref *deps;//This module relies on the module, because the number is fixed, so is the number of the group struct MODULE_REF *refs;// Who quoted this moduleint (*init) (void);//init_modulevoid (*cleanup) (void);//cleanup_moduleconst struct Exception_table_ Entry *ex_table_start;const struct exception_table_entry *ex_table_end; #ifdef __alpha__unsigned long GP; #endif/*  Members past this point is extensions to the basic module, support and is optional. Use Mod_member_present () to examine them. */const struct module_persist *persist_start;const struct module_persist *persist_end;int (*can_unload) (void); int runsize;/* in Modutils, not currently used */const char *kallsyms_start;/* all symbols for kernel debugging */const char * Kallsyms_end;const Char *archdata_start;/* arch specific data for module */const Char *archdata_end;const char *kernel_dat a;/* Reserved for kernel internal Use */}


Look again,create_module creates a module data structure in the kernel and "bookings" the required system (kernel) space, the code is as follows:

Asmlinkage unsigned longsys_create_module (const char *name_user, size_t size)//name_user is the name of the module, Size is the module structure size plus the mirror size of the one-way connection is completed {char *name;long namelen, error;struct module *mod;if (!capable (Cap_sys_module)) Return-eperm;lock_kernel (); if ((Namelen = Get_mod_name (Name_user, &name)) < 0) {//Copy name from user space to system space error = Namelen;goto Err0;} if (Size < sizeof (struct module) +namelen) {error =-einval;goto err1;} if (find_module (name) = NULL) {//Find the corresponding module structure in module_list error =-eexist;goto err1;} if (mod = (struct module *) module_map (size) = = NULL) {//Application for module structure error =-enomem;goto err1;} memset (mod, 0, sizeof (*MOD)), mod->size_of_struct = sizeof (*MOD);//module structure size mod->next = module_list;mod-> Name = (char *) (mod + 1);//name is stored after the module structure mod->size = size;//module structure size +name size + completed one-way-connected modules mirror size + other parameters, as shown above Mod_ usermemcpy ((char*) (mod+1), name, namelen+1),//name copied to the specified location (immediately following module) put_mod_name (name); module_list = mod;// Link into module_list error = (long) Mod;goto Err0;err1:put_mod_name (name); Err0:unlock_kernel (); return error;} 


Finally, let's seeInit_module, the module image that completes the one-way connection in the user space is loaded into the kernel space, and a function called Init_module is invoked in the module, the code is as follows:

Asmlinkage longsys_init_module (const char *name_user, struct module *mod_user)//mod_user is described above, which is the module structure in user space { struct module mod_tmp, *mod;char *name, *n_name, *name_tmp = Null;long Namelen, N_namelen, I, error;unsigned long mod_user _size;struct module_ref *dep;if (!capable (Cap_sys_module)) Return-eperm;lock_kernel (); if (Namelen = Get_mod_name ( Name_user, &name)) < 0) {//Copy name from user space to system space error = Namelen;goto err0;} if (mod = find_module (name)) = = NULL) {//Find the corresponding module structure in Module_list, we have just created error =-enoent;goto err1;}  /* Check module header size.  We allow a bit of slop over the size we is familiar with to cope with a version of Insmod for a newer kernel. But don ' t it. */if (Error = Get_user (mod_user_size, &mod_user->size_of_struct))! = 0)//Copy the size of the module structure from user space to Mod_user_ Sizegoto Err1;if (Mod_user_size < (unsigned long) & ((struct module *) 0L)->persist_start | | mod_user_size > sizeof (struct module) + 16*sizeof (void*)) {//Size checked PRINTK (kern_err"Init_module:invalid Module Header size.\n" Kern_err "A new version of the modutils is likely" "needed.\n"); error = -einval;goto err1;}  /* Hold the current contents and we play with the user's idea of righteousness. */mod_tmp = *mod;//assigns the newly found kernel space module structure mod to mod_tmpname_tmp = Kmalloc (strlen (mod->name) + 1, gfp_kernel);/* Where ' s Kstrdup ()? */if (name_tmp = = NULL) {error =-enomem;goto err1;} strcpy (name_tmp, mod->name);//Save the original name in name_tmp error = Copy_from_user (mod, Mod_user, mod_user_size);// Copy the module structure Mod_user from the user space to the kernel space module structure MODIF (error) {error =-efault;goto err2;}  /* Sanity Check the size of the module. */error =-einval;if (Mod->size > Mod_tmp.size) {printk (kern_err "Init_module:size of initialized module" "Exceeds Size of created module.\n "); goto ERR2;} Mod_bound is used to check if the object provided by the user is falling within the bounds of the module (within size) if (!mod_bound (mod->name, Namelen, MoD)) {PRINTK (Kern_err init_ Module:mod->name out of bounds.\n "); goto ERR2;} if (mod->nsyms &&!mod_bound (mod->syms, mod->nsyms, MoD) {PRINTK (kern_err "init_module:mod->syms out of bounds.\n"); goto ERR2;} if (mod->ndeps &&!mod_bound (mod->deps, mod->ndeps, MoD)) {PRINTK (Kern_err) init_module:mod->deps Out of bounds.\n "); goto ERR2;} if (Mod->init &&!mod_bound (mod->init, 0, MoD)) {PRINTK (kern_err "Init_module:mod->init out of bounds.\ n "); goto ERR2;} if (Mod->cleanup &&!mod_bound (mod->cleanup, 0, MoD)) {PRINTK (kern_err "Init_module:mod->cleanup out of bounds.\n "); goto ERR2;} if (Mod->ex_table_start > Mod->ex_table_end | | (Mod->ex_table_start &&! ((unsigned long) Mod->ex_table_start >= ((unsigned long) mod + mod->size_of_struct) && ((unsigned long) Mod->ex_table_end < (unsigned long) mod + mod->size)) | | ((unsigned long) mod->ex_table_start-(unsigned long) mod->ex_table_end)% sizeof (struct exception_table_entry) ) {PRINTK (kern_err "init_module:mod->ex_table_* invalid. \ n "); goto ERR2;} if (Mod->flags & ~mod_autoclean) {PRINTK (kern_err "Init_module:mod->flags invalid.\n"); goto ERR2;} #ifdef __alpha__if (!mod_bound (mod->gp-0x8000, 0, MoD)) {PRINTK (kern_err "init_module:mod->gp out of bounds.\n"); Goto ERR2;} #endifif (mod_member_present (mod, can_unload) && mod->can_unload &&!mod_bound (mod->can_unload , 0, MoD) {PRINTK (kern_err "init_module:mod->can_unload out of bounds.\n"); goto ERR2;} if (Mod_member_present (mod, kallsyms_end)) {if (Mod->kallsyms_end && (!mod_bound (mod->kallsyms_start, 0 , MoD) | | !mod_bound (mod->kallsyms_end, 0, MoD)) {PRINTK (kern_err "init_module:mod->kallsyms out of bounds.\n"); Goto ERR2    ; } if (Mod->kallsyms_start > Mod->kallsyms_end) {printk (kern_err "init_module:mod->kallsyms invalid.\n"); g    Oto ERR2; }}if (mod_member_present (mod, archdata_end)) {if (Mod->archdata_end && (!mod_bound (Mod->archdata_start , 0, mod) | | !mod_bound (Mod->archdata_end, 0, MoD)) {PRINTK (kern_err "Init_module:mod->archdata out of bounds.\n"); goto ERR2; } if (Mod->archdata_start > Mod->archdata_end) {printk (kern_err "Init_module:mod->archdata invalid.\n"); g    Oto ERR2; }}if (mod_member_present (mod, kernel_data) && mod->kernel_data) {PRINTK (Kern_err) init_module:mod->ker    Nel_data must be zero.\n "); Goto ERR2;}  /* Check the the user isn ' t doing something silly with the name. */if ((N_namelen = Get_mod_name (Mod->name-(unsigned long) mod + (unsigned long) mod_user, &n_name)) < 0) {//Copy the name of the module structure of the user space Mod_user to N_NAMEPRINTK (kern_err "Init_module:get_mod_name failure.\n"); error = N_namelen; Goto ERR2;} if (namelen! = N_namelen | | strcmp (N_NAME, mod_tmp.name)! = 0) {//n_name compared to the original mod_tmp.name, is consistent printk (Kern_err "Init_ Module:changed module name to "'%s ' from '%s ' \ n", N_name, Mod_tmp.name); goto ERR3;} Passed the check if (Copy_from_user (char *) mod+mod_user_size, (char *) mod_user+mod_user_size, Mod->size-mod_user_size)) {//Mirror module (contains Init_module and cleanup_module) and other parameters (e.g. Deps) The collection is copied from the user space to the kernel space module structure mod after error =-efault;goto ERR3;} if (Module_arch_init (mod)) goto err3;/* on some machines it's necessary to does something here's make the I and D caches  Consistent. */flush_icache_range (unsigned long) mod, (unsigned long) mod + mod->size); mod->next = Mod_tmp.next;mod->refs = null;/* sanity Check the module ' s dependents */for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++DEP) {struct m  Odule *o, *d = dep->dep;/* Make sure the indicated dependencies is really modules. */if (d = = MoD) {//Check dependent module is not its own MODULEPRINTK (kern_err "Init_module:self-referential" "dependency in mod->deps.\ n "); goto ERR3;} /* Scan The current modules for this dependency */for (o = module_list; O! = &kernel_module && o! = d; o = o-& Gt;next); if (o! = d) {//Check dependent module must be PRINTK in Module_list (Kern_err "Init_module:found dependency That's" "(No longer?) A module.\n "); goto ERR3;}}  /* Update module references. */for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++DEP) {struct module *d = dep->dep;//based on "dependency" relationship, determine "reference" relationship DEP ->ref = Mod;dep->next_ref = D->refs;d->refs = dep;/* Being referenced by a dependent module counts as a use  As far as Kmod is concerned. */d->flags |= mod_used_once;}  /* Free our temporary memory.  */put_mod_name (n_name);p ut_mod_name (name);/* Initialize the module. */mod->flags |= Mod_initializing;atomic_set (&mod->uc.usecount,1); if (mod->init && (Error = mod- >init ())! = 0) {//Call the Init function, i.e. init_moduleatomic_set (&mod->uc.usecount,0); Mod->flags &= ~mod_ Initializing;if (Error > 0)/* Buggy module */error =-ebusy;goto err0;}  Atomic_dec (&mod->uc.usecount);/* and set it running. */mod->flags = (Mod->flags | mod_running) & ~mod_initializing;error = 0;goto err0;err3:put_mod_name (n_name); err2:*mod = mod_tmp;strcpy ((char *) Mod->name, Name_tmp);/* We know there is the guest for this */err1:put_mod_name (name); Err0:unlock_kernel (); Kfree (name_tmp); return error;} 
Mod_bound, which checks to see if the object that the user-supplied pointer refers to falls within the bounds of the module (within size), the code is as follows:

#define MOD_BOUND (P, N, M) ((unsigned long) (p) >= ((unsigned long) (m) + (((m)->size_of_struct)) &&          (unsi gned long) ((p) + (n)) <= (unsigned long) (m) + (m)->size)
For, Mod_bound (Mod->name, Namelen, MoD):

((unsigned long) (Mod->name) >= ((unsigned long) (MoD) + ((mod)->size_of_struct)) &&          (unsigned long) ((Mod->name) + (Namelen)) <= (unsigned long) (mod) + (mod)->size)
Finally Sys_init_module, called the Mod->init method, that is Init_module, for the Linux character device driver, that is, Freg_init.

Linux Kernel source code scenario analysis-insmod

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.