//System call, the corresponding kernel function is sys_init_module() function, enter the kernel space
init_module(image, image_size, options);
rc = errno;
if (mmaped)
munmap(image, image_size);
else
free(image);
return rc;
}
void* FAST_FUNC try_to_mmap_module(const char *filename, size_t *image_size_p)
{
void *image;
struct stat st;
int fd;
//Open the module .ko file and get the file descriptor
fd = xopen(filename, O_RDONLY);
//Get the file status from the file descriptor
fstat(fd, &st);
image = NULL;
//Whether the file size exceeds the maximum file size
if (st.st_size <= *image_size_p) {
size_t image_size = st.st_size;//File size
//Map the .ko file into memory in read-only mode and return the starting address in memory
image = mmap(NULL, image_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (image == MAP_FAILED) {
image = NULL;
}
// Check if the beginning of the .ko file is in ELF standard format
else if (*(uint32_t*)image != SWAP_BE32(0x7f454C46)) {
munmap(image, image_size);
image = NULL;
} else {
*image_size_p = image_size; //Return file size
}
}
close(fd);
return image;
}
//sys_init_module(void __user *umod, unsigned long len, const char __user *uargs)
//umod: is a pointer to the area in the user address space where the module's binary code is located.
//len: the length of the area.
//uargs: is a pointer that specifies the parameters of the module.
SYSCALL_DEFINE3(init_module, void __user *, umod, unsigned long, len, const char __user *, uargs)
{
int err;
struct load_info info = { };
//Whether you have permission to load the module: capable(CAP_SYS_MODULE)
err = may_init_module();
if (err)
return err;
pr_debug("init_module: umod=%p, len=%lu, uargs=%pn",umod, len, uargs);
//Copy the memory image (elf format) of the .ko file in user space to kernel space and fill in the info structure
err = copy_module_from_user(umod, len, &info);
if (err)
return err;
//The main operation of the module
return load_module(&info, uargs, 0);
}
static int copy_module_from_user(const void __user *umod, unsigned long len,struct load_info *info)
{
int err;
//The size of the module file mapped to the user space (that is, the size of the .ko file itself)
info->len = len;
if (info->len < sizeof(*(info->hdr)))
return -ENOEXEC;
err = security_kernel_module_from_file(NULL);
if (err)
return err;
// Allocate memory for the module in kernel space and pay the starting address of the memory to member hdr, that is, the member now points to the entire module memory
info->hdr = vmalloc(info->len);
if (!info->hdr)
return -ENOMEM;
//Copy the memory image (elf format) of the .ko file in the user space to info->hdr in the kernel space
if (copy_from_user(info->hdr, umod, info->len) != 0) {
vfree(info->hdr);
return -EFAULT;
}
return 0;
}
static int load_module(struct load_info *info, const char __user *uargs,int flags)
{
struct module *mod;
long err;
err = module_sig_check(info); //Check certificate
if (err)
goto free_copy;
err = elf_header_check(info); //Check elf header
if (err)
goto free_copy;
// Arrange the modules, allocate relevant memory, and copy the relevant sections to the final image
mod = layout_and_allocate(info, flags);
if (IS_ERR(mod)) {
err = PTR_ERR(mod);
goto free_copy;
}
//Because the module image has been copied to the kernel space memory, the module object also points to the corresponding location, and then add this module object to the modules list
err = add_unformed_module(mod);
if (err)
goto free_module;
#ifdef CONFIG_MODULE_SIG
mod->sig_ok = info->sig_ok;
if (!mod->sig_ok) {
printk_once(KERN_NOTICE
"%s: module verification failed: signature and/or"
"required key missing - tainting kerneln",mod->name);
add_taint_module(mod, TAINT_FORCED_MODULE, LOCKDEP_STILL_OK);
}
#endif
// Allocate space for the pcpu section for multi-processors, which is not considered here
err = percpu_modalloc(mod, info);
if (err)
goto unlink_mod;
//Increase the module count by 1 and initialize the module list
err = module_unload_init(mod);
if (err)
goto unlink_mod;
//Find the addresses of the remaining sections and initialize the pointers related to the module object
find_module_sections(mod, info);
// Check license and version
err = check_module_license_and_versions(mod);
if (err)
goto free_unload;
//Set module information according to the .modinfo section
setup_modinfo(mod, info);
//According to the starting address of the module in the kernel set above, the starting address of the section has been updated, but the address of the symbol in the section has not been updated. Here, the symbol address is updated according to the memory address of the section.
err = simplify_symbols(mod, info);
if (err < 0)
goto free_modinfo;
//Relocate the relocation section in the module
err = apply_relocations(mod, info);
if (err < 0)
goto free_modinfo;
err = post_relocation(mod, info);
if (err < 0)
goto free_modinfo;
//Flush the instruction cache, no care
flush_module_icache(mod);
//Copy the optional parameters from user space to kernel space
mod->args = strndup_user(uargs, ~0UL >> 1);
if (IS_ERR(mod->args)) {
err = PTR_ERR(mod->args);
goto free_arch_cleanup;
}
//Processing for debug section
dynamic_debug_setup(info->debug, info->num_debug);
//Confirm whether there is a redefinition symbol and set the module status to running
err = complete_formation(mod, info);
if (err)
goto ddebug_cleanup;
/* Module is ready to execute: parsing args may do that. */
//Analyze whether the parameters are valid
err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,-32768, 32767, unknown_module_param_cb);
if (err < 0)
goto bug_cleanup;
//sysfs file system related, create corresponding items for the module in sysfs
err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
if (err < 0)
goto bug_cleanup;
//Release temporary module images and other temporary auxiliary memory areas
free_copy(info);
/* */
trace_module_load(mod);
//Call do_init_module to start running the module
return do_init_module(mod);
bug_cleanup:
/* module_bug_cleanup needs module_mutex protection */
mutex_lock(&module_mutex);
module_bug_cleanup(mod);
mutex_unlock(&module_mutex);
ddebug_cleanup:
dynamic_debug_remove(info->debug);
synchronize_sched();
kfree(mod->args);
free_arch_cleanup:
module_arch_cleanup(mod);
free_modinfo:
free_modinfo(mod);
free_unload:
module_unload_free(mod);
unlink_mod:
mutex_lock(&module_mutex);
/* Unlink carefully: kallsyms could be walking list. */
list_del_rcu(&mod->list);
wake_up_all(&module_wq);
mutex_unlock(&module_mutex);
free_module:
module_deallocate(mod, info);
free_copy:
free_copy(info);
return err;
}
static int module_sig_check(struct load_info *info)
{
//#define MODULE_SIG_STRING "~Module signature appended~n"
int err = -ENOKEY;
const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
const void *mod = info->hdr;
// Check whether the length of the elf file is greater than the length of the signature string, and compare whether the module file in the elf format has a signature string at the end of the file. If yes, subtract the length of the string from the length of the file, and confirm that the signature is of module type.
if (info->len > markerlen && memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0)
{
info->len -= markerlen; //module length minus signature string length
err = mod_verify_sig(mod, &info->len); //Verify module signature
}
if (!err) {
info->sig_ok = true;
return 0;
}
/* Not having a signature is only an error if we're strict. */
if (err < 0 && fips_enabled)
panic("Module verification failed with error %d in FIPS moden",err);
if (err == -ENOKEY && !sig_enforce)
err = 0;
return err;
}
struct module_signature {
u8 algo; /* Public-key crypto algorithm [enum pkey_algo] */
u8 hash; /* Digest algorithm [enum pkey_hash_algo] */
u8 id_type; /* Key identifier type [enum pkey_id_type] */
u8 signer_len; /* Length of signer's name */
u8 key_id_len; /* Length of key identifier */
u8 __pad[3];
__be32 sig_len; /* Length of signature data */
};
int mod_verify_sig(const void *mod, unsigned long *_modlen)
{
//mod is the starting address of the module file, _modlen is the size of the module file (removing the final signature string length)
struct public_key_signature *pks;
struct module_signature ms;
struct key *key;
const void *sig;
size_t modlen = *_modlen, sig_len;
int ret;
pr_devel("==>%s(,%zu)n", __func__, modlen);
// Check length
if (modlen <= sizeof(ms))
return -EBADMSG;
//If there is a signature string at the end of the .ko file, there is a module_signature structure above the signature string. Read the contents of this structure
memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
modlen -= sizeof(ms); //Modify the module file length accordingly
sig_len = be32_to_cpu(ms.sig_len); //Get the signature data length
if (sig_len >= modlen)
return -EBADMSG;
modlen -= sig_len; //Module file length minus signature data length
if ((size_t)ms.signer_len + ms.key_id_len >= modlen)
return -EBADMSG;
//Module file length minus the signer's name length and key length
Previous article:Linux driver to create a hello module
Next article:S3C2440 Watchdog Timer Principle
Recommended ReadingLatest update time:2024-11-16 20:38
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 to achieve automated testing of LCR?
- Which company can make PCB boards with a width of about 2MM?
- How to speed up the program running speed of Huada HC32F460 HC32F4A0?
- Namisoft's design report on labview spectrum analyzer
- [Iprober 520 current probe] Calibration and use in PCB mode
- A brief history of hard disk interface evolution
- Hot plug and unplug
- EEWORLD University ---- STM32CubeMX and STM32Cube HAL basics
- [TI mmWave Radar Evaluation]_3_AWR1843BOOST Corridor Ranging Test Environment
- What is the relationship between the Internet of Things and embedded systems?