Linux内核相关信息杂谈笔记

2023-12-14 23:27:15

1.x86的一种方式修改内核内存读写属性cr0方式

当自己编写对应的驱动,要将驱动数据写入内核使用,需要驱动文件ko文件中编写关闭跟打开内核内存的相关函数,通常x86架构的通过如下汇编修改cr0属性即可。如下:

// 关闭当前x86内核属性保护
unsigned int get_cr0(void)
{
    unsigned int cr0 = 0;
    unsigned int ret;
    asm volatile ("movq %%cr0, %%rax": "=a"(cr0));
    ret = cr0;
    // clear the 20th bit of CR0
    cr0 &= 0xfffeffff;
    asm volatile ("movq %%rax, %%cr0"::"a"(cr0));
    return ret;
}

//重新打开x86内核属性保护
void set_cr0(unsigned int val)
{
    asm volatile ("movq %%rax, %%cr0": : "a"(val));
}


//系统函数设置
void funcr0()
{
    write_cr0(read_cr0() & (~0x10000));
    //doing

	write_cr0(read_cr0() | (0x10000));
}

2.符号表信息的获取以及通过符号表调用实现修改内存的cr0读写属性修改

符号表是一种系统调用的列表,系统内核存储在一个数组当中。sys_call_table_ptr,当通过系统内部的数组标识,可以获取到对应内核方法。

a.通过从/proc/kallsyms符号表中读取对应的符号表信息,找到名称为 “sys_call_table”符号表对应的地址,可通过该符号表收地址,通过具体的类型的类型索引找到对应的回调函数,当有事件触发时,调用对应的回调函数。

例如:

// 通过读取上文件:
unsigned long* pSyscallAddr = NULL;
char* p = NULL;
while (p = fgets(buf, sizeof(buf), fileallsyms)) {
        if (strstr(buf, " sys_call_table")) {
            sscanf(buf, "%lx", pSyscallAddr);
            break;
        }
}

b.或者/boot/System.map-内核版本号,相关文件获取对应的符号表地址。

    struct utsname fileName; //获取name -r信息
    char szFileName[256];
    strcpy(szFileName, "/boot/System.map-");
    uname(&fileName);
    strcat(szFileName, fileName.release);
    if(F_OK == access(szFileName, R_OK)){
        return fopen(szFileName, "r");
    }

c.arm架构关闭系统内存读写属性

void (*updte_mapping_prot)(phys_addr_t phys,unsigned long virtphys_addr_t size pgprot_t prot);
static unsigned long start_ro,end_ro,section_size;

void initMapping()
{
    updte_mapping_prot = (void*)kallsyms_lookup_name("update_mapping_prot");
    start_ro = (unsigned long)kallsyms_lookup_name("__start_rodata")
    end_ro = (unsigned long)kallsyms_lookup_name("__end_rodata")
    section_size = end_ro - start_ro;
}

//cr0系统内核的读写属性
void close_cr0()
{
    update_mapping_prot(__pa_symbol(start_ro),(unsigned long)start_ro,section_size,PAGE_KERNEL);
}

void open_cr0()
{
    update_mapping_prot(__pa_symbol(start_ro),(unsigned long)start_ro,section_size,PAGE_KERNEL_R0);
}

3.Linux内核相关属性杂谈笔记

3.1 linux内核中current结构体

current 是一个指向当前运行进程(或者说任务)的指针。它是 task_struct 结构体的一个实例,而 task_struct 结构体用于表示进程或任务的描述信息。current 变量是一个宏,其定义通常是通过一个内联汇编实现的。

以下是 current 在内核源代码中的定义:

#include <linux/sched.h>

#define current (current_thread_info()->task)

这里,current_thread_info() 用于获取当前线程信息的指针,而 tasktask_struct 结构体中的一个成员,表示指向进程描述信息的指针。

task_struct 结构体包含了关于进程的大量信息,如进程状态、进程 ID、进程的地址空间信息、调度信息等。current 通过指向当前运行进程的 task_struct 结构体,提供了对当前进程各种属性的访问。

在内核代码中,可以通过 current 来访问当前运行进程的信息,例如:

pid_t current_pid = current->pid; // 获取当前进程的进程ID

需要注意的是,由于 current 在全局范围内使用,它只能在进程上下文中(而非中断上下文)使用。在中断上下文中,可以使用 get_current() 函数获取当前运行的任务指针。

#include <linux/sched.h>

struct task_struct *task = get_current();

总的来说,current 提供了一种方便的方式来访问当前运行进程的信息,但在使用时需要小心,确保在适当的上下文中使用。

注:其中两个变量常使用:

? ? ? ? ?current->comm :进程名称。?current->pid:进程id

3.2 内核中GFP_KERNEL定义

在 Linux 内核中,GFP_KERNEL 是一个用于内存分配的标志位。它表示内核正在以进程的上下文(即在进程上下文中运行的代码)中进行内存分配。这是一种常见的内存分配标志,用于表示分配是在内核代码执行期间进行的,因此可能需要使用进程上下文可用的资源。

GFP 代表 "Get Free Pages",而 KERNEL 表示在内核上下文中进行分配。这种标志通常用于在内核模块、驱动程序或其他运行在内核空间的代码中进行内存分配。

例如,在使用 kmalloc 函数进行内存分配时,可以使用 GFP_KERNEL 标志:

#include <linux/slab.h> void* ptr = kmalloc(size, GFP_KERNEL);

这表示 kmalloc 将在内核上下文中尝试分配内存,并且在分配失败时可能会睡眠等待内存可用。与之相对的是 GFP_ATOMIC,表示在不睡眠的情况下进行内存分配,通常用于中断处理程序等不能休眠的上下文。

这些标志提供了有关内存分配行为的信息,以确保分配的内存满足特定上下文的要求。

3.3 内核中的DEFINE_RWLOCK宏定义

?DEFINE_RWLOCK 是一个用于定义读写锁(rwlock)的宏。读写锁是一种特殊的锁机制,允许多个读者同时访问共享资源,但只允许一个写者访问。这有助于提高并发性能,因为多个线程可以同时读取数据,但写操作需要独占性。例如:

#include <linux/rwlock.h>

DEFINE_RWLOCK(my_rwlock);

void example_function(void) {
    // 读者加锁
    read_lock(&my_rwlock);

    // 执行读操作

    // 读者解锁
    read_unlock(&my_rwlock);

    // 写者加锁
    write_lock(&my_rwlock);

    // 执行写操作

    // 写者解锁
    write_unlock(&my_rwlock);
}

代码中,DEFINE_RWLOCK(my_rwlock) 定义了一个名为 my_rwlock 的读写锁,并在 example_function 中展示了如何使用这个读写锁。读者使用 read_lockread_unlock 加锁和解锁,而写者使用 write_lockwrite_unlock

在实际的内核代码中,读写锁常用于保护对共享数据结构的并发访问。通过使用读写锁,内核可以实现高效的读取和适当的写入同步。需要注意的是,读写锁的正确使用需要开发人员仔细考虑并发访问的模式,以防止潜在的竞态条件和死锁。

? ? ? ?

文章来源:https://blog.csdn.net/qq_26105397/article/details/128523859
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。