diff options
| -rw-r--r-- | Documentation/livepatch/shadow-vars.txt | 31 | ||||
| -rw-r--r-- | include/linux/livepatch.h | 14 | ||||
| -rw-r--r-- | kernel/livepatch/shadow.c | 82 | ||||
| -rw-r--r-- | samples/livepatch/livepatch-shadow-fix1.c | 18 | ||||
| -rw-r--r-- | samples/livepatch/livepatch-shadow-fix2.c | 6 |
5 files changed, 104 insertions, 47 deletions
diff --git a/Documentation/livepatch/shadow-vars.txt b/Documentation/livepatch/shadow-vars.txt index 89c66634d600..9c7ae191641c 100644 --- a/Documentation/livepatch/shadow-vars.txt +++ b/Documentation/livepatch/shadow-vars.txt | |||
| @@ -34,9 +34,13 @@ meta-data and shadow-data: | |||
| 34 | - data[] - storage for shadow data | 34 | - data[] - storage for shadow data |
| 35 | 35 | ||
| 36 | It is important to note that the klp_shadow_alloc() and | 36 | It is important to note that the klp_shadow_alloc() and |
| 37 | klp_shadow_get_or_alloc() calls, described below, store a *copy* of the | 37 | klp_shadow_get_or_alloc() are zeroing the variable by default. |
| 38 | data that the functions are provided. Callers should provide whatever | 38 | They also allow to call a custom constructor function when a non-zero |
| 39 | mutual exclusion is required of the shadow data. | 39 | value is needed. Callers should provide whatever mutual exclusion |
| 40 | is required. | ||
| 41 | |||
| 42 | Note that the constructor is called under klp_shadow_lock spinlock. It allows | ||
| 43 | to do actions that can be done only once when a new variable is allocated. | ||
| 40 | 44 | ||
| 41 | * klp_shadow_get() - retrieve a shadow variable data pointer | 45 | * klp_shadow_get() - retrieve a shadow variable data pointer |
| 42 | - search hashtable for <obj, id> pair | 46 | - search hashtable for <obj, id> pair |
| @@ -47,7 +51,7 @@ mutual exclusion is required of the shadow data. | |||
| 47 | - WARN and return NULL | 51 | - WARN and return NULL |
| 48 | - if <obj, id> doesn't already exist | 52 | - if <obj, id> doesn't already exist |
| 49 | - allocate a new shadow variable | 53 | - allocate a new shadow variable |
| 50 | - copy data into the new shadow variable | 54 | - initialize the variable using a custom constructor and data when provided |
| 51 | - add <obj, id> to the global hashtable | 55 | - add <obj, id> to the global hashtable |
| 52 | 56 | ||
| 53 | * klp_shadow_get_or_alloc() - get existing or alloc a new shadow variable | 57 | * klp_shadow_get_or_alloc() - get existing or alloc a new shadow variable |
| @@ -56,7 +60,7 @@ mutual exclusion is required of the shadow data. | |||
| 56 | - return existing shadow variable | 60 | - return existing shadow variable |
| 57 | - if <obj, id> doesn't already exist | 61 | - if <obj, id> doesn't already exist |
| 58 | - allocate a new shadow variable | 62 | - allocate a new shadow variable |
| 59 | - copy data into the new shadow variable | 63 | - initialize the variable using a custom constructor and data when provided |
| 60 | - add <obj, id> pair to the global hashtable | 64 | - add <obj, id> pair to the global hashtable |
| 61 | 65 | ||
| 62 | * klp_shadow_free() - detach and free a <obj, id> shadow variable | 66 | * klp_shadow_free() - detach and free a <obj, id> shadow variable |
| @@ -107,7 +111,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 107 | sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp); | 111 | sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp); |
| 108 | 112 | ||
| 109 | /* Attach a corresponding shadow variable, then initialize it */ | 113 | /* Attach a corresponding shadow variable, then initialize it */ |
| 110 | ps_lock = klp_shadow_alloc(sta, PS_LOCK, NULL, sizeof(*ps_lock), gfp); | 114 | ps_lock = klp_shadow_alloc(sta, PS_LOCK, sizeof(*ps_lock), gfp, |
| 115 | NULL, NULL); | ||
| 111 | if (!ps_lock) | 116 | if (!ps_lock) |
| 112 | goto shadow_fail; | 117 | goto shadow_fail; |
| 113 | spin_lock_init(ps_lock); | 118 | spin_lock_init(ps_lock); |
| @@ -148,16 +153,24 @@ shadow variables to parents already in-flight. | |||
| 148 | For commit 1d147bfa6429, a good spot to allocate a shadow spinlock is | 153 | For commit 1d147bfa6429, a good spot to allocate a shadow spinlock is |
| 149 | inside ieee80211_sta_ps_deliver_wakeup(): | 154 | inside ieee80211_sta_ps_deliver_wakeup(): |
| 150 | 155 | ||
| 156 | int ps_lock_shadow_ctor(void *obj, void *shadow_data, void *ctor_data) | ||
| 157 | { | ||
| 158 | spinlock_t *lock = shadow_data; | ||
| 159 | |||
| 160 | spin_lock_init(lock); | ||
| 161 | return 0; | ||
| 162 | } | ||
| 163 | |||
| 151 | #define PS_LOCK 1 | 164 | #define PS_LOCK 1 |
| 152 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | 165 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) |
| 153 | { | 166 | { |
| 154 | DEFINE_SPINLOCK(ps_lock_fallback); | ||
| 155 | spinlock_t *ps_lock; | 167 | spinlock_t *ps_lock; |
| 156 | 168 | ||
| 157 | /* sync with ieee80211_tx_h_unicast_ps_buf */ | 169 | /* sync with ieee80211_tx_h_unicast_ps_buf */ |
| 158 | ps_lock = klp_shadow_get_or_alloc(sta, PS_LOCK, | 170 | ps_lock = klp_shadow_get_or_alloc(sta, PS_LOCK, |
| 159 | &ps_lock_fallback, sizeof(ps_lock_fallback), | 171 | sizeof(*ps_lock), GFP_ATOMIC, |
| 160 | GFP_ATOMIC); | 172 | ps_lock_shadow_ctor, NULL); |
| 173 | |||
| 161 | if (ps_lock) | 174 | if (ps_lock) |
| 162 | spin_lock(ps_lock); | 175 | spin_lock(ps_lock); |
| 163 | ... | 176 | ... |
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h index 4754f01c1abb..7e084321b146 100644 --- a/include/linux/livepatch.h +++ b/include/linux/livepatch.h | |||
| @@ -186,11 +186,17 @@ static inline bool klp_have_reliable_stack(void) | |||
| 186 | IS_ENABLED(CONFIG_HAVE_RELIABLE_STACKTRACE); | 186 | IS_ENABLED(CONFIG_HAVE_RELIABLE_STACKTRACE); |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | typedef int (*klp_shadow_ctor_t)(void *obj, | ||
| 190 | void *shadow_data, | ||
| 191 | void *ctor_data); | ||
| 192 | |||
| 189 | void *klp_shadow_get(void *obj, unsigned long id); | 193 | void *klp_shadow_get(void *obj, unsigned long id); |
| 190 | void *klp_shadow_alloc(void *obj, unsigned long id, void *data, | 194 | void *klp_shadow_alloc(void *obj, unsigned long id, |
| 191 | size_t size, gfp_t gfp_flags); | 195 | size_t size, gfp_t gfp_flags, |
| 192 | void *klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data, | 196 | klp_shadow_ctor_t ctor, void *ctor_data); |
| 193 | size_t size, gfp_t gfp_flags); | 197 | void *klp_shadow_get_or_alloc(void *obj, unsigned long id, |
| 198 | size_t size, gfp_t gfp_flags, | ||
| 199 | klp_shadow_ctor_t ctor, void *ctor_data); | ||
| 194 | void klp_shadow_free(void *obj, unsigned long id); | 200 | void klp_shadow_free(void *obj, unsigned long id); |
| 195 | void klp_shadow_free_all(unsigned long id); | 201 | void klp_shadow_free_all(unsigned long id); |
| 196 | 202 | ||
diff --git a/kernel/livepatch/shadow.c b/kernel/livepatch/shadow.c index fdac27588d60..b10a0bbb7f84 100644 --- a/kernel/livepatch/shadow.c +++ b/kernel/livepatch/shadow.c | |||
| @@ -113,8 +113,10 @@ void *klp_shadow_get(void *obj, unsigned long id) | |||
| 113 | } | 113 | } |
| 114 | EXPORT_SYMBOL_GPL(klp_shadow_get); | 114 | EXPORT_SYMBOL_GPL(klp_shadow_get); |
| 115 | 115 | ||
| 116 | static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data, | 116 | static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, |
| 117 | size_t size, gfp_t gfp_flags, bool warn_on_exist) | 117 | size_t size, gfp_t gfp_flags, |
| 118 | klp_shadow_ctor_t ctor, void *ctor_data, | ||
| 119 | bool warn_on_exist) | ||
| 118 | { | 120 | { |
| 119 | struct klp_shadow *new_shadow; | 121 | struct klp_shadow *new_shadow; |
| 120 | void *shadow_data; | 122 | void *shadow_data; |
| @@ -125,18 +127,15 @@ static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data, | |||
| 125 | if (shadow_data) | 127 | if (shadow_data) |
| 126 | goto exists; | 128 | goto exists; |
| 127 | 129 | ||
| 128 | /* Allocate a new shadow variable for use inside the lock below */ | 130 | /* |
| 131 | * Allocate a new shadow variable. Fill it with zeroes by default. | ||
| 132 | * More complex setting can be done by @ctor function. But it is | ||
| 133 | * called only when the buffer is really used (under klp_shadow_lock). | ||
| 134 | */ | ||
| 129 | new_shadow = kzalloc(size + sizeof(*new_shadow), gfp_flags); | 135 | new_shadow = kzalloc(size + sizeof(*new_shadow), gfp_flags); |
| 130 | if (!new_shadow) | 136 | if (!new_shadow) |
| 131 | return NULL; | 137 | return NULL; |
| 132 | 138 | ||
| 133 | new_shadow->obj = obj; | ||
| 134 | new_shadow->id = id; | ||
| 135 | |||
| 136 | /* Initialize the shadow variable if data provided */ | ||
| 137 | if (data) | ||
| 138 | memcpy(new_shadow->data, data, size); | ||
| 139 | |||
| 140 | /* Look for <obj, id> again under the lock */ | 139 | /* Look for <obj, id> again under the lock */ |
| 141 | spin_lock_irqsave(&klp_shadow_lock, flags); | 140 | spin_lock_irqsave(&klp_shadow_lock, flags); |
| 142 | shadow_data = klp_shadow_get(obj, id); | 141 | shadow_data = klp_shadow_get(obj, id); |
| @@ -150,6 +149,22 @@ static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data, | |||
| 150 | goto exists; | 149 | goto exists; |
| 151 | } | 150 | } |
| 152 | 151 | ||
| 152 | new_shadow->obj = obj; | ||
| 153 | new_shadow->id = id; | ||
| 154 | |||
| 155 | if (ctor) { | ||
| 156 | int err; | ||
| 157 | |||
| 158 | err = ctor(obj, new_shadow->data, ctor_data); | ||
| 159 | if (err) { | ||
| 160 | spin_unlock_irqrestore(&klp_shadow_lock, flags); | ||
| 161 | kfree(new_shadow); | ||
| 162 | pr_err("Failed to construct shadow variable <%p, %lx> (%d)\n", | ||
| 163 | obj, id, err); | ||
| 164 | return NULL; | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 153 | /* No <obj, id> found, so attach the newly allocated one */ | 168 | /* No <obj, id> found, so attach the newly allocated one */ |
| 154 | hash_add_rcu(klp_shadow_hash, &new_shadow->node, | 169 | hash_add_rcu(klp_shadow_hash, &new_shadow->node, |
| 155 | (unsigned long)new_shadow->obj); | 170 | (unsigned long)new_shadow->obj); |
| @@ -170,26 +185,32 @@ exists: | |||
| 170 | * klp_shadow_alloc() - allocate and add a new shadow variable | 185 | * klp_shadow_alloc() - allocate and add a new shadow variable |
| 171 | * @obj: pointer to parent object | 186 | * @obj: pointer to parent object |
| 172 | * @id: data identifier | 187 | * @id: data identifier |
| 173 | * @data: pointer to data to attach to parent | ||
| 174 | * @size: size of attached data | 188 | * @size: size of attached data |
| 175 | * @gfp_flags: GFP mask for allocation | 189 | * @gfp_flags: GFP mask for allocation |
| 190 | * @ctor: custom constructor to initialize the shadow data (optional) | ||
| 191 | * @ctor_data: pointer to any data needed by @ctor (optional) | ||
| 192 | * | ||
| 193 | * Allocates @size bytes for new shadow variable data using @gfp_flags. | ||
| 194 | * The data are zeroed by default. They are further initialized by @ctor | ||
| 195 | * function if it is not NULL. The new shadow variable is then added | ||
| 196 | * to the global hashtable. | ||
| 176 | * | 197 | * |
| 177 | * Allocates @size bytes for new shadow variable data using @gfp_flags | 198 | * If an existing <obj, id> shadow variable can be found, this routine will |
| 178 | * and copies @size bytes from @data into the new shadow variable's own | 199 | * issue a WARN, exit early and return NULL. |
| 179 | * data space. If @data is NULL, @size bytes are still allocated, but | ||
| 180 | * no copy is performed. The new shadow variable is then added to the | ||
| 181 | * global hashtable. | ||
| 182 | * | 200 | * |
| 183 | * If an existing <obj, id> shadow variable can be found, this routine | 201 | * This function guarantees that the constructor function is called only when |
| 184 | * will issue a WARN, exit early and return NULL. | 202 | * the variable did not exist before. The cost is that @ctor is called |
| 203 | * in atomic context under a spin lock. | ||
| 185 | * | 204 | * |
| 186 | * Return: the shadow variable data element, NULL on duplicate or | 205 | * Return: the shadow variable data element, NULL on duplicate or |
| 187 | * failure. | 206 | * failure. |
| 188 | */ | 207 | */ |
| 189 | void *klp_shadow_alloc(void *obj, unsigned long id, void *data, | 208 | void *klp_shadow_alloc(void *obj, unsigned long id, |
| 190 | size_t size, gfp_t gfp_flags) | 209 | size_t size, gfp_t gfp_flags, |
| 210 | klp_shadow_ctor_t ctor, void *ctor_data) | ||
| 191 | { | 211 | { |
| 192 | return __klp_shadow_get_or_alloc(obj, id, data, size, gfp_flags, true); | 212 | return __klp_shadow_get_or_alloc(obj, id, size, gfp_flags, |
| 213 | ctor, ctor_data, true); | ||
| 193 | } | 214 | } |
| 194 | EXPORT_SYMBOL_GPL(klp_shadow_alloc); | 215 | EXPORT_SYMBOL_GPL(klp_shadow_alloc); |
| 195 | 216 | ||
| @@ -197,25 +218,28 @@ EXPORT_SYMBOL_GPL(klp_shadow_alloc); | |||
| 197 | * klp_shadow_get_or_alloc() - get existing or allocate a new shadow variable | 218 | * klp_shadow_get_or_alloc() - get existing or allocate a new shadow variable |
| 198 | * @obj: pointer to parent object | 219 | * @obj: pointer to parent object |
| 199 | * @id: data identifier | 220 | * @id: data identifier |
| 200 | * @data: pointer to data to attach to parent | ||
| 201 | * @size: size of attached data | 221 | * @size: size of attached data |
| 202 | * @gfp_flags: GFP mask for allocation | 222 | * @gfp_flags: GFP mask for allocation |
| 223 | * @ctor: custom constructor to initialize the shadow data (optional) | ||
| 224 | * @ctor_data: pointer to any data needed by @ctor (optional) | ||
| 203 | * | 225 | * |
| 204 | * Returns a pointer to existing shadow data if an <obj, id> shadow | 226 | * Returns a pointer to existing shadow data if an <obj, id> shadow |
| 205 | * variable is already present. Otherwise, it creates a new shadow | 227 | * variable is already present. Otherwise, it creates a new shadow |
| 206 | * variable like klp_shadow_alloc(). | 228 | * variable like klp_shadow_alloc(). |
| 207 | * | 229 | * |
| 208 | * This function guarantees that only one shadow variable exists with | 230 | * This function guarantees that only one shadow variable exists with the given |
| 209 | * the given @id for the given @obj. It also guarantees that the shadow | 231 | * @id for the given @obj. It also guarantees that the constructor function |
| 210 | * variable will be initialized by the given @data only when it did not | 232 | * will be called only when the variable did not exist before. The cost is |
| 211 | * exist before. | 233 | * that @ctor is called in atomic context under a spin lock. |
| 212 | * | 234 | * |
| 213 | * Return: the shadow variable data element, NULL on failure. | 235 | * Return: the shadow variable data element, NULL on failure. |
| 214 | */ | 236 | */ |
| 215 | void *klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data, | 237 | void *klp_shadow_get_or_alloc(void *obj, unsigned long id, |
| 216 | size_t size, gfp_t gfp_flags) | 238 | size_t size, gfp_t gfp_flags, |
| 239 | klp_shadow_ctor_t ctor, void *ctor_data) | ||
| 217 | { | 240 | { |
| 218 | return __klp_shadow_get_or_alloc(obj, id, data, size, gfp_flags, false); | 241 | return __klp_shadow_get_or_alloc(obj, id, size, gfp_flags, |
| 242 | ctor, ctor_data, false); | ||
| 219 | } | 243 | } |
| 220 | EXPORT_SYMBOL_GPL(klp_shadow_get_or_alloc); | 244 | EXPORT_SYMBOL_GPL(klp_shadow_get_or_alloc); |
| 221 | 245 | ||
diff --git a/samples/livepatch/livepatch-shadow-fix1.c b/samples/livepatch/livepatch-shadow-fix1.c index 830c55514f9f..04151c7f2631 100644 --- a/samples/livepatch/livepatch-shadow-fix1.c +++ b/samples/livepatch/livepatch-shadow-fix1.c | |||
| @@ -56,6 +56,21 @@ struct dummy { | |||
| 56 | unsigned long jiffies_expire; | 56 | unsigned long jiffies_expire; |
| 57 | }; | 57 | }; |
| 58 | 58 | ||
| 59 | /* | ||
| 60 | * The constructor makes more sense together with klp_shadow_get_or_alloc(). | ||
| 61 | * In this example, it would be safe to assign the pointer also to the shadow | ||
| 62 | * variable returned by klp_shadow_alloc(). But we wanted to show the more | ||
| 63 | * complicated use of the API. | ||
| 64 | */ | ||
| 65 | static int shadow_leak_ctor(void *obj, void *shadow_data, void *ctor_data) | ||
| 66 | { | ||
| 67 | void **shadow_leak = shadow_data; | ||
| 68 | void *leak = ctor_data; | ||
| 69 | |||
| 70 | *shadow_leak = leak; | ||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | |||
| 59 | struct dummy *livepatch_fix1_dummy_alloc(void) | 74 | struct dummy *livepatch_fix1_dummy_alloc(void) |
| 60 | { | 75 | { |
| 61 | struct dummy *d; | 76 | struct dummy *d; |
| @@ -74,7 +89,8 @@ struct dummy *livepatch_fix1_dummy_alloc(void) | |||
| 74 | * pointer to handle resource release. | 89 | * pointer to handle resource release. |
| 75 | */ | 90 | */ |
| 76 | leak = kzalloc(sizeof(int), GFP_KERNEL); | 91 | leak = kzalloc(sizeof(int), GFP_KERNEL); |
| 77 | klp_shadow_alloc(d, SV_LEAK, &leak, sizeof(leak), GFP_KERNEL); | 92 | klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL, |
| 93 | shadow_leak_ctor, leak); | ||
| 78 | 94 | ||
| 79 | pr_info("%s: dummy @ %p, expires @ %lx\n", | 95 | pr_info("%s: dummy @ %p, expires @ %lx\n", |
| 80 | __func__, d, d->jiffies_expire); | 96 | __func__, d, d->jiffies_expire); |
diff --git a/samples/livepatch/livepatch-shadow-fix2.c b/samples/livepatch/livepatch-shadow-fix2.c index ff9948f0ec00..d6c62844dc15 100644 --- a/samples/livepatch/livepatch-shadow-fix2.c +++ b/samples/livepatch/livepatch-shadow-fix2.c | |||
| @@ -53,17 +53,15 @@ struct dummy { | |||
| 53 | bool livepatch_fix2_dummy_check(struct dummy *d, unsigned long jiffies) | 53 | bool livepatch_fix2_dummy_check(struct dummy *d, unsigned long jiffies) |
| 54 | { | 54 | { |
| 55 | int *shadow_count; | 55 | int *shadow_count; |
| 56 | int count; | ||
| 57 | 56 | ||
| 58 | /* | 57 | /* |
| 59 | * Patch: handle in-flight dummy structures, if they do not | 58 | * Patch: handle in-flight dummy structures, if they do not |
| 60 | * already have a SV_COUNTER shadow variable, then attach a | 59 | * already have a SV_COUNTER shadow variable, then attach a |
| 61 | * new one. | 60 | * new one. |
| 62 | */ | 61 | */ |
| 63 | count = 0; | ||
| 64 | shadow_count = klp_shadow_get_or_alloc(d, SV_COUNTER, | 62 | shadow_count = klp_shadow_get_or_alloc(d, SV_COUNTER, |
| 65 | &count, sizeof(count), | 63 | sizeof(*shadow_count), GFP_NOWAIT, |
| 66 | GFP_NOWAIT); | 64 | NULL, NULL); |
| 67 | if (shadow_count) | 65 | if (shadow_count) |
| 68 | *shadow_count += 1; | 66 | *shadow_count += 1; |
| 69 | 67 | ||
