Change our ELF binary branding to something more acceptable to the Binutils

maintainers.

After we established our branding method of writing upto 8 characters of
the OS name into the ELF header in the padding; the Binutils maintainers
and/or SCO (as USL) decided that instead the ELF header should grow two new
fields -- EI_OSABI and EI_ABIVERSION.  Each of these are an 8-bit unsigned
integer.  SCO has assigned official values for the EI_OSABI field.  In
addition to this, the Binutils maintainers and NetBSD decided that a better
ELF branding method was to include ABI information in a ".note" ELF
section.

With this set of changes, we will now create ELF binaries branded using
both "official" methods.  Due to the complexity of adding a section to a
binary, binaries branded with ``brandelf'' will only brand using the
EI_OSABI method.  Also due to the complexity of pulling a section out of an
ELF file vs. poking around in the ELF header, our image activator only
looks at the EI_OSABI header field.

Note that a new kernel can still properly load old binaries except for
Linux static binaries branded in our old method.

  *
  * For a short period of time, ``ld'' will also brand ELF binaries
  * using our old method.  This is so people can still use kernel.old
  * with a new world.  This support will be removed before 5.0-RELEASE,
  * and may not last anywhere upto the actual release.  My expiration
  * time for this is about 6mo.
  *
This commit is contained in:
David E. O'Brien 2000-04-18 02:39:26 +00:00
parent 8d396be510
commit c815a20cb2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=59342
14 changed files with 190 additions and 106 deletions

View File

@ -40,13 +40,6 @@ SECTION
#define ARCH_SIZE 0
#include "elf-bfd.h"
#define EI_BRAND_OFFSET 8 /* should be in binutils/include/elf/common.h */
#if defined(__FreeBSD__)
#define BRANDING "FreeBSD"
#else
#define BRANDING ""
#endif
static INLINE struct elf_segment_map *make_mapping
PARAMS ((bfd *, asection **, unsigned int, unsigned int, boolean));
static boolean map_sections_to_segments PARAMS ((bfd *));
@ -2932,9 +2925,24 @@ prep_headers (abfd)
bfd_big_endian (abfd) ? ELFDATA2MSB : ELFDATA2LSB;
i_ehdrp->e_ident[EI_VERSION] = bed->s->ev_current;
#ifdef __FreeBSD__
/* Quick and dirty hack to brand the file as a FreeBSD ELF file. */
i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
i_ehdrp->e_ident[EI_ABIVERSION] = 0;
#endif
for (count = EI_PAD; count < EI_NIDENT; count++)
i_ehdrp->e_ident[count] = 0;
#ifdef __FreeBSD__
/* #ifdef BRANDELF_CHANGE_BOOTSTRAP */
#define _OLD_EI_BRAND_OFFSET 8
#define _OLD_BRANDING "FreeBSD"
strncpy((char *) &i_ehdrp->e_ident[_OLD_EI_BRAND_OFFSET], _OLD_BRANDING,
EI_NIDENT-_OLD_EI_BRAND_OFFSET);
/* #endif */
#endif
if ((abfd->flags & DYNAMIC) != 0)
i_ehdrp->e_type = ET_DYN;
else if ((abfd->flags & EXEC_P) != 0)
@ -2949,7 +2957,7 @@ prep_headers (abfd)
break;
case bfd_arch_sparc:
if (bed->s->arch_size == 64)
i_ehdrp->e_machine = EM_SPARC64;
i_ehdrp->e_machine = EM_SPARCV9;
else
i_ehdrp->e_machine = EM_SPARC;
break;
@ -3009,11 +3017,6 @@ prep_headers (abfd)
i_ehdrp->e_version = bed->s->ev_current;
i_ehdrp->e_ehsize = bed->s->sizeof_ehdr;
/* Some OS's brands all ELF binaries so the image loader knows what system
call set, etc. to use. */
strncpy((char *) &i_ehdrp->e_ident[EI_BRAND_OFFSET], BRANDING,
EI_NIDENT-EI_BRAND_OFFSET);
/* no program header, for now. */
i_ehdrp->e_phoff = 0;
i_ehdrp->e_phentsize = 0;

View File

@ -25,6 +25,20 @@
* $FreeBSD$
*/
/* See http://www.netbsd.org/Documentation/kernel/elf-notes.html for
details on the ELF .note section as we are using it. */
.section .note.ABI-tag, "a"
.align 4
.long 1f - 0f # name length
.long 3f - 2f # data length
.long 1 # note type
0: .asciz "FreeBSD" # vendor name
1: .align 4
2: .long 500000 # data - ABI tag
# (from __FreeBSD_version (param.h))
3: .align 4 # pad out section
.section .init,"ax",@progbits
.align 4
.globl _init

View File

@ -25,6 +25,20 @@
* $FreeBSD$
*/
/* See http://www.netbsd.org/Documentation/kernel/elf-notes.html for
details on the ELF .note section as we are using it. */
.section .note.ABI-tag, "a"
.align 4
.long 1f - 0f # name length
.long 3f - 2f # data length
.long 1 # note type
0: .asciz "FreeBSD" # vendor name
1: .align 4
2: .long 500000 # data - ABI tag
# (from __FreeBSD_version (param.h))
3: .align 4 # pad out section
.section .init,"ax",@progbits
.align 4
.globl _init

View File

@ -439,14 +439,14 @@ struct sysentvec elf_linux_sysvec = {
};
static Elf32_Brandinfo linux_brand = {
"Linux",
ELFOSABI_LINUX,
"/compat/linux",
"/lib/ld-linux.so.1",
&elf_linux_sysvec
};
static Elf32_Brandinfo linux_glibc2brand = {
"Linux",
ELFOSABI_LINUX,
"/compat/linux",
"/lib/ld-linux.so.2",
&elf_linux_sysvec

View File

@ -155,7 +155,7 @@ int bsd_to_svr4_errno[ELAST+1] = {
};
static int svr4_fixup(long **stack_base, struct image_params *imgp);
static int svr4_fixup(register_t **stack_base, struct image_params *imgp);
extern struct sysent svr4_sysent[];
#undef szsigcode
@ -183,8 +183,8 @@ struct sysentvec svr4_sysvec = {
};
Elf32_Brandinfo svr4_brand = {
"SVR4",
"/compat/svr4",
ELFOSABI_SOLARIS, /* XXX Or should we use ELFOSABI_SYSV here? */
svr4_emul_path,
"/lib/libc.so.1",
&svr4_sysvec
};
@ -192,10 +192,10 @@ Elf32_Brandinfo svr4_brand = {
const char svr4_emul_path[] = "/compat/svr4";
static int
svr4_fixup(long **stack_base, struct image_params *imgp)
svr4_fixup(register_t **stack_base, struct image_params *imgp)
{
Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
long *pos;
register_t *pos;
pos = *stack_base + (imgp->argc + imgp->envc + 2);

View File

@ -439,14 +439,14 @@ struct sysentvec elf_linux_sysvec = {
};
static Elf32_Brandinfo linux_brand = {
"Linux",
ELFOSABI_LINUX,
"/compat/linux",
"/lib/ld-linux.so.1",
&elf_linux_sysvec
};
static Elf32_Brandinfo linux_glibc2brand = {
"Linux",
ELFOSABI_LINUX,
"/compat/linux",
"/lib/ld-linux.so.2",
&elf_linux_sysvec

View File

@ -65,6 +65,8 @@
#include <machine/elf.h>
#include <machine/md_var.h>
#define OLD_EI_BRAND 8
__ElfType(Brandinfo);
__ElfType(Auxargs);
@ -82,12 +84,6 @@ static int exec_elf_imgact __P((struct image_params *imgp));
static int elf_trace = 0;
SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, "");
/*
* XXX Maximum length of an ELF brand (sysctl wants a statically-allocated
* buffer).
*/
#define MAXBRANDLEN 16
static struct sysentvec elf_freebsd_sysvec = {
SYS_MAXSYSCALL,
sysent,
@ -107,7 +103,7 @@ static struct sysentvec elf_freebsd_sysvec = {
};
static Elf_Brandinfo freebsd_brand_info = {
"FreeBSD",
ELFOSABI_FREEBSD,
"",
"/usr/libexec/ld-elf.so.1",
&elf_freebsd_sysvec
@ -412,9 +408,9 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry)
return error;
}
static char fallback_elf_brand[MAXBRANDLEN+1] = { "none" };
SYSCTL_STRING(_kern, OID_AUTO, fallback_elf_brand, CTLFLAG_RW,
fallback_elf_brand, sizeof(fallback_elf_brand),
static int fallback_elf_brand = ELFOSABI_FREEBSD;
SYSCTL_INT(_kern, OID_AUTO, fallback_elf_brand, CTLFLAG_RW,
&fallback_elf_brand, ELFOSABI_FREEBSD,
"ELF brand of last resort");
static int
@ -431,7 +427,6 @@ exec_elf_imgact(struct image_params *imgp)
int error, i;
const char *interp = NULL;
Elf_Brandinfo *brand_info;
const char *brand;
char path[MAXPATHLEN];
/*
@ -526,14 +521,23 @@ exec_elf_imgact(struct image_params *imgp)
imgp->entry_addr = entry;
/* If the executable has a brand, search for it in the brand list. */
brand_info = NULL;
brand = (const char *)&hdr->e_ident[EI_BRAND];
if (brand[0] != '\0') {
/* XXX For now we look for the magic "FreeBSD" that we used to put
* into the ELF header at the EI_ABIVERSION location. If found use
* that information rather than figuring out the ABI from proper
* branding. This should be removed for 5.0-RELEASE. The Linux caes
* can be figured out from the `interp_path' field.
*/
if (strcmp("FreeBSD", (const char *)&hdr->e_ident[OLD_EI_BRAND]) == 0)
brand_info = &freebsd_brand_info;
/* If the executable has a brand, search for it in the brand list. */
if (brand_info == NULL) {
for (i = 0; i < MAX_BRANDS; i++) {
Elf_Brandinfo *bi = elf_brand_list[i];
if (bi != NULL && strcmp(brand, bi->brand) == 0) {
if (bi != NULL && hdr->e_ident[EI_OSABI] == bi->brand) {
brand_info = bi;
break;
}
@ -554,31 +558,24 @@ exec_elf_imgact(struct image_params *imgp)
}
/* Lacking a recognized interpreter, try the default brand */
if (brand_info == NULL && fallback_elf_brand[0] != '\0') {
if (brand_info == NULL) {
for (i = 0; i < MAX_BRANDS; i++) {
Elf_Brandinfo *bi = elf_brand_list[i];
if (bi != NULL
&& strcmp(fallback_elf_brand, bi->brand) == 0) {
if (bi != NULL && fallback_elf_brand == bi->brand) {
brand_info = bi;
break;
}
}
}
#ifdef __alpha__
/* XXX - Assume FreeBSD on the alpha. */
/* XXX - Assume FreeBSD after the branding method change. */
if (brand_info == NULL)
brand_info = &freebsd_brand_info;
#endif
if (brand_info == NULL) {
if (brand[0] == 0)
uprintf("ELF binary type not known."
" Use \"brandelf\" to brand it.\n");
else
uprintf("ELF binary type \"%.*s\" not known.\n",
EI_NIDENT - EI_BRAND, brand);
uprintf("ELF binary type \"%u\" not known.\n",
hdr->e_ident[EI_OSABI]);
error = ENOEXEC;
goto fail;
}
@ -932,9 +929,9 @@ elf_puthdr(struct proc *p, void *dst, size_t *off, const prstatus_t *status,
ehdr->e_ident[EI_CLASS] = ELF_CLASS;
ehdr->e_ident[EI_DATA] = ELF_DATA;
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
ehdr->e_ident[EI_ABIVERSION] = 0;
ehdr->e_ident[EI_PAD] = 0;
strncpy(ehdr->e_ident + EI_BRAND, "FreeBSD",
EI_NIDENT - EI_BRAND);
ehdr->e_type = ET_CORE;
ehdr->e_machine = ELF_ARCH;
ehdr->e_version = EV_CURRENT;

View File

@ -155,7 +155,7 @@ int bsd_to_svr4_errno[ELAST+1] = {
};
static int svr4_fixup(long **stack_base, struct image_params *imgp);
static int svr4_fixup(register_t **stack_base, struct image_params *imgp);
extern struct sysent svr4_sysent[];
#undef szsigcode
@ -183,8 +183,8 @@ struct sysentvec svr4_sysvec = {
};
Elf32_Brandinfo svr4_brand = {
"SVR4",
"/compat/svr4",
ELFOSABI_SOLARIS, /* XXX Or should we use ELFOSABI_SYSV here? */
svr4_emul_path,
"/lib/libc.so.1",
&svr4_sysvec
};
@ -192,10 +192,10 @@ Elf32_Brandinfo svr4_brand = {
const char svr4_emul_path[] = "/compat/svr4";
static int
svr4_fixup(long **stack_base, struct image_params *imgp)
svr4_fixup(register_t **stack_base, struct image_params *imgp)
{
Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
long *pos;
register_t *pos;
pos = *stack_base + (imgp->argc + imgp->envc + 2);

View File

@ -48,7 +48,8 @@ typedef struct {
u_int32_t n_type; /* Type of this note. */
} Elf_Note;
/* Indexes into the e_ident array. */
/* Indexes into the e_ident array. Keep synced with
http://www.sco.com/developer/gabi/ch4.eheader.html */
#define EI_MAG0 0 /* Magic number, byte 0. */
#define EI_MAG1 1 /* Magic number, byte 1. */
#define EI_MAG2 2 /* Magic number, byte 2. */
@ -56,8 +57,10 @@ typedef struct {
#define EI_CLASS 4 /* Class of machine. */
#define EI_DATA 5 /* Data format. */
#define EI_VERSION 6 /* ELF format version. */
#define EI_PAD 7 /* Start of padding (per SVR4 ABI). */
#define EI_BRAND 8 /* Start of architecture identification. */
#define EI_OSABI 7 /* Operating system / ABI identification */
#define EI_ABIVERSION 8 /* ABI version */
#define OLD_EI_BRAND 8 /* Start of architecture identification. */
#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */
#define EI_NIDENT 16 /* Size of e_ident array. */
/* Values for the magic number bytes. */
@ -80,6 +83,21 @@ typedef struct {
#define ELFDATA2LSB 1 /* 2's complement little-endian. */
#define ELFDATA2MSB 2 /* 2's complement big-endian. */
/* Values for e_ident[EI_OSABI]. */
#define ELFOSABI_SYSV 0 /* UNIX System V ABI */
#define ELFOSABI_HPUX 1 /* HP-UX operating system */
#define ELFOSABI_NETBSD 2 /* NetBSD */
#define ELFOSABI_LINUX 3 /* GNU/Linux */
#define ELFOSABI_HURD 4 /* GNU/Hurd */
#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */
#define ELFOSABI_SOLARIS 6 /* Solaris */
#define ELFOSABI_MONTEREY 7 /* Monterey */
#define ELFOSABI_IRIX 8 /* IRIX */
#define ELFOSABI_FREEBSD 9 /* FreeBSD */
#define ELFOSABI_TRU64 10 /* TRU64 UNIX */
#define ELFOSABI_ARM 97 /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
/* e_ident */
#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
(ehdr).e_ident[EI_MAG1] == ELFMAG1 && \

View File

@ -56,9 +56,9 @@ typedef struct {
} Elf32_Auxargs;
typedef struct {
char *brand;
char *emul_path;
char *interp_path;
int brand;
const char *emul_path;
const char *interp_path;
struct sysentvec *sysvec;
} Elf32_Brandinfo;

View File

@ -1,4 +1,6 @@
# $FreeBSD$
PROG= brandelf
CFLAGS+=-Wall
CFLAGS+= -Wall
.include <bsd.prog.mk>

View File

@ -35,7 +35,7 @@
.Nd mark an ELF binary for a specific ABI
.Sh SYNOPSIS
.Nm brandelf
.Op Fl f
.Op Fl f Ar ELF ABI number
.Op Fl l
.Op Fl v
.Op Fl t Ar string
@ -46,17 +46,18 @@ This command marks an ELF binary to be run under a certain ABI for
.Pp
The options are as follows:
.Bl -tag -width Fl
.It Fl f
forces branding even if the brand requested is unknown, and disables
warnings for unknown brands.
.It Fl f Ar ELF ABI number
forces branding with the supplied ELF ABI number. In compatable with the
.It Fl t
option. These values are assigned by SCO/USL.
.It Fl l
lists all known ELF types on the standard error channel.
.It Fl v
turns on verbose reporting
.It Fl t Ar string
Brands the given ELF binaries with
Brands the given ELF binaries to be of the
.Ar string
as the ABI type. Currently supported ABI's are
ABI type. Currently supported ABI's are
.Dq Tn FreeBSD
and
.Dq Linux .
@ -65,7 +66,7 @@ If
.Fl t Ar string
is given it will brand
.Ar file
with
to be of type
.Ar string ,
otherwise it will simply display the branding of
.Ar file .
@ -84,6 +85,13 @@ fails if a file doesn't exist, is too short, fails to brand properly,
or the brand requested is not one of the known types and the
.Fl f
option is not set.
.Sh SEE ALSO
.Rs
.%A The Scanta Cruz Operation, Inc.
.%T System V Application Binary Interface
.%D April 29, 1998 (DRAFT)
.%O http://www.sco.com/developer/devspecs/
.Re
.Sh HISTORY
The
.Nm

View File

@ -34,24 +34,46 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/errno.h>
#include <err.h>
static int iselftype(const char *);
static int elftype(const char *);
static const char *iselftype(int);
static void printelftypes(void);
static void usage __P((void));
struct ELFtypes {
const char *str;
int value;
};
/* XXX - any more types? */
static struct ELFtypes elftypes[] = {
{ "FreeBSD", ELFOSABI_FREEBSD },
{ "SVR4", ELFOSABI_SYSV },
{ "Linux", ELFOSABI_LINUX }
};
int
main(int argc, char **argv)
{
const char *type = "FreeBSD";
const char *strtype = "FreeBSD";
int type = ELFOSABI_FREEBSD;
int retval = 0;
int ch, change = 0, verbose = 0, force = 0, listed = 0;
while ((ch = getopt(argc, argv, "flt:v")) != -1)
while ((ch = getopt(argc, argv, "f:lt:v")) != -1)
switch (ch) {
case 'f':
if (change)
errx(1, "f option incompatable with t option");
force = 1;
type = atoi(optarg);
if (errno == ERANGE || type < 0 || type > 255) {
warnx("invalid argument to option f: %s",
optarg);
usage();
}
break;
case 'l':
printelftypes();
@ -61,8 +83,10 @@ main(int argc, char **argv)
verbose = 1;
break;
case 't':
if (force)
errx(1, "t option incompatable with f option");
change = 1;
type = optarg;
strtype = optarg;
break;
default:
usage();
@ -78,8 +102,8 @@ main(int argc, char **argv)
}
}
if (!force && !iselftype(type)) {
warnx("invalid ELF type '%s'", type);
if (!force && (type = elftype(strtype)) == -1) {
warnx("invalid ELF type '%s'", strtype);
printelftypes();
usage();
}
@ -87,9 +111,8 @@ main(int argc, char **argv)
while (argc) {
int fd;
char buffer[EI_NIDENT];
char string[(EI_NIDENT-EI_BRAND)+1];
if ((fd = open(argv[0], change? O_RDWR: O_RDONLY, 0)) < 0) {
if ((fd = open(argv[0], change || force ? O_RDWR : O_RDONLY, 0)) < 0) {
warn("error opening file %s", argv[0]);
retval = 1;
goto fail;
@ -105,28 +128,22 @@ main(int argc, char **argv)
retval = 1;
goto fail;
}
if (!change) {
bzero(string, sizeof(string));
strncpy(string, &buffer[EI_BRAND], EI_NIDENT-EI_BRAND);
if (strlen(string)) {
fprintf(stdout,
"File '%s' is of brand '%s'.\n",
argv[0], string);
if (!force && !iselftype(string)) {
warnx("Brand '%s' is unknown",
string);
printelftypes();
}
if (!change && !force) {
fprintf(stdout,
"File '%s' is of brand '%s' (%u).\n",
argv[0], iselftype(buffer[EI_OSABI]),
buffer[EI_OSABI]);
if (!iselftype(type)) {
warnx("ELF ABI Brand '%u' is unknown",
type);
printelftypes();
}
else
fprintf(stdout, "File '%s' has no branding.\n",
argv[0]);
}
else {
strncpy(&buffer[EI_BRAND], type, EI_NIDENT-EI_BRAND);
buffer[EI_OSABI] = type;
lseek(fd, 0, SEEK_SET);
if (write(fd, buffer, EI_NIDENT) != EI_NIDENT) {
warnx("error writing %s", argv[0]);
warn("error writing %s %d", argv[0], fd);
retval = 1;
goto fail;
}
@ -142,26 +159,36 @@ main(int argc, char **argv)
static void
usage()
{
fprintf(stderr, "usage: brandelf [-f] [-v] [-l] [-t string] file ...\n");
fprintf(stderr, "usage: brandelf [-f ELF ABI number] [-v] [-l] [-t string] file ...\n");
exit(1);
}
/* XXX - any more types? */
static const char *elftypes[] = { "FreeBSD", "Linux", "SVR4" };
static int
iselftype(const char *elftype)
static const char *
iselftype(int elftype)
{
int elfwalk;
for (elfwalk = 0;
elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
elfwalk++)
if (strcmp(elftype, elftypes[elfwalk]) == 0)
return 1;
if (elftype == elftypes[elfwalk].value)
return elftypes[elfwalk].str;
return 0;
}
static int
elftype(const char *elfstrtype)
{
int elfwalk;
for (elfwalk = 0;
elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
elfwalk++)
if (strcmp(elfstrtype, elftypes[elfwalk].str) == 0)
return elftypes[elfwalk].value;
return -1;
}
static void
printelftypes()
{
@ -171,6 +198,7 @@ printelftypes()
for (elfwalk = 0;
elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
elfwalk++)
fprintf(stderr, "%s ", elftypes[elfwalk]);
fprintf(stderr, "%s(%u) ", elftypes[elfwalk].str,
elftypes[elfwalk].value);
fprintf(stderr, "\n");
}

View File

@ -287,9 +287,9 @@ elf_puthdr(vm_map_entry_t map, void *dst, size_t *off, const prstatus_t *status,
ehdr->e_ident[EI_CLASS] = ELF_CLASS;
ehdr->e_ident[EI_DATA] = ELF_DATA;
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
ehdr->e_ident[EI_ABIVERSION] = 0;
ehdr->e_ident[EI_PAD] = 0;
strncpy(ehdr->e_ident + EI_BRAND, "FreeBSD",
EI_NIDENT - EI_BRAND);
ehdr->e_type = ET_CORE;
ehdr->e_machine = ELF_ARCH;
ehdr->e_version = EV_CURRENT;