forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
3.8 KiB
102 lines
3.8 KiB
=================================== |
|
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.
|
|
|