aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-kernel-livepatch12
-rw-r--r--Documentation/livepatch/livepatch.txt16
-rw-r--r--kernel/livepatch/core.c32
-rw-r--r--kernel/livepatch/transition.c82
-rw-r--r--kernel/livepatch/transition.h1
5 files changed, 48 insertions, 95 deletions
diff --git a/Documentation/ABI/testing/sysfs-kernel-livepatch b/Documentation/ABI/testing/sysfs-kernel-livepatch
index dac7e1e62a8b..85db352f68f9 100644
--- a/Documentation/ABI/testing/sysfs-kernel-livepatch
+++ b/Documentation/ABI/testing/sysfs-kernel-livepatch
@@ -33,18 +33,6 @@ Description:
33 An attribute which indicates whether the patch is currently in 33 An attribute which indicates whether the patch is currently in
34 transition. 34 transition.
35 35
36What: /sys/kernel/livepatch/<patch>/signal
37Date: Nov 2017
38KernelVersion: 4.15.0
39Contact: live-patching@vger.kernel.org
40Description:
41 A writable attribute that allows administrator to affect the
42 course of an existing transition. Writing 1 sends a fake
43 signal to all remaining blocking tasks. The fake signal
44 means that no proper signal is delivered (there is no data in
45 signal pending structures). Tasks are interrupted or woken up,
46 and forced to change their patched state.
47
48What: /sys/kernel/livepatch/<patch>/force 36What: /sys/kernel/livepatch/<patch>/force
49Date: Nov 2017 37Date: Nov 2017
50KernelVersion: 4.15.0 38KernelVersion: 4.15.0
diff --git a/Documentation/livepatch/livepatch.txt b/Documentation/livepatch/livepatch.txt
index 407e0f03dc99..4627b41ff02e 100644
--- a/Documentation/livepatch/livepatch.txt
+++ b/Documentation/livepatch/livepatch.txt
@@ -158,13 +158,11 @@ If a patch is in transition, this file shows 0 to indicate the task is
158unpatched and 1 to indicate it's patched. Otherwise, if no patch is in 158unpatched and 1 to indicate it's patched. Otherwise, if no patch is in
159transition, it shows -1. Any tasks which are blocking the transition 159transition, it shows -1. Any tasks which are blocking the transition
160can be signaled with SIGSTOP and SIGCONT to force them to change their 160can be signaled with SIGSTOP and SIGCONT to force them to change their
161patched state. This may be harmful to the system though. 161patched state. This may be harmful to the system though. Sending a fake signal
162/sys/kernel/livepatch/<patch>/signal attribute provides a better alternative. 162to all remaining blocking tasks is a better alternative. No proper signal is
163Writing 1 to the attribute sends a fake signal to all remaining blocking 163actually delivered (there is no data in signal pending structures). Tasks are
164tasks. No proper signal is actually delivered (there is no data in signal 164interrupted or woken up, and forced to change their patched state. The fake
165pending structures). Tasks are interrupted or woken up, and forced to change 165signal is automatically sent every 15 seconds.
166their patched state. Despite the sysfs attribute the fake signal is also sent
167every 15 seconds automatically.
168 166
169Administrator can also affect a transition through 167Administrator can also affect a transition through
170/sys/kernel/livepatch/<patch>/force attribute. Writing 1 there clears 168/sys/kernel/livepatch/<patch>/force attribute. Writing 1 there clears
@@ -412,8 +410,8 @@ Information about the registered patches can be found under
412/sys/kernel/livepatch. The patches could be enabled and disabled 410/sys/kernel/livepatch. The patches could be enabled and disabled
413by writing there. 411by writing there.
414 412
415/sys/kernel/livepatch/<patch>/signal and /sys/kernel/livepatch/<patch>/force 413/sys/kernel/livepatch/<patch>/force attributes allow administrator to affect a
416attributes allow administrator to affect a patching operation. 414patching operation.
417 415
418See Documentation/ABI/testing/sysfs-kernel-livepatch for more details. 416See Documentation/ABI/testing/sysfs-kernel-livepatch for more details.
419 417
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index adca5cf07f7e..fe1993399823 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -313,7 +313,6 @@ static int klp_write_object_relocations(struct module *pmod,
313 * /sys/kernel/livepatch/<patch> 313 * /sys/kernel/livepatch/<patch>
314 * /sys/kernel/livepatch/<patch>/enabled 314 * /sys/kernel/livepatch/<patch>/enabled
315 * /sys/kernel/livepatch/<patch>/transition 315 * /sys/kernel/livepatch/<patch>/transition
316 * /sys/kernel/livepatch/<patch>/signal
317 * /sys/kernel/livepatch/<patch>/force 316 * /sys/kernel/livepatch/<patch>/force
318 * /sys/kernel/livepatch/<patch>/<object> 317 * /sys/kernel/livepatch/<patch>/<object>
319 * /sys/kernel/livepatch/<patch>/<object>/<function,sympos> 318 * /sys/kernel/livepatch/<patch>/<object>/<function,sympos>
@@ -382,35 +381,6 @@ static ssize_t transition_show(struct kobject *kobj,
382 patch == klp_transition_patch); 381 patch == klp_transition_patch);
383} 382}
384 383
385static ssize_t signal_store(struct kobject *kobj, struct kobj_attribute *attr,
386 const char *buf, size_t count)
387{
388 struct klp_patch *patch;
389 int ret;
390 bool val;
391
392 ret = kstrtobool(buf, &val);
393 if (ret)
394 return ret;
395
396 if (!val)
397 return count;
398
399 mutex_lock(&klp_mutex);
400
401 patch = container_of(kobj, struct klp_patch, kobj);
402 if (patch != klp_transition_patch) {
403 mutex_unlock(&klp_mutex);
404 return -EINVAL;
405 }
406
407 klp_send_signals();
408
409 mutex_unlock(&klp_mutex);
410
411 return count;
412}
413
414static ssize_t force_store(struct kobject *kobj, struct kobj_attribute *attr, 384static ssize_t force_store(struct kobject *kobj, struct kobj_attribute *attr,
415 const char *buf, size_t count) 385 const char *buf, size_t count)
416{ 386{
@@ -442,12 +412,10 @@ static ssize_t force_store(struct kobject *kobj, struct kobj_attribute *attr,
442 412
443static struct kobj_attribute enabled_kobj_attr = __ATTR_RW(enabled); 413static struct kobj_attribute enabled_kobj_attr = __ATTR_RW(enabled);
444static struct kobj_attribute transition_kobj_attr = __ATTR_RO(transition); 414static struct kobj_attribute transition_kobj_attr = __ATTR_RO(transition);
445static struct kobj_attribute signal_kobj_attr = __ATTR_WO(signal);
446static struct kobj_attribute force_kobj_attr = __ATTR_WO(force); 415static struct kobj_attribute force_kobj_attr = __ATTR_WO(force);
447static struct attribute *klp_patch_attrs[] = { 416static struct attribute *klp_patch_attrs[] = {
448 &enabled_kobj_attr.attr, 417 &enabled_kobj_attr.attr,
449 &transition_kobj_attr.attr, 418 &transition_kobj_attr.attr,
450 &signal_kobj_attr.attr,
451 &force_kobj_attr.attr, 419 &force_kobj_attr.attr,
452 NULL 420 NULL
453}; 421};
diff --git a/kernel/livepatch/transition.c b/kernel/livepatch/transition.c
index ea7697bb753e..183b2086ba03 100644
--- a/kernel/livepatch/transition.c
+++ b/kernel/livepatch/transition.c
@@ -348,6 +348,47 @@ done:
348} 348}
349 349
350/* 350/*
351 * Sends a fake signal to all non-kthread tasks with TIF_PATCH_PENDING set.
352 * Kthreads with TIF_PATCH_PENDING set are woken up.
353 */
354static void klp_send_signals(void)
355{
356 struct task_struct *g, *task;
357
358 if (klp_signals_cnt == SIGNALS_TIMEOUT)
359 pr_notice("signaling remaining tasks\n");
360
361 read_lock(&tasklist_lock);
362 for_each_process_thread(g, task) {
363 if (!klp_patch_pending(task))
364 continue;
365
366 /*
367 * There is a small race here. We could see TIF_PATCH_PENDING
368 * set and decide to wake up a kthread or send a fake signal.
369 * Meanwhile the task could migrate itself and the action
370 * would be meaningless. It is not serious though.
371 */
372 if (task->flags & PF_KTHREAD) {
373 /*
374 * Wake up a kthread which sleeps interruptedly and
375 * still has not been migrated.
376 */
377 wake_up_state(task, TASK_INTERRUPTIBLE);
378 } else {
379 /*
380 * Send fake signal to all non-kthread tasks which are
381 * still not migrated.
382 */
383 spin_lock_irq(&task->sighand->siglock);
384 signal_wake_up(task, 0);
385 spin_unlock_irq(&task->sighand->siglock);
386 }
387 }
388 read_unlock(&tasklist_lock);
389}
390
391/*
351 * Try to switch all remaining tasks to the target patch state by walking the 392 * Try to switch all remaining tasks to the target patch state by walking the
352 * stacks of sleeping tasks and looking for any to-be-patched or 393 * stacks of sleeping tasks and looking for any to-be-patched or
353 * to-be-unpatched functions. If such functions are found, the task can't be 394 * to-be-unpatched functions. If such functions are found, the task can't be
@@ -587,47 +628,6 @@ void klp_copy_process(struct task_struct *child)
587} 628}
588 629
589/* 630/*
590 * Sends a fake signal to all non-kthread tasks with TIF_PATCH_PENDING set.
591 * Kthreads with TIF_PATCH_PENDING set are woken up.
592 */
593void klp_send_signals(void)
594{
595 struct task_struct *g, *task;
596
597 if (klp_signals_cnt == SIGNALS_TIMEOUT)
598 pr_notice("signaling remaining tasks\n");
599
600 read_lock(&tasklist_lock);
601 for_each_process_thread(g, task) {
602 if (!klp_patch_pending(task))
603 continue;
604
605 /*
606 * There is a small race here. We could see TIF_PATCH_PENDING
607 * set and decide to wake up a kthread or send a fake signal.
608 * Meanwhile the task could migrate itself and the action
609 * would be meaningless. It is not serious though.
610 */
611 if (task->flags & PF_KTHREAD) {
612 /*
613 * Wake up a kthread which sleeps interruptedly and
614 * still has not been migrated.
615 */
616 wake_up_state(task, TASK_INTERRUPTIBLE);
617 } else {
618 /*
619 * Send fake signal to all non-kthread tasks which are
620 * still not migrated.
621 */
622 spin_lock_irq(&task->sighand->siglock);
623 signal_wake_up(task, 0);
624 spin_unlock_irq(&task->sighand->siglock);
625 }
626 }
627 read_unlock(&tasklist_lock);
628}
629
630/*
631 * Drop TIF_PATCH_PENDING of all tasks on admin's request. This forces an 631 * Drop TIF_PATCH_PENDING of all tasks on admin's request. This forces an
632 * existing transition to finish. 632 * existing transition to finish.
633 * 633 *
diff --git a/kernel/livepatch/transition.h b/kernel/livepatch/transition.h
index f9d0bc016067..322db16233de 100644
--- a/kernel/livepatch/transition.h
+++ b/kernel/livepatch/transition.h
@@ -11,7 +11,6 @@ void klp_cancel_transition(void);
11void klp_start_transition(void); 11void klp_start_transition(void);
12void klp_try_complete_transition(void); 12void klp_try_complete_transition(void);
13void klp_reverse_transition(void); 13void klp_reverse_transition(void);
14void klp_send_signals(void);
15void klp_force_transition(void); 14void klp_force_transition(void);
16 15
17#endif /* _LIVEPATCH_TRANSITION_H */ 16#endif /* _LIVEPATCH_TRANSITION_H */