Skip to content
/ linux Public
forked from torvalds/linux

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/livepatching/livepatching

Pull livepatching updates from Jiri Kosina:

 - support for something we call 'atomic replace', and allows for much
   better handling of cumulative patches (which is something very useful
   for distros), from Jason Baron with help of Petr Mladek and Joe
   Lawrence

 - improvement of handling of tasks blocking finalization, from Miroslav
   Benes

 - update of MAINTAINERS file to reflect move towards group
   maintainership

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching: (22 commits)
  livepatch/selftests: use "$@" to preserve argument list
  livepatch: Module coming and going callbacks can proceed with all listed patches
  livepatch: Proper error handling in the shadow variables selftest
  livepatch: return -ENOMEM on ptr_id() allocation failure
  livepatch: Introduce klp_for_each_patch macro
  livepatch: core: Return EOPNOTSUPP instead of ENOSYS
  selftests/livepatch: add DYNAMIC_DEBUG config dependency
  livepatch: samples: non static warnings fix
  livepatch: update MAINTAINERS
  livepatch: Remove signal sysfs attribute
  livepatch: Send a fake signal periodically
  selftests/livepatch: introduce tests
  livepatch: Remove ordering (stacking) of the livepatches
  livepatch: Atomic replace and cumulative patches documentation
  livepatch: Remove Nop structures when unused
  livepatch: Add atomic replace
  livepatch: Use lists to manage patches, objects and functions
  livepatch: Simplify API by removing registration step
  livepatch: Don't block the removal of patches loaded after a forced transition
  livepatch: Consolidate klp_free functions
  ...
  • Loading branch information
torvalds committed Mar 8, 2019
2 parents 851ca77 + f9d1381 commit b7af27b
Show file tree
Hide file tree
Showing 35 changed files with 2,649 additions and 1,071 deletions.
12 changes: 0 additions & 12 deletions Documentation/ABI/testing/sysfs-kernel-livepatch
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,6 @@ Description:
An attribute which indicates whether the patch is currently in
transition.

What: /sys/kernel/livepatch/<patch>/signal
Date: Nov 2017
KernelVersion: 4.15.0
Contact: [email protected]
Description:
A writable attribute that allows administrator to affect the
course of an existing transition. Writing 1 sends a fake
signal to all remaining blocking tasks. The fake signal
means that no proper signal is delivered (there is no data in
signal pending structures). Tasks are interrupted or woken up,
and forced to change their patched state.

What: /sys/kernel/livepatch/<patch>/force
Date: Nov 2017
KernelVersion: 4.15.0
Expand Down
489 changes: 5 additions & 484 deletions Documentation/livepatch/callbacks.txt

Large diffs are not rendered by default.

102 changes: 102 additions & 0 deletions Documentation/livepatch/cumulative-patches.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
===================================
Atomic Replace & Cumulative Patches
===================================

There might be dependencies between livepatches. If multiple patches need
to do different changes to the same function(s) then we need to define
an order in which the patches will be installed. And function implementations
from any newer livepatch must be done on top of the older ones.

This might become a maintenance nightmare. Especially when more patches
modified the same function in different ways.

An elegant solution comes with the feature called "Atomic Replace". It allows
creation of so called "Cumulative Patches". They include all wanted changes
from all older livepatches and completely replace them in one transition.

Usage
-----

The atomic replace can be enabled by setting "replace" flag in struct klp_patch,
for example:

static struct klp_patch patch = {
.mod = THIS_MODULE,
.objs = objs,
.replace = true,
};

All processes are then migrated to use the code only from the new patch.
Once the transition is finished, all older patches are automatically
disabled.

Ftrace handlers are transparently removed from functions that are no
longer modified by the new cumulative patch.

As a result, the livepatch authors might maintain sources only for one
cumulative patch. It helps to keep the patch consistent while adding or
removing various fixes or features.

Users could keep only the last patch installed on the system after
the transition to has finished. It helps to clearly see what code is
actually in use. Also the livepatch might then be seen as a "normal"
module that modifies the kernel behavior. The only difference is that
it can be updated at runtime without breaking its functionality.


Features
--------

The atomic replace allows:

+ Atomically revert some functions in a previous patch while
upgrading other functions.

+ Remove eventual performance impact caused by core redirection
for functions that are no longer patched.

+ Decrease user confusion about dependencies between livepatches.


Limitations:
------------

+ Once the operation finishes, there is no straightforward way
to reverse it and restore the replaced patches atomically.

A good practice is to set .replace flag in any released livepatch.
Then re-adding an older livepatch is equivalent to downgrading
to that patch. This is safe as long as the livepatches do _not_ do
extra modifications in (un)patching callbacks or in the module_init()
or module_exit() functions, see below.

Also note that the replaced patch can be removed and loaded again
only when the transition was not forced.


+ Only the (un)patching callbacks from the _new_ cumulative livepatch are
executed. Any callbacks from the replaced patches are ignored.

In other words, the cumulative patch is responsible for doing any actions
that are necessary to properly replace any older patch.

As a result, it might be dangerous to replace newer cumulative patches by
older ones. The old livepatches might not provide the necessary callbacks.

This might be seen as a limitation in some scenarios. But it makes life
easier in many others. Only the new cumulative livepatch knows what
fixes/features are added/removed and what special actions are necessary
for a smooth transition.

In any case, it would be a nightmare to think about the order of
the various callbacks and their interactions if the callbacks from all
enabled patches were called.


+ There is no special handling of shadow variables. Livepatch authors
must create their own rules how to pass them from one cumulative
patch to the other. Especially that they should not blindly remove
them in module_exit() functions.

A good practice might be to remove shadow variables in the post-unpatch
callback. It is called only when the livepatch is properly disabled.
182 changes: 87 additions & 95 deletions Documentation/livepatch/livepatch.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ Table of Contents:
4. Livepatch module
4.1. New functions
4.2. Metadata
4.3. Livepatch module handling
5. Livepatch life-cycle
5.1. Registration
5.1. Loading
5.2. Enabling
5.3. Disabling
5.4. Unregistration
5.3. Replacing
5.4. Disabling
5.5. Removing
6. Sysfs
7. Limitations

Expand Down Expand Up @@ -143,9 +143,9 @@ without HAVE_RELIABLE_STACKTRACE are not considered fully supported by
the kernel livepatching.

The /sys/kernel/livepatch/<patch>/transition file shows whether a patch
is in transition. Only a single patch (the topmost patch on the stack)
can be in transition at a given time. A patch can remain in transition
indefinitely, if any of the tasks are stuck in the initial patch state.
is in transition. Only a single patch can be in transition at a given
time. A patch can remain in transition indefinitely, if any of the tasks
are stuck in the initial patch state.

A transition can be reversed and effectively canceled by writing the
opposite value to the /sys/kernel/livepatch/<patch>/enabled file while
Expand All @@ -158,12 +158,11 @@ If a patch is in transition, this file shows 0 to indicate the task is
unpatched and 1 to indicate it's patched. Otherwise, if no patch is in
transition, it shows -1. Any tasks which are blocking the transition
can be signaled with SIGSTOP and SIGCONT to force them to change their
patched state. This may be harmful to the system though.
/sys/kernel/livepatch/<patch>/signal attribute provides a better alternative.
Writing 1 to the attribute sends a fake signal to all remaining blocking
tasks. No proper signal is actually delivered (there is no data in signal
pending structures). Tasks are interrupted or woken up, and forced to change
their patched state.
patched state. This may be harmful to the system though. Sending a fake signal
to all remaining blocking tasks is a better alternative. No proper signal is
actually delivered (there is no data in signal pending structures). Tasks are
interrupted or woken up, and forced to change their patched state. The fake
signal is automatically sent every 15 seconds.

Administrator can also affect a transition through
/sys/kernel/livepatch/<patch>/force attribute. Writing 1 there clears
Expand Down Expand Up @@ -298,117 +297,110 @@ into three levels:
see the "Consistency model" section.


4.3. Livepatch module handling
------------------------------

The usual behavior is that the new functions will get used when
the livepatch module is loaded. For this, the module init() function
has to register the patch (struct klp_patch) and enable it. See the
section "Livepatch life-cycle" below for more details about these
two operations.

Module removal is only safe when there are no users of the underlying
functions. This is the reason why the force feature permanently disables
the removal. The forced tasks entered the functions but we cannot say
that they returned back. Therefore it cannot be decided when the
livepatch module can be safely removed. When the system is successfully
transitioned to a new patch state (patched/unpatched) without being
forced it is guaranteed that no task sleeps or runs in the old code.


5. Livepatch life-cycle
=======================

Livepatching defines four basic operations that define the life cycle of each
live patch: registration, enabling, disabling and unregistration. There are
several reasons why it is done this way.
Livepatching can be described by five basic operations:
loading, enabling, replacing, disabling, removing.

First, the patch is applied only when all patched symbols for already
loaded objects are found. The error handling is much easier if this
check is done before particular functions get redirected.
Where the replacing and the disabling operations are mutually
exclusive. They have the same result for the given patch but
not for the system.

Second, it might take some time until the entire system is migrated with
the hybrid consistency model being used. The patch revert might block
the livepatch module removal for too long. Therefore it is useful to
revert the patch using a separate operation that might be called
explicitly. But it does not make sense to remove all information until
the livepatch module is really removed.

5.1. Loading
------------

5.1. Registration
-----------------
The only reasonable way is to enable the patch when the livepatch kernel
module is being loaded. For this, klp_enable_patch() has to be called
in the module_init() callback. There are two main reasons:

Each patch first has to be registered using klp_register_patch(). This makes
the patch known to the livepatch framework. Also it does some preliminary
computing and checks.
First, only the module has an easy access to the related struct klp_patch.

In particular, the patch is added into the list of known patches. The
addresses of the patched functions are found according to their names.
The special relocations, mentioned in the section "New functions", are
applied. The relevant entries are created under
/sys/kernel/livepatch/<name>. The patch is rejected when any operation
fails.
Second, the error code might be used to refuse loading the module when
the patch cannot get enabled.


5.2. Enabling
-------------

Registered patches might be enabled either by calling klp_enable_patch() or
by writing '1' to /sys/kernel/livepatch/<name>/enabled. The system will
start using the new implementation of the patched functions at this stage.
The livepatch gets enabled by calling klp_enable_patch() from
the module_init() callback. The system will start using the new
implementation of the patched functions at this stage.

When a patch is enabled, livepatch enters into a transition state where
tasks are converging to the patched state. This is indicated by a value
of '1' in /sys/kernel/livepatch/<name>/transition. Once all tasks have
been patched, the 'transition' value changes to '0'. For more
information about this process, see the "Consistency model" section.
First, the addresses of the patched functions are found according to their
names. The special relocations, mentioned in the section "New functions",
are applied. The relevant entries are created under
/sys/kernel/livepatch/<name>. The patch is rejected when any above
operation fails.

If an original function is patched for the first time, a function
specific struct klp_ops is created and an universal ftrace handler is
registered.
Second, livepatch enters into a transition state where tasks are converging
to the patched state. If an original function is patched for the first
time, a function specific struct klp_ops is created and an universal
ftrace handler is registered[*]. This stage is indicated by a value of '1'
in /sys/kernel/livepatch/<name>/transition. For more information about
this process, see the "Consistency model" section.

Functions might be patched multiple times. The ftrace handler is registered
only once for the given function. Further patches just add an entry to the
list (see field `func_stack`) of the struct klp_ops. The last added
entry is chosen by the ftrace handler and becomes the active function
replacement.
Finally, once all tasks have been patched, the 'transition' value changes
to '0'.

Note that the patches might be enabled in a different order than they were
registered.
[*] Note that functions might be patched multiple times. The ftrace handler
is registered only once for a given function. Further patches just add
an entry to the list (see field `func_stack`) of the struct klp_ops.
The right implementation is selected by the ftrace handler, see
the "Consistency model" section.

That said, it is highly recommended to use cumulative livepatches
because they help keeping the consistency of all changes. In this case,
functions might be patched two times only during the transition period.

5.3. Disabling

5.3. Replacing
--------------

Enabled patches might get disabled either by calling klp_disable_patch() or
by writing '0' to /sys/kernel/livepatch/<name>/enabled. At this stage
either the code from the previously enabled patch or even the original
code gets used.
All enabled patches might get replaced by a cumulative patch that
has the .replace flag set.

Once the new patch is enabled and the 'transition' finishes then
all the functions (struct klp_func) associated with the replaced
patches are removed from the corresponding struct klp_ops. Also
the ftrace handler is unregistered and the struct klp_ops is
freed when the related function is not modified by the new patch
and func_stack list becomes empty.

See Documentation/livepatch/cumulative-patches.txt for more details.

When a patch is disabled, livepatch enters into a transition state where
tasks are converging to the unpatched state. This is indicated by a
value of '1' in /sys/kernel/livepatch/<name>/transition. Once all tasks
have been unpatched, the 'transition' value changes to '0'. For more
information about this process, see the "Consistency model" section.

Here all the functions (struct klp_func) associated with the to-be-disabled
5.4. Disabling
--------------

Enabled patches might get disabled by writing '0' to
/sys/kernel/livepatch/<name>/enabled.

First, livepatch enters into a transition state where tasks are converging
to the unpatched state. The system starts using either the code from
the previously enabled patch or even the original one. This stage is
indicated by a value of '1' in /sys/kernel/livepatch/<name>/transition.
For more information about this process, see the "Consistency model"
section.

Second, once all tasks have been unpatched, the 'transition' value changes
to '0'. All the functions (struct klp_func) associated with the to-be-disabled
patch are removed from the corresponding struct klp_ops. The ftrace handler
is unregistered and the struct klp_ops is freed when the func_stack list
becomes empty.

Patches must be disabled in exactly the reverse order in which they were
enabled. It makes the problem and the implementation much easier.

Third, the sysfs interface is destroyed.

5.4. Unregistration
-------------------

Disabled patches might be unregistered by calling klp_unregister_patch().
This can be done only when the patch is disabled and the code is no longer
used. It must be called before the livepatch module gets unloaded.
5.5. Removing
-------------

At this stage, all the relevant sys-fs entries are removed and the patch
is removed from the list of known patches.
Module removal is only safe when there are no users of functions provided
by the module. This is the reason why the force feature permanently
disables the removal. Only when the system is successfully transitioned
to a new patch state (patched/unpatched) without being forced it is
guaranteed that no task sleeps or runs in the old code.


6. Sysfs
Expand All @@ -418,8 +410,8 @@ Information about the registered patches can be found under
/sys/kernel/livepatch. The patches could be enabled and disabled
by writing there.

/sys/kernel/livepatch/<patch>/signal and /sys/kernel/livepatch/<patch>/force
attributes allow administrator to affect a patching operation.
/sys/kernel/livepatch/<patch>/force attributes allow administrator to affect a
patching operation.

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

Expand Down
7 changes: 4 additions & 3 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -8967,10 +8967,10 @@ F: drivers/platform/x86/hp_accel.c

LIVE PATCHING
M: Josh Poimboeuf <[email protected]>
M: Jessica Yu <[email protected]>
M: Jiri Kosina <[email protected]>
M: Miroslav Benes <[email protected]>
R: Petr Mladek <[email protected]>
M: Petr Mladek <[email protected]>
R: Joe Lawrence <[email protected]>
S: Maintained
F: kernel/livepatch/
F: include/linux/livepatch.h
Expand All @@ -8979,8 +8979,9 @@ F: arch/x86/kernel/livepatch.c
F: Documentation/livepatch/
F: Documentation/ABI/testing/sysfs-kernel-livepatch
F: samples/livepatch/
F: tools/testing/selftests/livepatch/
L: [email protected]
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching.git

LLC (802.2)
L: [email protected]
Expand Down
Loading

0 comments on commit b7af27b

Please sign in to comment.