Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20240723225340.GU10433@brightrain.aerifal.cx>
Date: Tue, 23 Jul 2024 18:53:41 -0400
From: Rich Felker <dalias@...c.org>
To: Markus Mayer <mmayer@...adcom.com>,
	Musl Mailing List <musl@...ts.openwall.com>,
	Colin Cross <ccross@...roid.com>, Colin Cross <ccross@...gle.com>
Subject: Re: [PATCH 1/1] Ignore incorrect elf architecture libraries

On Tue, Jul 23, 2024 at 11:08:49PM +0200, Szabolcs Nagy wrote:
> * Markus Mayer <mmayer@...adcom.com> [2024-07-05 14:12:28 -0700]:
> > From: Colin Cross <ccross@...roid.com>
> > 
> > In multilib systems LD_LIBRARY_PATH is sometimes set to a list that
> > contains both the lib32 and lib64 directories, for example when
> > running code that may execute 32-bit or 64-bit subprocesses or both.
> > Musl's dynamic loader aborts searching a path list when it finds any
> > library that is not loadable, preventing searching the other multilib
> > directory.
> > 
> > Modify the loader to continue searching when a file is found that is
> > a valid elf file but for the an elf machine or class that differs from
> > that of the loader itself.
> 
> fwiw i think the proposed feature is reasonable, i added review
> comments that may help inclusion into musl.
> 
> 
> i'd note that skipping wrong e_machine and e_ident[EI_CLASS] is
> required by the elf spec:
> 
>  When the dynamic linker is searching for shared objects, it is
>  not a fatal error if an ELF file with the wrong attributes is
>  encountered in the search. Instead, the dynamic linker shall
>  exhaust the search of all paths before determining that a
>  matching object could not be found. For this determination, the
>  relevant attributes are contained in the following ELF header
>  fields: e_ident[EI_DATA], e_ident[EI_CLASS], e_ident[EI_OSABI],
>  e_ident[EI_ABIVERSION], e_machine, e_type, e_flags and e_version.
> 
> if we do this change i think e_ident[EI_DATA] should be checked
> too for le/be and e_flags for abi variants like arm hf.
> 
> e_type, e_version, EI_OSABI and EI_ABIVERSION are unlikely to be
> useful (the latter may be used in the future to bump musl abi)
> i don't have a strong opinion about these.
> 
> https://www.sco.com/developers/gabi/latest/ch5.dynamic.html#shobj_dependencies

FWIW we don't necessarily follow everything in this spec (it's not one
of the ones we claim conformance to), but yes it can be a good model
for how to do things.

> > ---
> >  ldso/dynlink.c | 77 +++++++++++++++++++++++++++++++++++++++-----------
> >  1 file changed, 61 insertions(+), 16 deletions(-)
> > 
> > diff --git a/ldso/dynlink.c b/ldso/dynlink.c
> > index 324aa85919f0..2f1ac7e9d089 100644
> > --- a/ldso/dynlink.c
> > +++ b/ldso/dynlink.c
> > @@ -68,6 +68,8 @@ struct dso {
> >  	size_t *dynv;
> >  	struct dso *next, *prev;
> >  
> > +	int elfmachine;
> > +	int elfclass;
> 
> i don't think we need this in every dso. i'd make them global
> 
> e.g. ldso_ehdr (or just the ldso_e_machine and ldso_e_class)

Yes, let's avoid size creep for struct dso.

> >  	phsize = eh->e_phentsize * eh->e_phnum;
> >  	if (phsize > sizeof buf - sizeof *eh) {
> >  		allocated_buf = malloc(phsize);
> > @@ -870,29 +889,53 @@ error:
> >  	return 0;
> >  }
> >  
> > -static int path_open(const char *name, const char *s, char *buf, size_t buf_size)
> > +static int path_open_library(const char *name, const char *s, char *buf, size_t buf_size)
> 
> no need to rename.

IIRC at one point it was my proposal to rename it *and* change the
signature to make it load the start of the file into a caller-provided
buffer that map_library would then reuse...

> >  		if (l-1 >= INT_MAX) return -1;
> > -		if (snprintf(buf, buf_size, "%.*s/%s", (int)l, s, name) < buf_size) {
> > -			if ((fd = open(buf, O_RDONLY|O_CLOEXEC))>=0) return fd;
> > -			switch (errno) {
> > -			case ENOENT:
> > -			case ENOTDIR:
> > -			case EACCES:
> > -			case ENAMETOOLONG:
> > -				break;
> > -			default:
> > -				/* Any negative value but -1 will inhibit
> > -				 * futher path search. */
> > +		s += l;
> > +		if (snprintf(buf, buf_size, "%.*s/%s", (int)l, p, name) < buf_size) {
> > +			fd = open(buf, O_RDONLY|O_CLOEXEC);
> > +			if (fd < 0) {
> > +				switch (errno) {
> > +				case ENOENT:
> > +				case ENOTDIR:
> > +				case EACCES:
> > +				case ENAMETOOLONG:
> > +					/* Keep searching in path list. */
> > +					continue;
> > +				default:
> > +					/* Any negative value but -1 will
> > +					 * inhibit further path search in
> > +					 * load_library. */
> > +					return -2;
> > +				}
> > +			}
> > +			Ehdr eh;
> > +			ssize_t n = pread(fd, &eh, sizeof(eh), 0);
> 
> i'd use read instead of pread
> 
> this adds an extra syscall per dso that uses path lookup.
> this is the main cost of the patch, so i'd note this in
> the commit msg.

...so that there is not an extra syscall per DSO loaded.

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.