Blame doc/patch-author-guide.md

Packit Service ac8aad
kpatch Patch Author Guide
Packit Service ac8aad
=========================
Packit Service ac8aad
Packit Service ac8aad
Because kpatch-build is relatively easy to use, it can be easy to assume that a
Packit Service ac8aad
successful patch module build means that the patch is safe to apply.  But in
Packit Service ac8aad
fact that's a very dangerous assumption.
Packit Service ac8aad
Packit Service ac8aad
There are many pitfalls that can be encountered when creating a live patch.
Packit Service ac8aad
This document attempts to guide the patch creation process.  It's a work in
Packit Service ac8aad
progress.  If you find it useful, please contribute!
Packit Service ac8aad
Packit Service ac8aad
Patch Analysis
Packit Service ac8aad
--------------
Packit Service ac8aad
Packit Service ac8aad
kpatch provides _some_ guarantees, but it does not guarantee that all patches
Packit Service ac8aad
are safe to apply.  Every patch must also be analyzed in-depth by a human.
Packit Service ac8aad
Packit Service ac8aad
The most important point here cannot be stressed enough.  Here comes the bold:
Packit Service ac8aad
Packit Service ac8aad
**Do not blindly apply patches.  There is no substitute for human analysis and
Packit Service ac8aad
reasoning on a per-patch basis.  All patches must be thoroughly analyzed by a
Packit Service ac8aad
human kernel expert who completely understands the patch and the affected code
Packit Service ac8aad
and how they relate to the live patching environment.**
Packit Service ac8aad
Packit Service ac8aad
kpatch vs livepatch vs kGraft
Packit Service ac8aad
-----------------------------
Packit Service ac8aad
Packit Service da4517
This document assumes that the kpatch-build tool is being used to create
Packit Service da4517
livepatch kernel modules.  Other live patching systems may have different
Packit Service da4517
consistency models, their own guarantees, and other subtle differences.
Packit Service da4517
The guidance in this document applies **only** to kpatch-build generated
Packit Service da4517
livepatches.
Packit Service ac8aad
Packit Service ac8aad
Patch upgrades
Packit Service ac8aad
--------------
Packit Service ac8aad
Packit Service ac8aad
Due to potential unexpected interactions between patches, it's highly
Packit Service ac8aad
recommended that when patching a system which has already been patched, the
Packit Service ac8aad
second patch should be a cumulative upgrade which is a superset of the first
Packit Service ac8aad
patch.
Packit Service ac8aad
Packit Service ac8aad
Data structure changes
Packit Service ac8aad
----------------------
Packit Service ac8aad
Packit Service ac8aad
kpatch patches functions, not data.  If the original patch involves a change to
Packit Service ac8aad
a data structure, the patch will require some rework, as changes to data
Packit Service ac8aad
structures are not allowed by default.
Packit Service ac8aad
Packit Service ac8aad
Usually you have to get creative.  There are several possible ways to handle
Packit Service ac8aad
this:
Packit Service ac8aad
Packit Service ac8aad
### Change the code which uses the data structure
Packit Service ac8aad
Packit Service ac8aad
Sometimes, instead of changing the data structure itself, you can change the
Packit Service ac8aad
code which uses it.
Packit Service ac8aad
Packit Service ac8aad
For example, consider this
Packit Service ac8aad
[patch](http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=54a20552e1eae07aa240fa370a0293e006b5faed).
Packit Service ac8aad
which has the following hunk:
Packit Service ac8aad
Packit Service ac8aad
```
Packit Service ac8aad
@@ -3270,6 +3277,7 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
Packit Service ac8aad
 	[SVM_EXIT_EXCP_BASE + PF_VECTOR]	= pf_interception,
Packit Service ac8aad
 	[SVM_EXIT_EXCP_BASE + NM_VECTOR]	= nm_interception,
Packit Service ac8aad
 	[SVM_EXIT_EXCP_BASE + MC_VECTOR]	= mc_interception,
Packit Service ac8aad
+	[SVM_EXIT_EXCP_BASE + AC_VECTOR]	= ac_interception,
Packit Service ac8aad
 	[SVM_EXIT_INTR]				= intr_interception,
Packit Service ac8aad
 	[SVM_EXIT_NMI]				= nmi_interception,
Packit Service ac8aad
 	[SVM_EXIT_SMI]				= nop_on_interception,
Packit Service ac8aad
```
Packit Service ac8aad
Packit Service ac8aad
`svm_exit_handlers[]` is an array of function pointers.  The patch adds a
Packit Service ac8aad
`ac_interception` function pointer to the array at index `[SVM_EXIT_EXCP_BASE +
Packit Service ac8aad
AC_VECTOR]`.  That change is incompatible with kpatch.
Packit Service ac8aad
Packit Service ac8aad
Looking at the source file, we can see that this function pointer is only
Packit Service ac8aad
accessed by a single function, `handle_exit()`:
Packit Service ac8aad
Packit Service ac8aad
```
Packit Service ac8aad
        if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
Packit Service ac8aad
            || !svm_exit_handlers[exit_code]) {
Packit Service ac8aad
                WARN_ONCE(1, "svm: unexpected exit reason 0x%x\n", exit_code);
Packit Service ac8aad
                kvm_queue_exception(vcpu, UD_VECTOR);
Packit Service ac8aad
                return 1;
Packit Service ac8aad
        }
Packit Service ac8aad
Packit Service ac8aad
        return svm_exit_handlers[exit_code](svm);
Packit Service ac8aad
```
Packit Service ac8aad
Packit Service ac8aad
So an easy solution here is to just change the code to manually check for the
Packit Service ac8aad
new case before looking in the data structure:
Packit Service ac8aad
Packit Service ac8aad
```
Packit Service ac8aad
@@ -3580,6 +3580,9 @@ static int handle_exit(struct kvm_vcpu *vcpu)
Packit Service ac8aad
                return 1;
Packit Service ac8aad
        }
Packit Service ac8aad
Packit Service ac8aad
+       if (exit_code == SVM_EXIT_EXCP_BASE + AC_VECTOR)
Packit Service ac8aad
+               return ac_interception(svm);
Packit Service ac8aad
+
Packit Service ac8aad
        return svm_exit_handlers[exit_code](svm);
Packit Service ac8aad
 }
Packit Service ac8aad
```
Packit Service ac8aad
Packit Service ac8aad
Not only is this an easy solution, it's also safer than touching data since
Packit Service da4517
`svm_exit_handlers[]` may be in use by tasks that haven't been patched
Packit Service da4517
yet.
Packit Service ac8aad
Packit Service ac8aad
### Use a kpatch callback macro
Packit Service ac8aad
Packit Service da4517
Kpatch supports the kernel's livepatch [(Un)patching
Packit Service da4517
callbacks](https://github.com/torvalds/linux/blob/master/Documentation/livepatch/callbacks.rst).
Packit Service da4517
The kernel API requires callback registration through `struct klp_callbacks`,
Packit Service da4517
but to do so through kpatch-build, `kpatch-macros.h` defines the following:
Packit Service ac8aad
Packit Service ac8aad
* `KPATCH_PRE_PATCH_CALLBACK` - executed before patching
Packit Service ac8aad
* `KPATCH_POST_PATCH_CALLBACK` - executed after patching
Packit Service ac8aad
* `KPATCH_PRE_UNPATCH_CALLBACK` - executed before unpatching, complements the
Packit Service ac8aad
                                  post-patch callback.
Packit Service ac8aad
* `KPATCH_POST_UNPATCH_CALLBACK` - executed after unpatching, complements the
Packit Service ac8aad
                                   pre-patch callback.
Packit Service ac8aad
Packit Service ac8aad
A pre-patch callback routine has the following signature:
Packit Service ac8aad
Packit Service ac8aad
```
Packit Service ac8aad
static int callback(patch_object *obj) { }
Packit Service da4517
KPATCH_PRE_PATCH_CALLBACK(callback);
Packit Service ac8aad
```
Packit Service ac8aad
Packit Service da4517
and any non-zero return status indicates failure to the kernel.  For more
Packit Service ac8aad
information on pre-patch callback failure, see the **Pre-patch return status**
Packit Service ac8aad
section below.
Packit Service ac8aad
Packit Service ac8aad
Post-patch, pre-unpatch, and post-unpatch callback routines all share the
Packit Service ac8aad
following signature:
Packit Service ac8aad
Packit Service ac8aad
```
Packit Service ac8aad
static void callback(patch_object *obj) { }
Packit Service da4517
KPATCH_POST_PATCH_CALLBACK(callback);            /* or */
Packit Service da4517
KPATCH_PRE_UNPATCH_CALLBACK(callback);           /* or */
Packit Service da4517
KPATCH_POST_UNPATCH_CALLBACK(callback);
Packit Service ac8aad
```
Packit Service ac8aad
Packit Service ac8aad
Generally pre-patch callbacks are paired with post-unpatch callbacks, meaning
Packit Service ac8aad
that anything the former allocates or sets up should be torn down by the former
Packit Service ac8aad
callback.  Likewise for post-patch and pre-unpatch callbacks.
Packit Service ac8aad
Packit Service ac8aad
#### Pre-patch return status
Packit Service ac8aad
Packit Service da4517
If kpatch is currently patching already loaded objects (vmlinux always by
Packit Service ac8aad
definition as well as any currently loaded kernel modules), a non-zero pre-patch
Packit Service da4517
callback status stops the current patch in progress.  The kpatch-module
Packit Service da4517
is rejected, completely reverted, and unloaded.
Packit Service ac8aad
Packit Service da4517
If an already loaded kpatch is patching an incoming kernel module, then
Packit Service da4517
a failing pre-patch callback will result in the kernel module loader
Packit Service da4517
rejecting the new module.
Packit Service ac8aad
Packit Service da4517
In both cases, if a pre-patch callback fails, none of its other
Packit Service da4517
associated callbacks will be executed.
Packit Service ac8aad
Packit Service ac8aad
#### Callback context
Packit Service ac8aad
Packit Service ac8aad
* For patches to vmlinux or already loaded kernel modules, callback functions
Packit Service da4517
will be run around the livepatch transitions in the `klp_enable_patch()`
Packit Service da4517
callchain.  This is executed automatically on kpatch module init.
Packit Service ac8aad
Packit Service ac8aad
* For patches to kernel modules which haven't been loaded yet, a
Packit Service da4517
module-notifier will execute callbacks when the module is loaded into
Packit Service da4517
the `MODULE_STATE_COMING` state.  The pre and post-patch callbacks are
Packit Service da4517
called before any module_init code.
Packit Service ac8aad
Packit Service ac8aad
Example: a kpatch fix for CVE-2016-5389 could utilize the
Packit Service ac8aad
`KPATCH_PRE_PATCH_CALLBACK` and `KPATCH_POST_UNPATCH_CALLBACK` macros to modify
Packit Service ac8aad
variable `sysctl_tcp_challenge_ack_limit` in-place:
Packit Service ac8aad
Packit Service ac8aad
```
Packit Service ac8aad
+#include "kpatch-macros.h"
Packit Service ac8aad
+
Packit Service ac8aad
+static bool kpatch_write = false;
Packit Service ac8aad
+static int kpatch_pre_patch_tcp_send_challenge_ack(patch_object *obj)
Packit Service ac8aad
+{
Packit Service ac8aad
+	if (sysctl_tcp_challenge_ack_limit == 100) {
Packit Service ac8aad
+		sysctl_tcp_challenge_ack_limit = 1000;
Packit Service ac8aad
+		kpatch_write = true;
Packit Service ac8aad
+	}
Packit Service ac8aad
+	return 0;
Packit Service ac8aad
+}
Packit Service ac8aad
static void kpatch_post_unpatch_tcp_send_challenge_ack(patch_object *obj)
Packit Service ac8aad
+{
Packit Service ac8aad
+	if (kpatch_write && sysctl_tcp_challenge_ack_limit == 1000)
Packit Service ac8aad
+		sysctl_tcp_challenge_ack_limit = 100;
Packit Service ac8aad
+}
Packit Service ac8aad
+KPATCH_PRE_PATCH_CALLBACK(kpatch_pre_patch_tcp_send_challenge_ack);
Packit Service ac8aad
+KPATCH_POST_UNPATCH_CALLBACK(kpatch_post_unpatch_tcp_send_challenge_ack);
Packit Service ac8aad
```
Packit Service ac8aad
Packit Service da4517
Don't forget to protect access to data as needed. Spinlocks and mutexes /
Packit Service da4517
sleeping locks **may be used** (this is a change of behavior from when kpatch
Packit Service da4517
relied on the kpatch.ko support module and `stop_machine()` context.)
Packit Service ac8aad
Packit Service da4517
Be careful when upgrading.  If patch A has a pre/post-patch callback which
Packit Service ac8aad
writes to X, and then you load patch B which is a superset of A, in some cases
Packit Service ac8aad
you may want to prevent patch B from writing to X, if A is already loaded.
Packit Service ac8aad
Packit Service ac8aad
Packit Service ac8aad
### Use a shadow variable
Packit Service ac8aad
Packit Service ac8aad
If you need to add a field to an existing data structure, or even many existing
Packit Service da4517
data structures, you can use the kernel's
Packit Service da4517
[Shadow Variable](https://www.kernel.org/doc/html/latest/livepatch/shadow-vars.html) API.
Packit Service ac8aad
Packit Service da4517
Example: The `shadow-newpid.patch` integration test employs shadow variables
Packit Service da4517
to add a rolling counter to the new `struct task_struct` instances.  A
Packit Service da4517
simplified version is presented here.
Packit Service ac8aad
Packit Service ac8aad
A shadow PID variable is allocated in `do_fork()`: it is associated with the
Packit Service da4517
current `struct task_struct *p` value, given an ID of `KPATCH_SHADOW_NEWPID`,
Packit Service da4517
sized accordingly, and allocated as per `GFP_KERNEL` flag rules.  Note that
Packit Service da4517
the shadow variable <obj, id> association is global -- hence it is best to
Packit Service da4517
provide unique ID enumerations per kpatch as needed.
Packit Service ac8aad
Packit Service da4517
`klp_shadow_alloc()` returns a pointer to the shadow variable, so we can
Packit Service ac8aad
dereference and make assignments as usual.  In this patch chunk, the shadow
Packit Service ac8aad
`newpid` is allocated then assigned to a rolling `ctr` counter value:
Packit Service ac8aad
```
Packit Service da4517
diff --git a/kernel/fork.c b/kernel/fork.c
Packit Service da4517
index 9bff3b28c357..18374fd35bd9 100644
Packit Service da4517
--- a/kernel/fork.c
Packit Service da4517
+++ b/kernel/fork.c
Packit Service da4517
@@ -1751,6 +1751,8 @@ struct task_struct *fork_idle(int cpu)
Packit Service da4517
 	return task;
Packit Service da4517
 }
Packit Service da4517
 
Packit Service da4517
+#include <linux/livepatch.h>
Packit Service da4517
+#define KPATCH_SHADOW_NEWPID 0
Packit Service da4517
 /*
Packit Service da4517
  *  Ok, this is the main fork-routine.
Packit Service da4517
  *
Packit Service da4517
@@ -1794,6 +1796,14 @@ long do_fork(unsigned long clone_flags,
Packit Service da4517
 	if (!IS_ERR(p)) {
Packit Service da4517
 		struct completion vfork;
Packit Service da4517
 		struct pid *pid;
Packit Service ac8aad
+		int *newpid;
Packit Service ac8aad
+		static int ctr = 0;
Packit Service ac8aad
+
Packit Service da4517
+		newpid = klp_shadow_get_or_alloc(p, KPATCH_SHADOW_NEWPID,
Packit Service da4517
+						 sizeof(*newpid), GFP_KERNEL,
Packit Service da4517
+						 NULL, NULL);
Packit Service ac8aad
+		if (newpid)
Packit Service ac8aad
+			*newpid = ctr++;
Packit Service da4517
 
Packit Service da4517
 		trace_sched_process_fork(current, p);
Packit Service ac8aad
```
Packit Service ac8aad
Packit Service da4517
A shadow variable may be accessed via `klp_shadow_get()`.  Here the patch
Packit Service da4517
modifies `task_context_switch_counts()` to fetch the shadow variable
Packit Service da4517
associated with the current `struct task_struct *p` object and a
Packit Service da4517
`KPATCH_SHADOW_NEWPID ID`.  As in the previous patch chunk, the shadow
Packit Service da4517
variable pointer may be accessed as an ordinary pointer type:
Packit Service ac8aad
```
Packit Service da4517
diff --git a/fs/proc/array.c b/fs/proc/array.c
Packit Service da4517
index 39684c79e8e2..fe0259d057a3 100644
Packit Service da4517
--- a/fs/proc/array.c
Packit Service da4517
+++ b/fs/proc/array.c
Packit Service da4517
@@ -394,13 +394,19 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p)
Packit Service ac8aad
 	seq_putc(m, '\n');
Packit Service da4517
 }
Packit Service da4517
 
Packit Service da4517
+#include <linux/livepatch.h>
Packit Service da4517
+#define KPATCH_SHADOW_NEWPID 0
Packit Service da4517
 static inline void task_context_switch_counts(struct seq_file *m,
Packit Service da4517
 						struct task_struct *p)
Packit Service da4517
 {
Packit Service da4517
+	int *newpid;
Packit Service da4517
 	seq_printf(m,	"voluntary_ctxt_switches:\t%lu\n"
Packit Service da4517
 			"nonvoluntary_ctxt_switches:\t%lu\n",
Packit Service da4517
 			p->nvcsw,
Packit Service da4517
 			p->nivcsw);
Packit Service da4517
+	newpid = klp_shadow_get(p, KPATCH_SHADOW_NEWPID);
Packit Service ac8aad
+	if (newpid)
Packit Service ac8aad
+		seq_printf(m, "newpid:\t%d\n", *newpid);
Packit Service da4517
 }
Packit Service da4517
 
Packit Service da4517
 static void task_cpus_allowed(struct seq_file *m, struct task_struct *task)
Packit Service ac8aad
```
Packit Service ac8aad
Packit Service da4517
A shadow variable is freed by calling `klp_shadow_free()` and providing
Packit Service da4517
the object / enum ID combination.  Once freed, the shadow variable is no
Packit Service da4517
longer safe to access:
Packit Service ac8aad
```
Packit Service da4517
diff --git a/kernel/exit.c b/kernel/exit.c
Packit Service da4517
index 148a7842928d..44b6fe61e912 100644
Packit Service da4517
--- a/kernel/exit.c
Packit Service da4517
+++ b/kernel/exit.c
Packit Service da4517
@@ -791,6 +791,8 @@ static void check_stack_usage(void)
Packit Service da4517
 static inline void check_stack_usage(void) {}
Packit Service da4517
 #endif
Packit Service da4517
 
Packit Service da4517
+#include <linux/livepatch.h>
Packit Service da4517
+#define KPATCH_SHADOW_NEWPID 0
Packit Service da4517
 void do_exit(long code)
Packit Service da4517
 {
Packit Service da4517
 	struct task_struct *tsk = current;
Packit Service da4517
@@ -888,6 +890,8 @@ void do_exit(long code)
Packit Service da4517
 	check_stack_usage();
Packit Service da4517
 	exit_thread();
Packit Service ac8aad
 
Packit Service da4517
+	klp_shadow_free(tsk, KPATCH_SHADOW_NEWPID, NULL);
Packit Service ac8aad
+
Packit Service ac8aad
 	/*
Packit Service ac8aad
 	 * Flush inherited counters to the parent - before the parent
Packit Service ac8aad
 	 * gets woken up by child-exit notifications.
Packit Service ac8aad
```
Packit Service ac8aad
Notes:
Packit Service da4517
* `klp_shadow_alloc()` and `klp_shadow_get_or_alloc()` initialize only shadow
Packit Service da4517
  variable metadata. They allocate variable storage via `kmalloc` with the
Packit Service da4517
  `gfp_t` flags given, but otherwise leave the area untouched. Initialization
Packit Service da4517
  of a shadow variable is the responsibility of the caller.
Packit Service da4517
* As soon as `klp_shadow_alloc()` or `klp_shadow_get_or_alloc()` create a shadow
Packit Service da4517
  variable, its presence will be reported by `klp_shadow_get()`. Care should be
Packit Service da4517
  taken to avoid any potential race conditions between a kernel thread that
Packit Service da4517
  allocates a shadow variable and concurrent threads that may attempt to use
Packit Service da4517
  it.
Packit Service da4517
* Patches may need to call `klp_shadow_free_all()` from a post-unpatch handler
Packit Service da4517
  to safely cleanup any shadow variables of a particular ID.  From post-unpatch
Packit Service da4517
  context, unloading kpatch module code (aside from .exit) should be
Packit Service da4517
  completely inactive.  As long as these shadow variables were only accessed by
Packit Service da4517
  the unloaded kpatch, they are be safe to release.
Packit Service ac8aad
Packit Service ac8aad
Data semantic changes
Packit Service ac8aad
---------------------
Packit Service ac8aad
Packit Service ac8aad
Part of the stable-tree [backport](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/commit/fs/aio.c?h=linux-3.10.y&id=6745cb91b5ec93a1b34221279863926fba43d0d7)
Packit Service ac8aad
to fix CVE-2014-0206 changed the reference count semantic of `struct
Packit Service ac8aad
kioctx.reqs_active`. Associating a shadow variable to new instances of this
Packit Service ac8aad
structure can be used by patched code to handle both new (post-patch) and
Packit Service ac8aad
existing (pre-patch) instances.
Packit Service ac8aad
Packit Service da4517
(Note: this example is trimmed to highlight this use-case. Boilerplate code is
Packit Service da4517
also required to allocate/free a shadow variable with enum ID
Packit Service da4517
`KPATCH_SHADOW_REQS_ACTIVE_V2` whenever a new `struct kioctx` is
Packit Service da4517
created/released. No values are ever assigned to the shadow variable.)
Packit Service da4517
Packit Service da4517
```
Packit Service da4517
diff --git a/fs/aio.c b/fs/aio.c
Packit Service da4517
index ebd06fd0de89..6a33b73c9107 100644
Packit Service da4517
--- a/fs/aio.c
Packit Service da4517
+++ b/fs/aio.c
Packit Service da4517
@@ -280,6 +280,8 @@ static void free_ioctx_rcu(struct rcu_head *head)
Packit Service da4517
  * and ctx->users has dropped to 0, so we know no more kiocbs can be submitted -
Packit Service da4517
  * now it's safe to cancel any that need to be.
Packit Service da4517
  */
Packit Service da4517
+#include <linux/livepatch.h>
Packit Service da4517
+#define KPATCH_SHADOW_REQS_ACTIVE_V2 1
Packit Service da4517
 static void free_ioctx(struct kioctx *ctx)
Packit Service da4517
 {
Packit Service da4517
        struct aio_ring *ring;
Packit Service da4517
```
Packit Service ac8aad
Packit Service da4517
Shadow variable existence can be verified before applying the *new* data
Packit Service ac8aad
semantic of the associated object:
Packit Service ac8aad
```
Packit Service da4517
@@ -678,6 +681,8 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
Packit Service ac8aad
 put_rq:
Packit Service da4517
        /* everything turned out well, dispose of the aiocb. */
Packit Service da4517
        aio_put_req(iocb);
Packit Service da4517
+       if (klp_shadow_get(ctx, KPATCH_SHADOW_REQS_ACTIVE_V2))
Packit Service da4517
+               atomic_dec(&ctx->reqs_active);
Packit Service ac8aad
 
Packit Service da4517
        /*
Packit Service da4517
         * We have to order our ring_info tail store above and test
Packit Service ac8aad
```
Packit Service ac8aad
Packit Service ac8aad
Likewise, shadow variable non-existence can be tested to continue applying the
Packit Service da4517
*old* data semantic:
Packit Service ac8aad
```
Packit Service da4517
@@ -310,7 +312,8 @@ static void free_ioctx(struct kioctx *ctx)
Packit Service ac8aad
 
Packit Service da4517
                avail = (head <= ctx->tail ? ctx->tail : ctx->nr_events) - head;
Packit Service ac8aad
 
Packit Service da4517
-               atomic_sub(avail, &ctx->reqs_active);
Packit Service da4517
+               if (!klp_shadow_get(ctx, KPATCH_SHADOW_REQS_ACTIVE_V2))
Packit Service da4517
+                       atomic_sub(avail, &ctx->reqs_active);
Packit Service da4517
                head += avail;
Packit Service da4517
                head %= ctx->nr_events;
Packit Service da4517
        }
Packit Service da4517
@@ -757,6 +762,8 @@ static long aio_read_events_ring(struct kioctx *ctx,
Packit Service da4517
        pr_debug("%li  h%u t%u\n", ret, head, ctx->tail);
Packit Service ac8aad
 
Packit Service da4517
        atomic_sub(ret, &ctx->reqs_active);
Packit Service da4517
+       if (!klp_shadow_get(ctx, KPATCH_SHADOW_REQS_ACTIVE_V2))
Packit Service da4517
+               atomic_sub(ret, &ctx->reqs_active);
Packit Service ac8aad
 out:
Packit Service da4517
        mutex_unlock(&ctx->ring_lock);
Packit Service ac8aad
```
Packit Service ac8aad
 
Packit Service ac8aad
The previous example can be extended to use shadow variable storage to handle
Packit Service ac8aad
locking semantic changes.  Consider the [upstream fix](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1d147bfa64293b2723c4fec50922168658e613ba)
Packit Service ac8aad
for CVE-2014-2706, which added a `ps_lock` to `struct sta_info` to protect
Packit Service ac8aad
critical sections throughout `net/mac80211/sta_info.c`.
Packit Service ac8aad
Packit Service da4517
When allocating a new `struct sta_info`, allocate a corresponding shadow
Packit Service da4517
variable large enough to hold a `spinlock_t` instance, then initialize the
Packit Service da4517
spinlock:
Packit Service ac8aad
```
Packit Service da4517
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
Packit Service da4517
index decd30c1e290..758533dda4d8 100644
Packit Service da4517
--- a/net/mac80211/sta_info.c
Packit Service da4517
+++ b/net/mac80211/sta_info.c
Packit Service da4517
@@ -287,6 +287,8 @@ static int sta_prepare_rate_control(struct ieee80211_local *local,
Packit Service da4517
 	return 0;
Packit Service da4517
 }
Packit Service da4517
 
Packit Service da4517
+#include <linux/livepatch.h>
Packit Service da4517
+#define KPATCH_SHADOW_PS_LOCK 2
Packit Service da4517
 struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
Packit Service da4517
 				const u8 *addr, gfp_t gfp)
Packit Service da4517
 {
Packit Service da4517
@@ -295,6 +297,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
Packit Service ac8aad
 	struct timespec uptime;
Packit Service da4517
 	struct ieee80211_tx_latency_bin_ranges *tx_latency;
Packit Service ac8aad
 	int i;
Packit Service ac8aad
+	spinlock_t *ps_lock;
Packit Service ac8aad
 
Packit Service ac8aad
 	sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
Packit Service ac8aad
 	if (!sta)
Packit Service da4517
@@ -330,6 +333,10 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
Packit Service da4517
 	rcu_read_unlock();
Packit Service ac8aad
 
Packit Service ac8aad
 	spin_lock_init(&sta->lock);
Packit Service da4517
+	ps_lock = klp_shadow_alloc(sta, KPATCH_SHADOW_PS_LOCK,
Packit Service da4517
+				   sizeof(*ps_lock), gfp, NULL, NULL);
Packit Service ac8aad
+	if (ps_lock)
Packit Service ac8aad
+		spin_lock_init(ps_lock);
Packit Service ac8aad
 	INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
Packit Service ac8aad
 	INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
Packit Service ac8aad
 	mutex_init(&sta->ampdu_mlme.mtx);
Packit Service ac8aad
```
Packit Service ac8aad
Packit Service da4517
Patched code can reference the shadow variable associated with a given `struct
Packit Service da4517
sta_info` to determine and apply the correct locking semantic for that
Packit Service da4517
instance:
Packit Service ac8aad
```
Packit Service da4517
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
Packit Service da4517
index 97a02d3f7d87..0edb0ed8dc60 100644
Packit Service da4517
--- a/net/mac80211/tx.c
Packit Service da4517
+++ b/net/mac80211/tx.c
Packit Service da4517
@@ -459,12 +459,15 @@ static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta,
Packit Service da4517
 	return 1;
Packit Service da4517
 }
Packit Service da4517
 
Packit Service da4517
+#include <linux/livepatch.h>
Packit Service da4517
+#define KPATCH_SHADOW_PS_LOCK 2
Packit Service da4517
 static ieee80211_tx_result
Packit Service da4517
 ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
Packit Service da4517
 {
Packit Service da4517
 	struct sta_info *sta = tx->sta;
Packit Service da4517
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
Packit Service da4517
 	struct ieee80211_local *local = tx->local;
Packit Service da4517
+	spinlock_t *ps_lock;
Packit Service da4517
 
Packit Service da4517
 	if (unlikely(!sta))
Packit Service da4517
 		return TX_CONTINUE;
Packit Service da4517
@@ -478,6 +481,23 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
Packit Service ac8aad
 		       sta->sta.addr, sta->sta.aid, ac);
Packit Service ac8aad
 		if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
Packit Service ac8aad
 			purge_old_ps_buffers(tx->local);
Packit Service ac8aad
+
Packit Service ac8aad
+		/* sync with ieee80211_sta_ps_deliver_wakeup */
Packit Service da4517
+		ps_lock = klp_shadow_get(sta, KPATCH_SHADOW_PS_LOCK);
Packit Service ac8aad
+		if (ps_lock) {
Packit Service ac8aad
+			spin_lock(ps_lock);
Packit Service ac8aad
+			/*
Packit Service ac8aad
+			 * STA woke up the meantime and all the frames on ps_tx_buf have
Packit Service ac8aad
+			 * been queued to pending queue. No reordering can happen, go
Packit Service ac8aad
+			 * ahead and Tx the packet.
Packit Service ac8aad
+			 */
Packit Service ac8aad
+			if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
Packit Service ac8aad
+			    !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
Packit Service ac8aad
+				spin_unlock(ps_lock);
Packit Service ac8aad
+				return TX_CONTINUE;
Packit Service ac8aad
+			}
Packit Service ac8aad
+		}
Packit Service ac8aad
+
Packit Service ac8aad
 		if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
Packit Service ac8aad
 			struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
Packit Service ac8aad
 			ps_dbg(tx->sdata,
Packit Service ac8aad
```
Packit Service ac8aad
Packit Service ac8aad
Init code changes
Packit Service ac8aad
-----------------
Packit Service ac8aad
Packit Service ac8aad
Any code which runs in an `__init` function or during module or device
Packit Service ac8aad
initialization is problematic, as it may have already run before the patch was
Packit Service ac8aad
applied.  The patch may require a pre-patch callback which detects whether such
Packit Service ac8aad
init code has run, and which rewrites or changes the original initialization to
Packit Service ac8aad
force it into the desired state.  Some changes involving hardware init are
Packit Service ac8aad
inherently incompatible with live patching.
Packit Service ac8aad
Packit Service ac8aad
Header file changes
Packit Service ac8aad
-------------------
Packit Service ac8aad
Packit Service ac8aad
When changing header files, be extra careful.  If data is being changed, you
Packit Service ac8aad
probably need to modify the patch.  See "Data struct changes" above.
Packit Service ac8aad
Packit Service ac8aad
If a function prototype is being changed, make sure it's not an exported
Packit Service ac8aad
function.  Otherwise it could break out-of-tree modules.  One way to
Packit Service ac8aad
workaround this is to define an entirely new copy of the function (with
Packit Service ac8aad
updated code) and patch in-tree callers to invoke it rather than the
Packit Service ac8aad
deprecated version.
Packit Service ac8aad
Packit Service ac8aad
Many header file changes result in a complete rebuild of the kernel tree, which
Packit Service ac8aad
makes kpatch-build have to compare every .o file in the kernel.  It slows the
Packit Service ac8aad
build down a lot, and can even fail to build if kpatch-build has any bugs
Packit Service ac8aad
lurking.  If it's a trivial header file change, like adding a macro, it's
Packit Service ac8aad
advisable to just move that macro into the .c file where it's needed to avoid
Packit Service ac8aad
changing the header file at all.
Packit Service ac8aad
Packit Service ac8aad
Dealing with unexpected changed functions
Packit Service ac8aad
-----------------------------------------
Packit Service ac8aad
Packit Service ac8aad
In general, it's best to patch as minimally as possible.  If kpatch-build is
Packit Service ac8aad
reporting some unexpected function changes, it's always a good idea to try to
Packit Service ac8aad
figure out why it thinks they changed.  In many cases you can change the source
Packit Service ac8aad
patch so that they no longer change.
Packit Service ac8aad
Packit Service ac8aad
Some examples:
Packit Service ac8aad
Packit Service ac8aad
* If a changed function was inlined, then the callers which inlined the
Packit Service ac8aad
  function will also change.  In this case there's nothing you can do to
Packit Service ac8aad
  prevent the extra changes.
Packit Service ac8aad
Packit Service ac8aad
* If a changed function was originally inlined, but turned into a callable
Packit Service ac8aad
  function after patching, consider adding `__always_inline` to the function
Packit Service ac8aad
  definition.  Likewise, if a function is only inlined after patching,
Packit Service ac8aad
  consider using `noinline` to prevent the compiler from doing so.
Packit Service ac8aad
Packit Service ac8aad
* If your patch adds a call to a function where the original version of the
Packit Service ac8aad
  function's ELF symbol has a .constprop or .isra suffix, and the corresponding
Packit Service ac8aad
  patched function doesn't, that means the patch caused gcc to no longer
Packit Service ac8aad
  perform an interprocedural optimization, which affects the function and all
Packit Service ac8aad
  its callers.  If you want to prevent this from happening, copy/paste the
Packit Service ac8aad
  function with a new name and call the new function from your patch.
Packit Service ac8aad
Packit Service ac8aad
* Moving around source code lines can introduce unique instructions if any
Packit Service ac8aad
  `__LINE__` preprocessor macros are in use. This can be mitigated by adding
Packit Service ac8aad
  any new functions to the bottom of source files, using newline whitespace to
Packit Service ac8aad
  maintain original line counts, etc. A more exact fix can be employed by
Packit Service ac8aad
  modifying the source code that invokes `__LINE__` and hard-coding the
Packit Service da4517
  original line number in place.  This occurred in issue #1124 for example.
Packit Service ac8aad
Packit Service ac8aad
Removing references to static local variables
Packit Service ac8aad
---------------------------------------------
Packit Service ac8aad
Packit Service ac8aad
Removing references to static locals will fail to patch unless extra steps are taken.
Packit Service ac8aad
Static locals are basically global variables because they outlive the function's
Packit Service ac8aad
scope. They need to be correlated so that the new function will use the old static
Packit Service ac8aad
local. That way patching the function doesn't inadvertently reset the variable
Packit Service ac8aad
to zero; instead the variable keeps its old value.
Packit Service ac8aad
Packit Service ac8aad
To work around this limitation one needs to retain the reference to the static local.
Packit Service ac8aad
This might be as simple as adding the variable back in the patched function in a 
Packit Service ac8aad
non-functional way and ensuring the compiler doesn't optimize it away.
Packit Service ac8aad
Packit Service ac8aad
Code removal
Packit Service ac8aad
------------
Packit Service ac8aad
Packit Service ac8aad
Some fixes may replace or completely remove functions and references
Packit Service ac8aad
to them. Remember that kpatch modules can only add new functions and
Packit Service ac8aad
redirect existing functions, so "removed" functions will continue to exist in
Packit Service ac8aad
kernel address space as effectively dead code.
Packit Service ac8aad
Packit Service ac8aad
That means this patch (source code removal of `cmdline_proc_show`):
Packit Service ac8aad
```
Packit Service ac8aad
diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c
Packit Service ac8aad
--- src.orig/fs/proc/cmdline.c	2016-11-30 19:39:49.317737234 +0000
Packit Service ac8aad
+++ src/fs/proc/cmdline.c	2016-11-30 19:39:52.696737234 +0000
Packit Service ac8aad
@@ -3,15 +3,15 @@
Packit Service ac8aad
 #include <linux/proc_fs.h>
Packit Service ac8aad
 #include <linux/seq_file.h>
Packit Service ac8aad
 
Packit Service ac8aad
-static int cmdline_proc_show(struct seq_file *m, void *v)
Packit Service ac8aad
-{
Packit Service ac8aad
-	seq_printf(m, "%s\n", saved_command_line);
Packit Service ac8aad
-	return 0;
Packit Service ac8aad
-}
Packit Service ac8aad
+static int cmdline_proc_show_v2(struct seq_file *m, void *v)
Packit Service ac8aad
+{
Packit Service ac8aad
+	seq_printf(m, "%s kpatch\n", saved_command_line);
Packit Service ac8aad
+	return 0;
Packit Service ac8aad
+}
Packit Service ac8aad
 
Packit Service ac8aad
 static int cmdline_proc_open(struct inode *inode, struct file *file)
Packit Service ac8aad
 {
Packit Service ac8aad
-	return single_open(file, cmdline_proc_show, NULL);
Packit Service ac8aad
+	return single_open(file, cmdline_proc_show_v2, NULL);
Packit Service ac8aad
 }
Packit Service ac8aad
 
Packit Service ac8aad
 static const struct file_operations cmdline_proc_fops = {
Packit Service ac8aad
```
Packit Service ac8aad
will generate an equivalent kpatch module to this patch (dead
Packit Service ac8aad
`cmdline_proc_show` left in source):
Packit Service ac8aad
```
Packit Service ac8aad
diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c
Packit Service ac8aad
--- src.orig/fs/proc/cmdline.c	2016-11-30 19:39:49.317737234 +0000
Packit Service ac8aad
+++ src/fs/proc/cmdline.c	2016-11-30 19:39:52.696737234 +0000
Packit Service ac8aad
@@ -9,9 +9,15 @@ static int cmdline_proc_show(struct seq_
Packit Service ac8aad
 	return 0;
Packit Service ac8aad
 }
Packit Service ac8aad
 
Packit Service ac8aad
+static int cmdline_proc_show_v2(struct seq_file *m, void *v)
Packit Service ac8aad
+{
Packit Service ac8aad
+	seq_printf(m, "%s kpatch\n", saved_command_line);
Packit Service ac8aad
+	return 0;
Packit Service ac8aad
+}
Packit Service ac8aad
+
Packit Service ac8aad
 static int cmdline_proc_open(struct inode *inode, struct file *file)
Packit Service ac8aad
 {
Packit Service ac8aad
-	return single_open(file, cmdline_proc_show, NULL);
Packit Service ac8aad
+	return single_open(file, cmdline_proc_show_v2, NULL);
Packit Service ac8aad
 }
Packit Service ac8aad
 
Packit Service ac8aad
 static const struct file_operations cmdline_proc_fops = {
Packit Service ac8aad
```
Packit Service ac8aad
In both versions, `kpatch-build` will determine that only
Packit Service ac8aad
`cmdline_proc_open` has changed and that `cmdline_proc_show_v2` is a
Packit Service ac8aad
new function.
Packit Service ac8aad
Packit Service ac8aad
In some patching cases it might be necessary to completely remove the original
Packit Service ac8aad
function to avoid the compiler complaining about a defined, but unused
Packit Service ac8aad
function.  This will depend on symbol scope and kernel build options.
Packit Service ac8aad
Packit Service da4517
"Once" macros
Packit Service da4517
-------------
Packit Service ac8aad
Packit Service ac8aad
When adding a call to `printk_once()`, `pr_warn_once()`, or any other "once"
Packit Service ac8aad
variation of `printk()`, you'll get the following eror:
Packit Service ac8aad
Packit Service ac8aad
```
Packit Service ac8aad
ERROR: vmx.o: 1 unsupported section change(s)
Packit Service ac8aad
vmx.o: WARNING: unable to correlate static local variable __print_once.60588 used by vmx_update_pi_irte, assuming variable is new
Packit Service ac8aad
vmx.o: changed function: vmx_update_pi_irte
Packit Service ac8aad
vmx.o: data section .data..read_mostly selected for inclusion
Packit Service ac8aad
/usr/lib/kpatch/create-diff-object: unreconcilable difference
Packit Service ac8aad
```
Packit Service ac8aad
This error occurs because the `printk_once()` adds a static local variable to
Packit Service ac8aad
the `.data..read_mostly` section.  kpatch-build strict disallows any changes to
Packit Service ac8aad
that section, because in some cases a change to this section indicates a bug.
Packit Service ac8aad
Packit Service ac8aad
To work around this issue, you'll need to manually implement your own "once"
Packit Service ac8aad
logic which doesn't store the static variable in the `.data..read_mostly`
Packit Service ac8aad
section.
Packit Service ac8aad
Packit Service ac8aad
For example, a `pr_warn_once()` can be replaced with:
Packit Service ac8aad
```
Packit Service ac8aad
	static bool print_once;
Packit Service ac8aad
	...
Packit Service ac8aad
	if (!print_once) {
Packit Service ac8aad
		print_once = true;
Packit Service ac8aad
		pr_warn("...");
Packit Service ac8aad
	}
Packit Service ac8aad
```
Packit Service da4517
Packit Service da4517
inline implies notrace
Packit Service da4517
----------------------
Packit Service da4517
Packit Service da4517
The linux kernel defines its own version of "inline" in
Packit Service da4517
include/linux/compiler_types.h which includes "notrace" as well:
Packit Service da4517
Packit Service da4517
```
Packit Service da4517
#if !defined(CONFIG_OPTIMIZE_INLINING)
Packit Service da4517
#define inline inline __attribute__((__always_inline__)) __gnu_inline \
Packit Service da4517
        __inline_maybe_unused notrace
Packit Service da4517
#else
Packit Service da4517
#define inline inline                                    __gnu_inline \
Packit Service da4517
        __inline_maybe_unused notrace
Packit Service da4517
#endif
Packit Service da4517
```
Packit Service da4517
Packit Service da4517
With the implicit "notrace", use of "inline" in patch sources may lead
Packit Service da4517
to kpatch-build errors like the following:
Packit Service da4517
Packit Service da4517
1. `__tcp_mtu_to_mss()` is marked as inline:
Packit Service da4517
Packit Service da4517
```
Packit Service da4517
net/ipv4/tcp_output.c:
Packit Service da4517
Packit Service da4517
/* Calculate MSS not accounting any TCP options.  */
Packit Service da4517
static inline int __tcp_mtu_to_mss(struct sock *sk, int pmtu)
Packit Service da4517
{
Packit Service da4517
```
Packit Service da4517
Packit Service da4517
2. the compiler decides not to inline it and keeps it in its own
Packit Service da4517
   function-section.  Then kpatch-build notices that it doesn't have an
Packit Service da4517
   fentry/mcount call:
Packit Service da4517
Packit Service da4517
```
Packit Service da4517
% kpatch-build ...
Packit Service da4517
Packit Service da4517
tcp_output.o: function __tcp_mtu_to_mss has no fentry/mcount call, unable to patch
Packit Service da4517
```
Packit Service da4517
Packit Service da4517
3. a peek at the generated code:
Packit Service da4517
Packit Service da4517
```
Packit Service da4517
Disassembly of section .text.__tcp_mtu_to_mss:
Packit Service da4517
Packit Service da4517
0000000000000000 <__tcp_mtu_to_mss>:
Packit Service da4517
   0:   48 8b 87 60 05 00 00    mov    0x560(%rdi),%rax
Packit Service da4517
   7:   0f b7 50 30             movzwl 0x30(%rax),%edx
Packit Service da4517
   b:   0f b7 40 32             movzwl 0x32(%rax),%eax
Packit Service da4517
   f:   29 d6                   sub    %edx,%esi
Packit Service da4517
  11:   83 ee 14                sub    $0x14,%esi
Packit Service da4517
  ...
Packit Service da4517
```
Packit Service da4517
Packit Service da4517
This could be a little confusing since one might have expected to see
Packit Service da4517
changes to all of `__tcp_mtu_to_mss()` callers (ie, it was inlined as
Packit Service da4517
requested).  In this case, a simple workaround is to specify
Packit Service da4517
`__tcp_mtu_to_mss()` as `__always_inline` to force the compiler to do so.
Packit Service da4517
Packit Service da4517
Jump labels
Packit Service da4517
-----------
Packit Service da4517
Packit Service da4517
When modifying a function that contains a jump label, kpatch-build may
Packit Service da4517
return an error like: `ERROR: oom_kill.o: kpatch_regenerate_special_section: 2109: Found a jump label at out_of_memory()+0x10a, using key cpusets_enabled_key.  Jump labels aren't currently supported.  Use static_key_enabled() instead.`
Packit Service da4517
Packit Service da4517
This is due to a limitation in the kernel to process static key
Packit Service da4517
livepatch relocations (resolved by late-module patching).  Older
Packit Service da4517
versions of kpatch-build may have reported successfully building
Packit Service da4517
kpatch module, but issue
Packit Service da4517
[#931](https://github.com/dynup/kpatch/issues/931) revealed potentially
Packit Service da4517
dangerous behavior if the static key value had been modified from its
Packit Service da4517
compiled default.
Packit Service da4517
Packit Service da4517
The current workaround is to remove the jump label by explictly checking
Packit Service da4517
the static key:
Packit Service da4517
Packit Service da4517
```
Packit Service da4517
DEFINE_STATIC_KEY_TRUE(true_key);
Packit Service da4517
DEFINE_STATIC_KEY_FALSE(false_key);
Packit Service da4517
Packit Service da4517
/* unsupported */
Packit Service da4517
if (static_key_true(&true_key))
Packit Service da4517
if (static_key_false(&false_key))
Packit Service da4517
if (static_branch_likely(&key))
Packit Service da4517
Packit Service da4517
/* supported */
Packit Service da4517
if (static_key_enabled(&true_key))
Packit Service da4517
if (static_key_enabled(&false_key))
Packit Service da4517
if (likely(static_key_enabled(&key)))
Packit Service da4517
```
Packit Service da4517
Packit Service da4517
Sibling calls
Packit Service da4517
-------------
Packit Service da4517
Packit Service da4517
GCC may generate sibling calls that are incompatible with kpatch, resulting in
Packit Service da4517
an error like: `ERROR("Found an unsupported sibling call at foo()+0x123.  Add __attribute__((optimize("-fno-optimize-sibling-calls"))) to foo() definition."`
Packit Service da4517
Packit Service da4517
For example, if function A() calls function B() at the end of A() and both
Packit Service da4517
return similar data-types, GCC may deem them "sibling calls" and apply a tail
Packit Service da4517
call optimization in which A() restores the stack to is callee state before
Packit Service da4517
setting up B()'s arguments and jumping to B().
Packit Service da4517
Packit Service da4517
This may be an issue for kpatches on PowerPC which modify only A() or B() and
Packit Service da4517
the function call crosses a kernel module boundary: the sibling call
Packit Service da4517
optimization has changed expected calling conventions and (un)patched code may
Packit Service da4517
not be similarly modified.
Packit Service da4517
Packit Service da4517
Commit [8b952bd77130](https://github.com/dynup/kpatch/commit/8b952bd77130)
Packit Service da4517
("create-diff-object/ppc64le: Don't allow sibling calls") contains an
Packit Service da4517
excellent example and description of this problem with annotated disassembly.
Packit Service da4517
Packit Service da4517
Adding `__attribute__((optimize("-fno-optimize-sibling-calls")))` instructs
Packit Service da4517
GCC to turn off the optimization for the given function.
Packit Service da4517
Packit Service da4517
Exported symbol versioning
Packit Service da4517
--------------------------
Packit Service da4517
Packit Service da4517
### Background
Packit Service da4517
Packit Service da4517
`CONFIG_MODVERSIONS` enables an ABI check between exported kernel symbols and
Packit Service da4517
modules referencing those symbols, enforced on module load.  When building the
Packit Service da4517
kernel, preprocessor output from `gcc -E` for each source file is passed to
Packit Service da4517
scripts/genksyms.  The genksyms script recursively expands each exported symbol
Packit Service da4517
to its basic types.  A hash is generated for each symbol as it traverses back up
Packit Service da4517
the symbol tree.  The end result is a CRC for each exported function in
Packit Service da4517
the Module.symvers file and embedded in the vmlinux kernel object itself.
Packit Service da4517
Packit Service da4517
A similar checksumming is performed when building modules: referenced exported
Packit Service da4517
symbol CRCs are stored in the module’s `__versions` section (you can also find
Packit Service da4517
these in plain-text intermediate \*.mod.c files.)
Packit Service da4517
Packit Service da4517
When the kernel loads a module, the symbol CRCs found in its `__versions` are
Packit Service da4517
compared to those of the kernel, if the two do not match, the kernel will refuse
Packit Service da4517
to load it:
Packit Service da4517
```
Packit Service da4517
<module>: disagrees about version of symbol <symbol>
Packit Service da4517
<module>: Unknown symbol <symbol> (err -22)
Packit Service da4517
```
Packit Service da4517
Packit Service da4517
### Kpatch detection
Packit Service da4517
Packit Service da4517
After building the original and patched sources, kpatch-build compares the
Packit Service da4517
newly calculated Module.symvers against the original.  Discrepancies are
Packit Service da4517
reported:
Packit Service da4517
Packit Service da4517
```
Packit Service da4517
ERROR: Version disagreement for symbol <symbol>
Packit Service da4517
```
Packit Service da4517
Packit Service da4517
These reports should be addressed to ensure that the resulting kpatch module
Packit Service da4517
can be loaded.
Packit Service da4517
Packit Service da4517
#### False positives
Packit Service da4517
Packit Service da4517
It is rare, but possible for a kpatch to introduce inadvertent symbol CRC
Packit Service da4517
changes that are not true ABI changes.  The following conditions must occur:
Packit Service da4517
Packit Service da4517
1. The kpatch must modify the definition of an exported symbol.  For example,
Packit Service da4517
   introducing a new header file may further define an opaque data type:
Packit Service da4517
   Before the kpatch, compilation unit U from the original kernel build only
Packit Service da4517
   knew about a `struct S` declaration (not its complete type).  At the same
Packit Service da4517
   time, U contains function F, which has an interface that references S.  If
Packit Service da4517
   the kpatch adds a header file to U that now fully defines `struct S { int
Packit Service da4517
   a, b, c; }`, its symbol type graph changes, CRCs generated for F are updated,
Packit Service da4517
   but its ABI remains consistent.
Packit Service da4517
Packit Service da4517
2. The kpatch must introduce either a change or reference to F such that it is
Packit Service da4517
   included in the resulting kpatch module.  This will force a `__version`
Packit Service da4517
   entry based on the new CRC.
Packit Service da4517
Packit Service da4517
   Note: if a kpatch doesn't change or reference F such that it is **not**
Packit Service da4517
   included in the resulting kpatch module, the new CRC value won't be added
Packit Service da4517
   to the module's `__version` table.  However, if a future accumulative patch
Packit Service da4517
   does add a new change or reference to F, the new CRC will become a problem.
Packit Service da4517
Packit Service da4517
#### Avoidance
Packit Service da4517
Packit Service da4517
Kpatches should introduce new `#include` directives sparingly.  Whenever
Packit Service da4517
possible, extract the required definitions from header filers into kpatched
Packit Service da4517
compilation units directly.
Packit Service da4517
Packit Service da4517
If additional header files or symbol definitions cannot be avoided, consider
Packit Service da4517
surrounding the offending include/definitions in an `#ifndef __GENKSYMS__`
Packit Service da4517
macro.  The genksyms script will skip over those blocks when performing its CRC
Packit Service da4517
calculations.
Packit Service da4517
Packit Service da4517
### But what about a real ABI change?
Packit Service da4517
Packit Service da4517
If a kpatch introduces a true ABI change, each of calling functions would
Packit Service da4517
consequently need to be updated in the kpatch module.  For unexported functions,
Packit Service da4517
this may be handled safely if the kpatch does indeed update all callers.
Packit Service da4517
However, since motivation behind `CONFIG_MODVERSIONS` is to provide basic ABI
Packit Service da4517
verification between the kernel and modules for  **exported** functions, kpatch
Packit Service da4517
cannot safely change this ABI without worrying about breaking other out-of-tree
Packit Service da4517
drivers.  Those drivers have been built against the reference kernel's original
Packit Service da4517
set of CRCs and expect the original ABI.
Packit Service da4517
Packit Service da4517
To track down specifically what caused a symbol CRC change, tools like
Packit Service da4517
[kabi-dw](https://github.com/skozina/kabi-dw) can be employed to produce a
Packit Service da4517
detailed symbol definition report.  For a kpatch-build, kabi-dw can be modified
Packit Service da4517
to operate on .o object files (not just .ko and vmlinux files) and the
Packit Service da4517
`$CACHEDIR/tmp/{orig, patched}` directories compared.