mirror of https://github.com/dynup/kpatch
doc: patch author guide, first take
Been wanting to write this forever, have to start somewhere...
This commit is contained in:
parent
aab5240df8
commit
85b7a76acc
|
@ -322,6 +322,15 @@ Done! The kernel is now patched.
|
|||
$ grep -i chunk /proc/meminfo
|
||||
VMALLOCCHUNK: 34359337092 kB
|
||||
|
||||
|
||||
Patch Author Guide
|
||||
------------------
|
||||
|
||||
Unfortunately, live patching isn't always as easy as the previous example, and
|
||||
can have some major pitfalls if you're not careful. To learn more about how to
|
||||
properly create live patches, see the [Patch Author
|
||||
Guide](doc/patch-author-guide.md).
|
||||
|
||||
How it works
|
||||
------------
|
||||
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
kpatch Patch Author Guide
|
||||
=========================
|
||||
|
||||
Because kpatch-build is relatively easy to use, it can be easy to assume that a
|
||||
successful patch module build means that the patch is safe to apply. But in
|
||||
fact that's a very dangerous assumption.
|
||||
|
||||
There are many pitfalls that can be encountered when creating a live patch.
|
||||
This document attempts to guide the patch creation process. It's a work in
|
||||
progress. If you find it useful, please contribute!
|
||||
|
||||
Patch Analysis
|
||||
--------------
|
||||
|
||||
kpatch provides _some_ guarantees, but it does not guarantee that all patches
|
||||
are safe to apply. Every patch must also be analyzed in-depth by a human.
|
||||
|
||||
The most important point here cannot be stressed enough. Here comes the bold:
|
||||
|
||||
**Do not blindly apply patches. There is no subsitute for human analysis and
|
||||
reasoning on a per-patch basis. All patches must be thoroughly analyzed by a
|
||||
human kernel expert who completely understands the patch and the affected code
|
||||
and how they relate to the live patching environment.**
|
||||
|
||||
kpatch vs livepatch vs kGraft
|
||||
-----------------------------
|
||||
|
||||
This document assumes that the kpatch core module is being used. Other live
|
||||
patching systems (e.g., livepatch and kGraft) have different consistency
|
||||
models. Each comes with its own guarantees, and there are some subtle
|
||||
differences. The guidance in this document applies **only** to kpatch.
|
||||
|
||||
Patch upgrades
|
||||
--------------
|
||||
|
||||
Due to potential unexpected interactions between patches, it's highly
|
||||
recommended that when patching a system which has already been patched, the
|
||||
second patch should be a cumulative upgrade which is a superset of the first
|
||||
patch.
|
||||
|
||||
Data structure changes
|
||||
----------------------
|
||||
|
||||
kpatch patches functions, not data. If the original patch involves a change to
|
||||
a data structure, the patch will require some rework, as changes to data
|
||||
structures are not allowed by default.
|
||||
|
||||
Usually you have to get creative. There are several possible ways to handle
|
||||
this:
|
||||
|
||||
### Change the code which uses the data structure
|
||||
|
||||
Sometimes, instead of changing the data structure itself, you can change the
|
||||
code which uses it.
|
||||
|
||||
For example, consider this
|
||||
[patch](http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=54a20552e1eae07aa240fa370a0293e006b5faed).
|
||||
which has the following hunk:
|
||||
|
||||
```
|
||||
@@ -3270,6 +3277,7 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
|
||||
[SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception,
|
||||
[SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception,
|
||||
[SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception,
|
||||
+ [SVM_EXIT_EXCP_BASE + AC_VECTOR] = ac_interception,
|
||||
[SVM_EXIT_INTR] = intr_interception,
|
||||
[SVM_EXIT_NMI] = nmi_interception,
|
||||
[SVM_EXIT_SMI] = nop_on_interception,
|
||||
```
|
||||
|
||||
`svm_exit_handlers[]` is an array of function pointers. The patch adds a
|
||||
`ac_interception` function pointer to the array at index `[SVM_EXIT_EXCP_BASE +
|
||||
AC_VECTOR]`. That change is incompatible with kpatch.
|
||||
|
||||
Looking at the source file, we can see that this function pointer is only
|
||||
accessed by a single function, `handle_exit()`:
|
||||
|
||||
```
|
||||
if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
|
||||
|| !svm_exit_handlers[exit_code]) {
|
||||
WARN_ONCE(1, "svm: unexpected exit reason 0x%x\n", exit_code);
|
||||
kvm_queue_exception(vcpu, UD_VECTOR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return svm_exit_handlers[exit_code](svm);
|
||||
```
|
||||
|
||||
So an easy solution here is to just change the code to manually check for the
|
||||
new case before looking in the data structure:
|
||||
|
||||
```
|
||||
@@ -3580,6 +3580,9 @@ static int handle_exit(struct kvm_vcpu *vcpu)
|
||||
return 1;
|
||||
}
|
||||
|
||||
+ if (exit_code == SVM_EXIT_EXCP_BASE + AC_VECTOR)
|
||||
+ return ac_interception(svm);
|
||||
+
|
||||
return svm_exit_handlers[exit_code](svm);
|
||||
}
|
||||
```
|
||||
|
||||
Not only is this an easy solution, it's also safer than touching data since
|
||||
kpatch creates a barrier between the calling of old functions and new
|
||||
functions.
|
||||
|
||||
### Use a kpatch load hook
|
||||
|
||||
If you need to change the contents of an existing variable in-place, you can
|
||||
use the KPATCH_LOAD_HOOK macro to specify a function to be called when the
|
||||
patch module is loaded.
|
||||
|
||||
Don't forget to protect access to the data as needed.
|
||||
|
||||
Also be careful when upgrading. If patch A has a load hook which writes to X,
|
||||
and then you load patch B which is a superset of A, in some cases you may want
|
||||
to prevent patch B from writing to X, if A is already loaded.
|
||||
|
||||
Examples needed.
|
||||
|
||||
### Use a shadow variable
|
||||
|
||||
If you need to add a field to an existing data structure, or even many existing
|
||||
data structures, you can use the `kpatch_shadow_*()` functions.
|
||||
|
||||
Example needed (see shadow-newpid.patch in the integration tests directory).
|
||||
|
||||
Data semantic changes
|
||||
---------------------
|
||||
|
||||
Sometimes, the data itself remains the same, but how it's used is changed. A
|
||||
common example is locking semantic changes.
|
||||
|
||||
Example needed.
|
||||
|
||||
Init code changes
|
||||
-----------------
|
||||
|
||||
Any code which runs in an `__init` function or during module or device
|
||||
initialization is problematic, as it may have already run before the patch was
|
||||
applied. The patch may require a load hook function which detects whether such
|
||||
init code has run, and which rewrites or changes the original initialization to
|
||||
force it into the desired state. Some changes involving hardware init are
|
||||
inherently incompatible with live patching.
|
Loading…
Reference in New Issue