Analysis of Linux driver kernel loading module process

Publisher:upsilon30Latest update time:2024-08-20 Source: cnblogs Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

//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

[1] [2] [3] [4] [5] [6] [7] [8]
Reference address:Analysis of Linux driver kernel loading module process

Previous article:Linux driver to create a hello module
Next article:S3C2440 Watchdog Timer Principle

Recommended ReadingLatest update time:2024-11-16 20:38

Linux driver: s3c2410_ts/s3c2440_ts module loading process
Preface By analyzing the s3c2410_ts/s3c2440_ts module loading process, the bus-device-driver model and input subsystem framework in the Linux driver are analyzed . Main process analysis diagram s3c2440_ts main process analysis system initialization MACHINE_START(SMDK2410,"SMDK2410") MACHINE_START(SMDK2410, "SMDK241
[Microcontroller]
[Linux bottom layer] U-boot ksz8081 network driver debugging
Micrel is an excellent PHY chip. For more information about the chip, please refer to: ksz8081 datasheet interpretation System version: Ubuntu18.04-64 Compiler version: gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1) uboot version: 2018.07-linux4sam_6.0 Board model: at91sama5d3x-xplained MCU mode
[Microcontroller]
LCD device driver in Linux (1) - framebuffer
1. framebuffer Framebuffer is an interface provided by Linux system for display devices. It abstracts the display buffer, shields the underlying differences of image hardware, and allows upper-level applications to directly read and write the display buffer in graphics mode. Users do not need to care about the speci
[Microcontroller]
LCD device driver in Linux (1) - framebuffer
09-S3C2440 driver learning (Part 3) Embedded Linux platform bus driver and separation and layering driver framework
Introduction Platform: The kernel has IIC bus, PCI bus, serial bus, SPI bus, CAN bus, single bus, etc. Some devices can be mounted on these buses, and then the devices and drivers are matched through bus matching. However, some devices do not belong to these buses, so a virtual bus, that is, Platform bus, is introdu
[Microcontroller]
09-S3C2440 driver learning (Part 3) Embedded Linux platform bus driver and separation and layering driver framework
S3C6410 RTC driver in Linux (3)
The previous article talked about the s3c_rtc_probe function, but because it was too long, I didn’t finish it. This article continues the previous article. After talking about this function, we can go back to the s3c_rtc_probe function and continue talking about it in the next article. Do you still remember this sen
[Microcontroller]
S3C6410 RTC driver in Linux (3)
S3C2416 Linux2.6.21 driver porting - added UART3 and baud rate setting bug eliminated
1. Transplantation Environment (The red bold text indicates the modified content, and the blue bold text indicates the content with special attention) 1.Host environment: Ubuntu-10.10 under Virtualbox 2. Compilation Compilation environment: arm-linux-gcc v4.4.3 3.uboot: U-Boot 1.3.4 (provided by Youjian) 4. Li
[Microcontroller]
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号