Skip to content

Commit f9d1381

Browse files
author
Jiri Kosina
committed
Merge branch 'for-5.1/atomic-replace' into for-linus
The atomic replace allows to create cumulative patches. They are useful when you maintain many livepatches and want to remove one that is lower on the stack. In addition it is very useful when more patches touch the same function and there are dependencies between them. It's also a feature some of the distros are using already to distribute their patches.
2 parents 7185a96 + fbb76d5 commit f9d1381

File tree

5 files changed

+48
-39
lines changed

5 files changed

+48
-39
lines changed

kernel/livepatch/core.c

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ static int klp_add_nops(struct klp_patch *patch)
522522
struct klp_patch *old_patch;
523523
struct klp_object *old_obj;
524524

525-
list_for_each_entry(old_patch, &klp_patches, list) {
525+
klp_for_each_patch(old_patch) {
526526
klp_for_each_object(old_patch, old_obj) {
527527
int err;
528528

@@ -1004,7 +1004,7 @@ int klp_enable_patch(struct klp_patch *patch)
10041004

10051005
if (!klp_have_reliable_stack()) {
10061006
pr_err("This architecture doesn't have support for the livepatch consistency model.\n");
1007-
return -ENOSYS;
1007+
return -EOPNOTSUPP;
10081008
}
10091009

10101010

@@ -1057,7 +1057,7 @@ void klp_discard_replaced_patches(struct klp_patch *new_patch)
10571057
{
10581058
struct klp_patch *old_patch, *tmp_patch;
10591059

1060-
list_for_each_entry_safe(old_patch, tmp_patch, &klp_patches, list) {
1060+
klp_for_each_patch_safe(old_patch, tmp_patch) {
10611061
if (old_patch == new_patch)
10621062
return;
10631063

@@ -1101,29 +1101,22 @@ static void klp_cleanup_module_patches_limited(struct module *mod,
11011101
struct klp_patch *patch;
11021102
struct klp_object *obj;
11031103

1104-
list_for_each_entry(patch, &klp_patches, list) {
1104+
klp_for_each_patch(patch) {
11051105
if (patch == limit)
11061106
break;
11071107

11081108
klp_for_each_object(patch, obj) {
11091109
if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
11101110
continue;
11111111

1112-
/*
1113-
* Only unpatch the module if the patch is enabled or
1114-
* is in transition.
1115-
*/
1116-
if (patch->enabled || patch == klp_transition_patch) {
1117-
1118-
if (patch != klp_transition_patch)
1119-
klp_pre_unpatch_callback(obj);
1112+
if (patch != klp_transition_patch)
1113+
klp_pre_unpatch_callback(obj);
11201114

1121-
pr_notice("reverting patch '%s' on unloading module '%s'\n",
1122-
patch->mod->name, obj->mod->name);
1123-
klp_unpatch_object(obj);
1115+
pr_notice("reverting patch '%s' on unloading module '%s'\n",
1116+
patch->mod->name, obj->mod->name);
1117+
klp_unpatch_object(obj);
11241118

1125-
klp_post_unpatch_callback(obj);
1126-
}
1119+
klp_post_unpatch_callback(obj);
11271120

11281121
klp_free_object_loaded(obj);
11291122
break;
@@ -1148,7 +1141,7 @@ int klp_module_coming(struct module *mod)
11481141
*/
11491142
mod->klp_alive = true;
11501143

1151-
list_for_each_entry(patch, &klp_patches, list) {
1144+
klp_for_each_patch(patch) {
11521145
klp_for_each_object(patch, obj) {
11531146
if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
11541147
continue;
@@ -1162,13 +1155,6 @@ int klp_module_coming(struct module *mod)
11621155
goto err;
11631156
}
11641157

1165-
/*
1166-
* Only patch the module if the patch is enabled or is
1167-
* in transition.
1168-
*/
1169-
if (!patch->enabled && patch != klp_transition_patch)
1170-
break;
1171-
11721158
pr_notice("applying patch '%s' to loading module '%s'\n",
11731159
patch->mod->name, obj->mod->name);
11741160

kernel/livepatch/core.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
extern struct mutex klp_mutex;
88
extern struct list_head klp_patches;
99

10+
#define klp_for_each_patch_safe(patch, tmp_patch) \
11+
list_for_each_entry_safe(patch, tmp_patch, &klp_patches, list)
12+
13+
#define klp_for_each_patch(patch) \
14+
list_for_each_entry(patch, &klp_patches, list)
15+
1016
void klp_free_patch_start(struct klp_patch *patch);
1117
void klp_discard_replaced_patches(struct klp_patch *new_patch);
1218
void klp_discard_nops(struct klp_patch *new_patch);

kernel/livepatch/transition.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,6 @@ void klp_force_transition(void)
652652
for_each_possible_cpu(cpu)
653653
klp_update_patch_state(idle_task(cpu));
654654

655-
list_for_each_entry(patch, &klp_patches, list)
655+
klp_for_each_patch(patch)
656656
patch->forced = true;
657657
}

lib/livepatch/test_klp_shadow_vars.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ static int ptr_id(void *ptr)
4444

4545
sp = kmalloc(sizeof(*sp), GFP_ATOMIC);
4646
if (!sp)
47-
return -1;
47+
return -ENOMEM;
4848
sp->ptr = ptr;
4949
sp->id = count++;
5050

@@ -154,22 +154,37 @@ static int test_klp_shadow_vars_init(void)
154154
* Allocate a few shadow variables with different <obj> and <id>.
155155
*/
156156
sv1 = shadow_alloc(obj, id, size, gfp_flags, shadow_ctor, &var1);
157+
if (!sv1)
158+
return -ENOMEM;
159+
157160
sv2 = shadow_alloc(obj + 1, id, size, gfp_flags, shadow_ctor, &var2);
161+
if (!sv2)
162+
return -ENOMEM;
163+
158164
sv3 = shadow_alloc(obj, id + 1, size, gfp_flags, shadow_ctor, &var3);
165+
if (!sv3)
166+
return -ENOMEM;
159167

160168
/*
161169
* Verify we can find our new shadow variables and that they point
162170
* to expected data.
163171
*/
164172
ret = shadow_get(obj, id);
173+
if (!ret)
174+
return -EINVAL;
165175
if (ret == sv1 && *sv1 == &var1)
166176
pr_info(" got expected PTR%d -> PTR%d result\n",
167177
ptr_id(sv1), ptr_id(*sv1));
178+
168179
ret = shadow_get(obj + 1, id);
180+
if (!ret)
181+
return -EINVAL;
169182
if (ret == sv2 && *sv2 == &var2)
170183
pr_info(" got expected PTR%d -> PTR%d result\n",
171184
ptr_id(sv2), ptr_id(*sv2));
172185
ret = shadow_get(obj, id + 1);
186+
if (!ret)
187+
return -EINVAL;
173188
if (ret == sv3 && *sv3 == &var3)
174189
pr_info(" got expected PTR%d -> PTR%d result\n",
175190
ptr_id(sv3), ptr_id(*sv3));
@@ -179,7 +194,12 @@ static int test_klp_shadow_vars_init(void)
179194
* The second invocation should return the same shadow var.
180195
*/
181196
sv4 = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4);
197+
if (!sv4)
198+
return -ENOMEM;
199+
182200
ret = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4);
201+
if (!ret)
202+
return -EINVAL;
183203
if (ret == sv4 && *sv4 == &var4)
184204
pr_info(" got expected PTR%d -> PTR%d result\n",
185205
ptr_id(sv4), ptr_id(*sv4));
@@ -207,6 +227,8 @@ static int test_klp_shadow_vars_init(void)
207227
* We should still find an <id+1> variable.
208228
*/
209229
ret = shadow_get(obj, id + 1);
230+
if (!ret)
231+
return -EINVAL;
210232
if (ret == sv3 && *sv3 == &var3)
211233
pr_info(" got expected PTR%d -> PTR%d result\n",
212234
ptr_id(sv3), ptr_id(*sv3));

tools/testing/selftests/livepatch/functions.sh

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,10 @@ function is_livepatch_mod() {
5555

5656
function __load_mod() {
5757
local mod="$1"; shift
58-
local args="$*"
5958

60-
local msg="% modprobe $mod $args"
59+
local msg="% modprobe $mod $*"
6160
log "${msg%% }"
62-
ret=$(modprobe "$mod" "$args" 2>&1)
61+
ret=$(modprobe "$mod" "$@" 2>&1)
6362
if [[ "$ret" != "" ]]; then
6463
die "$ret"
6564
fi
@@ -75,12 +74,11 @@ function __load_mod() {
7574
# params - module parameters to pass to modprobe
7675
function load_mod() {
7776
local mod="$1"; shift
78-
local args="$*"
7977

8078
is_livepatch_mod "$mod" &&
8179
die "use load_lp() to load the livepatch module $mod"
8280

83-
__load_mod "$mod" "$args"
81+
__load_mod "$mod" "$@"
8482
}
8583

8684
# load_lp_nowait(modname, params) - load a kernel module with a livepatch
@@ -89,12 +87,11 @@ function load_mod() {
8987
# params - module parameters to pass to modprobe
9088
function load_lp_nowait() {
9189
local mod="$1"; shift
92-
local args="$*"
9390

9491
is_livepatch_mod "$mod" ||
9592
die "module $mod is not a livepatch"
9693

97-
__load_mod "$mod" "$args"
94+
__load_mod "$mod" "$@"
9895

9996
# Wait for livepatch in sysfs ...
10097
loop_until '[[ -e "/sys/kernel/livepatch/$mod" ]]' ||
@@ -106,9 +103,8 @@ function load_lp_nowait() {
106103
# params - module parameters to pass to modprobe
107104
function load_lp() {
108105
local mod="$1"; shift
109-
local args="$*"
110106

111-
load_lp_nowait "$mod" "$args"
107+
load_lp_nowait "$mod" "$@"
112108

113109
# Wait until the transition finishes ...
114110
loop_until 'grep -q '^0$' /sys/kernel/livepatch/$mod/transition' ||
@@ -120,11 +116,10 @@ function load_lp() {
120116
# params - module parameters to pass to modprobe
121117
function load_failing_mod() {
122118
local mod="$1"; shift
123-
local args="$*"
124119

125-
local msg="% modprobe $mod $args"
120+
local msg="% modprobe $mod $*"
126121
log "${msg%% }"
127-
ret=$(modprobe "$mod" "$args" 2>&1)
122+
ret=$(modprobe "$mod" "$@" 2>&1)
128123
if [[ "$ret" == "" ]]; then
129124
die "$mod unexpectedly loaded"
130125
fi

0 commit comments

Comments
 (0)