aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2019-03-05 09:56:59 -0500
committerJiri Kosina <jkosina@suse.cz>2019-03-05 09:56:59 -0500
commitf9d138145686b52b48ccb36557d6842076e2b9dd (patch)
tree95f5c8952a06616ddf4e7ed0288b82bfdb3aea72
parent7185a96981a2f8bb523dd87cad20a6b96c721ad5 (diff)
parentfbb76d579dff4a2e332566dcd1d5979ac92bc34b (diff)
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.
-rw-r--r--kernel/livepatch/core.c36
-rw-r--r--kernel/livepatch/core.h6
-rw-r--r--kernel/livepatch/transition.c2
-rw-r--r--lib/livepatch/test_klp_shadow_vars.c24
-rw-r--r--tools/testing/selftests/livepatch/functions.sh19
5 files changed, 48 insertions, 39 deletions
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index fe1993399823..eb0ee10a1981 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -522,7 +522,7 @@ static int klp_add_nops(struct klp_patch *patch)
522 struct klp_patch *old_patch; 522 struct klp_patch *old_patch;
523 struct klp_object *old_obj; 523 struct klp_object *old_obj;
524 524
525 list_for_each_entry(old_patch, &klp_patches, list) { 525 klp_for_each_patch(old_patch) {
526 klp_for_each_object(old_patch, old_obj) { 526 klp_for_each_object(old_patch, old_obj) {
527 int err; 527 int err;
528 528
@@ -1004,7 +1004,7 @@ int klp_enable_patch(struct klp_patch *patch)
1004 1004
1005 if (!klp_have_reliable_stack()) { 1005 if (!klp_have_reliable_stack()) {
1006 pr_err("This architecture doesn't have support for the livepatch consistency model.\n"); 1006 pr_err("This architecture doesn't have support for the livepatch consistency model.\n");
1007 return -ENOSYS; 1007 return -EOPNOTSUPP;
1008 } 1008 }
1009 1009
1010 1010
@@ -1057,7 +1057,7 @@ void klp_discard_replaced_patches(struct klp_patch *new_patch)
1057{ 1057{
1058 struct klp_patch *old_patch, *tmp_patch; 1058 struct klp_patch *old_patch, *tmp_patch;
1059 1059
1060 list_for_each_entry_safe(old_patch, tmp_patch, &klp_patches, list) { 1060 klp_for_each_patch_safe(old_patch, tmp_patch) {
1061 if (old_patch == new_patch) 1061 if (old_patch == new_patch)
1062 return; 1062 return;
1063 1063
@@ -1101,7 +1101,7 @@ static void klp_cleanup_module_patches_limited(struct module *mod,
1101 struct klp_patch *patch; 1101 struct klp_patch *patch;
1102 struct klp_object *obj; 1102 struct klp_object *obj;
1103 1103
1104 list_for_each_entry(patch, &klp_patches, list) { 1104 klp_for_each_patch(patch) {
1105 if (patch == limit) 1105 if (patch == limit)
1106 break; 1106 break;
1107 1107
@@ -1109,21 +1109,14 @@ static void klp_cleanup_module_patches_limited(struct module *mod,
1109 if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) 1109 if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
1110 continue; 1110 continue;
1111 1111
1112 /* 1112 if (patch != klp_transition_patch)
1113 * Only unpatch the module if the patch is enabled or 1113 klp_pre_unpatch_callback(obj);
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);
1120 1114
1121 pr_notice("reverting patch '%s' on unloading module '%s'\n", 1115 pr_notice("reverting patch '%s' on unloading module '%s'\n",
1122 patch->mod->name, obj->mod->name); 1116 patch->mod->name, obj->mod->name);
1123 klp_unpatch_object(obj); 1117 klp_unpatch_object(obj);
1124 1118
1125 klp_post_unpatch_callback(obj); 1119 klp_post_unpatch_callback(obj);
1126 }
1127 1120
1128 klp_free_object_loaded(obj); 1121 klp_free_object_loaded(obj);
1129 break; 1122 break;
@@ -1148,7 +1141,7 @@ int klp_module_coming(struct module *mod)
1148 */ 1141 */
1149 mod->klp_alive = true; 1142 mod->klp_alive = true;
1150 1143
1151 list_for_each_entry(patch, &klp_patches, list) { 1144 klp_for_each_patch(patch) {
1152 klp_for_each_object(patch, obj) { 1145 klp_for_each_object(patch, obj) {
1153 if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) 1146 if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
1154 continue; 1147 continue;
@@ -1162,13 +1155,6 @@ int klp_module_coming(struct module *mod)
1162 goto err; 1155 goto err;
1163 } 1156 }
1164 1157
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
1172 pr_notice("applying patch '%s' to loading module '%s'\n", 1158 pr_notice("applying patch '%s' to loading module '%s'\n",
1173 patch->mod->name, obj->mod->name); 1159 patch->mod->name, obj->mod->name);
1174 1160
diff --git a/kernel/livepatch/core.h b/kernel/livepatch/core.h
index e6200f38701f..ec43a40b853f 100644
--- a/kernel/livepatch/core.h
+++ b/kernel/livepatch/core.h
@@ -7,6 +7,12 @@
7extern struct mutex klp_mutex; 7extern struct mutex klp_mutex;
8extern struct list_head klp_patches; 8extern struct list_head klp_patches;
9 9
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
10void klp_free_patch_start(struct klp_patch *patch); 16void klp_free_patch_start(struct klp_patch *patch);
11void klp_discard_replaced_patches(struct klp_patch *new_patch); 17void klp_discard_replaced_patches(struct klp_patch *new_patch);
12void klp_discard_nops(struct klp_patch *new_patch); 18void klp_discard_nops(struct klp_patch *new_patch);
diff --git a/kernel/livepatch/transition.c b/kernel/livepatch/transition.c
index 183b2086ba03..9c89ae8b337a 100644
--- a/kernel/livepatch/transition.c
+++ b/kernel/livepatch/transition.c
@@ -652,6 +652,6 @@ void klp_force_transition(void)
652 for_each_possible_cpu(cpu) 652 for_each_possible_cpu(cpu)
653 klp_update_patch_state(idle_task(cpu)); 653 klp_update_patch_state(idle_task(cpu));
654 654
655 list_for_each_entry(patch, &klp_patches, list) 655 klp_for_each_patch(patch)
656 patch->forced = true; 656 patch->forced = true;
657} 657}
diff --git a/lib/livepatch/test_klp_shadow_vars.c b/lib/livepatch/test_klp_shadow_vars.c
index 02f892f941dc..fe5c413efe96 100644
--- a/lib/livepatch/test_klp_shadow_vars.c
+++ b/lib/livepatch/test_klp_shadow_vars.c
@@ -44,7 +44,7 @@ static int ptr_id(void *ptr)
44 44
45 sp = kmalloc(sizeof(*sp), GFP_ATOMIC); 45 sp = kmalloc(sizeof(*sp), GFP_ATOMIC);
46 if (!sp) 46 if (!sp)
47 return -1; 47 return -ENOMEM;
48 sp->ptr = ptr; 48 sp->ptr = ptr;
49 sp->id = count++; 49 sp->id = count++;
50 50
@@ -154,22 +154,37 @@ static int test_klp_shadow_vars_init(void)
154 * Allocate a few shadow variables with different <obj> and <id>. 154 * Allocate a few shadow variables with different <obj> and <id>.
155 */ 155 */
156 sv1 = shadow_alloc(obj, id, size, gfp_flags, shadow_ctor, &var1); 156 sv1 = shadow_alloc(obj, id, size, gfp_flags, shadow_ctor, &var1);
157 if (!sv1)
158 return -ENOMEM;
159
157 sv2 = shadow_alloc(obj + 1, id, size, gfp_flags, shadow_ctor, &var2); 160 sv2 = shadow_alloc(obj + 1, id, size, gfp_flags, shadow_ctor, &var2);
161 if (!sv2)
162 return -ENOMEM;
163
158 sv3 = shadow_alloc(obj, id + 1, size, gfp_flags, shadow_ctor, &var3); 164 sv3 = shadow_alloc(obj, id + 1, size, gfp_flags, shadow_ctor, &var3);
165 if (!sv3)
166 return -ENOMEM;
159 167
160 /* 168 /*
161 * Verify we can find our new shadow variables and that they point 169 * Verify we can find our new shadow variables and that they point
162 * to expected data. 170 * to expected data.
163 */ 171 */
164 ret = shadow_get(obj, id); 172 ret = shadow_get(obj, id);
173 if (!ret)
174 return -EINVAL;
165 if (ret == sv1 && *sv1 == &var1) 175 if (ret == sv1 && *sv1 == &var1)
166 pr_info(" got expected PTR%d -> PTR%d result\n", 176 pr_info(" got expected PTR%d -> PTR%d result\n",
167 ptr_id(sv1), ptr_id(*sv1)); 177 ptr_id(sv1), ptr_id(*sv1));
178
168 ret = shadow_get(obj + 1, id); 179 ret = shadow_get(obj + 1, id);
180 if (!ret)
181 return -EINVAL;
169 if (ret == sv2 && *sv2 == &var2) 182 if (ret == sv2 && *sv2 == &var2)
170 pr_info(" got expected PTR%d -> PTR%d result\n", 183 pr_info(" got expected PTR%d -> PTR%d result\n",
171 ptr_id(sv2), ptr_id(*sv2)); 184 ptr_id(sv2), ptr_id(*sv2));
172 ret = shadow_get(obj, id + 1); 185 ret = shadow_get(obj, id + 1);
186 if (!ret)
187 return -EINVAL;
173 if (ret == sv3 && *sv3 == &var3) 188 if (ret == sv3 && *sv3 == &var3)
174 pr_info(" got expected PTR%d -> PTR%d result\n", 189 pr_info(" got expected PTR%d -> PTR%d result\n",
175 ptr_id(sv3), ptr_id(*sv3)); 190 ptr_id(sv3), ptr_id(*sv3));
@@ -179,7 +194,12 @@ static int test_klp_shadow_vars_init(void)
179 * The second invocation should return the same shadow var. 194 * The second invocation should return the same shadow var.
180 */ 195 */
181 sv4 = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4); 196 sv4 = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4);
197 if (!sv4)
198 return -ENOMEM;
199
182 ret = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4); 200 ret = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4);
201 if (!ret)
202 return -EINVAL;
183 if (ret == sv4 && *sv4 == &var4) 203 if (ret == sv4 && *sv4 == &var4)
184 pr_info(" got expected PTR%d -> PTR%d result\n", 204 pr_info(" got expected PTR%d -> PTR%d result\n",
185 ptr_id(sv4), ptr_id(*sv4)); 205 ptr_id(sv4), ptr_id(*sv4));
@@ -207,6 +227,8 @@ static int test_klp_shadow_vars_init(void)
207 * We should still find an <id+1> variable. 227 * We should still find an <id+1> variable.
208 */ 228 */
209 ret = shadow_get(obj, id + 1); 229 ret = shadow_get(obj, id + 1);
230 if (!ret)
231 return -EINVAL;
210 if (ret == sv3 && *sv3 == &var3) 232 if (ret == sv3 && *sv3 == &var3)
211 pr_info(" got expected PTR%d -> PTR%d result\n", 233 pr_info(" got expected PTR%d -> PTR%d result\n",
212 ptr_id(sv3), ptr_id(*sv3)); 234 ptr_id(sv3), ptr_id(*sv3));
diff --git a/tools/testing/selftests/livepatch/functions.sh b/tools/testing/selftests/livepatch/functions.sh
index c7b9fb45d7c9..30195449c63c 100644
--- a/tools/testing/selftests/livepatch/functions.sh
+++ b/tools/testing/selftests/livepatch/functions.sh
@@ -55,11 +55,10 @@ function is_livepatch_mod() {
55 55
56function __load_mod() { 56function __load_mod() {
57 local mod="$1"; shift 57 local mod="$1"; shift
58 local args="$*"
59 58
60 local msg="% modprobe $mod $args" 59 local msg="% modprobe $mod $*"
61 log "${msg%% }" 60 log "${msg%% }"
62 ret=$(modprobe "$mod" "$args" 2>&1) 61 ret=$(modprobe "$mod" "$@" 2>&1)
63 if [[ "$ret" != "" ]]; then 62 if [[ "$ret" != "" ]]; then
64 die "$ret" 63 die "$ret"
65 fi 64 fi
@@ -75,12 +74,11 @@ function __load_mod() {
75# params - module parameters to pass to modprobe 74# params - module parameters to pass to modprobe
76function load_mod() { 75function load_mod() {
77 local mod="$1"; shift 76 local mod="$1"; shift
78 local args="$*"
79 77
80 is_livepatch_mod "$mod" && 78 is_livepatch_mod "$mod" &&
81 die "use load_lp() to load the livepatch module $mod" 79 die "use load_lp() to load the livepatch module $mod"
82 80
83 __load_mod "$mod" "$args" 81 __load_mod "$mod" "$@"
84} 82}
85 83
86# load_lp_nowait(modname, params) - load a kernel module with a livepatch 84# load_lp_nowait(modname, params) - load a kernel module with a livepatch
@@ -89,12 +87,11 @@ function load_mod() {
89# params - module parameters to pass to modprobe 87# params - module parameters to pass to modprobe
90function load_lp_nowait() { 88function load_lp_nowait() {
91 local mod="$1"; shift 89 local mod="$1"; shift
92 local args="$*"
93 90
94 is_livepatch_mod "$mod" || 91 is_livepatch_mod "$mod" ||
95 die "module $mod is not a livepatch" 92 die "module $mod is not a livepatch"
96 93
97 __load_mod "$mod" "$args" 94 __load_mod "$mod" "$@"
98 95
99 # Wait for livepatch in sysfs ... 96 # Wait for livepatch in sysfs ...
100 loop_until '[[ -e "/sys/kernel/livepatch/$mod" ]]' || 97 loop_until '[[ -e "/sys/kernel/livepatch/$mod" ]]' ||
@@ -106,9 +103,8 @@ function load_lp_nowait() {
106# params - module parameters to pass to modprobe 103# params - module parameters to pass to modprobe
107function load_lp() { 104function load_lp() {
108 local mod="$1"; shift 105 local mod="$1"; shift
109 local args="$*"
110 106
111 load_lp_nowait "$mod" "$args" 107 load_lp_nowait "$mod" "$@"
112 108
113 # Wait until the transition finishes ... 109 # Wait until the transition finishes ...
114 loop_until 'grep -q '^0$' /sys/kernel/livepatch/$mod/transition' || 110 loop_until 'grep -q '^0$' /sys/kernel/livepatch/$mod/transition' ||
@@ -120,11 +116,10 @@ function load_lp() {
120# params - module parameters to pass to modprobe 116# params - module parameters to pass to modprobe
121function load_failing_mod() { 117function load_failing_mod() {
122 local mod="$1"; shift 118 local mod="$1"; shift
123 local args="$*"
124 119
125 local msg="% modprobe $mod $args" 120 local msg="% modprobe $mod $*"
126 log "${msg%% }" 121 log "${msg%% }"
127 ret=$(modprobe "$mod" "$args" 2>&1) 122 ret=$(modprobe "$mod" "$@" 2>&1)
128 if [[ "$ret" == "" ]]; then 123 if [[ "$ret" == "" ]]; then
129 die "$mod unexpectedly loaded" 124 die "$mod unexpectedly loaded"
130 fi 125 fi