lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <354f6b41-83d1-4496-aec8-764c205990e1@huaweicloud.com>
Date: Wed, 20 Aug 2025 16:34:46 +0800
From: Tengda Wu <wutengda@...weicloud.com>
To: Steven Rostedt <rostedt@...dmis.org>
Cc: Masami Hiramatsu <mhiramat@...nel.org>,
 Mark Rutland <mark.rutland@....com>,
 Mathieu Desnoyers <mathieu.desnoyers@...icios.com>,
 linux-trace-kernel@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH -next 2/2] ftrace: Fix potential use-after-free for
 set_ftrace_{notrace,filter} files



On 2025/8/20 9:05, Steven Rostedt wrote:
> On Wed, 13 Aug 2025 02:30:44 +0000
> Tengda Wu <wutengda@...weicloud.com> wrote:
> 
> 
>> Since the reader's hash is always tied to its file descriptor (fd),
>> the writer cannot directly manage the reader's hash. To fix this,
>> introduce a refcount for ftrace_hash, initialized to 1. The count
>> is incremented only when a reader opens it, and decremented when
>> either a reader or writer releases it, thereby controlling the timing
>> of ftrace_hash deallocation.
> 
> Hmm, I think the code that the first patch touches is the issue here too.
> 
> Instead of doing all these extra hacks, we should simply copy the hash for
> read too.
> 
> That is, the real fix for both patches is this:
> 
> -- Steve
> 
> From: Steven Rostedt <rostedt@...dmis.org>
> Subject: [PATCH] ftrace: Also allocate hash for reading of filter files
> 
> Currently the reader of set_ftrace_filter and set_ftrace_notrace just adds
> the pointer to the global tracer hash to its iterator. Unlike the writer
> that allocates a copy of the hash, the reader keeps the pointer to the
> filter hashes. This is problematic because this pointer is static across
> function calls that release the locks that can update the global tracer
> hashes. This can cause UAF and similar bugs.
> 
> Allocate the hash for reading the filter files like it is done for the
> writers. This not only fixes UAF bugs, but also makes the code a bit
> simpler as it doesn't have to differentiate when to free the iterator's
> hash between writers and readers.

Agreed. That is a much cleaner solution. I just tested this code and it
worked perfectly. Looking forward to getting it into the mainline soon.

-- Tengda

> 
> Cc: stable@...r.kernel.org
> Fixes: c20489dad156 ("ftrace: Assign iter->hash to filter or notrace hashes on seq read")
> Closes: https://lore.kernel.org/all/20250813023044.2121943-1-wutengda@huaweicloud.com/
> Reported-by: Tengda Wu <wutengda@...weicloud.com>
> Signed-off-by: Steven Rostedt (Google) <rostedt@...dmis.org>
> ---
>  kernel/trace/ftrace.c | 16 +++++++---------
>  1 file changed, 7 insertions(+), 9 deletions(-)
> 
> diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> index 00b76d450a89..f992a5eb878e 100644
> --- a/kernel/trace/ftrace.c
> +++ b/kernel/trace/ftrace.c
> @@ -4661,13 +4661,14 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
>  	        } else {
>  			iter->hash = alloc_and_copy_ftrace_hash(size_bits, hash);
>  		}
> +	} else {
> +		iter->hash = alloc_and_copy_ftrace_hash(hash->size_bits, hash);
> +	}
>  
> -		if (!iter->hash) {
> -			trace_parser_put(&iter->parser);
> -			goto out_unlock;
> -		}
> -	} else
> -		iter->hash = hash;
> +	if (!iter->hash) {
> +		trace_parser_put(&iter->parser);
> +		goto out_unlock;
> +	}
>  
>  	ret = 0;
>  
> @@ -6543,9 +6544,6 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
>  		ftrace_hash_move_and_update_ops(iter->ops, orig_hash,
>  						      iter->hash, filter_hash);
>  		mutex_unlock(&ftrace_lock);
> -	} else {
> -		/* For read only, the hash is the ops hash */
> -		iter->hash = NULL;
>  	}
>  
>  	mutex_unlock(&iter->ops->func_hash->regex_lock);


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ