Unverified Commit df1193cd authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!9259 Fix CVE-2024-38588

Merge Pull Request from: @ci-robot 
 
PR sync from: Zheng Yejian <zhengyejian1@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/REHL2CIU22M6MYYP3JTT4G2QZ5JI6EON/ 
Linus Torvalds (1):
  ftrace: Store the order of pages allocated in ftrace_page

Zheng Yejian (2):
  ftrace: Fix possible warning on checking all pages used in
    ftrace_process_locs()
  ftrace: Fix possible use-after-free issue in ftrace_location()


-- 
2.25.1
 
https://gitee.com/src-openeuler/kernel/issues/IA6S5H 
 
Link:https://gitee.com/openeuler/kernel/pulls/9259

 

Reviewed-by: default avatarXu Kuohai <xukuohai@huawei.com>
Reviewed-by: default avatarYe Weihua <yeweihua4@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents edfa8c5c 41eab5bf
Loading
Loading
Loading
Loading
+58 −32
Original line number Diff line number Diff line
@@ -1092,7 +1092,7 @@ struct ftrace_page {
	struct ftrace_page	*next;
	struct dyn_ftrace	*records;
	int			index;
	int			size;
	int			order;
};

#define ENTRY_SIZE sizeof(struct dyn_ftrace)
@@ -1566,12 +1566,15 @@ static struct dyn_ftrace *lookup_rec(unsigned long start, unsigned long end)
unsigned long ftrace_location_range(unsigned long start, unsigned long end)
{
	struct dyn_ftrace *rec;
	unsigned long ip = 0;

	rcu_read_lock();
	rec = lookup_rec(start, end);
	if (rec)
		return rec->ip;
		ip = rec->ip;
	rcu_read_unlock();

	return 0;
	return ip;
}

/**
@@ -3188,7 +3191,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count)
	ftrace_number_of_groups++;

	cnt = (PAGE_SIZE << order) / ENTRY_SIZE;
	pg->size = cnt;
	pg->order = order;

	if (cnt > count)
		cnt = count;
@@ -3196,12 +3199,27 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count)
	return cnt;
}

static void ftrace_free_pages(struct ftrace_page *pages)
{
	struct ftrace_page *pg = pages;

	while (pg) {
		if (pg->records) {
			free_pages((unsigned long)pg->records, pg->order);
			ftrace_number_of_pages -= 1 << pg->order;
		}
		pages = pg->next;
		kfree(pg);
		pg = pages;
		ftrace_number_of_groups--;
	}
}

static struct ftrace_page *
ftrace_allocate_pages(unsigned long num_to_init)
{
	struct ftrace_page *start_pg;
	struct ftrace_page *pg;
	int order;
	int cnt;

	if (!num_to_init)
@@ -3235,17 +3253,7 @@ ftrace_allocate_pages(unsigned long num_to_init)
	return start_pg;

 free_pages:
	pg = start_pg;
	while (pg) {
		order = get_count_order(pg->size / ENTRIES_PER_PAGE);
		if (order >= 0)
			free_pages((unsigned long)pg->records, order);
		start_pg = pg->next;
		kfree(pg);
		pg = start_pg;
		ftrace_number_of_pages -= 1 << order;
		ftrace_number_of_groups--;
	}
	ftrace_free_pages(start_pg);
	pr_info("ftrace: FAILED to allocate memory for functions\n");
	return NULL;
}
@@ -6191,9 +6199,11 @@ static int ftrace_process_locs(struct module *mod,
			       unsigned long *start,
			       unsigned long *end)
{
	struct ftrace_page *pg_unuse = NULL;
	struct ftrace_page *start_pg;
	struct ftrace_page *pg;
	struct dyn_ftrace *rec;
	unsigned long skipped = 0;
	unsigned long count;
	unsigned long *p;
	unsigned long addr;
@@ -6239,6 +6249,7 @@ static int ftrace_process_locs(struct module *mod,
	p = start;
	pg = start_pg;
	while (p < end) {
		unsigned long end_offset;
		addr = ftrace_call_adjust(*p++);
		/*
		 * Some architecture linkers will pad between
@@ -6246,10 +6257,13 @@ static int ftrace_process_locs(struct module *mod,
		 * object files to satisfy alignments.
		 * Skip any NULL pointers.
		 */
		if (!addr)
		if (!addr) {
			skipped++;
			continue;
		}

		if (pg->index == pg->size) {
		end_offset = (pg->index+1) * sizeof(pg->records[0]);
		if (end_offset > PAGE_SIZE << pg->order) {
			/* We should have allocated enough */
			if (WARN_ON(!pg->next))
				break;
@@ -6260,8 +6274,10 @@ static int ftrace_process_locs(struct module *mod,
		rec->ip = addr;
	}

	/* We should have used all pages */
	WARN_ON(pg->next);
	if (pg->next) {
		pg_unuse = pg->next;
		pg->next = NULL;
	}

	/* Assign the last page to ftrace_pages */
	ftrace_pages = pg;
@@ -6283,6 +6299,13 @@ static int ftrace_process_locs(struct module *mod,
 out:
	mutex_unlock(&ftrace_lock);

	/* We should have used all pages unless we skipped some */
	if (pg_unuse) {
		WARN_ON(!skipped);
		/* Need to synchronize with ftrace_location_range() */
		synchronize_rcu();
		ftrace_free_pages(pg_unuse);
	}
	return ret;
}

@@ -6418,7 +6441,6 @@ void ftrace_release_mod(struct module *mod)
	struct ftrace_page **last_pg;
	struct ftrace_page *tmp_page = NULL;
	struct ftrace_page *pg;
	int order;

	mutex_lock(&ftrace_lock);

@@ -6464,17 +6486,20 @@ void ftrace_release_mod(struct module *mod)
 out_unlock:
	mutex_unlock(&ftrace_lock);

	/* Need to synchronize with ftrace_location_range() */
	if (tmp_page)
		synchronize_rcu();
	for (pg = tmp_page; pg; pg = tmp_page) {

		/* Needs to be called outside of ftrace_lock */
		clear_mod_from_hashes(pg);

		order = get_count_order(pg->size / ENTRIES_PER_PAGE);
		if (order >= 0)
			free_pages((unsigned long)pg->records, order);
		if (pg->records) {
			free_pages((unsigned long)pg->records, pg->order);
			ftrace_number_of_pages -= 1 << pg->order;
		}
		tmp_page = pg->next;
		kfree(pg);
		ftrace_number_of_pages -= 1 << order;
		ftrace_number_of_groups--;
	}
}
@@ -6786,13 +6811,13 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
	unsigned long start = (unsigned long)(start_ptr);
	unsigned long end = (unsigned long)(end_ptr);
	struct ftrace_page **last_pg = &ftrace_pages_start;
	struct ftrace_page *tmp_page = NULL;
	struct ftrace_page *pg;
	struct dyn_ftrace *rec;
	struct dyn_ftrace key;
	struct ftrace_mod_map *mod_map = NULL;
	struct ftrace_init_func *func, *func_next;
	struct list_head clear_hash;
	int order;

	INIT_LIST_HEAD(&clear_hash);

@@ -6830,12 +6855,8 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
		ftrace_update_tot_cnt--;
		if (!pg->index) {
			*last_pg = pg->next;
			order = get_count_order(pg->size / ENTRIES_PER_PAGE);
			if (order >= 0)
				free_pages((unsigned long)pg->records, order);
			ftrace_number_of_pages -= 1 << order;
			ftrace_number_of_groups--;
			kfree(pg);
			pg->next = tmp_page;
			tmp_page = pg;
			pg = container_of(last_pg, struct ftrace_page, next);
			if (!(*last_pg))
				ftrace_pages = pg;
@@ -6852,6 +6873,11 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
		clear_func_from_hashes(func);
		kfree(func);
	}
	/* Need to synchronize with ftrace_location_range() */
	if (tmp_page) {
		synchronize_rcu();
		ftrace_free_pages(tmp_page);
	}
}

void __init ftrace_free_init_mem(void)