Skip to content

Conversation

@kernel-patches-daemon-bpf
Copy link

Pull request for series with
subject: kallsyms: Prevent invalid access when showing module buildid
version: 1
url: https://patchwork.kernel.org/project/netdevbpf/list/?series=1019899

@kernel-patches-daemon-bpf
Copy link
Author

Upstream branch: 4cb4897
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1019899
version: 1

@kernel-patches-review-bot
Copy link

commit d094bb95fa49daf320295876b997d7dbcfcbb7ef
Author: Petr Mladek <[email protected]>

kallsyms: Cleanup code for appending the module buildid

Put the code for appending the optional "buildid" into a helper
function, It makes __sprint_symbol() better readable.

Also print a warning when the "modname" is set and the "buildid" isn't.
It might catch a situation when some lookup function in
kallsyms_lookup_buildid() does not handle the "buildid".

Use pr_*_once() to avoid an infinite recursion when the function is
called from printk(). The recursion is rather theoretical but better be
on the safe side.

> diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
> index 1e7635864..9455e3bb0 100644
> --- a/kernel/kallsyms.c
> +++ b/kernel/kallsyms.c
> @@ -423,6 +423,37 @@ int lookup_symbol_name(unsigned long addr, char *symname)
>  	return lookup_module_symbol_name(addr, symname);
>  }
>
> +#ifdef CONFIG_STACKTRACE_BUILD_ID
> +
> +static int append_buildid(char *buffer,  const char *modname,
> +			  const unsigned char *buildid)
> +{
> +	if (!modname)
> +		return 0;
> +
> +	if (!buildid) {
> +		pr_warn_once("Undefined buildid for the module %s\n", modname);
> +		return 0;
> +	}

When ftrace_mod_address_lookup() succeeds in kallsyms_lookup_buildid(),
it sets *modname but doesn't initialize *modbuildid. This leaves the
buildid variable uninitialized when __sprint_symbol() calls
append_buildid(). Can the check above read uninitialized memory?

Looking at kallsyms_lookup_buildid():
- module_address_lookup() properly initializes both modname and
  modbuildid
- bpf_address_lookup() sets modname=NULL (so append_buildid isn't
  called)
- ftrace_mod_address_lookup() sets modname=mod_map->mod->name but has
  no modbuildid parameter

The commit message mentions wanting to catch when lookup functions don't
handle buildid, but shouldn't kallsyms_lookup_buildid() initialize
*modbuildid=NULL before calling the lookup functions to avoid undefined
behavior?

> +
> +	/* build ID should match length of sprintf */
> +#ifdef CONFIG_MODULES
> +	static_assert(sizeof(typeof_member(struct module, build_id)) == 20);
> +#endif
> +
> +	return sprintf(buffer, " %20phN", buildid);
> +}

[ ... ]

> @@ -445,15 +476,8 @@ static int __sprint_symbol(char *buffer, unsigned long address,
>
>  	if (modname) {
>  		len += sprintf(buffer + len, " [%s", modname);
> -#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
> -		if (add_buildid && buildid) {
> -			/* build ID should match length of sprintf */
> -#if IS_ENABLED(CONFIG_MODULES)
> -			static_assert(sizeof(typeof_member(struct module, build_id)) == 20);
> -#endif
> -			len += sprintf(buffer + len, " %20phN", buildid);
> -		}
> -#endif
> +		if (add_buildid)
> +			len += append_buildid(buffer + len, modname, buildid);
>  		len += sprintf(buffer + len, "]");
>  	}



AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

In-Reply-To-Subject: kallsyms: Cleanup code for appending the module buildid
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/19105560191

@kernel-patches-daemon-bpf
Copy link
Author

Forwarding comment 3491665677 via email
In-Reply-To: [email protected]
Patch: https://patchwork.kernel.org/project/netdevbpf/patch/[email protected]/

@kernel-patches-daemon-bpf
Copy link
Author

Upstream branch: 4cb4897
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1019899
version: 1

@kernel-patches-daemon-bpf
Copy link
Author

Upstream branch: b54a8e1
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1019899
version: 1

Add a helper function for reading the optional "build_id" member
of struct module. It is going to be used also in
ftrace_mod_address_lookup().

Use "#ifdef" instead of "#if IS_ENABLED()" to match the declaration
of the optional field in struct module.

Signed-off-by: Petr Mladek <[email protected]>
Reviewed-by: Petr Pavlu <[email protected]>
Put the code for appending the optional "buildid" into a helper
function, It makes __sprint_symbol() better readable.

Also print a warning when the "modname" is set and the "buildid" isn't.
It might catch a situation when some lookup function in
kallsyms_lookup_buildid() does not handle the "buildid".

Use pr_*_once() to avoid an infinite recursion when the function
is called from printk(). The recursion is rather theoretical but
better be on the safe side.

Signed-off-by: Petr Mladek <[email protected]>
Make bpf_address_lookup() compatible with module_address_lookup()
and clear the pointer to @modbuildid together with @modname.

It is not strictly needed because __sprint_symbol() reads @modbuildid
only when @modname is set. But better be on the safe side and make
the API more safe.

Fixes: 9294523 ("module: add printk formats to add module build ID to stacktraces")
Signed-off-by: Petr Mladek <[email protected]>
@kernel-patches-daemon-bpf
Copy link
Author

Upstream branch: b54a8e1
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1019899
version: 1

__sprint_symbol() might access an invalid pointer when
kallsyms_lookup_buildid() returns a symbol found by
ftrace_mod_address_lookup().

The ftrace lookup function must set both @modname and @modbuildid
the same way as module_address_lookup().

Fixes: 9294523 ("module: add printk formats to add module build ID to stacktraces")
Signed-off-by: Petr Mladek <[email protected]>
Acked-by: Steven Rostedt (Google) <[email protected]>
The function kallsyms_lookup_buildid() initializes the given @namebuf
by clearing the first and the last byte. It is not clear why.

The 1st byte makes sense because some callers ignore the return code
and expect that the buffer contains a valid string, for example:

  - function_stat_show()
    - kallsyms_lookup()
      - kallsyms_lookup_buildid()

The initialization of the last byte does not make much sense because it
can later be overwritten. Fortunately, it seems that all called
functions behave correctly:

  -  kallsyms_expand_symbol() explicitly adds the trailing '\0'
     at the end of the function.

  - All *__address_lookup() functions either use the safe strscpy()
    or they do not touch the buffer at all.

Document the reason for clearing the first byte. And remove the useless
initialization of the last byte.

Signed-off-by: Petr Mladek <[email protected]>
kallsyms_lookup_buildid() copies the symbol name into the given buffer
so that it can be safely read anytime later. But it just copies pointers
to mod->name and mod->build_id which might get reused after the related
struct module gets removed.

The lifetime of struct module is synchronized using RCU. Take the rcu
read lock for the entire __sprint_symbol().

Signed-off-by: Petr Mladek <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants