Skip to content

Commit c99a2be

Browse files
mirabJiri Kosina
authored andcommitted
livepatch: force transition to finish
If a task sleeps in a set of patched functions uninterruptedly, it could block the whole transition indefinitely. Thus it may be useful to clear its TIF_PATCH_PENDING to allow the process to finish. Admin can do that now by writing to force sysfs attribute in livepatch sysfs directory. TIF_PATCH_PENDING is then cleared for all tasks and the transition can finish successfully. Important note! Administrator should not use this feature without a clearance from a patch distributor. It must be checked that by doing so the consistency model guarantees are not violated. Removal (rmmod) of patch modules is permanently disabled when the feature is used. It cannot be guaranteed there is no task sleeping in such module. Signed-off-by: Miroslav Benes <mbenes@suse.cz> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com> Reviewed-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent 43347d5 commit c99a2be

File tree

5 files changed

+95
-4
lines changed

5 files changed

+95
-4
lines changed

Documentation/ABI/testing/sysfs-kernel-livepatch

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,20 @@ Description:
4545
signal pending structures). Tasks are interrupted or woken up,
4646
and forced to change their patched state.
4747

48+
What: /sys/kernel/livepatch/<patch>/force
49+
Date: Nov 2017
50+
KernelVersion: 4.15.0
51+
Contact: live-patching@vger.kernel.org
52+
Description:
53+
A writable attribute that allows administrator to affect the
54+
course of an existing transition. Writing 1 clears
55+
TIF_PATCH_PENDING flag of all tasks and thus forces the tasks to
56+
the patched or unpatched state. Administrator should not
57+
use this feature without a clearance from a patch
58+
distributor. Removal (rmmod) of patch modules is permanently
59+
disabled when the feature is used. See
60+
Documentation/livepatch/livepatch.txt for more information.
61+
4862
What: /sys/kernel/livepatch/<patch>/<object>
4963
Date: Nov 2014
5064
KernelVersion: 3.19.0

Documentation/livepatch/livepatch.txt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,20 @@ tasks. No proper signal is actually delivered (there is no data in signal
183183
pending structures). Tasks are interrupted or woken up, and forced to change
184184
their patched state.
185185

186+
Administrator can also affect a transition through
187+
/sys/kernel/livepatch/<patch>/force attribute. Writing 1 there clears
188+
TIF_PATCH_PENDING flag of all tasks and thus forces the tasks to the patched
189+
state. Important note! The force attribute is intended for cases when the
190+
transition gets stuck for a long time because of a blocking task. Administrator
191+
is expected to collect all necessary data (namely stack traces of such blocking
192+
tasks) and request a clearance from a patch distributor to force the transition.
193+
Unauthorized usage may cause harm to the system. It depends on the nature of the
194+
patch, which functions are (un)patched, and which functions the blocking tasks
195+
are sleeping in (/proc/<pid>/stack may help here). Removal (rmmod) of patch
196+
modules is permanently disabled when the force feature is used. It cannot be
197+
guaranteed there is no task sleeping in such module. It implies unbounded
198+
reference count if a patch module is disabled and enabled in a loop.
199+
186200
3.1 Adding consistency model support to new architectures
187201
---------------------------------------------------------
188202

@@ -439,8 +453,8 @@ Information about the registered patches can be found under
439453
/sys/kernel/livepatch. The patches could be enabled and disabled
440454
by writing there.
441455

442-
/sys/kernel/livepatch/<patch>/signal attribute allows administrator to affect a
443-
patching operation.
456+
/sys/kernel/livepatch/<patch>/signal and /sys/kernel/livepatch/<patch>/force
457+
attributes allow administrator to affect a patching operation.
444458

445459
See Documentation/ABI/testing/sysfs-kernel-livepatch for more details.
446460

kernel/livepatch/core.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ EXPORT_SYMBOL_GPL(klp_enable_patch);
455455
* /sys/kernel/livepatch/<patch>/enabled
456456
* /sys/kernel/livepatch/<patch>/transition
457457
* /sys/kernel/livepatch/<patch>/signal
458+
* /sys/kernel/livepatch/<patch>/force
458459
* /sys/kernel/livepatch/<patch>/<object>
459460
* /sys/kernel/livepatch/<patch>/<object>/<function,sympos>
460461
*/
@@ -556,13 +557,42 @@ static ssize_t signal_store(struct kobject *kobj, struct kobj_attribute *attr,
556557
return count;
557558
}
558559

560+
static ssize_t force_store(struct kobject *kobj, struct kobj_attribute *attr,
561+
const char *buf, size_t count)
562+
{
563+
struct klp_patch *patch;
564+
int ret;
565+
bool val;
566+
567+
patch = container_of(kobj, struct klp_patch, kobj);
568+
569+
/*
570+
* klp_mutex lock is not grabbed here intentionally. It is not really
571+
* needed. The race window is harmless and grabbing the lock would only
572+
* hold the action back.
573+
*/
574+
if (patch != klp_transition_patch)
575+
return -EINVAL;
576+
577+
ret = kstrtobool(buf, &val);
578+
if (ret)
579+
return ret;
580+
581+
if (val)
582+
klp_force_transition();
583+
584+
return count;
585+
}
586+
559587
static struct kobj_attribute enabled_kobj_attr = __ATTR_RW(enabled);
560588
static struct kobj_attribute transition_kobj_attr = __ATTR_RO(transition);
561589
static struct kobj_attribute signal_kobj_attr = __ATTR_WO(signal);
590+
static struct kobj_attribute force_kobj_attr = __ATTR_WO(force);
562591
static struct attribute *klp_patch_attrs[] = {
563592
&enabled_kobj_attr.attr,
564593
&transition_kobj_attr.attr,
565594
&signal_kobj_attr.attr,
595+
&force_kobj_attr.attr,
566596
NULL
567597
};
568598

kernel/livepatch/transition.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ struct klp_patch *klp_transition_patch;
3333

3434
static int klp_target_state = KLP_UNDEFINED;
3535

36+
static bool klp_forced = false;
37+
3638
/*
3739
* This work can be performed periodically to finish patching or unpatching any
3840
* "straggler" tasks which failed to transition in the first attempt.
@@ -146,9 +148,12 @@ static void klp_complete_transition(void)
146148
/*
147149
* See complementary comment in __klp_enable_patch() for why we
148150
* keep the module reference for immediate patches.
151+
*
152+
* klp_forced or immediate_func set implies unbounded increase of
153+
* module's ref count if the module is disabled/enabled in a loop.
149154
*/
150-
if (!klp_transition_patch->immediate && !immediate_func &&
151-
klp_target_state == KLP_UNPATCHED) {
155+
if (!klp_forced && !klp_transition_patch->immediate &&
156+
!immediate_func && klp_target_state == KLP_UNPATCHED) {
152157
module_put(klp_transition_patch->mod);
153158
}
154159

@@ -649,3 +654,30 @@ void klp_send_signals(void)
649654
}
650655
read_unlock(&tasklist_lock);
651656
}
657+
658+
/*
659+
* Drop TIF_PATCH_PENDING of all tasks on admin's request. This forces an
660+
* existing transition to finish.
661+
*
662+
* NOTE: klp_update_patch_state(task) requires the task to be inactive or
663+
* 'current'. This is not the case here and the consistency model could be
664+
* broken. Administrator, who is the only one to execute the
665+
* klp_force_transitions(), has to be aware of this.
666+
*/
667+
void klp_force_transition(void)
668+
{
669+
struct task_struct *g, *task;
670+
unsigned int cpu;
671+
672+
pr_warn("forcing remaining tasks to the patched state\n");
673+
674+
read_lock(&tasklist_lock);
675+
for_each_process_thread(g, task)
676+
klp_update_patch_state(task);
677+
read_unlock(&tasklist_lock);
678+
679+
for_each_possible_cpu(cpu)
680+
klp_update_patch_state(idle_task(cpu));
681+
682+
klp_forced = true;
683+
}

kernel/livepatch/transition.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ void klp_start_transition(void);
1212
void klp_try_complete_transition(void);
1313
void klp_reverse_transition(void);
1414
void klp_send_signals(void);
15+
void klp_force_transition(void);
1516

1617
#endif /* _LIVEPATCH_TRANSITION_H */

0 commit comments

Comments
 (0)