When matching brand to the ELF binary by notes, try to find a brand

with interpreter name exactly matching one wanted by the binary.  If
no such brand exists, return first brand which accepted the binary by
note.

The change fixes a regression after r292749, where e.g. our two ia32
compat brands, ia32_brand_info and ia32_brand_oinfo, only differ by
the interpeter path and binary matches to a brand by linkage order.
Then old binaries which require /usr/libexec/ld-elf.so.1 but matched
against ia32_brand_info with interp_path /libexec/ld-elf.so.1, were
considered requiring non-standard interpreter name, and magic to force
ld-elf32.so.1 did not happen.

Note that it might make sense to apply the same selection of brands
for other matching criteria, SCO EI_OSABI and 3.x string.

Reported and tested by:	dwmalone
Sponsored by:	The FreeBSD Foundation
MFC after:	3 days
This commit is contained in:
Konstantin Belousov 2016-02-04 20:55:49 +00:00
parent dd4637c078
commit af582aaed1

View File

@ -258,7 +258,7 @@ __elfN(get_brandinfo)(struct image_params *imgp, const char *interp,
int interp_name_len, int32_t *osrel)
{
const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header;
Elf_Brandinfo *bi;
Elf_Brandinfo *bi, *bi_m;
boolean_t ret;
int i;
@ -270,6 +270,7 @@ __elfN(get_brandinfo)(struct image_params *imgp, const char *interp,
*/
/* Look for an ".note.ABI-tag" ELF section */
bi_m = NULL;
for (i = 0; i < MAX_BRANDS; i++) {
bi = elf_brand_list[i];
if (bi == NULL)
@ -280,10 +281,28 @@ __elfN(get_brandinfo)(struct image_params *imgp, const char *interp,
/* Give brand a chance to veto check_note's guess */
if (ret && bi->header_supported)
ret = bi->header_supported(imgp);
/*
* If note checker claimed the binary, but the
* interpreter path in the image does not
* match default one for the brand, try to
* search for other brands with the same
* interpreter. Either there is better brand
* with the right interpreter, or, failing
* this, we return first brand which accepted
* our note and, optionally, header.
*/
if (ret && bi_m == NULL && (strlen(bi->interp_path) +
1 != interp_name_len || strncmp(interp,
bi->interp_path, interp_name_len) != 0)) {
bi_m = bi;
ret = 0;
}
if (ret)
return (bi);
}
}
if (bi_m != NULL)
return (bi_m);
/* If the executable has a brand, search for it in the brand list. */
for (i = 0; i < MAX_BRANDS; i++) {