History

lib: prevent module unloading if memory is not freed

Skip freeing module's data section if there are non-zero allocation tags because otherwise, once these allocations are freed, the access to their code tag would cause UAF.

Suren Baghdasaryan committed 2 years ago

Commit 47a92df1 parent a4735733 files · +30 −14Browse files

Unified · Split

3 files
  1. include/linux/codetag.h +3 −3
  2. kernel/module/main.c +19 −8
  3. lib/codetag.c +8 −3
include/linux/codetag.h+3−3
@@ -35,7 +35,7 @@ struct codetag_type_desc { · 34 unmodified lines
35 size_t tag_size;35 size_t tag_size;
36 void (*module_load)(struct codetag_type *cttype,36 void (*module_load)(struct codetag_type *cttype,
37 struct codetag_module *cmod);37 struct codetag_module *cmod);
38 void (*module_unload)(struct codetag_type *cttype,38 bool (*module_unload)(struct codetag_type *cttype,
39 struct codetag_module *cmod);39 struct codetag_module *cmod);
40};40};
41 41
@@ -71,10 +71,10 @@ codetag_register_type(const struct codetag_type_desc *desc); · 29 unmodified lines
71 71
72#if defined(CONFIG_CODE_TAGGING) && defined(CONFIG_MODULES)72#if defined(CONFIG_CODE_TAGGING) && defined(CONFIG_MODULES)
73void codetag_load_module(struct module *mod);73void codetag_load_module(struct module *mod);
74void codetag_unload_module(struct module *mod);74bool codetag_unload_module(struct module *mod);
75#else75#else
76static inline void codetag_load_module(struct module *mod) {}76static inline void codetag_load_module(struct module *mod) {}
77static inline void codetag_unload_module(struct module *mod) {}77static inline bool codetag_unload_module(struct module *mod) { return true; }
78#endif78#endif
79 79
80#endif /* _LINUX_CODETAG_H */80#endif /* _LINUX_CODETAG_H */
kernel/module/main.c+19−8
@@ -1211,15 +1211,19 @@ static void *module_memory_alloc(unsigned int size, enum mod_mem_type type) · 1210 unmodified lines
1211 return module_alloc(size);1211 return module_alloc(size);
1212}1212}
1213 1213
1214static void module_memory_free(void *ptr, enum mod_mem_type type)1214static void module_memory_free(void *ptr, enum mod_mem_type type,
1215 bool unload_codetags)
1215{1216{
1217 if (!unload_codetags && mod_mem_type_is_core_data(type))
1218 return;
1219
1216 if (mod_mem_use_vmalloc(type))1220 if (mod_mem_use_vmalloc(type))
1217 vfree(ptr);1221 vfree(ptr);
1218 else1222 else
1219 module_memfree(ptr);1223 module_memfree(ptr);
1220}1224}
1221 1225
1222static void free_mod_mem(struct module *mod)1226static void free_mod_mem(struct module *mod, bool unload_codetags)
1223{1227{
1224 for_each_mod_mem_type(type) {1228 for_each_mod_mem_type(type) {
1225 struct module_memory *mod_mem = &mod->mem[type];1229 struct module_memory *mod_mem = &mod->mem[type];
@@ -1230,20 +1234,27 @@ static void free_mod_mem(struct module *mod) · 4 unmodified lines
1230 /* Free lock-classes; relies on the preceding sync_rcu(). */1234 /* Free lock-classes; relies on the preceding sync_rcu(). */
1231 lockdep_free_key_range(mod_mem->base, mod_mem->size);1235 lockdep_free_key_range(mod_mem->base, mod_mem->size);
1232 if (mod_mem->size)1236 if (mod_mem->size)
1233 module_memory_free(mod_mem->base, type);1237 module_memory_free(mod_mem->base, type,
1238 unload_codetags);
1234 }1239 }
1235 1240
1236 /* MOD_DATA hosts mod, so free it at last */1241 /* MOD_DATA hosts mod, so free it at last */
1237 lockdep_free_key_range(mod->mem[MOD_DATA].base, mod->mem[MOD_DATA].size);1242 lockdep_free_key_range(mod->mem[MOD_DATA].base, mod->mem[MOD_DATA].size);
1238 module_memory_free(mod->mem[MOD_DATA].base, MOD_DATA);1243 module_memory_free(mod->mem[MOD_DATA].base, MOD_DATA, unload_codetags);
1239}1244}
1240 1245
1241/* Free a module, remove from lists, etc. */1246/* Free a module, remove from lists, etc. */
1242static void free_module(struct module *mod)1247static void free_module(struct module *mod)
1243{1248{
1249 bool unload_codetags;
1250
1244 trace_module_free(mod);1251 trace_module_free(mod);
1245 1252
1246 codetag_unload_module(mod);1253 unload_codetags = codetag_unload_module(mod);
1254 if (!unload_codetags)
1255 pr_warn("%s: memory allocation(s) from the module still alive, cannot unload cleanly\n",
1256 mod->name);
1257
1247 mod_sysfs_teardown(mod);1258 mod_sysfs_teardown(mod);
1248 1259
1249 /*1260 /*
@@ -1285,7 +1296,7 @@ static void free_module(struct module *mod) · 35 unmodified lines
1285 kfree(mod->args);1296 kfree(mod->args);
1286 percpu_modfree(mod);1297 percpu_modfree(mod);
1287 1298
1288 free_mod_mem(mod);1299 free_mod_mem(mod, unload_codetags);
1289}1300}
1290 1301
1291void *__symbol_get(const char *symbol)1302void *__symbol_get(const char *symbol)
@@ -2298,7 +2309,7 @@ static int move_module(struct module *mod, struct load_info *info) · 1006 unmodified lines
2298 return 0;2309 return 0;
2299out_enomem:2310out_enomem:
2300 for (t--; t >= 0; t--)2311 for (t--; t >= 0; t--)
2301 module_memory_free(mod->mem[t].base, t);2312 module_memory_free(mod->mem[t].base, t, true);
2302 return ret;2313 return ret;
2303}2314}
2304 2315
@@ -2428,7 +2439,7 @@ static void module_deallocate(struct module *mod, struct load_info *info) · 123 unmodified lines
2428 percpu_modfree(mod);2439 percpu_modfree(mod);
2429 module_arch_freeing_init(mod);2440 module_arch_freeing_init(mod);
2430 2441
2431 free_mod_mem(mod);2442 free_mod_mem(mod, true);
2432}2443}
2433 2444
2434int __weak module_finalize(const Elf_Ehdr *hdr,2445int __weak module_finalize(const Elf_Ehdr *hdr,
lib/codetag.c+8−3
@@ -5,6 +5,7 @@ · 4 unmodified lines
5#include <linux/module.h>5#include <linux/module.h>
6#include <linux/seq_buf.h>6#include <linux/seq_buf.h>
7#include <linux/slab.h>7#include <linux/slab.h>
8#include <linux/vmalloc.h>
8 9
9struct codetag_type {10struct codetag_type {
10 struct list_head link;11 struct list_head link;
@@ -206,12 +207,13 @@ void codetag_load_module(struct module *mod) · 195 unmodified lines
206 mutex_unlock(&codetag_lock);207 mutex_unlock(&codetag_lock);
207}208}
208 209
209void codetag_unload_module(struct module *mod)210bool codetag_unload_module(struct module *mod)
210{211{
211 struct codetag_type *cttype;212 struct codetag_type *cttype;
213 bool unload_ok = true;
212 214
213 if (!mod)215 if (!mod)
214 return;216 return true;
215 217
216 mutex_lock(&codetag_lock);218 mutex_lock(&codetag_lock);
217 list_for_each_entry(cttype, &codetag_types, link) {219 list_for_each_entry(cttype, &codetag_types, link) {
@@ -228,7 +230,8 @@ void codetag_unload_module(struct module *mod) · 10 unmodified lines
228 }230 }
229 if (found) {231 if (found) {
230 if (cttype->desc.module_unload)232 if (cttype->desc.module_unload)
231 cttype->desc.module_unload(cttype, cmod);233 if (!cttype->desc.module_unload(cttype, cmod))
234 unload_ok = false;
232 235
233 cttype->count -= range_size(cttype, &cmod->range);236 cttype->count -= range_size(cttype, &cmod->range);
234 idr_remove(&cttype->mod_idr, mod_id);237 idr_remove(&cttype->mod_idr, mod_id);
@@ -237,6 +240,8 @@ void codetag_unload_module(struct module *mod) · 2 unmodified lines
237 up_write(&cttype->mod_lock);240 up_write(&cttype->mod_lock);
238 }241 }
239 mutex_unlock(&codetag_lock);242 mutex_unlock(&codetag_lock);
243
244 return unload_ok;
240}245}
241 246
242#else /* CONFIG_MODULES */247#else /* CONFIG_MODULES */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t