modlen -= (size_t)ms.signer_len + ms.key_id_len;
*_modlen = modlen; //Return the real size of the module after removing the signature verification information
//Move the file pointer to the signature information
sig = mod + modlen;
/* For the moment, only support RSA and X.509 identifiers */
if (ms.algo != PKEY_ALGO_RSA || ms.id_type != PKEY_ID_X509)
return -ENOPKG;
if (ms.hash >= PKEY_HASH__LAST || !pkey_hash_algo[ms.hash])
return -ENOPKG;
//Read the signer name and key identifier from the file sig and return the key
key = request_asymmetric_key(sig, ms.signer_len,sig + ms.signer_len, ms.key_id_len);
if (IS_ERR(key))
return PTR_ERR(key);
//Digest the module contents.
pks = mod_make_digest(ms.hash, mod, modlen);
if (IS_ERR(pks)) {
ret = PTR_ERR(pks);
goto error_put_key;
}
//Extract an MPI array from the signature data. This represents the actual signature. Each raw MPI is prefaced by a BE 2-byte value indicating the size of the MPI in bytes.RSA signatures only have one MPI, so currently we only read one.
ret = mod_extract_mpi_array(pks, sig + ms.signer_len + ms.key_id_len,sig_len);
if (ret < 0)
goto error_free_pks;
//Initiate the use of an asymmetric key to verify a signature
//key: The asymmetric key to verify against
//sig: The signature to check
ret = verify_signature(key, pks);
pr_devel("verify_signature() = %dn", ret);
error_free_pks:
mpi_free(pks->rsa.s);
kfree(pks);
error_put_key:
key_put(key);
pr_devel("<==%s() = %dn", __func__, ret);
return ret;
}
static int elf_header_check(struct load_info *info)
{
if (info->len < sizeof(*(info->hdr)))
return -ENOEXEC;
// Check the elf file header, file type (.ko file must be a relocatable file), architecture and section size to see if they are set correctly
if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0|| info->hdr->e_type != ET_REL
|| !elf_check_arch(info->hdr)|| info->hdr->e_shentsize != sizeof(Elf_Shdr))
return -ENOEXEC;
// Check the offset address of the section
if (info->hdr->e_shoff >= info->len
|| (info->hdr->e_shnum * sizeof(Elf_Shdr) >info->len - info->hdr->e_shoff))
return -ENOEXEC;
return 0;
}
static struct module *layout_and_allocate(struct load_info *info, int flags)
{
struct module *mod;
int err;
//Set the info structure, check the crc value of module_layout, and return a struct module structure stored in the .gnu.linkonce.this_module section. The starting address of the module is exactly the starting address of the .gnu.linkonce.this_module section.
mod = setup_load_info(info, flags);
if (IS_ERR(mod))
return mod;
// Check the information in the .modinfo section, including the version magic
err = check_modinfo(mod, info, flags);
if (err)
return ERR_PTR(err);
// Do nothing, return 0
err = module_frob_arch_sections(info->hdr, info->sechdrs,info->secstrings, mod);
if (err < 0)
return ERR_PTR(err);
//Remove the SHF_ALLOC flag
info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC;
//Only if the SHF_ALLOC flag is set in the section header will it be stored in memory, and the memory is divided into init part and core part
layout_sections(mod, info);
// Arrange the position for the symbol section and its related string table, and update the related size
layout_symtab(mod, info);
// Allocate memory for the SHF_ALLOC section marked in the temporary image pointed to by mod, copy it from the temporary image to the final location, and modify the starting address of the section
err = move_module(mod, info);
if (err)
return ERR_PTR(err);
//Because the module has been moved to the final memory location, the starting addresses of each section have changed, and the address pointed to by mod is invalid, so the starting address of the new ".gnu.linkonce.this_module" section (pointing to a module object) is assigned to the mod object again.
mod = (void *)info->sechdrs[info->index.mod].sh_addr;
//Scan to check for memory leaks???
kmemleak_load_module(mod, info);
return mod;
}
static struct module *setup_load_info(struct load_info *info)
{
unsigned int i;
int err;
struct module *mod;
//Find the start address of the section header table
info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;
//Find the starting address of the string section of the section name
info->secstrings = (void *)info->hdr + info->sechdrs[info->hdr->e_shstrndx].sh_offset;
//According to the virtual address copied to the kernel space memory in the elf format .ko file as the base address (ie (void *)info->hdr), rewrite the position where the first byte of the section should be located in the memory image
err = rewrite_section_headers(info);
if (err)
return ERR_PTR(err);
/*Traverse all sections to find the location of the symbol table (the only segment of type SHT_SYMTAB) and the associated symbol string table,
The sh_link of the former is the segment index of the latter*/
for (i = 1; i < info->hdr->e_shnum; i++) {
if (info->sechdrs[i].sh_type == SHT_SYMTAB){
//Find the symbol table section.symtab index
info->index.sym = i;
//Find the symbol table string section index, i.e. the .strtab section
info->index.str = info->sechdrs[i].sh_link;
//Start address of string section content
info->strtab = (char *)info->hdr + info->sechdrs[info->index.str].sh_offset;
break;
}
}
//In the .gnu.linkonce.this_module section, there is an instance of struct module. Most of the members of this structure are NULL. The compiler only initializes a few members such as name, init, exit and arch.
info->index.mod = find_sec(info, ".gnu.linkonce.this_module");
if (!info->index.mod) {
printk(KERN_WARNING "No module found in objectn");
return ERR_PTR(-ENOEXEC);
}
// mod points to an instance of struct module, which provides the module name and pointers to initialization and cleanup functions, but other members are still initialized to NULL or 0. The address of the module is temporarily set to the address given in the section of the temporary image, and the address of the module will be corrected later.
mod = (void *)info->sechdrs[info->index.mod].sh_addr;
if (info->index.sym == 0) {
printk(KERN_WARNING "%s: module has no symbols (stripped?)n", mod->name);
return ERR_PTR(-ENOEXEC);
}
//Find the ".data..percpu" section index number
info->index.pcpu = find_pcpusec(info);
// Check the crc value of the "module_layout" symbol in the module. If it fails, print the famous module loading error "Exec format error"
if (!check_modstruct_version(info->sechdrs, info->index.vers, mod))
return ERR_PTR(-ENOEXEC);
return mod;
}
static int rewrite_section_headers(struct load_info *info, int flags)
{
unsigned int i;
info->sechdrs[0].sh_addr = 0; //The address of section 0 is 0, indicating that this section does not appear in the memory image
for (i = 1; i < info->hdr->e_shnum; i++) {
Elf_Shdr *shdr = &info->sechdrs[i];
//Judge the section size
if (shdr->sh_type != SHT_NOBITS && info->len < shdr->sh_offset + shdr->sh_size) {
printk(KERN_ERR "Module len %lu truncatedn",info->len);
return -ENOEXEC;
}
//Reset the starting address of the section in the kernel space based on the base address of the elf file copied to the kernel space. shdr->sh_addr indicates the location of the first byte of the section in the memory image.
shdr->sh_addr = (size_t)info->hdr + shdr->sh_offset;
#ifndef CONFIG_MODULE_UNLOAD
/* Don't load .exit sections */
if (strstarts(info->secstrings+shdr->sh_name, ".exit"))
shdr->sh_flags &= ~(unsigned long)SHF_ALLOC;
#endif
}
//Find the __versions and .modinfo sections and record the section index
if (flags & MODULE_INIT_IGNORE_MODVERSIONS)
info->index.vers = 0;
else
info->index.vers = find_sec(info, "__versions");
info->index.info = find_sec(info, ".modinfo");
//These two sections clear the SHF_ALLOC flag, indicating that this section does not occupy memory during process execution
info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
return 0;
}
static inline int check_modstruct_version(Elf_Shdr *sechdrs,unsigned int versindex,struct module *mod)
{
const unsigned long *crc;
//Find the "module_layout" symbol in the system kernel and return the crc value of the symbol
if (!find_symbol(VMLINUX_SYMBOL_STR(module_layout), NULL,&crc, true, false))
BUG();
//Whether the crc value of the "module_layout" symbol in the system is consistent with the crc value of the "module_layout" symbol in the module
return check_version(sechdrs, versindex,VMLINUX_SYMBOL_STR(module_layout), mod, crc,NULL);
}
//Find the structure used by the symbol
struct find_symbol_arg {
//enter
const char *name; //Symbol name to be searched
bool gplok; //If true, it means the kernel module supports the GPL license
bool warn; //Warning message sign
// Output
struct module *owner; //The module to which the symbol belongs
const unsigned long *crc; //The crc value of the symbol
const struct kernel_symbol *sym; //symbol structure
};
const struct kernel_symbol *find_symbol(const char *name,struct module **owner,const unsigned long **crc,bool gplok,bool warn)
{
//Set the search symbol parameter structure
struct find_symbol_arg fsa;
fsa.name = name;
Previous article:Linux driver to create a hello module
Next article:S3C2440 Watchdog Timer Principle
Recommended ReadingLatest update time:2024-11-16 20:28
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- How do you spend the May Day holiday?
- [Chuanglong Technology Allwinner A40i Development Board] Qt performance test
- Antai Instruments Repair Sharing - Tektronix Oscilloscope Repair DPO5054B
- You can't change actors in a serialized TV series, otherwise it will become a different movie.
- The transformer in the power supply has no output after loading
- Compile imx6-ek200 with buildroot
- Using MSP430 to implement PWM signal
- Get the MPM54304 evaluation board for the first quad-output module with digital power management
- Dead time problem of IGBT drive waveform
- The difference between single-phase carrier and type 2 collector