103 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| ===================================
 | |
| 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.
 |