mirror of
https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
synced 2025-09-14 16:46:19 +10:00
When a module gets unloaded it checks whether any of its tags are still in
use and if so, we keep the memory containing module's allocation tags
alive until all tags are unused. However percpu counters referenced by
the tags are freed by free_module(). This will lead to UAF if the memory
allocated by a module is accessed after module was unloaded.
To fix this we allocate percpu counters for module allocation tags
dynamically and we keep it alive for tags which are still in use after
module unloading. This also removes the requirement of a larger
PERCPU_MODULE_RESERVE when memory allocation profiling is enabled because
percpu memory for counters does not need to be reserved anymore.
Link: https://lkml.kernel.org/r/20250517000739.5930-1-surenb@google.com
Fixes: 0db6f8d782
("alloc_tag: load module tags into separate contiguous memory")
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Reported-by: David Wang <00107082@163.com>
Closes: https://lore.kernel.org/all/20250516131246.6244-1-00107082@163.com/
Tested-by: David Wang <00107082@163.com>
Cc: Christoph Lameter (Ampere) <cl@gentwo.org>
Cc: Dennis Zhou <dennis@kernel.org>
Cc: Kent Overstreet <kent.overstreet@linux.dev>
Cc: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
112 lines
3.4 KiB
C
112 lines
3.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* code tagging framework
|
|
*/
|
|
#ifndef _LINUX_CODETAG_H
|
|
#define _LINUX_CODETAG_H
|
|
|
|
#include <linux/types.h>
|
|
|
|
struct codetag_iterator;
|
|
struct codetag_type;
|
|
struct codetag_module;
|
|
struct seq_buf;
|
|
struct module;
|
|
|
|
#define CODETAG_SECTION_START_PREFIX "__start_"
|
|
#define CODETAG_SECTION_STOP_PREFIX "__stop_"
|
|
|
|
/*
|
|
* An instance of this structure is created in a special ELF section at every
|
|
* code location being tagged. At runtime, the special section is treated as
|
|
* an array of these.
|
|
*/
|
|
struct codetag {
|
|
unsigned int flags; /* used in later patches */
|
|
unsigned int lineno;
|
|
const char *modname;
|
|
const char *function;
|
|
const char *filename;
|
|
} __aligned(8);
|
|
|
|
union codetag_ref {
|
|
struct codetag *ct;
|
|
};
|
|
|
|
struct codetag_type_desc {
|
|
const char *section;
|
|
size_t tag_size;
|
|
void (*module_load)(struct module *mod,
|
|
struct codetag *start, struct codetag *end);
|
|
void (*module_unload)(struct module *mod,
|
|
struct codetag *start, struct codetag *end);
|
|
#ifdef CONFIG_MODULES
|
|
void (*module_replaced)(struct module *mod, struct module *new_mod);
|
|
bool (*needs_section_mem)(struct module *mod, unsigned long size);
|
|
void *(*alloc_section_mem)(struct module *mod, unsigned long size,
|
|
unsigned int prepend, unsigned long align);
|
|
void (*free_section_mem)(struct module *mod, bool used);
|
|
#endif
|
|
};
|
|
|
|
struct codetag_iterator {
|
|
struct codetag_type *cttype;
|
|
struct codetag_module *cmod;
|
|
unsigned long mod_id;
|
|
struct codetag *ct;
|
|
};
|
|
|
|
#ifdef MODULE
|
|
#define CT_MODULE_NAME KBUILD_MODNAME
|
|
#else
|
|
#define CT_MODULE_NAME NULL
|
|
#endif
|
|
|
|
#define CODE_TAG_INIT { \
|
|
.modname = CT_MODULE_NAME, \
|
|
.function = __func__, \
|
|
.filename = __FILE__, \
|
|
.lineno = __LINE__, \
|
|
.flags = 0, \
|
|
}
|
|
|
|
void codetag_lock_module_list(struct codetag_type *cttype, bool lock);
|
|
bool codetag_trylock_module_list(struct codetag_type *cttype);
|
|
struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype);
|
|
struct codetag *codetag_next_ct(struct codetag_iterator *iter);
|
|
|
|
void codetag_to_text(struct seq_buf *out, struct codetag *ct);
|
|
|
|
struct codetag_type *
|
|
codetag_register_type(const struct codetag_type_desc *desc);
|
|
|
|
#if defined(CONFIG_CODE_TAGGING) && defined(CONFIG_MODULES)
|
|
|
|
bool codetag_needs_module_section(struct module *mod, const char *name,
|
|
unsigned long size);
|
|
void *codetag_alloc_module_section(struct module *mod, const char *name,
|
|
unsigned long size, unsigned int prepend,
|
|
unsigned long align);
|
|
void codetag_free_module_sections(struct module *mod);
|
|
void codetag_module_replaced(struct module *mod, struct module *new_mod);
|
|
void codetag_load_module(struct module *mod);
|
|
void codetag_unload_module(struct module *mod);
|
|
|
|
#else /* defined(CONFIG_CODE_TAGGING) && defined(CONFIG_MODULES) */
|
|
|
|
static inline bool
|
|
codetag_needs_module_section(struct module *mod, const char *name,
|
|
unsigned long size) { return false; }
|
|
static inline void *
|
|
codetag_alloc_module_section(struct module *mod, const char *name,
|
|
unsigned long size, unsigned int prepend,
|
|
unsigned long align) { return NULL; }
|
|
static inline void codetag_free_module_sections(struct module *mod) {}
|
|
static inline void codetag_module_replaced(struct module *mod, struct module *new_mod) {}
|
|
static inline void codetag_load_module(struct module *mod) {}
|
|
static inline void codetag_unload_module(struct module *mod) {}
|
|
|
|
#endif /* defined(CONFIG_CODE_TAGGING) && defined(CONFIG_MODULES) */
|
|
|
|
#endif /* _LINUX_CODETAG_H */
|