Commit | Line | Data |
---|---|---|
73727f4d PM |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * system_state.c - State of the system modified by livepatches | |
4 | * | |
5 | * Copyright (C) 2019 SUSE | |
6 | */ | |
7 | ||
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
9 | ||
10 | #include <linux/livepatch.h> | |
11 | #include "core.h" | |
92c9abf5 | 12 | #include "state.h" |
73727f4d PM |
13 | #include "transition.h" |
14 | ||
15 | #define klp_for_each_state(patch, state) \ | |
16 | for (state = patch->states; state && state->id; state++) | |
17 | ||
18 | /** | |
19 | * klp_get_state() - get information about system state modified by | |
20 | * the given patch | |
21 | * @patch: livepatch that modifies the given system state | |
22 | * @id: custom identifier of the modified system state | |
23 | * | |
24 | * Checks whether the given patch modifies the given system state. | |
25 | * | |
26 | * The function can be called either from pre/post (un)patch | |
27 | * callbacks or from the kernel code added by the livepatch. | |
28 | * | |
29 | * Return: pointer to struct klp_state when found, otherwise NULL. | |
30 | */ | |
31 | struct klp_state *klp_get_state(struct klp_patch *patch, unsigned long id) | |
32 | { | |
33 | struct klp_state *state; | |
34 | ||
35 | klp_for_each_state(patch, state) { | |
36 | if (state->id == id) | |
37 | return state; | |
38 | } | |
39 | ||
40 | return NULL; | |
41 | } | |
42 | EXPORT_SYMBOL_GPL(klp_get_state); | |
43 | ||
44 | /** | |
45 | * klp_get_prev_state() - get information about system state modified by | |
46 | * the already installed livepatches | |
47 | * @id: custom identifier of the modified system state | |
48 | * | |
49 | * Checks whether already installed livepatches modify the given | |
50 | * system state. | |
51 | * | |
52 | * The same system state can be modified by more non-cumulative | |
53 | * livepatches. It is expected that the latest livepatch has | |
54 | * the most up-to-date information. | |
55 | * | |
56 | * The function can be called only during transition when a new | |
57 | * livepatch is being enabled or when such a transition is reverted. | |
7b7b8a2c | 58 | * It is typically called only from pre/post (un)patch |
73727f4d PM |
59 | * callbacks. |
60 | * | |
61 | * Return: pointer to the latest struct klp_state from already | |
62 | * installed livepatches, NULL when not found. | |
63 | */ | |
64 | struct klp_state *klp_get_prev_state(unsigned long id) | |
65 | { | |
66 | struct klp_patch *patch; | |
67 | struct klp_state *state, *last_state = NULL; | |
68 | ||
69 | if (WARN_ON_ONCE(!klp_transition_patch)) | |
70 | return NULL; | |
71 | ||
72 | klp_for_each_patch(patch) { | |
73 | if (patch == klp_transition_patch) | |
74 | goto out; | |
75 | ||
76 | state = klp_get_state(patch, id); | |
77 | if (state) | |
78 | last_state = state; | |
79 | } | |
80 | ||
81 | out: | |
82 | return last_state; | |
83 | } | |
84 | EXPORT_SYMBOL_GPL(klp_get_prev_state); | |
92c9abf5 PM |
85 | |
86 | /* Check if the patch is able to deal with the existing system state. */ | |
87 | static bool klp_is_state_compatible(struct klp_patch *patch, | |
88 | struct klp_state *old_state) | |
89 | { | |
90 | struct klp_state *state; | |
91 | ||
92 | state = klp_get_state(patch, old_state->id); | |
93 | ||
94 | /* A cumulative livepatch must handle all already modified states. */ | |
95 | if (!state) | |
96 | return !patch->replace; | |
97 | ||
98 | return state->version >= old_state->version; | |
99 | } | |
100 | ||
101 | /* | |
102 | * Check that the new livepatch will not break the existing system states. | |
103 | * Cumulative patches must handle all already modified states. | |
104 | * Non-cumulative patches can touch already modified states. | |
105 | */ | |
106 | bool klp_is_patch_compatible(struct klp_patch *patch) | |
107 | { | |
108 | struct klp_patch *old_patch; | |
109 | struct klp_state *old_state; | |
110 | ||
111 | klp_for_each_patch(old_patch) { | |
112 | klp_for_each_state(old_patch, old_state) { | |
113 | if (!klp_is_state_compatible(patch, old_state)) | |
114 | return false; | |
115 | } | |
116 | } | |
117 | ||
118 | return true; | |
119 | } |