-
Notifications
You must be signed in to change notification settings - Fork 54.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
livepatch: kernel: add support for live patching
This commit introduces code for the live patching core. It implements an ftrace-based mechanism and kernel interface for doing live patching of kernel and kernel module functions. It represents the greatest common functionality set between kpatch and kgraft and can accept patches built using either method. This first version does not implement any consistency mechanism that ensures that old and new code do not run together. In practice, ~90% of CVEs are safe to apply in this way, since they simply add a conditional check. However, any function change that can not execute safely with the old version of the function can _not_ be safely applied in this version. [ jkosina@suse.cz: due to the number of contributions that got folded into this original patch from Seth Jennings, add SUSE's copyright as well, as discussed via e-mail ] Signed-off-by: Seth Jennings <sjenning@redhat.com> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Reviewed-by: Miroslav Benes <mbenes@suse.cz> Reviewed-by: Petr Mladek <pmladek@suse.cz> Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Miroslav Benes <mbenes@suse.cz> Signed-off-by: Petr Mladek <pmladek@suse.cz> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
- Loading branch information
Showing
11 changed files
with
1,273 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
What: /sys/kernel/livepatch | ||
Date: Nov 2014 | ||
KernelVersion: 3.19.0 | ||
Contact: live-patching@vger.kernel.org | ||
Description: | ||
Interface for kernel live patching | ||
|
||
The /sys/kernel/livepatch directory contains subdirectories for | ||
each loaded live patch module. | ||
|
||
What: /sys/kernel/livepatch/<patch> | ||
Date: Nov 2014 | ||
KernelVersion: 3.19.0 | ||
Contact: live-patching@vger.kernel.org | ||
Description: | ||
The patch directory contains subdirectories for each kernel | ||
object (vmlinux or a module) in which it patched functions. | ||
|
||
What: /sys/kernel/livepatch/<patch>/enabled | ||
Date: Nov 2014 | ||
KernelVersion: 3.19.0 | ||
Contact: live-patching@vger.kernel.org | ||
Description: | ||
A writable attribute that indicates whether the patched | ||
code is currently applied. Writing 0 will disable the patch | ||
while writing 1 will re-enable the patch. | ||
|
||
What: /sys/kernel/livepatch/<patch>/<object> | ||
Date: Nov 2014 | ||
KernelVersion: 3.19.0 | ||
Contact: live-patching@vger.kernel.org | ||
Description: | ||
The object directory contains subdirectories for each function | ||
that is patched within the object. | ||
|
||
What: /sys/kernel/livepatch/<patch>/<object>/<function> | ||
Date: Nov 2014 | ||
KernelVersion: 3.19.0 | ||
Contact: live-patching@vger.kernel.org | ||
Description: | ||
The function directory contains attributes regarding the | ||
properties and state of the patched function. | ||
|
||
There are currently no such attributes. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* livepatch.h - x86-specific Kernel Live Patching Core | ||
* | ||
* Copyright (C) 2014 Seth Jennings <sjenning@redhat.com> | ||
* Copyright (C) 2014 SUSE | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version 2 | ||
* of the License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#ifndef _ASM_X86_LIVEPATCH_H | ||
#define _ASM_X86_LIVEPATCH_H | ||
|
||
#include <linux/module.h> | ||
|
||
#ifdef CONFIG_LIVE_PATCHING | ||
#ifndef CC_USING_FENTRY | ||
#error Your compiler must support -mfentry for live patching to work | ||
#endif | ||
extern int klp_write_module_reloc(struct module *mod, unsigned long type, | ||
unsigned long loc, unsigned long value); | ||
|
||
#else | ||
#error Live patching support is disabled; check CONFIG_LIVE_PATCHING | ||
#endif | ||
|
||
#endif /* _ASM_X86_LIVEPATCH_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
* livepatch.c - x86-specific Kernel Live Patching Core | ||
* | ||
* Copyright (C) 2014 Seth Jennings <sjenning@redhat.com> | ||
* Copyright (C) 2014 SUSE | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version 2 | ||
* of the License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <linux/module.h> | ||
#include <linux/uaccess.h> | ||
#include <asm/cacheflush.h> | ||
#include <asm/page_types.h> | ||
#include <asm/elf.h> | ||
#include <asm/livepatch.h> | ||
|
||
/** | ||
* klp_write_module_reloc() - write a relocation in a module | ||
* @mod: module in which the section to be modified is found | ||
* @type: ELF relocation type (see asm/elf.h) | ||
* @loc: address that the relocation should be written to | ||
* @value: relocation value (sym address + addend) | ||
* | ||
* This function writes a relocation to the specified location for | ||
* a particular module. | ||
*/ | ||
int klp_write_module_reloc(struct module *mod, unsigned long type, | ||
unsigned long loc, unsigned long value) | ||
{ | ||
int ret, numpages, size = 4; | ||
bool readonly; | ||
unsigned long val; | ||
unsigned long core = (unsigned long)mod->module_core; | ||
unsigned long core_ro_size = mod->core_ro_size; | ||
unsigned long core_size = mod->core_size; | ||
|
||
switch (type) { | ||
case R_X86_64_NONE: | ||
return 0; | ||
case R_X86_64_64: | ||
val = value; | ||
size = 8; | ||
break; | ||
case R_X86_64_32: | ||
val = (u32)value; | ||
break; | ||
case R_X86_64_32S: | ||
val = (s32)value; | ||
break; | ||
case R_X86_64_PC32: | ||
val = (u32)(value - loc); | ||
break; | ||
default: | ||
/* unsupported relocation type */ | ||
return -EINVAL; | ||
} | ||
|
||
if (loc < core || loc >= core + core_size) | ||
/* loc does not point to any symbol inside the module */ | ||
return -EINVAL; | ||
|
||
if (loc < core + core_ro_size) | ||
readonly = true; | ||
else | ||
readonly = false; | ||
|
||
/* determine if the relocation spans a page boundary */ | ||
numpages = ((loc & PAGE_MASK) == ((loc + size) & PAGE_MASK)) ? 1 : 2; | ||
|
||
if (readonly) | ||
set_memory_rw(loc & PAGE_MASK, numpages); | ||
|
||
ret = probe_kernel_write((void *)loc, &val, size); | ||
|
||
if (readonly) | ||
set_memory_ro(loc & PAGE_MASK, numpages); | ||
|
||
return ret; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
/* | ||
* livepatch.h - Kernel Live Patching Core | ||
* | ||
* Copyright (C) 2014 Seth Jennings <sjenning@redhat.com> | ||
* Copyright (C) 2014 SUSE | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version 2 | ||
* of the License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#ifndef _LINUX_LIVEPATCH_H_ | ||
#define _LINUX_LIVEPATCH_H_ | ||
|
||
#include <linux/module.h> | ||
#include <linux/ftrace.h> | ||
|
||
#if IS_ENABLED(CONFIG_LIVE_PATCHING) | ||
|
||
#include <asm/livepatch.h> | ||
|
||
enum klp_state { | ||
KLP_DISABLED, | ||
KLP_ENABLED | ||
}; | ||
|
||
/** | ||
* struct klp_func - function structure for live patching | ||
* @old_name: name of the function to be patched | ||
* @new_func: pointer to the patched function code | ||
* @old_addr: a hint conveying at what address the old function | ||
* can be found (optional, vmlinux patches only) | ||
* @kobj: kobject for sysfs resources | ||
* @fops: ftrace operations structure | ||
* @state: tracks function-level patch application state | ||
*/ | ||
struct klp_func { | ||
/* external */ | ||
const char *old_name; | ||
void *new_func; | ||
/* | ||
* The old_addr field is optional and can be used to resolve | ||
* duplicate symbol names in the vmlinux object. If this | ||
* information is not present, the symbol is located by name | ||
* with kallsyms. If the name is not unique and old_addr is | ||
* not provided, the patch application fails as there is no | ||
* way to resolve the ambiguity. | ||
*/ | ||
unsigned long old_addr; | ||
|
||
/* internal */ | ||
struct kobject kobj; | ||
struct ftrace_ops *fops; | ||
enum klp_state state; | ||
}; | ||
|
||
/** | ||
* struct klp_reloc - relocation structure for live patching | ||
* @loc: address where the relocation will be written | ||
* @val: address of the referenced symbol (optional, | ||
* vmlinux patches only) | ||
* @type: ELF relocation type | ||
* @name: name of the referenced symbol (for lookup/verification) | ||
* @addend: offset from the referenced symbol | ||
* @external: symbol is either exported or within the live patch module itself | ||
*/ | ||
struct klp_reloc { | ||
unsigned long loc; | ||
unsigned long val; | ||
unsigned long type; | ||
const char *name; | ||
int addend; | ||
int external; | ||
}; | ||
|
||
/** | ||
* struct klp_object - kernel object structure for live patching | ||
* @name: module name (or NULL for vmlinux) | ||
* @relocs: relocation entries to be applied at load time | ||
* @funcs: function entries for functions to be patched in the object | ||
* @kobj: kobject for sysfs resources | ||
* @mod: kernel module associated with the patched object | ||
* (NULL for vmlinux) | ||
* @state: tracks object-level patch application state | ||
*/ | ||
struct klp_object { | ||
/* external */ | ||
const char *name; | ||
struct klp_reloc *relocs; | ||
struct klp_func *funcs; | ||
|
||
/* internal */ | ||
struct kobject *kobj; | ||
struct module *mod; | ||
enum klp_state state; | ||
}; | ||
|
||
/** | ||
* struct klp_patch - patch structure for live patching | ||
* @mod: reference to the live patch module | ||
* @objs: object entries for kernel objects to be patched | ||
* @list: list node for global list of registered patches | ||
* @kobj: kobject for sysfs resources | ||
* @state: tracks patch-level application state | ||
*/ | ||
struct klp_patch { | ||
/* external */ | ||
struct module *mod; | ||
struct klp_object *objs; | ||
|
||
/* internal */ | ||
struct list_head list; | ||
struct kobject kobj; | ||
enum klp_state state; | ||
}; | ||
|
||
extern int klp_register_patch(struct klp_patch *); | ||
extern int klp_unregister_patch(struct klp_patch *); | ||
extern int klp_enable_patch(struct klp_patch *); | ||
extern int klp_disable_patch(struct klp_patch *); | ||
|
||
#endif /* CONFIG_LIVE_PATCHING */ | ||
|
||
#endif /* _LINUX_LIVEPATCH_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
config ARCH_HAVE_LIVE_PATCHING | ||
boolean | ||
help | ||
Arch supports kernel live patching | ||
|
||
config LIVE_PATCHING | ||
boolean "Kernel Live Patching" | ||
depends on DYNAMIC_FTRACE_WITH_REGS | ||
depends on MODULES | ||
depends on SYSFS | ||
depends on KALLSYMS_ALL | ||
depends on ARCH_HAVE_LIVE_PATCHING | ||
help | ||
Say Y here if you want to support kernel live patching. | ||
This option has no runtime impact until a kernel "patch" | ||
module uses the interface provided by this option to register | ||
a patch, causing calls to patched functions to be redirected | ||
to new function code contained in the patch module. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
obj-$(CONFIG_LIVE_PATCHING) += livepatch.o | ||
|
||
livepatch-objs := core.o |
Oops, something went wrong.