|
| 1 | +=================================== |
| 2 | +Atomic Replace & Cumulative Patches |
| 3 | +=================================== |
| 4 | + |
| 5 | +There might be dependencies between livepatches. If multiple patches need |
| 6 | +to do different changes to the same function(s) then we need to define |
| 7 | +an order in which the patches will be installed. And function implementations |
| 8 | +from any newer livepatch must be done on top of the older ones. |
| 9 | + |
| 10 | +This might become a maintenance nightmare. Especially if anyone would want |
| 11 | +to remove a patch that is in the middle of the stack. |
| 12 | + |
| 13 | +An elegant solution comes with the feature called "Atomic Replace". It allows |
| 14 | +creation of so called "Cumulative Patches". They include all wanted changes |
| 15 | +from all older livepatches and completely replace them in one transition. |
| 16 | + |
| 17 | +Usage |
| 18 | +----- |
| 19 | + |
| 20 | +The atomic replace can be enabled by setting "replace" flag in struct klp_patch, |
| 21 | +for example: |
| 22 | + |
| 23 | + static struct klp_patch patch = { |
| 24 | + .mod = THIS_MODULE, |
| 25 | + .objs = objs, |
| 26 | + .replace = true, |
| 27 | + }; |
| 28 | + |
| 29 | +Such a patch is added on top of the livepatch stack when enabled. |
| 30 | + |
| 31 | +All processes are then migrated to use the code only from the new patch. |
| 32 | +Once the transition is finished, all older patches are automatically |
| 33 | +disabled and removed from the stack of patches. |
| 34 | + |
| 35 | +Ftrace handlers are transparently removed from functions that are no |
| 36 | +longer modified by the new cumulative patch. |
| 37 | + |
| 38 | +As a result, the livepatch authors might maintain sources only for one |
| 39 | +cumulative patch. It helps to keep the patch consistent while adding or |
| 40 | +removing various fixes or features. |
| 41 | + |
| 42 | +Users could keep only the last patch installed on the system after |
| 43 | +the transition to has finished. It helps to clearly see what code is |
| 44 | +actually in use. Also the livepatch might then be seen as a "normal" |
| 45 | +module that modifies the kernel behavior. The only difference is that |
| 46 | +it can be updated at runtime without breaking its functionality. |
| 47 | + |
| 48 | + |
| 49 | +Features |
| 50 | +-------- |
| 51 | + |
| 52 | +The atomic replace allows: |
| 53 | + |
| 54 | + + Atomically revert some functions in a previous patch while |
| 55 | + upgrading other functions. |
| 56 | + |
| 57 | + + Remove eventual performance impact caused by core redirection |
| 58 | + for functions that are no longer patched. |
| 59 | + |
| 60 | + + Decrease user confusion about stacking order and what code |
| 61 | + is actually in use. |
| 62 | + |
| 63 | + |
| 64 | +Limitations: |
| 65 | +------------ |
| 66 | + |
| 67 | + + Once the operation finishes, there is no straightforward way |
| 68 | + to reverse it and restore the replaced patches atomically. |
| 69 | + |
| 70 | + A good practice is to set .replace flag in any released livepatch. |
| 71 | + Then re-adding an older livepatch is equivalent to downgrading |
| 72 | + to that patch. This is safe as long as the livepatches do _not_ do |
| 73 | + extra modifications in (un)patching callbacks or in the module_init() |
| 74 | + or module_exit() functions, see below. |
| 75 | + |
| 76 | + Also note that the replaced patch can be removed and loaded again |
| 77 | + only when the transition was not forced. |
| 78 | + |
| 79 | + |
| 80 | + + Only the (un)patching callbacks from the _new_ cumulative livepatch are |
| 81 | + executed. Any callbacks from the replaced patches are ignored. |
| 82 | + |
| 83 | + In other words, the cumulative patch is responsible for doing any actions |
| 84 | + that are necessary to properly replace any older patch. |
| 85 | + |
| 86 | + As a result, it might be dangerous to replace newer cumulative patches by |
| 87 | + older ones. The old livepatches might not provide the necessary callbacks. |
| 88 | + |
| 89 | + This might be seen as a limitation in some scenarios. But it makes life |
| 90 | + easier in many others. Only the new cumulative livepatch knows what |
| 91 | + fixes/features are added/removed and what special actions are necessary |
| 92 | + for a smooth transition. |
| 93 | + |
| 94 | + In any case, it would be a nightmare to think about the order of |
| 95 | + the various callbacks and their interactions if the callbacks from all |
| 96 | + enabled patches were called. |
| 97 | + |
| 98 | + |
| 99 | + + There is no special handling of shadow variables. Livepatch authors |
| 100 | + must create their own rules how to pass them from one cumulative |
| 101 | + patch to the other. Especially that they should not blindly remove |
| 102 | + them in module_exit() functions. |
| 103 | + |
| 104 | + A good practice might be to remove shadow variables in the post-unpatch |
| 105 | + callback. It is called only when the livepatch is properly disabled. |
0 commit comments