11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2439e7271SJoe Lawrence /*
3439e7271SJoe Lawrence * shadow.c - Shadow Variables
4439e7271SJoe Lawrence *
5439e7271SJoe Lawrence * Copyright (C) 2014 Josh Poimboeuf <jpoimboe@redhat.com>
6439e7271SJoe Lawrence * Copyright (C) 2014 Seth Jennings <sjenning@redhat.com>
7439e7271SJoe Lawrence * Copyright (C) 2017 Joe Lawrence <joe.lawrence@redhat.com>
8439e7271SJoe Lawrence */
9439e7271SJoe Lawrence
10439e7271SJoe Lawrence /**
11439e7271SJoe Lawrence * DOC: Shadow variable API concurrency notes:
12439e7271SJoe Lawrence *
13439e7271SJoe Lawrence * The shadow variable API provides a simple relationship between an
14439e7271SJoe Lawrence * <obj, id> pair and a pointer value. It is the responsibility of the
15439e7271SJoe Lawrence * caller to provide any mutual exclusion required of the shadow data.
16439e7271SJoe Lawrence *
17439e7271SJoe Lawrence * Once a shadow variable is attached to its parent object via the
18439e7271SJoe Lawrence * klp_shadow_*alloc() API calls, it is considered live: any subsequent
19439e7271SJoe Lawrence * call to klp_shadow_get() may then return the shadow variable's data
20439e7271SJoe Lawrence * pointer. Callers of klp_shadow_*alloc() should prepare shadow data
21439e7271SJoe Lawrence * accordingly.
22439e7271SJoe Lawrence *
23439e7271SJoe Lawrence * The klp_shadow_*alloc() API calls may allocate memory for new shadow
24439e7271SJoe Lawrence * variable structures. Their implementation does not call kmalloc
25439e7271SJoe Lawrence * inside any spinlocks, but API callers should pass GFP flags according
26439e7271SJoe Lawrence * to their specific needs.
27439e7271SJoe Lawrence *
28439e7271SJoe Lawrence * The klp_shadow_hash is an RCU-enabled hashtable and is safe against
29439e7271SJoe Lawrence * concurrent klp_shadow_free() and klp_shadow_get() operations.
30439e7271SJoe Lawrence */
31439e7271SJoe Lawrence
32439e7271SJoe Lawrence #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
33439e7271SJoe Lawrence
34439e7271SJoe Lawrence #include <linux/hashtable.h>
35439e7271SJoe Lawrence #include <linux/slab.h>
36439e7271SJoe Lawrence #include <linux/livepatch.h>
37439e7271SJoe Lawrence
38439e7271SJoe Lawrence static DEFINE_HASHTABLE(klp_shadow_hash, 12);
39439e7271SJoe Lawrence
40439e7271SJoe Lawrence /*
41439e7271SJoe Lawrence * klp_shadow_lock provides exclusive access to the klp_shadow_hash and
42439e7271SJoe Lawrence * the shadow variables it references.
43439e7271SJoe Lawrence */
44439e7271SJoe Lawrence static DEFINE_SPINLOCK(klp_shadow_lock);
45439e7271SJoe Lawrence
46439e7271SJoe Lawrence /**
47439e7271SJoe Lawrence * struct klp_shadow - shadow variable structure
48439e7271SJoe Lawrence * @node: klp_shadow_hash hash table node
49439e7271SJoe Lawrence * @rcu_head: RCU is used to safely free this structure
50439e7271SJoe Lawrence * @obj: pointer to parent object
51439e7271SJoe Lawrence * @id: data identifier
52439e7271SJoe Lawrence * @data: data area
53439e7271SJoe Lawrence */
54439e7271SJoe Lawrence struct klp_shadow {
55439e7271SJoe Lawrence struct hlist_node node;
56439e7271SJoe Lawrence struct rcu_head rcu_head;
57439e7271SJoe Lawrence void *obj;
58439e7271SJoe Lawrence unsigned long id;
59439e7271SJoe Lawrence char data[];
60439e7271SJoe Lawrence };
61439e7271SJoe Lawrence
62439e7271SJoe Lawrence /**
63439e7271SJoe Lawrence * klp_shadow_match() - verify a shadow variable matches given <obj, id>
64439e7271SJoe Lawrence * @shadow: shadow variable to match
65439e7271SJoe Lawrence * @obj: pointer to parent object
66439e7271SJoe Lawrence * @id: data identifier
67439e7271SJoe Lawrence *
68439e7271SJoe Lawrence * Return: true if the shadow variable matches.
69439e7271SJoe Lawrence */
klp_shadow_match(struct klp_shadow * shadow,void * obj,unsigned long id)70439e7271SJoe Lawrence static inline bool klp_shadow_match(struct klp_shadow *shadow, void *obj,
71439e7271SJoe Lawrence unsigned long id)
72439e7271SJoe Lawrence {
73439e7271SJoe Lawrence return shadow->obj == obj && shadow->id == id;
74439e7271SJoe Lawrence }
75439e7271SJoe Lawrence
76439e7271SJoe Lawrence /**
77439e7271SJoe Lawrence * klp_shadow_get() - retrieve a shadow variable data pointer
78439e7271SJoe Lawrence * @obj: pointer to parent object
79439e7271SJoe Lawrence * @id: data identifier
80439e7271SJoe Lawrence *
81439e7271SJoe Lawrence * Return: the shadow variable data element, NULL on failure.
82439e7271SJoe Lawrence */
klp_shadow_get(void * obj,unsigned long id)83439e7271SJoe Lawrence void *klp_shadow_get(void *obj, unsigned long id)
84439e7271SJoe Lawrence {
85439e7271SJoe Lawrence struct klp_shadow *shadow;
86439e7271SJoe Lawrence
87439e7271SJoe Lawrence rcu_read_lock();
88439e7271SJoe Lawrence
89439e7271SJoe Lawrence hash_for_each_possible_rcu(klp_shadow_hash, shadow, node,
90439e7271SJoe Lawrence (unsigned long)obj) {
91439e7271SJoe Lawrence
92439e7271SJoe Lawrence if (klp_shadow_match(shadow, obj, id)) {
93439e7271SJoe Lawrence rcu_read_unlock();
94439e7271SJoe Lawrence return shadow->data;
95439e7271SJoe Lawrence }
96439e7271SJoe Lawrence }
97439e7271SJoe Lawrence
98439e7271SJoe Lawrence rcu_read_unlock();
99439e7271SJoe Lawrence
100439e7271SJoe Lawrence return NULL;
101439e7271SJoe Lawrence }
102439e7271SJoe Lawrence EXPORT_SYMBOL_GPL(klp_shadow_get);
103439e7271SJoe Lawrence
__klp_shadow_get_or_alloc(void * obj,unsigned long id,size_t size,gfp_t gfp_flags,klp_shadow_ctor_t ctor,void * ctor_data,bool warn_on_exist)104e91c2518SPetr Mladek static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id,
105e91c2518SPetr Mladek size_t size, gfp_t gfp_flags,
106e91c2518SPetr Mladek klp_shadow_ctor_t ctor, void *ctor_data,
107e91c2518SPetr Mladek bool warn_on_exist)
108439e7271SJoe Lawrence {
109439e7271SJoe Lawrence struct klp_shadow *new_shadow;
110439e7271SJoe Lawrence void *shadow_data;
111439e7271SJoe Lawrence unsigned long flags;
112439e7271SJoe Lawrence
113439e7271SJoe Lawrence /* Check if the shadow variable already exists */
114439e7271SJoe Lawrence shadow_data = klp_shadow_get(obj, id);
115439e7271SJoe Lawrence if (shadow_data)
116439e7271SJoe Lawrence goto exists;
117439e7271SJoe Lawrence
118e91c2518SPetr Mladek /*
119e91c2518SPetr Mladek * Allocate a new shadow variable. Fill it with zeroes by default.
120e91c2518SPetr Mladek * More complex setting can be done by @ctor function. But it is
121e91c2518SPetr Mladek * called only when the buffer is really used (under klp_shadow_lock).
122e91c2518SPetr Mladek */
123439e7271SJoe Lawrence new_shadow = kzalloc(size + sizeof(*new_shadow), gfp_flags);
124439e7271SJoe Lawrence if (!new_shadow)
125439e7271SJoe Lawrence return NULL;
126439e7271SJoe Lawrence
127439e7271SJoe Lawrence /* Look for <obj, id> again under the lock */
128439e7271SJoe Lawrence spin_lock_irqsave(&klp_shadow_lock, flags);
129439e7271SJoe Lawrence shadow_data = klp_shadow_get(obj, id);
130439e7271SJoe Lawrence if (unlikely(shadow_data)) {
131439e7271SJoe Lawrence /*
132439e7271SJoe Lawrence * Shadow variable was found, throw away speculative
133439e7271SJoe Lawrence * allocation.
134439e7271SJoe Lawrence */
135439e7271SJoe Lawrence spin_unlock_irqrestore(&klp_shadow_lock, flags);
136439e7271SJoe Lawrence kfree(new_shadow);
137439e7271SJoe Lawrence goto exists;
138439e7271SJoe Lawrence }
139439e7271SJoe Lawrence
140e91c2518SPetr Mladek new_shadow->obj = obj;
141e91c2518SPetr Mladek new_shadow->id = id;
142e91c2518SPetr Mladek
143e91c2518SPetr Mladek if (ctor) {
144e91c2518SPetr Mladek int err;
145e91c2518SPetr Mladek
146e91c2518SPetr Mladek err = ctor(obj, new_shadow->data, ctor_data);
147e91c2518SPetr Mladek if (err) {
148e91c2518SPetr Mladek spin_unlock_irqrestore(&klp_shadow_lock, flags);
149e91c2518SPetr Mladek kfree(new_shadow);
150e91c2518SPetr Mladek pr_err("Failed to construct shadow variable <%p, %lx> (%d)\n",
151e91c2518SPetr Mladek obj, id, err);
152e91c2518SPetr Mladek return NULL;
153e91c2518SPetr Mladek }
154e91c2518SPetr Mladek }
155e91c2518SPetr Mladek
156439e7271SJoe Lawrence /* No <obj, id> found, so attach the newly allocated one */
157439e7271SJoe Lawrence hash_add_rcu(klp_shadow_hash, &new_shadow->node,
158439e7271SJoe Lawrence (unsigned long)new_shadow->obj);
159439e7271SJoe Lawrence spin_unlock_irqrestore(&klp_shadow_lock, flags);
160439e7271SJoe Lawrence
161439e7271SJoe Lawrence return new_shadow->data;
162439e7271SJoe Lawrence
163439e7271SJoe Lawrence exists:
164439e7271SJoe Lawrence if (warn_on_exist) {
165439e7271SJoe Lawrence WARN(1, "Duplicate shadow variable <%p, %lx>\n", obj, id);
166439e7271SJoe Lawrence return NULL;
167439e7271SJoe Lawrence }
168439e7271SJoe Lawrence
169439e7271SJoe Lawrence return shadow_data;
170439e7271SJoe Lawrence }
171439e7271SJoe Lawrence
172439e7271SJoe Lawrence /**
173439e7271SJoe Lawrence * klp_shadow_alloc() - allocate and add a new shadow variable
174439e7271SJoe Lawrence * @obj: pointer to parent object
175439e7271SJoe Lawrence * @id: data identifier
176439e7271SJoe Lawrence * @size: size of attached data
177439e7271SJoe Lawrence * @gfp_flags: GFP mask for allocation
178e91c2518SPetr Mladek * @ctor: custom constructor to initialize the shadow data (optional)
179e91c2518SPetr Mladek * @ctor_data: pointer to any data needed by @ctor (optional)
180439e7271SJoe Lawrence *
181e91c2518SPetr Mladek * Allocates @size bytes for new shadow variable data using @gfp_flags.
182e91c2518SPetr Mladek * The data are zeroed by default. They are further initialized by @ctor
183e91c2518SPetr Mladek * function if it is not NULL. The new shadow variable is then added
184e91c2518SPetr Mladek * to the global hashtable.
185439e7271SJoe Lawrence *
186e91c2518SPetr Mladek * If an existing <obj, id> shadow variable can be found, this routine will
187e91c2518SPetr Mladek * issue a WARN, exit early and return NULL.
188e91c2518SPetr Mladek *
189e91c2518SPetr Mladek * This function guarantees that the constructor function is called only when
190e91c2518SPetr Mladek * the variable did not exist before. The cost is that @ctor is called
191e91c2518SPetr Mladek * in atomic context under a spin lock.
192439e7271SJoe Lawrence *
193439e7271SJoe Lawrence * Return: the shadow variable data element, NULL on duplicate or
194439e7271SJoe Lawrence * failure.
195439e7271SJoe Lawrence */
klp_shadow_alloc(void * obj,unsigned long id,size_t size,gfp_t gfp_flags,klp_shadow_ctor_t ctor,void * ctor_data)196e91c2518SPetr Mladek void *klp_shadow_alloc(void *obj, unsigned long id,
197e91c2518SPetr Mladek size_t size, gfp_t gfp_flags,
198e91c2518SPetr Mladek klp_shadow_ctor_t ctor, void *ctor_data)
199439e7271SJoe Lawrence {
200e91c2518SPetr Mladek return __klp_shadow_get_or_alloc(obj, id, size, gfp_flags,
201e91c2518SPetr Mladek ctor, ctor_data, true);
202439e7271SJoe Lawrence }
203439e7271SJoe Lawrence EXPORT_SYMBOL_GPL(klp_shadow_alloc);
204439e7271SJoe Lawrence
205439e7271SJoe Lawrence /**
206439e7271SJoe Lawrence * klp_shadow_get_or_alloc() - get existing or allocate a new shadow variable
207439e7271SJoe Lawrence * @obj: pointer to parent object
208439e7271SJoe Lawrence * @id: data identifier
209439e7271SJoe Lawrence * @size: size of attached data
210439e7271SJoe Lawrence * @gfp_flags: GFP mask for allocation
211e91c2518SPetr Mladek * @ctor: custom constructor to initialize the shadow data (optional)
212e91c2518SPetr Mladek * @ctor_data: pointer to any data needed by @ctor (optional)
213439e7271SJoe Lawrence *
214439e7271SJoe Lawrence * Returns a pointer to existing shadow data if an <obj, id> shadow
215439e7271SJoe Lawrence * variable is already present. Otherwise, it creates a new shadow
216439e7271SJoe Lawrence * variable like klp_shadow_alloc().
217439e7271SJoe Lawrence *
218e91c2518SPetr Mladek * This function guarantees that only one shadow variable exists with the given
219e91c2518SPetr Mladek * @id for the given @obj. It also guarantees that the constructor function
220e91c2518SPetr Mladek * will be called only when the variable did not exist before. The cost is
221e91c2518SPetr Mladek * that @ctor is called in atomic context under a spin lock.
222439e7271SJoe Lawrence *
223439e7271SJoe Lawrence * Return: the shadow variable data element, NULL on failure.
224439e7271SJoe Lawrence */
klp_shadow_get_or_alloc(void * obj,unsigned long id,size_t size,gfp_t gfp_flags,klp_shadow_ctor_t ctor,void * ctor_data)225e91c2518SPetr Mladek void *klp_shadow_get_or_alloc(void *obj, unsigned long id,
226e91c2518SPetr Mladek size_t size, gfp_t gfp_flags,
227e91c2518SPetr Mladek klp_shadow_ctor_t ctor, void *ctor_data)
228439e7271SJoe Lawrence {
229e91c2518SPetr Mladek return __klp_shadow_get_or_alloc(obj, id, size, gfp_flags,
230e91c2518SPetr Mladek ctor, ctor_data, false);
231439e7271SJoe Lawrence }
232439e7271SJoe Lawrence EXPORT_SYMBOL_GPL(klp_shadow_get_or_alloc);
233439e7271SJoe Lawrence
klp_shadow_free_struct(struct klp_shadow * shadow,klp_shadow_dtor_t dtor)2343b2c77d0SPetr Mladek static void klp_shadow_free_struct(struct klp_shadow *shadow,
2353b2c77d0SPetr Mladek klp_shadow_dtor_t dtor)
2363b2c77d0SPetr Mladek {
2373b2c77d0SPetr Mladek hash_del_rcu(&shadow->node);
2383b2c77d0SPetr Mladek if (dtor)
2393b2c77d0SPetr Mladek dtor(shadow->obj, shadow->data);
2403b2c77d0SPetr Mladek kfree_rcu(shadow, rcu_head);
2413b2c77d0SPetr Mladek }
2423b2c77d0SPetr Mladek
243439e7271SJoe Lawrence /**
244439e7271SJoe Lawrence * klp_shadow_free() - detach and free a <obj, id> shadow variable
245439e7271SJoe Lawrence * @obj: pointer to parent object
246439e7271SJoe Lawrence * @id: data identifier
2473b2c77d0SPetr Mladek * @dtor: custom callback that can be used to unregister the variable
2483b2c77d0SPetr Mladek * and/or free data that the shadow variable points to (optional)
249439e7271SJoe Lawrence *
250439e7271SJoe Lawrence * This function releases the memory for this <obj, id> shadow variable
251439e7271SJoe Lawrence * instance, callers should stop referencing it accordingly.
252439e7271SJoe Lawrence */
klp_shadow_free(void * obj,unsigned long id,klp_shadow_dtor_t dtor)2533b2c77d0SPetr Mladek void klp_shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor)
254439e7271SJoe Lawrence {
255439e7271SJoe Lawrence struct klp_shadow *shadow;
256439e7271SJoe Lawrence unsigned long flags;
257439e7271SJoe Lawrence
258439e7271SJoe Lawrence spin_lock_irqsave(&klp_shadow_lock, flags);
259439e7271SJoe Lawrence
260439e7271SJoe Lawrence /* Delete <obj, id> from hash */
261439e7271SJoe Lawrence hash_for_each_possible(klp_shadow_hash, shadow, node,
262439e7271SJoe Lawrence (unsigned long)obj) {
263439e7271SJoe Lawrence
264439e7271SJoe Lawrence if (klp_shadow_match(shadow, obj, id)) {
2653b2c77d0SPetr Mladek klp_shadow_free_struct(shadow, dtor);
266439e7271SJoe Lawrence break;
267439e7271SJoe Lawrence }
268439e7271SJoe Lawrence }
269439e7271SJoe Lawrence
270439e7271SJoe Lawrence spin_unlock_irqrestore(&klp_shadow_lock, flags);
271439e7271SJoe Lawrence }
272439e7271SJoe Lawrence EXPORT_SYMBOL_GPL(klp_shadow_free);
273439e7271SJoe Lawrence
274439e7271SJoe Lawrence /**
275*e368cd72SDavid Vernet * klp_shadow_free_all() - detach and free all <_, id> shadow variables
276439e7271SJoe Lawrence * @id: data identifier
2773b2c77d0SPetr Mladek * @dtor: custom callback that can be used to unregister the variable
2783b2c77d0SPetr Mladek * and/or free data that the shadow variable points to (optional)
279439e7271SJoe Lawrence *
280*e368cd72SDavid Vernet * This function releases the memory for all <_, id> shadow variable
281439e7271SJoe Lawrence * instances, callers should stop referencing them accordingly.
282439e7271SJoe Lawrence */
klp_shadow_free_all(unsigned long id,klp_shadow_dtor_t dtor)2833b2c77d0SPetr Mladek void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor)
284439e7271SJoe Lawrence {
285439e7271SJoe Lawrence struct klp_shadow *shadow;
286439e7271SJoe Lawrence unsigned long flags;
287439e7271SJoe Lawrence int i;
288439e7271SJoe Lawrence
289439e7271SJoe Lawrence spin_lock_irqsave(&klp_shadow_lock, flags);
290439e7271SJoe Lawrence
291*e368cd72SDavid Vernet /* Delete all <_, id> from hash */
292439e7271SJoe Lawrence hash_for_each(klp_shadow_hash, i, shadow, node) {
2933b2c77d0SPetr Mladek if (klp_shadow_match(shadow, shadow->obj, id))
2943b2c77d0SPetr Mladek klp_shadow_free_struct(shadow, dtor);
295439e7271SJoe Lawrence }
296439e7271SJoe Lawrence
297439e7271SJoe Lawrence spin_unlock_irqrestore(&klp_shadow_lock, flags);
298439e7271SJoe Lawrence }
299439e7271SJoe Lawrence EXPORT_SYMBOL_GPL(klp_shadow_free_all);
300