kernel中__init等宏总结

关于__init__initdata__exit__exitdata及类似的宏

打开Linux Kernel源代码树中的文件:include/init.h,可以看到有下面的宏定议:

#define __init  __attribute__ ((__section__ (".init.text")))  __cold
#define __initdata    __attribute__ (( __section__ (".init.data")))
#define __exitdata   __attribute__ (( __section__ (".exit.data")))
#define __exit_call  __attribute_used__ __attribute__ (( __section__ (".exitcall.exit")))
#define __init_refok  oninline __attribute__ ((__section__ (".text.init.refok")))
#define __initdata_refok __attribute__ ((__section__ (".data.init.refok")))
#define __exit_refok noinline __attribute__ ((__section__ (".exit.text.refok")))

.........

#ifdef MODULE
#define __exit  __attribute__ (( __section__ (".exit.text"))) __cold
#else
#define __exit __attribute_used__ __attribute__ ((__section__ (".exit.text"))) __cold
#endif

__init__initdata等属性标志,是要把这种属性的代码放入目标文件的.init.text节,数据放入.init.data节──这一过程是通过编译内核时为相关目标平台提供了xxx.lds链接脚本来指导ld完成的。
对编译成module的代码和数据来说,当模块加载时,__init属性的函数就被执行;
对静态编入内核的代码和数据来说,当内核引导时,do_basic_setup()函数调用do_initcalls()函数,后者负责所有.init节函数的执行。

关于__attribute__

要了解Linux Kernel代码的分段信息,需要了解一下gcc的__attribute__的编绎属性或定义的函数或数,__attribute__主要用于改变所声明据的特性,它有很多子项,用于改变作用对象的特性。比如对函数,noline将禁止进行内联扩展、noreturn表示没有返回值、pure表明函数除返回值外,不会通过其它(如全局变量、指针)对函数外部产生任何影响。但这里对代码段起作用是子项section。

__attribute__的section子项的使用格式为:

__attribute__((section("section_name")))

其作或用是将作用的函数数据放入指定名为”section_name”输入段。

这里还要注意一下两个概念:输入段和输出段

输入段和输出段是相对于要生成最终的elf或binary时的Link过程说的,Link过程的输入大都是由源代码编绎生成的目标文件.o,那么这些.o文件中包含的段相对link过程来说就是输入段,而Link的输出一般是可执行文件elf或库等,这些输出文件中也包含有段,这些输出文件中的段就叫做输出段。输入段和输出段本来没有什么必然的联系,是互相独立,只是在Link过程中,Link程序会根据一定的规则(这些规则其实来源于Link Script),将不同的输入段重新组合到不同的输出段中,即使是段的名字,输入段和输出段可以完全不同。

其用法举例如下:

int  var __attribute__((section(
<think>好的,用户现在问的是“__lsm_ro_after_init”,我需要先理解这个术语的含义和用途。首先,我记得LSM代表Linux安全模块,是Linux内核的安全框架。用户可能是在内核代码或者相关文档中遇到了这个标识符,想了解它的作用。 接下来,我需要确认“__lsm_ro_after_init”的具体作用。根据之前的知识,Linux内核中的一些数据结构或函数在初始化完成后会被标记为只读,以提高安全性,防止被恶意修改。这可能涉及到内核的 hardening 机制,比如通过内存保护属性来限制某些区域的写入权限。 然后,分解这个术语。“__lsm”可能指与LSM相关的部分,“ro”是read-only的缩写,“after_init”表示在内核初始化之后。结合起来,应该是在内核初始化阶之后,将某些LSM相关的数据或函数设置为只读,防止运行时被篡改。 需要验证这个理解是否正确。可能查阅内核文档或源码中的相关部分。比如,在内核的security/目录下,LSM相关的代码可能会使用类似__ro_after_init的属性,特别是在安全模块初始化后标记关键数据结构为只读。 另外,用户可能是在开发或调试内核模块时遇到了这个标识符,需要了解其使用场景和注意事项。例如,开发者可能需要知道如何正确应用这个属性,或者为什么他们的代码在修改某些结构时遇到问题。 还要考虑用户可能的背景。如果用户是内核开发者或系统安全工程师,他们可能需要详细的技术细节;如果是学生或爱好者,可能需要更基础的解释。因此,回答需要兼顾技术准确性和易懂性。 最后,需要总结这个属性的作用、应用场景和潜在影响,确保用户能够理解其在内核安全中的重要性,并正确使用它来增强系统的安全性。</think>### **`__lsm_ro_after_init` 详解** `__lsm_ro_after_init` 是 Linux 内核中与安全模块(LSM, Linux Security Module)相关的特殊标记,用于增强内核数据的安全性。以下是其核心作用和实现原理的解析: --- #### **1. 基本定义** - **语法形式**: ```c __lsm_ro_after_init ``` 该标记通常附加在内核变量或函数的声明中,例如: ```c static struct security_hook_list selinux_hooks[] __lsm_ro_after_init; ``` - **作用阶**: - 在内核初始化阶(`__init` 阶),允许对标记的数据进行读写操作。 - 在内核初始化完成后(`after_init`),将数据所在内存页设置为 **只读**(Read-Only),防止运行时被篡改。 --- #### **2. 安全设计原理** - **防御性编程**: - 内核安全模块(如 SELinux、AppArmor)的配置或钩子函数(hook)一旦初始化完成,通常不再需要修改。 - 通过将此类数据标记为只读,可阻止恶意代码或漏洞利用(如缓冲区溢出)对安全关键数据的篡改,提升内核的运行时安全性。 - **内存保护机制**: - 利用 CPU 的内存管理单元(MMU),通过设置内存页属性为 `PROT_READ`,禁止写入操作。 - 若尝试修改只读内存,会触发内核的 **页错误**(Page Fault),导致系统崩溃(保护性错误),而非允许潜在的攻击行为。 --- #### **3. 技术实现** - **内核代码中的实现**: - `__lsm_ro_after_init` 是定义,展开后可能关联到 `__ro_after_init` 或类似的属性标记。 - 具体实现依赖内核编译时的链接脚本(linker script),将标记的数据分配到特定的内存(如 `.data..ro_after_init`)。 - **初始化流程**: 1. **初始化阶**:数据被正常写入(例如通过 `security_add_hooks()` 加载 SELinux 钩子)。 2. **初始化完成后**:内核调用 `mark_rodata_ro()` 函数,将相关内存设为只读。 --- #### **4. 典型应用场景** - **LSM 钩子函数表**: ```c // SELinux 的钩子函数声明示例 static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(binder_transfer_file, selinux_binder_transfer_file), LSM_HOOK_INIT(ptrace_access_check, selinux_ptrace_access_check), // ... }; ``` - 初始化完成后,钩子函数表不再需要修改,设为只读可防止恶意模块篡改安全策略。 - **安全模块的全局配置**: 例如 SELinux 的 enforcing 模式标志(需在初始化后锁定状态)。 --- #### **5. 开发者注意事项** - **兼容性要求**: - 标记为 `__lsm_ro_after_init` 的变量或函数必须在内核初始化阶完成全部写入操作。 - 若在运行时尝试修改此类数据,会导致 **内核崩溃**(oops 或 panic)。 - **调试方法**: - 若需临时禁用只读保护(例如调试阶),可在内核配置中关闭 `CONFIG_DEBUG_RODATA` 或 `CONFIG_STRICT_KERNEL_RWX`。 - 注意:禁用保护会降低系统安全性,仅限临时使用! --- #### **6. 关联内核参数** - **`rodata=off`**: 启动时通过内核参数 `rodata=off` 可全局禁用只读数据保护(包括 `__lsm_ro_after_init` 标记的数据)。 - 用途:调试内核或兼容老旧硬件,但会显著降低系统安全性。 - 示例: ```bash # 在 GRUB_CMDLINE_LINUX 中添加 GRUB_CMDLINE_LINUX="... rodata=off" ``` --- ### **总结** `__lsm_ro_after_init` 是 Linux 内核安全模块的关键加固机制,通过 **内存只读化** 阻止对安全敏感数据的运行时篡改。它在 SELinux、AppArmor 等模块中广泛应用,是内核防御漏洞利用的重要技术手。开发者需确保相关数据在初始化阶完成配置,避免运行时写入引发崩溃。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值