linux-perf-users.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Namhyung Kim <namhyung@kernel.org>
To: sashiko-reviews@lists.linux.dev
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v2 06/10] perf tools: Factor out dso__find_binary_type()
Date: Fri, 9 Oct 2026 23:17:31 -0700	[thread overview]
Message-ID: <asnYe2GTSVTItnkd@z2> (raw)
In-Reply-To: <sashiko-outbox-162548@kernel.org>

On Wed, Oct 07, 2026 at 12:04:51AM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
> - [High] perf: Guest kernel modules fail to open due to hardcoded root_dir
> - [High] perf: Strict .text section check breaks data-only DSOs and NO_LIBELF builds
> - [High] perf: Concurrent Read-Modify-Write data race on struct dso bitfields
> - [High] perf: Use-After-Free of dso->nsinfo in __dso__find_binary_type due to missing dso__lock
> - [Medium] perf: Explicitly resolved binary types are unconditionally overwritten
> - [Medium] perf: Bypassing do_open() permanently caches EMFILE failures as NOT_FOUND
> - [Low] perf: Redundant double decompression of compressed kernel modules
> --
> 
> commit 8b41de1355b0e2f1d37b604c80238237fc833f0f
> Author: Namhyung Kim <namhyung@kernel.org>
> 
> perf tools: Factor out dso__find_binary_type()
> 
> Separate out the logic to detect binary type of a DSO.  It checks if the
> candidate file contains ".text" section.  It should be called under the
> _dso__data_open_lock.
> 
> Introduce bintype_searched flag and it accessors to prevent repeated
> (failed) search.
> 
> > diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
> > index 913877b84b2d4..f5054c18a2e93 100644
> > --- a/tools/perf/util/dso.c
> > +++ b/tools/perf/util/dso.c
> > @@ -833,7 +833,7 @@ void dso__data_close(struct dso *dso)
> >  	mutex_unlock(dso__data_open_lock());
> >  }
> >  
> > -static void try_to_open_dso(struct dso *dso, struct machine *machine)
> > +static enum dso_binary_type __dso__find_binary_type(struct dso *dso)
> >  	EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
> >  {
> >  	enum dso_binary_type binary_type_data[] = {
> > @@ -842,25 +842,103 @@ static void try_to_open_dso(struct dso *dso, struct machine *machine)
> >  		DSO_BINARY_TYPE__NOT_FOUND,
> >  	};
> >  	int i = 0;
> > -	struct dso_data *dso_data = dso__data(dso);
> > +	char *path;
> > +	bool found = false;
> > +	bool decomp = false;
> >  
> > -	if (dso_data->fd >= 0)
> > -		return;
> > +	if (dso__bintype_searched(dso))
> > +		return dso__binary_type(dso);
> > +	dso__set_bintype_searched(dso);
> 
> [Severity: High]
> Does this code introduce a data race on the struct dso bitfields?
> 
> The dso__set_bintype_searched() function modifies the bintype_searched
> bitfield under the global _dso__data_open_lock. However, adjacent bitfields
> like debuginfo_searched and long_name_allocated share the same memory
> location and are modified under different locks (dso__lock(dso) and
> dsos->lock).
> 
> Concurrent execution could cause compiler-generated read-modify-write
> operations to overlap, resulting in dropped flags or memory leaks if
> long_name_allocated is clobbered.

I was hoping it was fine just to grab _dso__data_open_lock but it seems
it should take dso__lock anyway.  I'll update the code.

> 
> [ ... ]
> 
> > +	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
> > +	case DSO_BINARY_TYPE__BUILD_ID_CACHE:
> > +		/* We don't expect these are set; fall through */
> > +	case DSO_BINARY_TYPE__NOT_FOUND:
> > +		/* Let's find it out (for user DSOs or kernel modules) */
> > +		break;
> 
> [Severity: Medium]
> Does this fall-through discard valid binary types that have already been
> resolved elsewhere in the system?
> 
> When symbol.c successfully resolves and sets the binary type (such as
> DSO_BINARY_TYPE__SYSTEM_PATH_DSO or DSO_BINARY_TYPE__BUILD_ID_CACHE),
> this switch statement deliberately falls through. The loop below then
> unconditionally overwrites the previously valid binary type.

As I said in the comment, I don't expect for user binaries and kernel
modules to set the binary_type before this function - I'll remove one
in the dso__load() later in this series as it may not be correct.

> 
> If the fallback types lack a .text section (such as data-only DSOs), the
> state is permanently left as NOT_FOUND, preventing perf from reading them.

I'm not sure if we have a use case to access contents of data-only DSOs.
If so, I can add a check for ".data" section later.

> 
> [ ... ]
> 
> >  	do {
> >  		dso__set_binary_type(dso, binary_type_data[i++]);
> >  
> > -		dso_data->fd = open_dso(dso, machine);
> > -		if (dso_data->fd >= 0)
> > -			goto out;
> > +		path = dso__get_filename(dso, "", &decomp, dso__binary_type(dso));
> 
> [Severity: High]
> Does hardcoding the root directory to an empty string break path resolution
> for guest kernel modules?
> 
> When the fallback logic looks up types like DSO_BINARY_TYPE__GUEST_KMODULE,
> it passes "" to dso__get_filename() instead of machine->root_dir.
> 
> This causes dso__get_filename() to construct an invalid path missing the
> guest's root directory. The file cannot be found, filename__has_section()
> fails, and subsequent calls to open_dso() will fail.

This is another concern.  IMHO we handle guest samples poorly and
there's no good way to access to the guest DSOs.  Only perf kvm command
has options to access to the guest mount directory where it assumes
sshfs is available under a pid for the VMM that controls the guest.

This code is not touched for a while, and I doubt if there are any
users.  We need a better way to track guest info.

Until then, I don't want to make the APIs complex unnecessarily and just
use the hard-coded empty root directory for now.

> 
> [Severity: High]
> Does calling dso__get_filename() without holding dso__lock(dso) cause a
> use-after-free of dso->nsinfo?
> 
> The new __dso__find_binary_type() helper executes with only the global
> _dso__data_open_lock held. It calls dso__get_filename(), which invokes
> dso__filename_with_chroot() and dereferences dso->nsinfo to read the
> process ID.
> 
> Concurrently, another thread could call dso__set_nsinfo() (which acquires
> dso__lock(dso)), replacing the nsinfo pointer and freeing the old one via
> nsinfo__put(). Since this read path ignores dso__lock(dso), it can read
> the freed pointer.

Ack, will grab the dso lock.

> 
> > +		if (path == NULL)
> > +			continue;
> > +
> > +		found = filename__has_section(path, ".text");
> 
> [Severity: High]
> Does this strict .text section check break data-only DSOs and NO_LIBELF
> builds?
> 
> Prior to this patch, try_to_open_dso() discovered the DSO by calling
> open_dso(). If the file existed and was readable, the open succeeded. This
> patch introduces a strict requirement that a DSO must contain a .text
> section.
> 
> Perf commonly profiles memory data accesses (like perf mem or perf c2c)
> hitting data-only DSOs. For these files, filename__has_section() evaluates
> to false, forcing the binary type to NOT_FOUND. Furthermore, if perf is
> compiled without libelf (NO_LIBELF=1), filename__has_section() is stubbed
> to unconditionally return false, breaking user DSO loading entirely.

As I said in another reply, I think it's ok to ignore data-only DSOs.

For NO_LIBELF=1 case, it didn't implement symbol loading.  So I don't
think it'd need binary data access for a DSO.  Since the primary use
case is perf annotate which works for symbols, I think it's ok not to
implement filename__has_section() in util/symbol-minimal.c

But it'd be not so hard to do it anyway.  We can add it later if it's
really needed.

> 
> [Severity: Medium]
> Can this bypass of do_open() permanently cache EMFILE failures as NOT_FOUND?
> 
> The filename__has_section() function uses a raw open() without the FD limit
> (EMFILE) handling and LRU eviction logic normally provided by do_open() and
> close_first_dso().
> 
> If perf hits RLIMIT_NOFILE, open() returns -1, and filename__has_section()
> silently returns false. __dso__find_binary_type() then assumes the binary
> is invalid, sets bintype_searched = 1, and permanently caches
> DSO_BINARY_TYPE__NOT_FOUND, breaking data access to the DSO for the rest
> of the execution.

Good point.  Maybe it need to save the errno and restore it before
return from filename__has_section().  Then the caller can check the
errno and retry as it can be called from dso__data_get_fd().

> 
> [ ... ]
> 
> > +static void try_to_open_dso(struct dso *dso, struct machine *machine)
> > +	EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
> > +{
> > +	struct dso_data *dso_data = dso__data(dso);
> > +
> > +	if (dso_data->fd >= 0)
> > +		return;
> > +
> > +	__dso__find_binary_type(dso);
> > +	dso_data->fd = open_dso(dso, machine);
> 
> [Severity: Low]
> Does this result in redundant double decompression of compressed kernel
> modules?
> 
> The call to dso__get_filename() in __dso__find_binary_type() decompresses
> a compressed kernel module to a temporary file. After checking for a .text
> section, dso__put_filename() unlinks this temporary file.
> 
> Immediately after returning, try_to_open_dso() calls open_dso(), which
> ultimately calls dso__get_filename() again, forcing a second decompression
> of the exact same kernel module.

Yep, but __dso__find_binary_type() would run only once.

Thanks,
Namhyung

> 
> -- 
> Sashiko AI review · https://sashiko.dev/#/patchset/20261006234315.920817-1-namhyung@kernel.org?part=6

  reply	other threads:[~2026-10-10  6:17 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-06 23:43 [PATCH v2 00/10] perf symbol: Properly set DSO binary/symtab types Namhyung Kim
2026-10-06 23:43 ` [PATCH v2 01/10] perf tools: Remove redundant dso data init Namhyung Kim
2026-10-06 23:49   ` sashiko-bot
2026-10-06 23:43 ` [PATCH v2 02/10] perf tools: Try linked debug files for DSO debug info Namhyung Kim
2026-10-06 23:54   ` sashiko-bot
2026-10-10  5:38     ` Namhyung Kim
2026-10-06 23:43 ` [PATCH v2 03/10] perf symbol: Update symtab type of vmlinux from build-id cache Namhyung Kim
2026-10-06 23:54   ` sashiko-bot
2026-10-06 23:43 ` [PATCH v2 04/10] perf symbol: Set binary/symtab type for split kallsyms Namhyung Kim
2026-10-06 23:58   ` sashiko-bot
2026-10-10  5:42     ` Namhyung Kim
2026-10-06 23:43 ` [PATCH v2 05/10] perf symbol: Set dso symtab type for libbfd Namhyung Kim
2026-10-06 23:57   ` sashiko-bot
2026-10-10  5:49     ` Namhyung Kim
2026-10-06 23:43 ` [PATCH v2 06/10] perf tools: Factor out dso__find_binary_type() Namhyung Kim
2026-10-07  0:04   ` sashiko-bot
2026-10-10  6:17     ` Namhyung Kim [this message]
2026-10-06 23:43 ` [PATCH v2 07/10] perf symbol: Set binary type for JIT map DSOs Namhyung Kim
2026-10-06 23:51   ` sashiko-bot
2026-10-06 23:43 ` [PATCH v2 08/10] perf symbol: Do not set binary type from symtab type Namhyung Kim
2026-10-06 23:57   ` sashiko-bot
2026-10-10  6:41     ` Namhyung Kim
2026-10-06 23:43 ` [PATCH v2 09/10] perf annotate: Simplify symbol__disassemble() with dso binary_type Namhyung Kim
2026-10-07  0:01   ` sashiko-bot
2026-10-10  6:47     ` Namhyung Kim
2026-10-06 23:43 ` [PATCH v2 10/10] perf test: Fix dso data tests Namhyung Kim
2026-10-06 23:59   ` sashiko-bot
2026-10-10  6:48     ` Namhyung Kim

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=asnYe2GTSVTItnkd@z2 \
    --to=namhyung@kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).