hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I7ZH67 CVE: NA
--------------------------------
After patch being enabled, the first few instructions would be modified to jump to the new function, then callers of old function would jump to new function but always through the old function.
Therefore when enabling a new patch or disable a patch on the old function, we should always consider that old function is running. Otherwise, there may be situations where old functions are being modified before jumping to new function and cause issues.
Signed-off-by: Zheng Yejian zhengyejian1@huawei.com --- arch/arm/kernel/livepatch.c | 24 +++++++++++++++++++++--- arch/arm64/kernel/livepatch.c | 24 +++++++++++++++++++++--- arch/powerpc/kernel/livepatch_32.c | 24 +++++++++++++++++++++--- arch/x86/kernel/livepatch.c | 25 +++++++++++++++++++++---- 4 files changed, 84 insertions(+), 13 deletions(-)
diff --git a/arch/arm/kernel/livepatch.c b/arch/arm/kernel/livepatch.c index b4d26474ba33..b1711d947dfe 100644 --- a/arch/arm/kernel/livepatch.c +++ b/arch/arm/kernel/livepatch.c @@ -134,12 +134,17 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, struct klp_object *obj; struct klp_func_node *func_node; struct klp_func *func; - unsigned long func_addr, func_size; + unsigned long func_addr = 0; + unsigned long func_size; struct klp_func_list *pcheck = NULL;
for (obj = patch->objs; obj->funcs; obj++) { for (func = obj->funcs; func->old_name; func++) { + unsigned long old_func = (unsigned long)func->old_func; + if (enable) { + bool need_check_old = false; + if (func->patched || func->force == KLP_ENFORCEMENT) continue; /* @@ -153,7 +158,7 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, * No patched on this function * [ the origin one ] */ - func_addr = (unsigned long)func->old_func; + func_addr = old_func; func_size = func->old_size; } else { /* @@ -184,6 +189,13 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, func->old_name, func->force); if (ret) return ret; + need_check_old = (func_addr != old_func); + } + if (need_check_old) { + ret = add_func_to_list(check_funcs, &pcheck, old_func, + func->old_size, func->old_name, func->force); + if (ret) + return ret; } } else { /* @@ -203,7 +215,7 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, * the stack. */ if (list_is_singular(&func_node->func_stack)) { - func_addr = (unsigned long)func->old_func; + func_addr = old_func; func_size = func->old_size; } else { struct klp_func *prev; @@ -219,6 +231,12 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, func->old_name, 0); if (ret) return ret; + if (func_addr != old_func) { + ret = add_func_to_list(check_funcs, &pcheck, old_func, + func->old_size, func->old_name, 0); + if (ret) + return ret; + } #endif func_addr = (unsigned long)func->new_func; func_size = func->new_size; diff --git a/arch/arm64/kernel/livepatch.c b/arch/arm64/kernel/livepatch.c index 6b5bcb491125..5b0171254820 100644 --- a/arch/arm64/kernel/livepatch.c +++ b/arch/arm64/kernel/livepatch.c @@ -126,13 +126,18 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, int ret; struct klp_object *obj; struct klp_func *func; - unsigned long func_addr, func_size; + unsigned long func_addr = 0; + unsigned long func_size; struct klp_func_node *func_node; struct klp_func_list *pcheck = NULL;
for (obj = patch->objs; obj->funcs; obj++) { for (func = obj->funcs; func->old_name; func++) { + unsigned long old_func = (unsigned long)func->old_func; + if (enable) { + bool need_check_old = false; + if (func->patched || func->force == KLP_ENFORCEMENT) continue; /* @@ -142,7 +147,7 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, func_node = klp_find_func_node(func->old_func); if (!func_node || list_empty(&func_node->func_stack)) { - func_addr = (unsigned long)func->old_func; + func_addr = old_func; func_size = func->old_size; } else { /* @@ -173,6 +178,13 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, func->old_name, func->force); if (ret) return ret; + need_check_old = (func_addr != old_func); + } + if (need_check_old) { + ret = add_func_to_list(check_funcs, &pcheck, old_func, + func->old_size, func->old_name, func->force); + if (ret) + return ret; } } else { /* @@ -193,7 +205,7 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, * the stack. */ if (list_is_singular(&func_node->func_stack)) { - func_addr = (unsigned long)func->old_func; + func_addr = old_func; func_size = func->old_size; } else { struct klp_func *prev; @@ -209,6 +221,12 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, func->old_name, 0); if (ret) return ret; + if (func_addr != old_func) { + ret = add_func_to_list(check_funcs, &pcheck, old_func, + func->old_size, func->old_name, 0); + if (ret) + return ret; + } #endif
func_addr = (unsigned long)func->new_func; diff --git a/arch/powerpc/kernel/livepatch_32.c b/arch/powerpc/kernel/livepatch_32.c index 7b4ed23bf2ca..3fe4f3c5790b 100644 --- a/arch/powerpc/kernel/livepatch_32.c +++ b/arch/powerpc/kernel/livepatch_32.c @@ -123,13 +123,18 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, int ret; struct klp_object *obj; struct klp_func *func; - unsigned long func_addr, func_size; + unsigned long func_addr = 0; + unsigned long func_size; struct klp_func_node *func_node; struct klp_func_list *pcheck = NULL;
for (obj = patch->objs; obj->funcs; obj++) { for (func = obj->funcs; func->old_name; func++) { + unsigned long old_func = (unsigned long)func->old_func; + if (enable) { + bool need_check_old = false; + if (func->patched || func->force == KLP_ENFORCEMENT) continue; /* @@ -143,7 +148,7 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, * No patched on this function * [ the origin one ] */ - func_addr = (unsigned long)func->old_func; + func_addr = old_func; func_size = func->old_size; } else { /* @@ -174,6 +179,13 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, func->old_name, func->force); if (ret) return ret; + need_check_old = (func_addr != old_func); + } + if (need_check_old) { + ret = add_func_to_list(check_funcs, &pcheck, old_func, + func->old_size, func->old_name, func->force); + if (ret) + return ret; } } else { /* @@ -193,7 +205,7 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, * the stack. */ if (list_is_singular(&func_node->func_stack)) { - func_addr = (unsigned long)func->old_func; + func_addr = old_func; func_size = func->old_size; } else { struct klp_func *prev; @@ -208,6 +220,12 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, func_size, func->old_name, 0); if (ret) return ret; + if (func_addr != old_func) { + ret = add_func_to_list(check_funcs, &pcheck, old_func, + func->old_size, func->old_name, 0); + if (ret) + return ret; + } #endif func_addr = (unsigned long)func->new_func; func_size = func->new_size; diff --git a/arch/x86/kernel/livepatch.c b/arch/x86/kernel/livepatch.c index 0241e560bd2e..43404fc1fdbb 100644 --- a/arch/x86/kernel/livepatch.c +++ b/arch/x86/kernel/livepatch.c @@ -120,16 +120,20 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, int ret; struct klp_object *obj; struct klp_func *func; - unsigned long func_addr, func_size; + unsigned long func_addr = 0; + unsigned long func_size; struct klp_func_node *func_node = NULL; struct klp_func_list *pcheck = NULL;
for (obj = patch->objs; obj->funcs; obj++) { for (func = obj->funcs; func->old_name; func++) { - func_node = klp_find_func_node(func->old_func); + unsigned long old_func = (unsigned long)func->old_func;
+ func_node = klp_find_func_node(func->old_func); /* Check func address in stack */ if (enable) { + bool need_check_old = false; + if (func->patched || func->force == KLP_ENFORCEMENT) continue; /* @@ -138,7 +142,7 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, */ if (!func_node || list_empty(&func_node->func_stack)) { - func_addr = (unsigned long)func->old_func; + func_addr = old_func; func_size = func->old_size; } else { /* @@ -169,6 +173,13 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, func->old_name, func->force); if (ret) return ret; + need_check_old = (func_addr != old_func); + } + if (need_check_old) { + ret = add_func_to_list(check_funcs, &pcheck, old_func, + func->old_size, func->old_name, func->force); + if (ret) + return ret; } } else { /* @@ -186,7 +197,7 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, * the stack. */ if (list_is_singular(&func_node->func_stack)) { - func_addr = (unsigned long)func->old_func; + func_addr = old_func; func_size = func->old_size; } else { struct klp_func *prev; @@ -201,6 +212,12 @@ static int klp_check_activeness_func(struct klp_patch *patch, int enable, func_size, func->old_name, 0); if (ret) return ret; + if (func_addr != old_func) { + ret = add_func_to_list(check_funcs, &pcheck, old_func, + func->old_size, func->old_name, 0); + if (ret) + return ret; + } #endif
func_addr = (unsigned long)func->new_func;