Skip to content

Commit 0e672ad

Browse files
committed
Merge branch 'for-5.5/system-state' into for-linus
2 parents d891433 + ecd2509 commit 0e672ad

File tree

15 files changed

+901
-21
lines changed

15 files changed

+901
-21
lines changed

Documentation/livepatch/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Kernel Livepatching
1212
cumulative-patches
1313
module-elf-format
1414
shadow-vars
15+
system-state
1516

1617
.. only:: subproject and html
1718

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
====================
2+
System State Changes
3+
====================
4+
5+
Some users are really reluctant to reboot a system. This brings the need
6+
to provide more livepatches and maintain some compatibility between them.
7+
8+
Maintaining more livepatches is much easier with cumulative livepatches.
9+
Each new livepatch completely replaces any older one. It can keep,
10+
add, and even remove fixes. And it is typically safe to replace any version
11+
of the livepatch with any other one thanks to the atomic replace feature.
12+
13+
The problems might come with shadow variables and callbacks. They might
14+
change the system behavior or state so that it is no longer safe to
15+
go back and use an older livepatch or the original kernel code. Also
16+
any new livepatch must be able to detect what changes have already been
17+
done by the already installed livepatches.
18+
19+
This is where the livepatch system state tracking gets useful. It
20+
allows to:
21+
22+
- store data needed to manipulate and restore the system state
23+
24+
- define compatibility between livepatches using a change id
25+
and version
26+
27+
28+
1. Livepatch system state API
29+
=============================
30+
31+
The state of the system might get modified either by several livepatch callbacks
32+
or by the newly used code. Also it must be possible to find changes done by
33+
already installed livepatches.
34+
35+
Each modified state is described by struct klp_state, see
36+
include/linux/livepatch.h.
37+
38+
Each livepatch defines an array of struct klp_states. They mention
39+
all states that the livepatch modifies.
40+
41+
The livepatch author must define the following two fields for each
42+
struct klp_state:
43+
44+
- *id*
45+
46+
- Non-zero number used to identify the affected system state.
47+
48+
- *version*
49+
50+
- Number describing the variant of the system state change that
51+
is supported by the given livepatch.
52+
53+
The state can be manipulated using two functions:
54+
55+
- *klp_get_state(patch, id)*
56+
57+
- Get struct klp_state associated with the given livepatch
58+
and state id.
59+
60+
- *klp_get_prev_state(id)*
61+
62+
- Get struct klp_state associated with the given feature id and
63+
already installed livepatches.
64+
65+
2. Livepatch compatibility
66+
==========================
67+
68+
The system state version is used to prevent loading incompatible livepatches.
69+
The check is done when the livepatch is enabled. The rules are:
70+
71+
- Any completely new system state modification is allowed.
72+
73+
- System state modifications with the same or higher version are allowed
74+
for already modified system states.
75+
76+
- Cumulative livepatches must handle all system state modifications from
77+
already installed livepatches.
78+
79+
- Non-cumulative livepatches are allowed to touch already modified
80+
system states.
81+
82+
3. Supported scenarios
83+
======================
84+
85+
Livepatches have their life-cycle and the same is true for the system
86+
state changes. Every compatible livepatch has to support the following
87+
scenarios:
88+
89+
- Modify the system state when the livepatch gets enabled and the state
90+
has not been already modified by a livepatches that are being
91+
replaced.
92+
93+
- Take over or update the system state modification when is has already
94+
been done by a livepatch that is being replaced.
95+
96+
- Restore the original state when the livepatch is disabled.
97+
98+
- Restore the previous state when the transition is reverted.
99+
It might be the original system state or the state modification
100+
done by livepatches that were being replaced.
101+
102+
- Remove any already made changes when error occurs and the livepatch
103+
cannot get enabled.
104+
105+
4. Expected usage
106+
=================
107+
108+
System states are usually modified by livepatch callbacks. The expected
109+
role of each callback is as follows:
110+
111+
*pre_patch()*
112+
113+
- Allocate *state->data* when necessary. The allocation might fail
114+
and *pre_patch()* is the only callback that could stop loading
115+
of the livepatch. The allocation is not needed when the data
116+
are already provided by previously installed livepatches.
117+
118+
- Do any other preparatory action that is needed by
119+
the new code even before the transition gets finished.
120+
For example, initialize *state->data*.
121+
122+
The system state itself is typically modified in *post_patch()*
123+
when the entire system is able to handle it.
124+
125+
- Clean up its own mess in case of error. It might be done by a custom
126+
code or by calling *post_unpatch()* explicitly.
127+
128+
*post_patch()*
129+
130+
- Copy *state->data* from the previous livepatch when they are
131+
compatible.
132+
133+
- Do the actual system state modification. Eventually allow
134+
the new code to use it.
135+
136+
- Make sure that *state->data* has all necessary information.
137+
138+
- Free *state->data* from replaces livepatches when they are
139+
not longer needed.
140+
141+
*pre_unpatch()*
142+
143+
- Prevent the code, added by the livepatch, relying on the system
144+
state change.
145+
146+
- Revert the system state modification..
147+
148+
*post_unpatch()*
149+
150+
- Distinguish transition reverse and livepatch disabling by
151+
checking *klp_get_prev_state()*.
152+
153+
- In case of transition reverse, restore the previous system
154+
state. It might mean doing nothing.
155+
156+
- Remove any not longer needed setting or data.
157+
158+
.. note::
159+
160+
*pre_unpatch()* typically does symmetric operations to *post_patch()*.
161+
Except that it is called only when the livepatch is being disabled.
162+
Therefore it does not need to care about any previously installed
163+
livepatch.
164+
165+
*post_unpatch()* typically does symmetric operations to *pre_patch()*.
166+
It might be called also during the transition reverse. Therefore it
167+
has to handle the state of the previously installed livepatches.

include/linux/livepatch.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,23 @@ struct klp_object {
130130
bool patched;
131131
};
132132

133+
/**
134+
* struct klp_state - state of the system modified by the livepatch
135+
* @id: system state identifier (non-zero)
136+
* @version: version of the change
137+
* @data: custom data
138+
*/
139+
struct klp_state {
140+
unsigned long id;
141+
unsigned int version;
142+
void *data;
143+
};
144+
133145
/**
134146
* struct klp_patch - patch structure for live patching
135147
* @mod: reference to the live patch module
136148
* @objs: object entries for kernel objects to be patched
149+
* @states: system states that can get modified
137150
* @replace: replace all actively used patches
138151
* @list: list node for global list of actively used patches
139152
* @kobj: kobject for sysfs resources
@@ -147,6 +160,7 @@ struct klp_patch {
147160
/* external */
148161
struct module *mod;
149162
struct klp_object *objs;
163+
struct klp_state *states;
150164
bool replace;
151165

152166
/* internal */
@@ -217,6 +231,9 @@ void *klp_shadow_get_or_alloc(void *obj, unsigned long id,
217231
void klp_shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor);
218232
void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor);
219233

234+
struct klp_state *klp_get_state(struct klp_patch *patch, unsigned long id);
235+
struct klp_state *klp_get_prev_state(unsigned long id);
236+
220237
#else /* !CONFIG_LIVEPATCH */
221238

222239
static inline int klp_module_coming(struct module *mod) { return 0; }

kernel/livepatch/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
obj-$(CONFIG_LIVEPATCH) += livepatch.o
33

4-
livepatch-objs := core.o patch.o shadow.o transition.o
4+
livepatch-objs := core.o patch.o shadow.o state.o transition.o

kernel/livepatch/core.c

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <asm/cacheflush.h>
2323
#include "core.h"
2424
#include "patch.h"
25+
#include "state.h"
2526
#include "transition.h"
2627

2728
/*
@@ -632,7 +633,7 @@ static void klp_free_objects_dynamic(struct klp_patch *patch)
632633
* The operation must be completed by calling klp_free_patch_finish()
633634
* outside klp_mutex.
634635
*/
635-
void klp_free_patch_start(struct klp_patch *patch)
636+
static void klp_free_patch_start(struct klp_patch *patch)
636637
{
637638
if (!list_empty(&patch->list))
638639
list_del(&patch->list);
@@ -677,6 +678,23 @@ static void klp_free_patch_work_fn(struct work_struct *work)
677678
klp_free_patch_finish(patch);
678679
}
679680

681+
void klp_free_patch_async(struct klp_patch *patch)
682+
{
683+
klp_free_patch_start(patch);
684+
schedule_work(&patch->free_work);
685+
}
686+
687+
void klp_free_replaced_patches_async(struct klp_patch *new_patch)
688+
{
689+
struct klp_patch *old_patch, *tmp_patch;
690+
691+
klp_for_each_patch_safe(old_patch, tmp_patch) {
692+
if (old_patch == new_patch)
693+
return;
694+
klp_free_patch_async(old_patch);
695+
}
696+
}
697+
680698
static int klp_init_func(struct klp_object *obj, struct klp_func *func)
681699
{
682700
if (!func->old_name)
@@ -992,6 +1010,13 @@ int klp_enable_patch(struct klp_patch *patch)
9921010

9931011
mutex_lock(&klp_mutex);
9941012

1013+
if (!klp_is_patch_compatible(patch)) {
1014+
pr_err("Livepatch patch (%s) is not compatible with the already installed livepatches.\n",
1015+
patch->mod->name);
1016+
mutex_unlock(&klp_mutex);
1017+
return -EINVAL;
1018+
}
1019+
9951020
ret = klp_init_patch_early(patch);
9961021
if (ret) {
9971022
mutex_unlock(&klp_mutex);
@@ -1022,31 +1047,30 @@ int klp_enable_patch(struct klp_patch *patch)
10221047
EXPORT_SYMBOL_GPL(klp_enable_patch);
10231048

10241049
/*
1025-
* This function removes replaced patches.
1050+
* This function unpatches objects from the replaced livepatches.
10261051
*
10271052
* We could be pretty aggressive here. It is called in the situation where
1028-
* these structures are no longer accessible. All functions are redirected
1029-
* by the klp_transition_patch. They use either a new code or they are in
1030-
* the original code because of the special nop function patches.
1053+
* these structures are no longer accessed from the ftrace handler.
1054+
* All functions are redirected by the klp_transition_patch. They
1055+
* use either a new code or they are in the original code because
1056+
* of the special nop function patches.
10311057
*
10321058
* The only exception is when the transition was forced. In this case,
10331059
* klp_ftrace_handler() might still see the replaced patch on the stack.
10341060
* Fortunately, it is carefully designed to work with removed functions
10351061
* thanks to RCU. We only have to keep the patches on the system. Also
10361062
* this is handled transparently by patch->module_put.
10371063
*/
1038-
void klp_discard_replaced_patches(struct klp_patch *new_patch)
1064+
void klp_unpatch_replaced_patches(struct klp_patch *new_patch)
10391065
{
1040-
struct klp_patch *old_patch, *tmp_patch;
1066+
struct klp_patch *old_patch;
10411067

1042-
klp_for_each_patch_safe(old_patch, tmp_patch) {
1068+
klp_for_each_patch(old_patch) {
10431069
if (old_patch == new_patch)
10441070
return;
10451071

10461072
old_patch->enabled = false;
10471073
klp_unpatch_objects(old_patch);
1048-
klp_free_patch_start(old_patch);
1049-
schedule_work(&old_patch->free_work);
10501074
}
10511075
}
10521076

kernel/livepatch/core.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ extern struct list_head klp_patches;
1313
#define klp_for_each_patch(patch) \
1414
list_for_each_entry(patch, &klp_patches, list)
1515

16-
void klp_free_patch_start(struct klp_patch *patch);
17-
void klp_discard_replaced_patches(struct klp_patch *new_patch);
16+
void klp_free_patch_async(struct klp_patch *patch);
17+
void klp_free_replaced_patches_async(struct klp_patch *new_patch);
18+
void klp_unpatch_replaced_patches(struct klp_patch *new_patch);
1819
void klp_discard_nops(struct klp_patch *new_patch);
1920

2021
static inline bool klp_is_object_loaded(struct klp_object *obj)

0 commit comments

Comments
 (0)