Merge 4e3c09e954 ("Merge tag 'v6.5-rc1-modules-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux") into android-mainline
Steps on the way to 6.5-rc1 Change-Id: I3b8dbac125725a81ce179004f1c820e86985ebc3 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -65,6 +65,9 @@ static inline void *dereference_symbol_descriptor(void *ptr)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* How and when do we show kallsyms values? */
|
||||
extern bool kallsyms_show_value(const struct cred *cred);
|
||||
|
||||
#ifdef CONFIG_KALLSYMS
|
||||
unsigned long kallsyms_sym_address(int idx);
|
||||
int kallsyms_on_each_symbol(int (*fn)(void *, const char *, unsigned long),
|
||||
@@ -93,10 +96,6 @@ extern int sprint_backtrace(char *buffer, unsigned long address);
|
||||
extern int sprint_backtrace_build_id(char *buffer, unsigned long address);
|
||||
|
||||
int lookup_symbol_name(unsigned long addr, char *symname);
|
||||
int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
|
||||
|
||||
/* How and when do we show kallsyms values? */
|
||||
extern bool kallsyms_show_value(const struct cred *cred);
|
||||
|
||||
#else /* !CONFIG_KALLSYMS */
|
||||
|
||||
@@ -155,16 +154,6 @@ static inline int lookup_symbol_name(unsigned long addr, char *symname)
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
static inline int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name)
|
||||
{
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
static inline bool kallsyms_show_value(const struct cred *cred)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int kallsyms_on_each_symbol(int (*fn)(void *, const char *, unsigned long),
|
||||
void *data)
|
||||
{
|
||||
|
||||
@@ -971,15 +971,6 @@ static inline int lookup_module_symbol_name(unsigned long addr, char *symname)
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
static inline int lookup_module_symbol_attrs(unsigned long addr,
|
||||
unsigned long *size,
|
||||
unsigned long *offset,
|
||||
char *modname,
|
||||
char *name)
|
||||
{
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
static inline int module_get_kallsym(unsigned int symnum, unsigned long *value,
|
||||
char *type, char *name,
|
||||
char *module_name, int *exported)
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ obj-y = fork.o exec_domain.o panic.o \
|
||||
extable.o params.o \
|
||||
kthread.o sys_ni.o nsproxy.o \
|
||||
notifier.o ksysfs.o cred.o reboot.o \
|
||||
async.o range.o smpboot.o ucount.o regset.o
|
||||
async.o range.o smpboot.o ucount.o regset.o ksyms_common.o
|
||||
|
||||
obj-$(CONFIG_USERMODE_DRIVER) += usermode_driver.o
|
||||
obj-$(CONFIG_MULTIUSER) += groups.o
|
||||
|
||||
+1
-90
@@ -484,34 +484,6 @@ found:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lookup_symbol_attrs(unsigned long addr, unsigned long *size,
|
||||
unsigned long *offset, char *modname, char *name)
|
||||
{
|
||||
int res;
|
||||
|
||||
name[0] = '\0';
|
||||
name[KSYM_NAME_LEN - 1] = '\0';
|
||||
|
||||
if (is_ksym_addr(addr)) {
|
||||
unsigned long pos;
|
||||
|
||||
pos = get_symbol_pos(addr, size, offset);
|
||||
/* Grab name */
|
||||
kallsyms_expand_symbol(get_symbol_offset(pos),
|
||||
name, KSYM_NAME_LEN);
|
||||
modname[0] = '\0';
|
||||
goto found;
|
||||
}
|
||||
/* See if it's in a module. */
|
||||
res = lookup_module_symbol_attrs(addr, size, offset, modname, name);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
found:
|
||||
cleanup_symbol_name(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Look up a kernel symbol and return it in a text buffer. */
|
||||
static int __sprint_symbol(char *buffer, unsigned long address,
|
||||
int symbol_offset, int add_offset, int add_buildid)
|
||||
@@ -646,7 +618,6 @@ int sprint_backtrace_build_id(char *buffer, unsigned long address)
|
||||
/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */
|
||||
struct kallsym_iter {
|
||||
loff_t pos;
|
||||
loff_t pos_arch_end;
|
||||
loff_t pos_mod_end;
|
||||
loff_t pos_ftrace_mod_end;
|
||||
loff_t pos_bpf_end;
|
||||
@@ -659,29 +630,9 @@ struct kallsym_iter {
|
||||
int show_value;
|
||||
};
|
||||
|
||||
int __weak arch_get_kallsym(unsigned int symnum, unsigned long *value,
|
||||
char *type, char *name)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int get_ksymbol_arch(struct kallsym_iter *iter)
|
||||
{
|
||||
int ret = arch_get_kallsym(iter->pos - kallsyms_num_syms,
|
||||
&iter->value, &iter->type,
|
||||
iter->name);
|
||||
|
||||
if (ret < 0) {
|
||||
iter->pos_arch_end = iter->pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_ksymbol_mod(struct kallsym_iter *iter)
|
||||
{
|
||||
int ret = module_get_kallsym(iter->pos - iter->pos_arch_end,
|
||||
int ret = module_get_kallsym(iter->pos - kallsyms_num_syms,
|
||||
&iter->value, &iter->type,
|
||||
iter->name, iter->module_name,
|
||||
&iter->exported);
|
||||
@@ -764,7 +715,6 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos)
|
||||
iter->nameoff = get_symbol_offset(new_pos);
|
||||
iter->pos = new_pos;
|
||||
if (new_pos == 0) {
|
||||
iter->pos_arch_end = 0;
|
||||
iter->pos_mod_end = 0;
|
||||
iter->pos_ftrace_mod_end = 0;
|
||||
iter->pos_bpf_end = 0;
|
||||
@@ -780,10 +730,6 @@ static int update_iter_mod(struct kallsym_iter *iter, loff_t pos)
|
||||
{
|
||||
iter->pos = pos;
|
||||
|
||||
if ((!iter->pos_arch_end || iter->pos_arch_end > pos) &&
|
||||
get_ksymbol_arch(iter))
|
||||
return 1;
|
||||
|
||||
if ((!iter->pos_mod_end || iter->pos_mod_end > pos) &&
|
||||
get_ksymbol_mod(iter))
|
||||
return 1;
|
||||
@@ -961,41 +907,6 @@ late_initcall(bpf_ksym_iter_register);
|
||||
|
||||
#endif /* CONFIG_BPF_SYSCALL */
|
||||
|
||||
static inline int kallsyms_for_perf(void)
|
||||
{
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
extern int sysctl_perf_event_paranoid;
|
||||
if (sysctl_perf_event_paranoid <= 1)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We show kallsyms information even to normal users if we've enabled
|
||||
* kernel profiling and are explicitly not paranoid (so kptr_restrict
|
||||
* is clear, and sysctl_perf_event_paranoid isn't set).
|
||||
*
|
||||
* Otherwise, require CAP_SYSLOG (assuming kptr_restrict isn't set to
|
||||
* block even that).
|
||||
*/
|
||||
bool kallsyms_show_value(const struct cred *cred)
|
||||
{
|
||||
switch (kptr_restrict) {
|
||||
case 0:
|
||||
if (kallsyms_for_perf())
|
||||
return true;
|
||||
fallthrough;
|
||||
case 1:
|
||||
if (security_capable(cred, &init_user_ns, CAP_SYSLOG,
|
||||
CAP_OPT_NOAUDIT) == 0)
|
||||
return true;
|
||||
fallthrough;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int kallsyms_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* ksyms_common.c: A split of kernel/kallsyms.c
|
||||
* Contains a few generic function definations independent of config KALLSYMS.
|
||||
*/
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/security.h>
|
||||
|
||||
static inline int kallsyms_for_perf(void)
|
||||
{
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
extern int sysctl_perf_event_paranoid;
|
||||
|
||||
if (sysctl_perf_event_paranoid <= 1)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We show kallsyms information even to normal users if we've enabled
|
||||
* kernel profiling and are explicitly not paranoid (so kptr_restrict
|
||||
* is clear, and sysctl_perf_event_paranoid isn't set).
|
||||
*
|
||||
* Otherwise, require CAP_SYSLOG (assuming kptr_restrict isn't set to
|
||||
* block even that).
|
||||
*/
|
||||
bool kallsyms_show_value(const struct cred *cred)
|
||||
{
|
||||
switch (kptr_restrict) {
|
||||
case 0:
|
||||
if (kallsyms_for_perf())
|
||||
return true;
|
||||
fallthrough;
|
||||
case 1:
|
||||
if (security_capable(cred, &init_user_ns, CAP_SYSLOG,
|
||||
CAP_OPT_NOAUDIT) == 0)
|
||||
return true;
|
||||
fallthrough;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -381,34 +381,6 @@ out:
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
|
||||
unsigned long *offset, char *modname, char *name)
|
||||
{
|
||||
struct module *mod;
|
||||
|
||||
preempt_disable();
|
||||
list_for_each_entry_rcu(mod, &modules, list) {
|
||||
if (mod->state == MODULE_STATE_UNFORMED)
|
||||
continue;
|
||||
if (within_module(addr, mod)) {
|
||||
const char *sym;
|
||||
|
||||
sym = find_kallsyms_symbol(mod, addr, size, offset);
|
||||
if (!sym)
|
||||
goto out;
|
||||
if (modname)
|
||||
strscpy(modname, mod->name, MODULE_NAME_LEN);
|
||||
if (name)
|
||||
strscpy(name, sym, KSYM_NAME_LEN);
|
||||
preempt_enable();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
out:
|
||||
preempt_enable();
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
|
||||
char *name, char *module_name, int *exported)
|
||||
{
|
||||
|
||||
+105
-31
@@ -821,10 +821,8 @@ static struct module_attribute modinfo_refcnt =
|
||||
void __module_get(struct module *module)
|
||||
{
|
||||
if (module) {
|
||||
preempt_disable();
|
||||
atomic_inc(&module->refcnt);
|
||||
trace_module_get(module, _RET_IP_);
|
||||
preempt_enable();
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(__module_get);
|
||||
@@ -834,15 +832,12 @@ bool try_module_get(struct module *module)
|
||||
bool ret = true;
|
||||
|
||||
if (module) {
|
||||
preempt_disable();
|
||||
/* Note: here, we can fail to get a reference */
|
||||
if (likely(module_is_live(module) &&
|
||||
atomic_inc_not_zero(&module->refcnt) != 0))
|
||||
trace_module_get(module, _RET_IP_);
|
||||
else
|
||||
ret = false;
|
||||
|
||||
preempt_enable();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -853,11 +848,9 @@ void module_put(struct module *module)
|
||||
int ret;
|
||||
|
||||
if (module) {
|
||||
preempt_disable();
|
||||
ret = atomic_dec_if_positive(&module->refcnt);
|
||||
WARN_ON(ret < 0); /* Failed to put refcount */
|
||||
trace_module_put(module, _RET_IP_);
|
||||
preempt_enable();
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(module_put);
|
||||
@@ -3090,12 +3083,111 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
|
||||
return load_module(&info, uargs, 0);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
|
||||
struct idempotent {
|
||||
const void *cookie;
|
||||
struct hlist_node entry;
|
||||
struct completion complete;
|
||||
int ret;
|
||||
};
|
||||
|
||||
#define IDEM_HASH_BITS 8
|
||||
static struct hlist_head idem_hash[1 << IDEM_HASH_BITS];
|
||||
static DEFINE_SPINLOCK(idem_lock);
|
||||
|
||||
static bool idempotent(struct idempotent *u, const void *cookie)
|
||||
{
|
||||
int hash = hash_ptr(cookie, IDEM_HASH_BITS);
|
||||
struct hlist_head *head = idem_hash + hash;
|
||||
struct idempotent *existing;
|
||||
bool first;
|
||||
|
||||
u->ret = 0;
|
||||
u->cookie = cookie;
|
||||
init_completion(&u->complete);
|
||||
|
||||
spin_lock(&idem_lock);
|
||||
first = true;
|
||||
hlist_for_each_entry(existing, head, entry) {
|
||||
if (existing->cookie != cookie)
|
||||
continue;
|
||||
first = false;
|
||||
break;
|
||||
}
|
||||
hlist_add_head(&u->entry, idem_hash + hash);
|
||||
spin_unlock(&idem_lock);
|
||||
|
||||
return !first;
|
||||
}
|
||||
|
||||
/*
|
||||
* We were the first one with 'cookie' on the list, and we ended
|
||||
* up completing the operation. We now need to walk the list,
|
||||
* remove everybody - which includes ourselves - fill in the return
|
||||
* value, and then complete the operation.
|
||||
*/
|
||||
static void idempotent_complete(struct idempotent *u, int ret)
|
||||
{
|
||||
const void *cookie = u->cookie;
|
||||
int hash = hash_ptr(cookie, IDEM_HASH_BITS);
|
||||
struct hlist_head *head = idem_hash + hash;
|
||||
struct hlist_node *next;
|
||||
struct idempotent *pos;
|
||||
|
||||
spin_lock(&idem_lock);
|
||||
hlist_for_each_entry_safe(pos, next, head, entry) {
|
||||
if (pos->cookie != cookie)
|
||||
continue;
|
||||
hlist_del(&pos->entry);
|
||||
pos->ret = ret;
|
||||
complete(&pos->complete);
|
||||
}
|
||||
spin_unlock(&idem_lock);
|
||||
}
|
||||
|
||||
static int init_module_from_file(struct file *f, const char __user * uargs, int flags)
|
||||
{
|
||||
struct idempotent idem;
|
||||
struct load_info info = { };
|
||||
void *buf = NULL;
|
||||
int len;
|
||||
int len, ret;
|
||||
|
||||
if (!f || !(f->f_mode & FMODE_READ))
|
||||
return -EBADF;
|
||||
|
||||
if (idempotent(&idem, file_inode(f))) {
|
||||
wait_for_completion(&idem.complete);
|
||||
return idem.ret;
|
||||
}
|
||||
|
||||
len = kernel_read_file(f, 0, &buf, INT_MAX, NULL, READING_MODULE);
|
||||
if (len < 0) {
|
||||
mod_stat_inc(&failed_kreads);
|
||||
mod_stat_add_long(len, &invalid_kread_bytes);
|
||||
return len;
|
||||
}
|
||||
|
||||
if (flags & MODULE_INIT_COMPRESSED_FILE) {
|
||||
int err = module_decompress(&info, buf, len);
|
||||
vfree(buf); /* compressed data is no longer needed */
|
||||
if (err) {
|
||||
mod_stat_inc(&failed_decompress);
|
||||
mod_stat_add_long(len, &invalid_decompress_bytes);
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
info.hdr = buf;
|
||||
info.len = len;
|
||||
}
|
||||
|
||||
ret = load_module(&info, uargs, flags);
|
||||
idempotent_complete(&idem, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
|
||||
{
|
||||
int err;
|
||||
struct fd f;
|
||||
|
||||
err = may_init_module();
|
||||
if (err)
|
||||
@@ -3108,28 +3200,10 @@ SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
|
||||
|MODULE_INIT_COMPRESSED_FILE))
|
||||
return -EINVAL;
|
||||
|
||||
len = kernel_read_file_from_fd(fd, 0, &buf, INT_MAX, NULL,
|
||||
READING_MODULE);
|
||||
if (len < 0) {
|
||||
mod_stat_inc(&failed_kreads);
|
||||
mod_stat_add_long(len, &invalid_kread_bytes);
|
||||
return len;
|
||||
}
|
||||
|
||||
if (flags & MODULE_INIT_COMPRESSED_FILE) {
|
||||
err = module_decompress(&info, buf, len);
|
||||
vfree(buf); /* compressed data is no longer needed */
|
||||
if (err) {
|
||||
mod_stat_inc(&failed_decompress);
|
||||
mod_stat_add_long(len, &invalid_decompress_bytes);
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
info.hdr = buf;
|
||||
info.len = len;
|
||||
}
|
||||
|
||||
return load_module(&info, uargs, flags);
|
||||
f = fdget(fd);
|
||||
err = init_module_from_file(f.file, uargs, flags);
|
||||
fdput(f);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */
|
||||
|
||||
@@ -59,9 +59,7 @@ int dump_ksym(struct bpf_iter__ksym *ctx)
|
||||
} else {
|
||||
BPF_SEQ_PRINTF(seq, "0x%llx %c %s ", value, type, iter->name);
|
||||
}
|
||||
if (!iter->pos_arch_end || iter->pos_arch_end > iter->pos)
|
||||
BPF_SEQ_PRINTF(seq, "CORE ");
|
||||
else if (!iter->pos_mod_end || iter->pos_mod_end > iter->pos)
|
||||
if (!iter->pos_mod_end || iter->pos_mod_end > iter->pos)
|
||||
BPF_SEQ_PRINTF(seq, "MOD ");
|
||||
else if (!iter->pos_ftrace_mod_end || iter->pos_ftrace_mod_end > iter->pos)
|
||||
BPF_SEQ_PRINTF(seq, "FTRACE_MOD ");
|
||||
|
||||
Reference in New Issue
Block a user