Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <180F067D-0E86-479C-942A-E1E9118D3431@digitalocean.com>
Date: Tue, 19 Nov 2019 15:51:52 -0600
From: Tianlin Li <tli@...italocean.com>
To: Kees Cook <keescook@...omium.org>
Cc: kernel-hardening@...ts.openwall.com,
 Steven Rostedt <rostedt@...dmis.org>,
 Ingo Molnar <mingo@...hat.com>,
 Russell King <linux@...linux.org.uk>,
 Catalin Marinas <catalin.marinas@....com>,
 Will Deacon <will@...nel.org>,
 Greentime Hu <green.hu@...il.com>,
 Vincent Chen <deanbo422@...il.com>,
 Thomas Gleixner <tglx@...utronix.de>,
 Borislav Petkov <bp@...en8.de>,
 "H . Peter Anvin" <hpa@...or.com>,
 x86@...nel.org,
 Jessica Yu <jeyu@...nel.org>,
 Josh Poimboeuf <jpoimboe@...hat.com>,
 Jiri Kosina <jikos@...nel.org>,
 Miroslav Benes <mbenes@...e.cz>,
 Petr Mladek <pmladek@...e.com>,
 Joe Lawrence <joe.lawrence@...hat.com>
Subject: Re: [RFC PATCH] kernel/module: have the callers of set_memory_*()
 check the return value


> On Nov 19, 2019, at 11:07 AM, Kees Cook <keescook@...omium.org> wrote:
> 
> On Tue, Nov 19, 2019 at 09:51:49AM -0600, Tianlin Li wrote:
>> Right now several architectures allow their set_memory_*() family of 
>> functions to fail, but callers may not be checking the return values. We 
>> need to fix the callers and add the __must_check attribute. They also may
>> not provide any level of atomicity, in the sense that the memory 
>> protections may be left incomplete on failure. This issue likely has a few 
>> steps on effects architectures[1]:
> 
> Awesome; thanks for working on this!
> 
> A few suggestions on this patch, which will help reviewers, below...
> 
>> 1)Have all callers of set_memory_*() helpers check the return value.
>> 2)Add __much_check to all set_memory_*() helpers so that new uses do not 
>> ignore the return value.
>> 3)Add atomicity to the calls so that the memory protections aren't left in 
>> a partial state.
> 
> Maybe clarify to say something like "this series is step 1”?
ok. Will add the clarification. Thanks!
> 
>> 
>> Ideally, the failure of set_memory_*() should be passed up the call stack, 
>> and callers should examine the failure and deal with it. But currently, 
>> some callers just have void return type.
>> 
>> We need to fix the callers to handle the return all the way to the top of 
>> stack, and it will require a large series of patches to finish all the three 
>> steps mentioned above. I start with kernel/module, and will move onto other 
>> subsystems. I am not entirely sure about the failure modes for each caller. 
>> So I would like to get some comments before I move forward. This single 
>> patch is just for fixing the return value of set_memory_*() function in 
>> kernel/module, and also the related callers. Any feedback would be greatly 
>> appreciated.
>> 
>> [1]:https://github.com/KSPP/linux/issues/7
>> 
>> Signed-off-by: Tianlin Li <tli@...italocean.com>
>> ---
>> arch/arm/kernel/ftrace.c   |   8 +-
>> arch/arm64/kernel/ftrace.c |   6 +-
>> arch/nds32/kernel/ftrace.c |   6 +-
>> arch/x86/kernel/ftrace.c   |  13 ++-
>> include/linux/module.h     |  16 ++--
>> kernel/livepatch/core.c    |  15 +++-
>> kernel/module.c            | 170 +++++++++++++++++++++++++++----------
>> kernel/trace/ftrace.c      |  15 +++-
>> 8 files changed, 175 insertions(+), 74 deletions(-)
> 
> - Can you break this patch into 3 separate patches, by "subsystem":
> 	- ftrace
> 	- module
> 	- livepatch (unless Jessica thinks maybe livepatch should go
> 	  with module?)
> - Please run patches through scripts/checkpatch.pl to catch common
>  coding style issues (e.g. blank line between variable declarations
>  and function body).
> - These changes look pretty straight forward, so I think it'd be fine
>  to drop the "RFC" tag and include linux-kernel@...r.kernel.org <mailto:linux-kernel@...r.kernel.org> in the
>  Cc list for the v2. For lots of detail, see:
>  https://www.kernel.org/doc/html/latest/process/submitting-patches.html <https://www.kernel.org/doc/html/latest/process/submitting-patches.html>

ok. I will fix them in v2. Thanks a lot! 
> More below...
> 
>> 
>> diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
>> index bda949fd84e8..7ea1338821d6 100644
>> --- a/arch/arm/kernel/ftrace.c
>> +++ b/arch/arm/kernel/ftrace.c
>> @@ -59,13 +59,15 @@ static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr)
>> 
>> int ftrace_arch_code_modify_prepare(void)
>> {
>> -	set_all_modules_text_rw();
>> -	return 0;
>> +	return set_all_modules_text_rw();
>> }
>> 
>> int ftrace_arch_code_modify_post_process(void)
>> {
>> -	set_all_modules_text_ro();
>> +	int ret;
> 
> Blank line here...
> 
>> +	ret = set_all_modules_text_ro();
>> +	if (ret)
>> +		return ret;
>> 	/* Make sure any TLB misses during machine stop are cleared. */
>> 	flush_tlb_all();
>> 	return 0;
> 
> Are callers of these ftrace functions checking return values too?
ftrace_arch_code_modify_prepare is called in ftrace_run_update_code and ftrace_module_enable. 
ftrace_run_update_code is checking the return value of ftrace_arch_code_modify_prepare already. 
ftrace_module_enable didn’t check. (I modifies this function in this patch to check the return value of ftrace_arch_code_modify_prepare ). 
Same for ftrace_arch_code_modify_post_process. 

>> diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c
>> index 171773257974..97a89c38f6b9 100644
>> --- a/arch/arm64/kernel/ftrace.c
>> +++ b/arch/arm64/kernel/ftrace.c
>> @@ -115,9 +115,11 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
>> 			}
>> 
>> 			/* point the trampoline to our ftrace entry point */
>> -			module_disable_ro(mod);
>> +			if (module_disable_ro(mod))
>> +				return -EINVAL;
>> 			*dst = trampoline;
>> -			module_enable_ro(mod, true);
>> +			if (module_enable_ro(mod, true))
>> +				return -EINVAL;
>> 
>> 			/*
>> 			 * Ensure updated trampoline is visible to instruction
>> diff --git a/arch/nds32/kernel/ftrace.c b/arch/nds32/kernel/ftrace.c
>> index fd2a54b8cd57..e9e63e703a3e 100644
>> --- a/arch/nds32/kernel/ftrace.c
>> +++ b/arch/nds32/kernel/ftrace.c
>> @@ -91,14 +91,12 @@ int __init ftrace_dyn_arch_init(void)
>> 
>> int ftrace_arch_code_modify_prepare(void)
>> {
>> -	set_all_modules_text_rw();
>> -	return 0;
>> +	return set_all_modules_text_rw();
>> }
>> 
>> int ftrace_arch_code_modify_post_process(void)
>> {
>> -	set_all_modules_text_ro();
>> -	return 0;
>> +	return set_all_modules_text_ro();
>> }
>> 
>> static unsigned long gen_sethi_insn(unsigned long addr)
>> diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
>> index 024c3053dbba..7fdee06e2a76 100644
>> --- a/arch/x86/kernel/ftrace.c
>> +++ b/arch/x86/kernel/ftrace.c
>> @@ -42,19 +42,26 @@ int ftrace_arch_code_modify_prepare(void)
>> 	 * and live kernel patching from changing the text permissions while
>> 	 * ftrace has it set to "read/write".
>> 	 */
>> +	int ret;
>> 	mutex_lock(&text_mutex);
>> 	set_kernel_text_rw();
>> -	set_all_modules_text_rw();
>> +	ret = set_all_modules_text_rw();
>> +	if (ret) {
>> +		set_kernel_text_ro();
> 
> Is the set_kernel_text_ro() here is an atomicity fix? Also, won't a future
> patch need to check the result of that function call? (i.e. should it
> be left out of this series and should atomicity fixes happen inside the
> set_memory_*() functions? Can they happen there?)
set_kernel_text_tro() here was not for an atomicity fix in step 3, it was just for reverting the status 
in ftrace_arch_code_modify_prepare, because set_kernel_text_rw() is called. 
Thanks for pointing it out.  I will check it. 
> 
>> +		mutex_unlock(&text_mutex);
>> +		return ret;
>> +	}
>> 	return 0;
>> }
>> 
>> int ftrace_arch_code_modify_post_process(void)
>>     __releases(&text_mutex)
>> {
>> -	set_all_modules_text_ro();
>> +	int ret;
> 
> blank line needed...
> 
>> +	ret = set_all_modules_text_ro();
>> 	set_kernel_text_ro();
>> 	mutex_unlock(&text_mutex);
>> -	return 0;
>> +	return ret;
>> }
>> 
>> union ftrace_code_union {
>> diff --git a/include/linux/module.h b/include/linux/module.h
>> index 1455812dd325..e6c7f3b719a3 100644
>> --- a/include/linux/module.h
>> +++ b/include/linux/module.h
>> @@ -847,15 +847,15 @@ extern int module_sysfs_initialized;
>> #define __MODULE_STRING(x) __stringify(x)
>> 
>> #ifdef CONFIG_STRICT_MODULE_RWX
>> -extern void set_all_modules_text_rw(void);
>> -extern void set_all_modules_text_ro(void);
>> -extern void module_enable_ro(const struct module *mod, bool after_init);
>> -extern void module_disable_ro(const struct module *mod);
>> +extern int set_all_modules_text_rw(void);
>> +extern int set_all_modules_text_ro(void);
>> +extern int module_enable_ro(const struct module *mod, bool after_init);
>> +extern int module_disable_ro(const struct module *mod);
>> #else
>> -static inline void set_all_modules_text_rw(void) { }
>> -static inline void set_all_modules_text_ro(void) { }
>> -static inline void module_enable_ro(const struct module *mod, bool after_init) { }
>> -static inline void module_disable_ro(const struct module *mod) { }
>> +static inline int set_all_modules_text_rw(void) { return 0; }
>> +static inline int set_all_modules_text_ro(void) { return 0; }
>> +static inline int module_enable_ro(const struct module *mod, bool after_init) { return 0; }
> 
> Please wrap this line (yes, the old one wasn't...)
> 
>> +static inline int module_disable_ro(const struct module *mod) { return 0; }
>> #endif
>> 
>> #ifdef CONFIG_GENERIC_BUG
>> diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
>> index c4ce08f43bd6..39bfc0685854 100644
>> --- a/kernel/livepatch/core.c
>> +++ b/kernel/livepatch/core.c
>> @@ -721,16 +721,25 @@ static int klp_init_object_loaded(struct klp_patch *patch,
>> 
>> 	mutex_lock(&text_mutex);
>> 
>> -	module_disable_ro(patch->mod);
>> +	ret = module_disable_ro(patch->mod);
>> +	if (ret) {
>> +		mutex_unlock(&text_mutex);
>> +		return ret;
>> +	}
>> 	ret = klp_write_object_relocations(patch->mod, obj);
>> 	if (ret) {
>> -		module_enable_ro(patch->mod, true);
>> +		if (module_enable_ro(patch->mod, true));
>> +			pr_err("module_enable_ro failed.\n");
> 
> Why the pr_err() here and not in other failure cases? (Also, should it
> instead be a WARN_ONCE() inside the set_memory_*() functions instead?)
Because module_enable_ro() is called in the checking of another return value. I can not return the value, so I print the error. 
Similar to the previous question, should it be fixed by atomicity patches later? 
> 
>> 		mutex_unlock(&text_mutex);
>> 		return ret;
>> 	}
>> 
>> 	arch_klp_init_object_loaded(patch, obj);
>> -	module_enable_ro(patch->mod, true);
>> +	ret = module_enable_ro(patch->mod, true);
>> +	if (ret) {
>> +		mutex_unlock(&text_mutex);
>> +		return ret;
>> +	}
>> 
>> 	mutex_unlock(&text_mutex);
>> 
>> diff --git a/kernel/module.c b/kernel/module.c
>> index 9ee93421269c..87125b5e315c 100644
>> --- a/kernel/module.c
>> +++ b/kernel/module.c
>> @@ -1900,111 +1900,162 @@ static void mod_sysfs_teardown(struct module *mod)
>>  *
>>  * These values are always page-aligned (as is base)
>>  */
>> -static void frob_text(const struct module_layout *layout,
>> +static int frob_text(const struct module_layout *layout,
>> 		      int (*set_memory)(unsigned long start, int num_pages))
>> {
>> 	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
>> 	BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
>> -	set_memory((unsigned long)layout->base,
>> +	return set_memory((unsigned long)layout->base,
>> 		   layout->text_size >> PAGE_SHIFT);
>> }
>> 
>> #ifdef CONFIG_STRICT_MODULE_RWX
>> -static void frob_rodata(const struct module_layout *layout,
>> +static int frob_rodata(const struct module_layout *layout,
>> 			int (*set_memory)(unsigned long start, int num_pages))
>> {
>> 	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
>> 	BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
>> 	BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
>> -	set_memory((unsigned long)layout->base + layout->text_size,
>> +	return set_memory((unsigned long)layout->base + layout->text_size,
>> 		   (layout->ro_size - layout->text_size) >> PAGE_SHIFT);
>> }
>> 
>> -static void frob_ro_after_init(const struct module_layout *layout,
>> +static int frob_ro_after_init(const struct module_layout *layout,
>> 				int (*set_memory)(unsigned long start, int num_pages))
>> {
>> 	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
>> 	BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
>> 	BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
>> -	set_memory((unsigned long)layout->base + layout->ro_size,
>> +	return set_memory((unsigned long)layout->base + layout->ro_size,
>> 		   (layout->ro_after_init_size - layout->ro_size) >> PAGE_SHIFT);
>> }
>> 
>> -static void frob_writable_data(const struct module_layout *layout,
>> +static int frob_writable_data(const struct module_layout *layout,
>> 			       int (*set_memory)(unsigned long start, int num_pages))
>> {
>> 	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
>> 	BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
>> 	BUG_ON((unsigned long)layout->size & (PAGE_SIZE-1));
>> -	set_memory((unsigned long)layout->base + layout->ro_after_init_size,
>> +	return set_memory((unsigned long)layout->base + layout->ro_after_init_size,
>> 		   (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT);
>> }
>> 
>> /* livepatching wants to disable read-only so it can frob module. */
>> -void module_disable_ro(const struct module *mod)
>> +int module_disable_ro(const struct module *mod)
>> {
>> +	int ret;
>> 	if (!rodata_enabled)
>> -		return;
>> +		return 0;
>> 
>> -	frob_text(&mod->core_layout, set_memory_rw);
>> -	frob_rodata(&mod->core_layout, set_memory_rw);
>> -	frob_ro_after_init(&mod->core_layout, set_memory_rw);
>> -	frob_text(&mod->init_layout, set_memory_rw);
>> -	frob_rodata(&mod->init_layout, set_memory_rw);
>> +	ret = frob_text(&mod->core_layout, set_memory_rw);
>> +	if (ret)
>> +		return ret;
>> +	ret = frob_rodata(&mod->core_layout, set_memory_rw);
>> +	if (ret)
>> +		return ret;
>> +	ret = frob_ro_after_init(&mod->core_layout, set_memory_rw);
>> +	if (ret)
>> +		return ret;
>> +	ret = frob_text(&mod->init_layout, set_memory_rw);
>> +	if (ret)
>> +		return ret;
>> +	ret = frob_rodata(&mod->init_layout, set_memory_rw);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return 0;
>> }
>> 
>> -void module_enable_ro(const struct module *mod, bool after_init)
>> +int module_enable_ro(const struct module *mod, bool after_init)
>> {
>> +	int ret;
>> 	if (!rodata_enabled)
>> -		return;
>> +		return 0;
>> 
>> 	set_vm_flush_reset_perms(mod->core_layout.base);
>> 	set_vm_flush_reset_perms(mod->init_layout.base);
>> -	frob_text(&mod->core_layout, set_memory_ro);
>> +	ret = frob_text(&mod->core_layout, set_memory_ro);
>> +	if (ret)
>> +		return ret;
>> 
>> -	frob_rodata(&mod->core_layout, set_memory_ro);
>> -	frob_text(&mod->init_layout, set_memory_ro);
>> -	frob_rodata(&mod->init_layout, set_memory_ro);
>> +	ret = frob_rodata(&mod->core_layout, set_memory_ro);
>> +	if (ret)
>> +		return ret;
>> +	ret = frob_text(&mod->init_layout, set_memory_ro);
>> +	if (ret)
>> +		return ret;
>> +	ret = frob_rodata(&mod->init_layout, set_memory_ro);
>> +	if (ret)
>> +		return ret;
>> 
>> -	if (after_init)
>> -		frob_ro_after_init(&mod->core_layout, set_memory_ro);
>> +	if (after_init) {
>> +		ret = frob_ro_after_init(&mod->core_layout, set_memory_ro);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +	return 0;
>> }
>> 
>> -static void module_enable_nx(const struct module *mod)
>> +static int module_enable_nx(const struct module *mod)
>> {
>> -	frob_rodata(&mod->core_layout, set_memory_nx);
>> -	frob_ro_after_init(&mod->core_layout, set_memory_nx);
>> -	frob_writable_data(&mod->core_layout, set_memory_nx);
>> -	frob_rodata(&mod->init_layout, set_memory_nx);
>> -	frob_writable_data(&mod->init_layout, set_memory_nx);
>> +	int ret;
>> +
>> +	ret = frob_rodata(&mod->core_layout, set_memory_nx);
>> +	if (ret)
>> +		return ret;
>> +	ret = frob_ro_after_init(&mod->core_layout, set_memory_nx);
>> +	if (ret)
>> +		return ret;
>> +	ret = frob_writable_data(&mod->core_layout, set_memory_nx);
>> +	if (ret)
>> +		return ret;
>> +	ret = frob_rodata(&mod->init_layout, set_memory_nx);
>> +	if (ret)
>> +		return ret;
>> +	ret = frob_writable_data(&mod->init_layout, set_memory_nx);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return 0;
>> }
>> 
>> /* Iterate through all modules and set each module's text as RW */
>> -void set_all_modules_text_rw(void)
>> +int set_all_modules_text_rw(void)
>> {
>> 	struct module *mod;
>> +	int ret;
>> 
>> 	if (!rodata_enabled)
>> -		return;
>> +		return 0;
>> 
>> 	mutex_lock(&module_mutex);
>> 	list_for_each_entry_rcu(mod, &modules, list) {
>> 		if (mod->state == MODULE_STATE_UNFORMED)
>> 			continue;
>> 
>> -		frob_text(&mod->core_layout, set_memory_rw);
>> -		frob_text(&mod->init_layout, set_memory_rw);
>> +		ret = frob_text(&mod->core_layout, set_memory_rw);
>> +		if (ret) {
>> +			mutex_unlock(&module_mutex);
>> +			return ret;
>> +		}
>> +		ret = frob_text(&mod->init_layout, set_memory_rw);
>> +		if (ret) {
>> +			mutex_unlock(&module_mutex);
>> +			return ret;
>> +		}
> 
> This pattern feels like it might be better with a "goto out" style:
> 
> 	mutex_lock...
> 	list_for_each... {
> 		ret = frob_...
> 		if (ret)
> 			goto out;
> 		ret = frob_...
> 		if (ret)
> 			goto out;
> 	}
> 	ret = 0;
> out:
> 	mutex_unlock...
> 	return ret;

Thanks! Will fix it in v2. 
> 
>> 	}
>> 	mutex_unlock(&module_mutex);
>> +	return 0;
>> }
>> 
>> /* Iterate through all modules and set each module's text as RO */
>> -void set_all_modules_text_ro(void)
>> +int set_all_modules_text_ro(void)
>> {
>> 	struct module *mod;
>> +	int ret;
>> 
>> 	if (!rodata_enabled)
>> -		return;
>> +		return 0;
>> 
>> 	mutex_lock(&module_mutex);
>> 	list_for_each_entry_rcu(mod, &modules, list) {
>> @@ -2017,22 +2068,37 @@ void set_all_modules_text_ro(void)
>> 			mod->state == MODULE_STATE_GOING)
>> 			continue;
>> 
>> -		frob_text(&mod->core_layout, set_memory_ro);
>> -		frob_text(&mod->init_layout, set_memory_ro);
>> +		ret = frob_text(&mod->core_layout, set_memory_ro);
>> +		if (ret) {
>> +			mutex_unlock(&module_mutex);
>> +			return ret;
>> +		}
>> +		ret = frob_text(&mod->init_layout, set_memory_ro);
>> +		if (ret) {
>> +			mutex_unlock(&module_mutex);
>> +			return ret;
>> +		}
>> 	}
>> 	mutex_unlock(&module_mutex);
>> +	return 0;
>> }
>> #else /* !CONFIG_STRICT_MODULE_RWX */
>> -static void module_enable_nx(const struct module *mod) { }
>> +static int module_enable_nx(const struct module *mod) { return 0; }
>> #endif /*  CONFIG_STRICT_MODULE_RWX */
>> -static void module_enable_x(const struct module *mod)
>> +static int module_enable_x(const struct module *mod)
>> {
>> -	frob_text(&mod->core_layout, set_memory_x);
>> -	frob_text(&mod->init_layout, set_memory_x);
>> +	int ret;
>> +	ret = frob_text(&mod->core_layout, set_memory_x);
>> +	if (ret)
>> +		return ret;
>> +	ret = frob_text(&mod->init_layout, set_memory_x);
>> +	if (ret)
>> +		return ret;
>> +	return 0;
>> }
>> #else /* !CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
>> -static void module_enable_nx(const struct module *mod) { }
>> -static void module_enable_x(const struct module *mod) { }
>> +static int module_enable_nx(const struct module *mod) { return 0; }
>> +static int module_enable_x(const struct module *mod) { return 0; }
>> #endif /* CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
>> 
>> 
>> @@ -3534,7 +3600,11 @@ static noinline int do_init_module(struct module *mod)
>> 	/* Switch to core kallsyms now init is done: kallsyms may be walking! */
>> 	rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms);
>> #endif
>> -	module_enable_ro(mod, true);
>> +	ret = module_enable_ro(mod, true);
>> +	if (ret) {
>> +		mutex_unlock(&module_mutex);
>> +		goto fail_free_freeinit;
>> +	}
>> 	mod_tree_remove_init(mod);
>> 	module_arch_freeing_init(mod);
>> 	mod->init_layout.base = NULL;
>> @@ -3640,9 +3710,15 @@ static int complete_formation(struct module *mod, struct load_info *info)
>> 	/* This relies on module_mutex for list integrity. */
>> 	module_bug_finalize(info->hdr, info->sechdrs, mod);
>> 
>> -	module_enable_ro(mod, false);
>> -	module_enable_nx(mod);
>> -	module_enable_x(mod);
>> +	err = module_enable_ro(mod, false);
>> +	if (err)
>> +		goto out;
>> +	err = module_enable_nx(mod);
>> +	if (err)
>> +		goto out;
>> +	err = module_enable_x(mod);
>> +	if (err)
>> +		goto out;
>> 
>> 	/* Mark state as coming so strong_try_module_get() ignores us,
>> 	 * but kallsyms etc. can see us. */
>> diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
>> index f9821a3374e9..d4532bb65d1b 100644
>> --- a/kernel/trace/ftrace.c
>> +++ b/kernel/trace/ftrace.c
>> @@ -5814,8 +5814,13 @@ void ftrace_module_enable(struct module *mod)
>> 	 * text to read-only, as we now need to set it back to read-write
>> 	 * so that we can modify the text.
>> 	 */
>> -	if (ftrace_start_up)
>> -		ftrace_arch_code_modify_prepare();
>> +	if (ftrace_start_up) {
>> +		int ret = ftrace_arch_code_modify_prepare();
>> +		if (ret) {
>> +			FTRACE_WARN_ON(ret);
>> +			goto out_unlock;
>> +		}
> 
> Can FTRACE_WARN_ON() be used in an "if" like WARN_ON? This could maybe
> look like:
> 
> 	ret = ftrace_arch...
> 	if (FTRACE_WARN_ON(ret))
> 		goto out_unlock
> 
> Though I not this doesn't result in an error getting passed up? i.e.
> ftrace_module_enable() is still "void". Does that matter here?
Thanks. I will fix it in v2. 

>> +	}
>> 
>> 	do_for_each_ftrace_rec(pg, rec) {
>> 		int cnt;
>> @@ -5854,8 +5859,10 @@ void ftrace_module_enable(struct module *mod)
>> 	} while_for_each_ftrace_rec();
>> 
>>  out_loop:
>> -	if (ftrace_start_up)
>> -		ftrace_arch_code_modify_post_process();
>> +	if (ftrace_start_up) {
>> +		int ret = ftrace_arch_code_modify_post_process();
>> +		FTRACE_WARN_ON(ret);
>> +	}
>> 
>>  out_unlock:
>> 	mutex_unlock(&ftrace_lock);
>> -- 
>> 2.17.1
>> 
> 
> Thanks,
Thanks for all detail suggestions! 
> -- 
> Kees Cook


Content of type "text/html" skipped

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.