Livepatching API

Livepatch 启用

int klp_enable_patch(struct klp_patch *patch)

启用 livepatch

参数

struct klp_patch *patch

要启用的补丁

描述

初始化与补丁关联的数据结构,创建 sysfs 接口,执行所需的符号查找和代码重定位,并将修补的函数注册到 ftrace。

此函数应从 livepatch module_init() 回调中调用。

返回

成功返回 0,否则返回错误

影子变量

void *klp_shadow_get(void *obj, unsigned long id)

检索影子变量数据指针

参数

void *obj

指向父对象的指针

unsigned long id

数据标识符

返回

影子变量数据元素,失败时为 NULL。

void *klp_shadow_alloc(void *obj, unsigned long id, size_t size, gfp_t gfp_flags, klp_shadow_ctor_t ctor, void *ctor_data)

分配并添加一个新的影子变量

参数

void *obj

指向父对象的指针

unsigned long id

数据标识符

size_t size

附加数据的大小

gfp_t gfp_flags

分配的 GFP 掩码

klp_shadow_ctor_t ctor

用于初始化影子数据的自定义构造函数(可选)

void *ctor_data

指向 ctor 所需的任何数据的指针(可选)

描述

使用 gfp_flags 为新的影子变量数据分配 size 字节。默认情况下,数据被清零。如果 ctor 函数不为 NULL,则会进一步初始化数据。然后,将新的影子变量添加到全局哈希表。

如果可以找到现有的 <obj, id> 影子变量,此例程将发出 WARN,提前退出并返回 NULL。

此函数保证仅当变量之前不存在时才调用构造函数。代价是 ctor 在自旋锁下的原子上下文中被调用。

返回

影子变量数据元素,重复或失败时为 NULL。

void *klp_shadow_get_or_alloc(void *obj, unsigned long id, size_t size, gfp_t gfp_flags, klp_shadow_ctor_t ctor, void *ctor_data)

获取现有或分配一个新的影子变量

参数

void *obj

指向父对象的指针

unsigned long id

数据标识符

size_t size

附加数据的大小

gfp_t gfp_flags

分配的 GFP 掩码

klp_shadow_ctor_t ctor

用于初始化影子数据的自定义构造函数(可选)

void *ctor_data

指向 ctor 所需的任何数据的指针(可选)

描述

如果已存在 <obj, id> 影子变量,则返回指向现有影子数据的指针。否则,它会创建一个新的影子变量,如 klp_shadow_alloc()

此函数保证对于给定的 obj,只有一个具有给定 id 的影子变量存在。它还保证构造函数仅在变量之前不存在时才会被调用。代价是 ctor 在自旋锁下的原子上下文中被调用。

返回

影子变量数据元素,失败时为 NULL。

void klp_shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor)

分离并释放一个 <obj, id> 影子变量

参数

void *obj

指向父对象的指针

unsigned long id

数据标识符

klp_shadow_dtor_t dtor

可用于取消注册变量和/或释放影子变量指向的数据的自定义回调(可选)

描述

此函数释放此 <obj, id> 影子变量实例的内存,调用者应相应地停止引用它。

void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor)

分离并释放所有 <_, id> 影子变量

参数

unsigned long id

数据标识符

klp_shadow_dtor_t dtor

可用于取消注册变量和/或释放影子变量指向的数据的自定义回调(可选)

描述

此函数释放所有 <_, id> 影子变量实例的内存,调用者应相应地停止引用它们。

系统状态更改

struct klp_state *klp_get_state(struct klp_patch *patch, unsigned long id)

获取有关给定补丁修改的系统状态的信息

参数

struct klp_patch *patch

修改给定系统状态的 livepatch

unsigned long id

已修改的系统状态的自定义标识符

描述

检查给定补丁是否修改了给定的系统状态。

该函数可以从预/后(取消)补丁回调或由 livepatch 添加的内核代码中调用。

返回

找到时指向 struct klp_state 的指针,否则为 NULL。

struct klp_state *klp_get_prev_state(unsigned long id)

获取有关已安装的 livepatch 修改的系统状态的信息

参数

unsigned long id

已修改的系统状态的自定义标识符

描述

检查已安装的 livepatch 是否修改了给定的系统状态。

同一个系统状态可以被多个非累积的热补丁修改。预期最新的热补丁拥有最新的信息。

该函数只能在新热补丁启用或此类转换被还原时在转换期间调用。它通常只从 pre/post (un)patch 回调中调用。

返回

指向已安装的热补丁中最新的 struct klp_state 的指针,如果未找到则为 NULL。

已安装热补丁中的最新 struct klp_state 指针,未找到则为 NULL。

对象类型

struct klp_func

用于热补丁的函数结构

定义:

struct klp_func {
    const char *old_name;
    void *new_func;
    unsigned long old_sympos;
    void *old_func;
    struct kobject kobj;
    struct list_head node;
    struct list_head stack_node;
    unsigned long old_size, new_size;
    bool nop;
    bool patched;
    bool transition;
};

成员

old_name

要修补的函数的名称

new_func

指向已修补的函数代码的指针

old_sympos

一个提示,指示可以在哪个符号位置找到旧函数(可选)

old_func

指向正在修补的函数的指针

kobj

用于 sysfs 资源的 kobject

node

klp_object func_list 的列表节点

stack_node

klp_ops func_stack 列表的列表节点

old_size

旧函数的大小

new_size

新函数的大小

nop

临时补丁,再次使用原始代码;动态分配

patched

该函数已添加到 klp_ops 列表

transition

该函数当前正在应用或还原

描述

patched 和 transition 变量定义了该函数的修补状态。当修补时,一个函数总是处于以下状态之一

patched=0 transition=0:未修补 patched=0 transition=1:未修补,临时起始状态 patched=1 transition=1:已修补,可能对某些任务可见 patched=1 transition=0:已修补,对所有任务可见

当取消修补时,顺序相反

patched=1 transition=0:已修补,对所有任务可见 patched=1 transition=1:已修补,可能对某些任务可见 patched=0 transition=1:未修补,临时结束状态 patched=0 transition=0:未修补

struct klp_callbacks

pre/post 热-(取消)补丁回调结构

定义:

struct klp_callbacks {
    int (*pre_patch)(struct klp_object *obj);
    void (*post_patch)(struct klp_object *obj);
    void (*pre_unpatch)(struct klp_object *obj);
    void (*post_unpatch)(struct klp_object *obj);
    bool post_unpatch_enabled;
};

成员

pre_patch

在代码修补之前执行

post_patch

在代码修补之后执行

pre_unpatch

在代码取消修补之前执行

post_unpatch

在代码取消修补之后执行

post_unpatch_enabled

标志,指示是否应运行 post-unpatch 回调

描述

所有回调都是可选的。只有 pre-patch 回调(如果提供)将被无条件执行。如果父 klp_object 因任何原因(包括从 pre-patch 回调返回的非零错误状态)未能修补,则不会执行任何进一步的回调。

struct klp_object

用于热补丁的内核对象结构

定义:

struct klp_object {
    const char *name;
    struct klp_func *funcs;
    struct klp_callbacks callbacks;
    struct kobject kobj;
    struct list_head func_list;
    struct list_head node;
    struct module *mod;
    bool dynamic;
    bool patched;
};

成员

name

模块名称(对于 vmlinux 为 NULL)

funcs

要在对象中修补的函数的函数条目

callbacks

在 pre/post (un)patch 之前/之后执行的函数

kobj

用于 sysfs 资源的 kobject

func_list

函数条目的动态列表

node

klp_patch obj_list 的列表节点

mod

与已修补对象关联的内核模块(对于 vmlinux 为 NULL)

dynamic

用于 nop 函数的临时对象;动态分配

patched

该对象的函数已添加到 klp_ops 列表

struct klp_state

由热补丁修改的系统状态

定义:

struct klp_state {
    unsigned long id;
    unsigned int version;
    void *data;
};

成员

id

系统状态标识符(非零)

version

更改的版本

data

自定义数据

struct klp_patch

用于热补丁的补丁结构

定义:

struct klp_patch {
    struct module *mod;
    struct klp_object *objs;
    struct klp_state *states;
    bool replace;
    struct list_head list;
    struct kobject kobj;
    struct list_head obj_list;
    bool enabled;
    bool forced;
    struct work_struct free_work;
    struct completion finish;
};

成员

mod

对热补丁模块的引用

objs

要修补的内核对象的对象条目

states

可以被修改的系统状态

replace

替换所有正在使用的补丁

list

用于全局活动使用补丁列表的列表节点

kobj

用于 sysfs 资源的 kobject

obj_list

对象条目的动态列表

enabled

该补丁已启用(但操作可能未完成)

forced

参与了强制转换

free_work

从工作队列上下文清除补丁

finish

用于等待直到可以安全删除补丁模块