Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * system_state.c - State of the system modified by livepatches
0004  *
0005  * Copyright (C) 2019 SUSE
0006  */
0007 
0008 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0009 
0010 #include <linux/livepatch.h>
0011 #include "core.h"
0012 #include "state.h"
0013 #include "transition.h"
0014 
0015 #define klp_for_each_state(patch, state)        \
0016     for (state = patch->states; state && state->id; state++)
0017 
0018 /**
0019  * klp_get_state() - get information about system state modified by
0020  *  the given patch
0021  * @patch:  livepatch that modifies the given system state
0022  * @id:     custom identifier of the modified system state
0023  *
0024  * Checks whether the given patch modifies the given system state.
0025  *
0026  * The function can be called either from pre/post (un)patch
0027  * callbacks or from the kernel code added by the livepatch.
0028  *
0029  * Return: pointer to struct klp_state when found, otherwise NULL.
0030  */
0031 struct klp_state *klp_get_state(struct klp_patch *patch, unsigned long id)
0032 {
0033     struct klp_state *state;
0034 
0035     klp_for_each_state(patch, state) {
0036         if (state->id == id)
0037             return state;
0038     }
0039 
0040     return NULL;
0041 }
0042 EXPORT_SYMBOL_GPL(klp_get_state);
0043 
0044 /**
0045  * klp_get_prev_state() - get information about system state modified by
0046  *  the already installed livepatches
0047  * @id:     custom identifier of the modified system state
0048  *
0049  * Checks whether already installed livepatches modify the given
0050  * system state.
0051  *
0052  * The same system state can be modified by more non-cumulative
0053  * livepatches. It is expected that the latest livepatch has
0054  * the most up-to-date information.
0055  *
0056  * The function can be called only during transition when a new
0057  * livepatch is being enabled or when such a transition is reverted.
0058  * It is typically called only from pre/post (un)patch
0059  * callbacks.
0060  *
0061  * Return: pointer to the latest struct klp_state from already
0062  *  installed livepatches, NULL when not found.
0063  */
0064 struct klp_state *klp_get_prev_state(unsigned long id)
0065 {
0066     struct klp_patch *patch;
0067     struct klp_state *state, *last_state = NULL;
0068 
0069     if (WARN_ON_ONCE(!klp_transition_patch))
0070         return NULL;
0071 
0072     klp_for_each_patch(patch) {
0073         if (patch == klp_transition_patch)
0074             goto out;
0075 
0076         state = klp_get_state(patch, id);
0077         if (state)
0078             last_state = state;
0079     }
0080 
0081 out:
0082     return last_state;
0083 }
0084 EXPORT_SYMBOL_GPL(klp_get_prev_state);
0085 
0086 /* Check if the patch is able to deal with the existing system state. */
0087 static bool klp_is_state_compatible(struct klp_patch *patch,
0088                     struct klp_state *old_state)
0089 {
0090     struct klp_state *state;
0091 
0092     state = klp_get_state(patch, old_state->id);
0093 
0094     /* A cumulative livepatch must handle all already modified states. */
0095     if (!state)
0096         return !patch->replace;
0097 
0098     return state->version >= old_state->version;
0099 }
0100 
0101 /*
0102  * Check that the new livepatch will not break the existing system states.
0103  * Cumulative patches must handle all already modified states.
0104  * Non-cumulative patches can touch already modified states.
0105  */
0106 bool klp_is_patch_compatible(struct klp_patch *patch)
0107 {
0108     struct klp_patch *old_patch;
0109     struct klp_state *old_state;
0110 
0111     klp_for_each_patch(old_patch) {
0112         klp_for_each_state(old_patch, old_state) {
0113             if (!klp_is_state_compatible(patch, old_state))
0114                 return false;
0115         }
0116     }
0117 
0118     return true;
0119 }