Fix handling of .note.ABI-tag section for GNU systems [1].
Handle GNU/Linux according to LSB Core Specification 4.0, Chapter 11. Object Format, 11.8. ABI note tag. Also check the first word of desc, not only name, according to glibc abi-tags specification to distinguish between Linux and kFreeBSD. Add explicit handling for Debian GNU/kFreeBSD, which runs on our kernels as well [2]. In {amd64,i386}/trap.c, when checking osrel of the current process, also check the ABI to not change the signal behaviour for Linux binary processes, now that we save an osrel version for all three from the lists above in struct proc [2]. These changes make it possible to run FreeBSD, Debian GNU/kFreeBSD and Linux binaries on the same machine again for at least i386 and amd64, and no longer break kFreeBSD which was detected as GNU(/Linux). PR: kern/135468 Submitted by: dchagin [1] (initial patch) Suggested by: kib [2] Tested by: Petr Salinger (Petr.Salinger seznam.cz) for kFreeBSD Reviewed by: kib MFC after: 3 days
This commit is contained in:
parent
20cb1f56a9
commit
89ffc202d6
@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/sysent.h>
|
||||
#include <sys/imgact_elf.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/sysent.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
@ -108,6 +109,22 @@ SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
|
||||
(sysinit_cfunc_t) elf64_insert_brand_entry,
|
||||
&freebsd_brand_oinfo);
|
||||
|
||||
static Elf64_Brandinfo kfreebsd_brand_info = {
|
||||
.brand = ELFOSABI_FREEBSD,
|
||||
.machine = EM_X86_64,
|
||||
.compat_3_brand = "FreeBSD",
|
||||
.emul_path = NULL,
|
||||
.interp_path = "/lib/ld-kfreebsd-x86-64.so.1",
|
||||
.sysvec = &elf64_freebsd_sysvec,
|
||||
.interp_newpath = NULL,
|
||||
.brand_note = &elf64_kfreebsd_brandnote,
|
||||
.flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
|
||||
};
|
||||
|
||||
SYSINIT(kelf64, SI_SUB_EXEC, SI_ORDER_ANY,
|
||||
(sysinit_cfunc_t) elf64_insert_brand_entry,
|
||||
&kfreebsd_brand_info);
|
||||
|
||||
|
||||
void
|
||||
elf64_dump_thread(struct thread *td __unused, void *dst __unused,
|
||||
|
@ -409,7 +409,9 @@ trap(struct trapframe *frame)
|
||||
* This check also covers the images
|
||||
* without the ABI-tag ELF note.
|
||||
*/
|
||||
if (p->p_osrel >= 700004) {
|
||||
if (SV_CURPROC_ABI() ==
|
||||
SV_ABI_FREEBSD &&
|
||||
p->p_osrel >= 700004) {
|
||||
i = SIGSEGV;
|
||||
ucode = SEGV_ACCERR;
|
||||
} else {
|
||||
|
@ -127,6 +127,7 @@ static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
|
||||
static void exec_linux_setregs(struct thread *td, u_long entry,
|
||||
u_long stack, u_long ps_strings);
|
||||
static void linux32_fixlimit(struct rlimit *rl, int which);
|
||||
static boolean_t linux32_trans_osrel(const Elf_Note *note, int32_t *osrel);
|
||||
|
||||
static eventhandler_tag linux_exit_tag;
|
||||
static eventhandler_tag linux_schedtail_tag;
|
||||
@ -1066,14 +1067,38 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_flags = SV_ABI_LINUX | SV_ILP32 | SV_IA32
|
||||
};
|
||||
|
||||
static char GNULINUX_ABI_VENDOR[] = "GNU";
|
||||
static char GNU_ABI_VENDOR[] = "GNU";
|
||||
static int GNULINUX_ABI_DESC = 0;
|
||||
|
||||
static boolean_t
|
||||
linux32_trans_osrel(const Elf_Note *note, int32_t *osrel)
|
||||
{
|
||||
const Elf32_Word *desc;
|
||||
uintptr_t p;
|
||||
|
||||
p = (uintptr_t)(note + 1);
|
||||
p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
|
||||
|
||||
desc = (const Elf32_Word *)p;
|
||||
if (desc[0] != GNULINUX_ABI_DESC)
|
||||
return (FALSE);
|
||||
|
||||
/*
|
||||
* For linux we encode osrel as follows (see linux_mib.c):
|
||||
* VVVMMMIII (version, major, minor), see linux_mib.c.
|
||||
*/
|
||||
*osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3];
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
static Elf_Brandnote linux32_brandnote = {
|
||||
.hdr.n_namesz = sizeof(GNULINUX_ABI_VENDOR),
|
||||
.hdr.n_descsz = 16,
|
||||
.hdr.n_namesz = sizeof(GNU_ABI_VENDOR),
|
||||
.hdr.n_descsz = 16, /* XXX at least 16 */
|
||||
.hdr.n_type = 1,
|
||||
.vendor = GNULINUX_ABI_VENDOR,
|
||||
.flags = 0
|
||||
.vendor = GNU_ABI_VENDOR,
|
||||
.flags = BN_TRANSLATE_OSREL,
|
||||
.trans_osrel = linux32_trans_osrel
|
||||
};
|
||||
|
||||
static Elf32_Brandinfo linux_brand = {
|
||||
|
@ -172,6 +172,21 @@ SYSINIT(oia32, SI_SUB_EXEC, SI_ORDER_ANY,
|
||||
(sysinit_cfunc_t) elf32_insert_brand_entry,
|
||||
&ia32_brand_oinfo);
|
||||
|
||||
static Elf32_Brandinfo kia32_brand_info = {
|
||||
.brand = ELFOSABI_FREEBSD,
|
||||
.machine = EM_386,
|
||||
.compat_3_brand = "FreeBSD",
|
||||
.emul_path = NULL,
|
||||
.interp_path = "/lib/ld.so.1",
|
||||
.sysvec = &ia32_freebsd_sysvec,
|
||||
.brand_note = &elf32_kfreebsd_brandnote,
|
||||
.flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
|
||||
};
|
||||
|
||||
SYSINIT(kia32, SI_SUB_EXEC, SI_ORDER_ANY,
|
||||
(sysinit_cfunc_t) elf32_insert_brand_entry,
|
||||
&kia32_brand_info);
|
||||
|
||||
|
||||
void
|
||||
elf32_dump_thread(struct thread *td __unused, void *dst __unused,
|
||||
|
@ -108,6 +108,22 @@ SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
|
||||
(sysinit_cfunc_t) elf32_insert_brand_entry,
|
||||
&freebsd_brand_oinfo);
|
||||
|
||||
static Elf32_Brandinfo kfreebsd_brand_info = {
|
||||
.brand = ELFOSABI_FREEBSD,
|
||||
.machine = EM_386,
|
||||
.compat_3_brand = "FreeBSD",
|
||||
.emul_path = NULL,
|
||||
.interp_path = "/lib/ld.so.1",
|
||||
.sysvec = &elf32_freebsd_sysvec,
|
||||
.interp_newpath = NULL,
|
||||
.brand_note = &elf32_kfreebsd_brandnote,
|
||||
.flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
|
||||
};
|
||||
|
||||
SYSINIT(kelf32, SI_SUB_EXEC, SI_ORDER_ANY,
|
||||
(sysinit_cfunc_t) elf32_insert_brand_entry,
|
||||
&kfreebsd_brand_info);
|
||||
|
||||
|
||||
void
|
||||
elf32_dump_thread(struct thread *td __unused, void *dst __unused,
|
||||
|
@ -423,7 +423,9 @@ trap(struct trapframe *frame)
|
||||
* This check also covers the images
|
||||
* without the ABI-tag ELF note.
|
||||
*/
|
||||
if (p->p_osrel >= 700004) {
|
||||
if (SV_CURPROC_ABI() ==
|
||||
SV_ABI_FREEBSD &&
|
||||
p->p_osrel >= 700004) {
|
||||
i = SIGSEGV;
|
||||
ucode = SEGV_ACCERR;
|
||||
} else {
|
||||
|
@ -108,6 +108,7 @@ static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
|
||||
static void exec_linux_setregs(struct thread *td, u_long entry,
|
||||
u_long stack, u_long ps_strings);
|
||||
static register_t *linux_copyout_strings(struct image_params *imgp);
|
||||
static boolean_t linux_trans_osrel(const Elf_Note *note, int32_t *osrel);
|
||||
|
||||
static int linux_szplatform;
|
||||
const char *linux_platform;
|
||||
@ -1027,14 +1028,38 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_flags = SV_ABI_LINUX | SV_IA32 | SV_ILP32
|
||||
};
|
||||
|
||||
static char GNULINUX_ABI_VENDOR[] = "GNU";
|
||||
static char GNU_ABI_VENDOR[] = "GNU";
|
||||
static int GNULINUX_ABI_DESC = 0;
|
||||
|
||||
static boolean_t
|
||||
linux_trans_osrel(const Elf_Note *note, int32_t *osrel)
|
||||
{
|
||||
const Elf32_Word *desc;
|
||||
uintptr_t p;
|
||||
|
||||
p = (uintptr_t)(note + 1);
|
||||
p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
|
||||
|
||||
desc = (const Elf32_Word *)p;
|
||||
if (desc[0] != GNULINUX_ABI_DESC)
|
||||
return (FALSE);
|
||||
|
||||
/*
|
||||
* For linux we encode osrel as follows (see linux_mib.c):
|
||||
* VVVMMMIII (version, major, minor), see linux_mib.c.
|
||||
*/
|
||||
*osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3];
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
static Elf_Brandnote linux_brandnote = {
|
||||
.hdr.n_namesz = sizeof(GNULINUX_ABI_VENDOR),
|
||||
.hdr.n_descsz = 16,
|
||||
.hdr.n_namesz = sizeof(GNU_ABI_VENDOR),
|
||||
.hdr.n_descsz = 16, /* XXX at least 16 */
|
||||
.hdr.n_type = 1,
|
||||
.vendor = GNULINUX_ABI_VENDOR,
|
||||
.flags = 0
|
||||
.vendor = GNU_ABI_VENDOR,
|
||||
.flags = BN_TRANSLATE_OSREL,
|
||||
.trans_osrel = linux_trans_osrel
|
||||
};
|
||||
|
||||
static Elf32_Brandinfo linux_brand = {
|
||||
|
@ -86,6 +86,9 @@ static int __elfN(load_section)(struct vmspace *vmspace, vm_object_t object,
|
||||
vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz,
|
||||
vm_prot_t prot, size_t pagesize);
|
||||
static int __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp);
|
||||
static boolean_t __elfN(freebsd_trans_osrel)(const Elf_Note *note,
|
||||
int32_t *osrel);
|
||||
static boolean_t kfreebsd_trans_osrel(const Elf_Note *note, int32_t *osrel);
|
||||
static boolean_t __elfN(check_note)(struct image_params *imgp,
|
||||
Elf_Brandnote *checknote, int32_t *osrel);
|
||||
|
||||
@ -116,9 +119,56 @@ Elf_Brandnote __elfN(freebsd_brandnote) = {
|
||||
.hdr.n_descsz = sizeof(int32_t),
|
||||
.hdr.n_type = 1,
|
||||
.vendor = FREEBSD_ABI_VENDOR,
|
||||
.flags = BN_CAN_FETCH_OSREL
|
||||
.flags = BN_TRANSLATE_OSREL,
|
||||
.trans_osrel = __elfN(freebsd_trans_osrel)
|
||||
};
|
||||
|
||||
static boolean_t
|
||||
__elfN(freebsd_trans_osrel)(const Elf_Note *note, int32_t *osrel)
|
||||
{
|
||||
uintptr_t p;
|
||||
|
||||
p = (uintptr_t)(note + 1);
|
||||
p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
|
||||
*osrel = *(const int32_t *)(p);
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
static const char GNU_ABI_VENDOR[] = "GNU";
|
||||
static int GNU_KFREEBSD_ABI_DESC = 3;
|
||||
|
||||
Elf_Brandnote __elfN(kfreebsd_brandnote) = {
|
||||
.hdr.n_namesz = sizeof(GNU_ABI_VENDOR),
|
||||
.hdr.n_descsz = 16, /* XXX at least 16 */
|
||||
.hdr.n_type = 1,
|
||||
.vendor = GNU_ABI_VENDOR,
|
||||
.flags = BN_TRANSLATE_OSREL,
|
||||
.trans_osrel = kfreebsd_trans_osrel
|
||||
};
|
||||
|
||||
static boolean_t
|
||||
kfreebsd_trans_osrel(const Elf_Note *note, int32_t *osrel)
|
||||
{
|
||||
const Elf32_Word *desc;
|
||||
uintptr_t p;
|
||||
|
||||
p = (uintptr_t)(note + 1);
|
||||
p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
|
||||
|
||||
desc = (const Elf32_Word *)p;
|
||||
if (desc[0] != GNU_KFREEBSD_ABI_DESC)
|
||||
return (FALSE);
|
||||
|
||||
/*
|
||||
* Debian GNU/kFreeBSD embed the earliest compatible kernel version
|
||||
* (__FreeBSD_version: <major><two digit minor>Rxx) in the LSB way.
|
||||
*/
|
||||
*osrel = desc[1] * 100000 + desc[2] * 1000 + desc[3];
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
int
|
||||
__elfN(insert_brand_entry)(Elf_Brandinfo *entry)
|
||||
{
|
||||
@ -1371,11 +1421,9 @@ __elfN(check_note)(struct image_params *imgp, Elf_Brandnote *checknote,
|
||||
* Fetch the osreldate for binary
|
||||
* from the ELF OSABI-note if necessary.
|
||||
*/
|
||||
if ((checknote->flags & BN_CAN_FETCH_OSREL) != 0 &&
|
||||
osrel != NULL)
|
||||
*osrel = *(const int32_t *) (note_name +
|
||||
roundup2(checknote->hdr.n_namesz,
|
||||
sizeof(Elf32_Addr)));
|
||||
if ((checknote->flags & BN_TRANSLATE_OSREL) != 0 &&
|
||||
checknote->trans_osrel != NULL)
|
||||
return (checknote->trans_osrel(note, osrel));
|
||||
return (TRUE);
|
||||
|
||||
nextnote:
|
||||
|
@ -58,7 +58,10 @@ typedef struct {
|
||||
Elf_Note hdr;
|
||||
const char * vendor;
|
||||
int flags;
|
||||
#define BN_CAN_FETCH_OSREL 0x0001
|
||||
boolean_t (*trans_osrel)(const Elf_Note *, int32_t *);
|
||||
#define BN_CAN_FETCH_OSREL 0x0001 /* Deprecated. */
|
||||
#define BN_TRANSLATE_OSREL 0x0002 /* Use trans_osrel fetch osrel after */
|
||||
/* checking ABI contraint if needed. */
|
||||
} Elf_Brandnote;
|
||||
|
||||
typedef struct {
|
||||
@ -91,6 +94,7 @@ void __elfN(dump_thread)(struct thread *, void *, size_t *);
|
||||
|
||||
extern int __elfN(fallback_brand);
|
||||
extern Elf_Brandnote __elfN(freebsd_brandnote);
|
||||
extern Elf_Brandnote __elfN(kfreebsd_brandnote);
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* !_SYS_IMGACT_ELF_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user