diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index f3d3d81..c29b544 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt @@ -55,6 +55,20 @@ config BINFMT_SHARED_FLAT help Support FLAT shared libraries +config BINFMT_MACHO + tristate "Kernel support for Mach-O and FAT Mach-O binaries" + ---help--- + Mach-O (Mach Object) is a format for libraries and executables used + by the Mach and Darwin operating systems on multiple architectures. + Saying Y here will enable your kernel to run Mach-O binaries built + for your platform. If the program or library is a FAT Mach-O + binary then it may be run on any platform where an appropriate + binary exists. + + If you wish to actually run programs compiled for either Darwin or + Mac OS X, you probably also want to enable + "Darwin syscall personality support" for your architecture. + config BINFMT_AOUT tristate "Kernel support for a.out and ECOFF binaries" depends on X86_32 || ALPHA || ARM || M68K || SPARC32 diff --git a/fs/Makefile b/fs/Makefile index 9edf411..bd70dd3 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o obj-$(CONFIG_BINFMT_ELF_FDPIC) += binfmt_elf_fdpic.o obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o +obj-$(CONFIG_BINFMT_MACHO) += mach-o/ obj-$(CONFIG_FS_MBCACHE) += mbcache.o obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o diff --git a/fs/mach-o/Makefile b/fs/mach-o/Makefile new file mode 100644 index 0000000..9d1d374 --- /dev/null +++ b/fs/mach-o/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for Mach-O binary format support +# + +obj-$(CONFIG_BINFMT_MACHO) += binfmt_mach-o.o + +binfmt_mach-o-objs := binfmt.o + diff --git a/fs/mach-o/binfmt.c b/fs/mach-o/binfmt.c new file mode 100644 index 0000000..b5ea936 --- /dev/null +++ b/fs/mach-o/binfmt.c @@ -0,0 +1,321 @@ +/* + * linux/fs/mach-o/binfmt.c + * + * These are the functions used to load Mach-O format executables as used + * on Mac OS X and Darwin machines. + * + * Copyright (C) 2006, Kyle Moffett + * + * Designed from public documentation and Darwin sources as well as the Linux + * ELF loader by Eric Youngdale (ericy@cais.com). + */ + +#include +#include +#include +#include + +#include "debug.h" +#include "cpus.h" +#include "headers.h" +#include "files.h" + +#if 0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#endif + +MODULE_LICENSE("GPL"); + +/* Function prototypes */ +static unsigned long get_arch_offset(struct linux_binprm *bprm); +static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs); + +/* Mach-O binary format */ +static struct linux_binfmt binfmt_macho = { + .module = THIS_MODULE, + .load_binary = load_macho_binary, + .load_shlib = NULL, + .core_dump = NULL, + .min_coredump = PAGE_SIZE, +}; + +/* Module init and exit */ +static int __init init_binfmt_macho(void) +{ + return register_binfmt(&binfmt_macho); +} +core_initcall(init_binfmt_macho); + +static void __exit exit_binfmt_macho(void) +{ + unregister_binfmt(&binfmt_macho); +} +module_exit(exit_binfmt_macho); + + +/* + * Read Mach-O file headers to find out where our architecture-specific + * portion is. + */ +#define MAX_ARCH_COUNT (PAGE_SIZE/sizeof(struct macho_fat_arch)) +static unsigned long get_arch_offset(struct linux_binprm *bprm) +{ + struct macho_fat_header *header; + struct macho_fat_arch *archs; + unsigned long arch_count, arch_data, i, offset = 0; + long retval; + unsigned int best_pref, best_arch; + + /* Without a FAT (multi-arch binary) header just assume no offset */ + header = (struct macho_fat_header *)bprm->buf; + if (header->magic != MACHO_FAT_MAGIC) + goto out; + + macho_dbg("Found a Mach-O FAT header!\n"); + + /* Figure out how many archs to read (no more than a page worth) */ + arch_count = __be32_to_cpu(header->arch_count); + if (arch_count > MAX_ARCH_COUNT) { + macho_dbg("Too many archs (%lu) in Mach-O binary. Only using" + " %lu!\n", arch_count, MAX_ARCH_COUNT); + arch_count = MAX_ARCH_COUNT; + } + + /* Size of the architecture data (for kmalloc and read) */ + arch_data = arch_count * sizeof(struct macho_fat_arch); + + /* Allocate memory for the architecture list */ + archs = kmalloc(arch_data, GFP_KERNEL); + if (!archs) { + offset = (unsigned long)(-ENOMEM); + goto out; + } + + /* Read in the architecture list */ + retval = kernel_read(bprm->file, sizeof(struct macho_fat_header), + (void *)archs, arch_data); + if (retval != arch_data) { + if (retval < 0) { + macho_dbg("Error while reading Mach-O architecture" + " list: %li\n", retval); + offset = (unsigned long)retval; + } else { + macho_dbg("Truncated arch list (got %lub, wanted" + " %lub)\n", retval, arch_data); + offset = (unsigned long)(-ENOEXEC); + } + goto out; + } + + /* + * Iterate over the architecture list looking for the most-preferred + * arch. NOTE: An architecture with a preference of 0 is not + * compatible with the current CPU. + */ + best_pref = 0; + best_arch = 0; + for (i = 0; i < arch_count; i++) { + unsigned int pref = macho_check_cpu( + __be32_to_cpu(archs[i].cpu_type), + __be32_to_cpu(archs[i].cpu_subtype)); + if (best_pref < pref) { + best_pref = pref; + best_arch = i; + } + } + + /* If we didn't find any useable architectures then give up */ + if (best_pref == 0) { + macho_dbg("No compatible binaries in Mach-O FAT binary\n"); + offset = (unsigned long)(-ENOEXEC); + goto out; + } + + /* Pick up the offset of the best available architecture */ + offset = __be32_to_cpu(archs[best_arch].offset); + + /* + * If the offset would be confused with an error value then + * it's too big (4GB program binary?!?!?) and we should just + * return ENOEXEC instead + */ + if (IS_ERR_VALUE(offset)) + offset = (unsigned long)(-ENOEXEC); + +out: + return offset; +} + +/* + * Load a Mach-O binary + */ +static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs) +{ + struct { + union { + /* The first 4 bytes of either header are the magic */ + __u32 magic; + struct macho_mach32_header mach32; + struct macho_mach64_header mach64; + } header; +#if 0 + struct macho_loadcmd loadcmd; +#endif + } *data = NULL; + unsigned long offset; + long retval; + int err; + + /* + * Read the Mach-O file headers to find the offset of our + * architecture-specific portion + */ + offset = get_arch_offset(bprm); + if (IS_ERR_VALUE(offset)) { + err = (long)offset; + goto out; + } + + /* Allocate space for the file headers and a load command */ + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto out; + } + + /* Read the header data and check the magic */ + retval = kernel_read(bprm->file, offset, + (void *)&data->header, sizeof(data->header)); + if (retval != sizeof(data->header)) { + /* + * If we didn't see an arch table then it must not really be + * a Mach-O file so just return as not executable. + */ + if (!offset) + err = -ENOEXEC; + + /* If kernel_read() returned an error, handle it */ + else if (retval < 0) { + macho_dbg("Error while reading Mach-O object" + " header: %li\n", retval); + err = retval; + } else { + macho_dbg("Truncated Mach-O object header: " + "(got %lub, wanted %lub)\n", retval, + sizeof(data->header)); + err = -ENOEXEC; + } + goto out; + } + + /* Check for backwards-endian files */ + if (data->header.magic == MACHO_MACH32_CIGAM || + data->header.magic == MACHO_MACH64_CIGAM) { + macho_dbg("Wrong endianness in Mach-O file\n"); + err = -ENOEXEC; + goto out; + } + + /* + * It's not a valid Mach-O file then return, but print an error + * message first if it was embedded in a Mach-O FAT wrapper. + */ + if (data->header.magic != MACHO_MACH32_MAGIC && + data->header.magic != MACHO_MACH64_MAGIC) { + if (offset) + macho_dbg("Corrupt embedded Mach-O object!\n"); + err = -ENOEXEC; + goto out; + } + + /* CPU type (lines up between 32-bit and 64-bit Mach-O files) */ + if (!macho_check_cpu(data->header.mach32.cpu_type, + data->header.mach32.cpu_subtype)) { + + /* + * The CPU didn't match, so either this is Mach-O file is for + * a different platform (offset == 0) or the FAT Mach-O has + * been corrupted. + */ + if (offset) + macho_dbg("FAT Mach-O wrapper has mismatched CPU" + " types: Mach-O file corrupt?\n"); + else + macho_dbg("Wrong architecture in Mach-O file\n"); + err = -ENOEXEC; + goto out; + } + + /* File type (also lines up between 32-bit and 64-bit) */ + if (!macho_check_file(data->header.mach32.filetype, + data->header.mach32.flags)) { + macho_dbg("Attempted to execute nonexecutable Mach-O file\n"); + err = -ENOEXEC; + goto out; + } + + /* Move past the Mach-O header to find the first load_command */ + if (data->header.magic == MACHO_MACH32_MAGIC) + offset += sizeof(struct macho_mach32_header); + else + offset += sizeof(struct macho_mach64_header); + + err = -EINVAL; + goto out; + +out: + kfree(data); + return err; +} + + + +#if 0 + char buf[BINPRM_BUF_SIZE]; + struct page *page[MAX_ARG_PAGES]; + struct mm_struct *mm; + unsigned long p; /* current top of mem */ + int sh_bang; + struct file * file; + int e_uid, e_gid; + kernel_cap_t cap_inheritable, cap_permitted, cap_effective; + void *security; + int argc, envc; + char * filename; /* Name of binary as seen by procps */ + char * interp; /* Name of the binary really executed. Most + of the time same as filename, but could be + different for binfmt_{misc,script} */ + unsigned interp_flags; + unsigned interp_data; + unsigned long loader, exec; +#endif + diff --git a/fs/mach-o/cpus.h b/fs/mach-o/cpus.h new file mode 100644 index 0000000..a1f2276 --- /dev/null +++ b/fs/mach-o/cpus.h @@ -0,0 +1,329 @@ +#ifndef _MACHO_CPUS_H +# define _MACHO_CPUS_H 1 + +# include +# include +# include + +/* + * Mach-O CPU types, borrowed from Darwin + */ +typedef __u32 __bitwise macho_cpu_type_t; +#define _ENTRY(type, num) \ + MACHO_CPU_TYPE_##type = ((__force macho_cpu_type_t)num) +enum { + _ENTRY(VAX, 0x00000001), + _ENTRY(M68K, 0x00000006), + _ENTRY(I386, 0x00000007), + _ENTRY(MIPS, 0x00000008), + _ENTRY(M98K, 0x0000000a), + _ENTRY(PARISC, 0x0000000b), + _ENTRY(ARM, 0x0000000c), + _ENTRY(M88K, 0x0000000d), + _ENTRY(SPARC, 0x0000000e), + _ENTRY(I860, 0x0000000f), + _ENTRY(ALPHA, 0x00000010), + _ENTRY(PPC32, 0x00000012), + _ENTRY(PPC64, 0x01000012), + _ENTRY(ANY, 0xffffffff), +}; +#undef _ENTRY + +/* + * Mach-O CPU subtypes, borrowed from Darwin + */ +typedef __u32 __bitwise macho_cpu_subtype_t; +#define _ENTRY(subtype, num) \ + MACHO_CPU_SUBTYPE_##subtype = ((__force macho_cpu_subtype_t)num) +enum { + /* Generic CPU subtypes (unused?) */ + _ENTRY(MULTIPLE, 0xffffffff), + _ENTRY(LITTLE_ENDIAN, 0x00000000), + _ENTRY(BIG_ENDIAN, 0x00000001), + + /* VAX subtypes */ + _ENTRY(VAX_ALL, 0x00000000), + _ENTRY(VAX_VAX780, 0x00000001), + _ENTRY(VAX_VAX785, 0x00000002), + _ENTRY(VAX_VAX750, 0x00000003), + _ENTRY(VAX_VAX730, 0x00000004), + _ENTRY(VAX_UVAXI, 0x00000005), + _ENTRY(VAX_UVAXII, 0x00000006), + _ENTRY(VAX_VAX8200, 0x00000007), + _ENTRY(VAX_VAX8500, 0x00000008), + _ENTRY(VAX_VAX8600, 0x00000009), + _ENTRY(VAX_VAX8650, 0x0000000a), + _ENTRY(VAX_VAX8800, 0x0000000b), + _ENTRY(VAX_UVAXIII, 0x0000000c), + + /* Motorola 680x0 subtypes */ + _ENTRY(M68K_MC680X0, 0x00000001), + _ENTRY(M68K_MC68040, 0x00000002), + _ENTRY(M68K_MC68030, 0x00000003), + + /* Intel/AMD x86 subtypes */ + _ENTRY(I386_ALL, 0x00000003), + _ENTRY(I386_386, 0x00000003), + _ENTRY(I386_486, 0x00000004), + _ENTRY(I386_486SX, 0x00000084), + _ENTRY(I386_586, 0x00000005), + _ENTRY(I386_PENTIUM, 0x00000005), + _ENTRY(I386_PPRO, 0x00000016), + _ENTRY(I386_PENTIUM2_M3, 0x00000036), + _ENTRY(I386_PENTIUM2_M5, 0x00000056), + _ENTRY(I386_CELERON, 0x00000067), + _ENTRY(I386_CELERON_M, 0x00000077), + _ENTRY(I386_PENTIUM3, 0x00000008), + _ENTRY(I386_PENTIUM3_M, 0x00000018), + _ENTRY(I386_PENTIUM3_XEON, 0x00000028), + _ENTRY(I386_PENTIUM_M, 0x00000009), + _ENTRY(I386_PENTIUM4, 0x0000000a), + _ENTRY(I386_PENTIUM4_M, 0x0000001a), + _ENTRY(I386_ITANIUM, 0x0000000b), + _ENTRY(I386_ITANIUM2, 0x0000001b), + _ENTRY(I386_XEON, 0x0000000c), + _ENTRY(I386_XEON_MP, 0x0000001c), + + /* MIPS subtypes */ + _ENTRY(MIPS_ALL, 0x00000000), + _ENTRY(MIPS_R2300, 0x00000001), + _ENTRY(MIPS_R2600, 0x00000002), + _ENTRY(MIPS_R2800, 0x00000003), + _ENTRY(MIPS_R2000A, 0x00000004), + _ENTRY(MIPS_R2000, 0x00000005), + _ENTRY(MIPS_R3000A, 0x00000006), + _ENTRY(MIPS_R3000, 0x00000007), + + /* Motorola 98xxx subtypes */ + _ENTRY(M98K_ALL, 0x00000000), + _ENTRY(M98K_MC98601, 0x00000001), + + /* HPPA subtypes */ + _ENTRY(PARISC_ALL, 0x00000000), + _ENTRY(PARISC_7100LC, 0x00000001), + + /* Motorola 88xxx subtypes */ + _ENTRY(M88K_ALL, 0x00000000), + _ENTRY(M88K_MC88100, 0x00000001), + _ENTRY(M88K_MC88110, 0x00000002), + + /* Sparc subtypes */ + _ENTRY(SPARC_ALL, 0x00000000), + + /* I860?? subtypes */ + _ENTRY(I860_ALL, 0x00000000), + _ENTRY(I860_860, 0x00000001), + + /* Motorola/Freescale/IBM PowerPC subtypes */ + _ENTRY(PPC32_ALL, 0x00000000), + _ENTRY(PPC32_601, 0x00000001), + _ENTRY(PPC32_602, 0x00000002), + _ENTRY(PPC32_603, 0x00000003), + _ENTRY(PPC32_603E, 0x00000004), + _ENTRY(PPC32_603EV, 0x00000005), + _ENTRY(PPC32_604, 0x00000006), + _ENTRY(PPC32_604E, 0x00000007), + _ENTRY(PPC32_620, 0x00000008), + _ENTRY(PPC32_750, 0x00000009), + _ENTRY(PPC32_7400, 0x0000000a), + _ENTRY(PPC32_7450, 0x0000000b), + _ENTRY(PPC32_970, 0x00000064), + + /* Motorola/Freescale/IBM PowerPC64 subtypes */ + _ENTRY(PPC64_ALL, 0x00000000), + /*_ENTRY(PPC64_970, 0x00000001),*/ +}; +#undef _ENTRY + +/* + * A CPU subtype mapping table with human-readable strings + */ +struct macho_cpu_subentry { + const char * name; + macho_cpu_type_t type; + macho_cpu_subtype_t subtype; + unsigned int preference; +}; + +#define _ENTRY(TYPE, SUBTYPE, NAME, PREFERENCE) { \ + .name = NAME, \ + .type = MACHO_CPU_TYPE_ ## TYPE, \ + .subtype = MACHO_CPU_SUBTYPE_ ## TYPE ## _ ## SUBTYPE, \ + .preference = (PREFERENCE) \ + } + +static const struct macho_cpu_subentry macho_cpu_vax_subtypes[] = { + _ENTRY(VAX, ALL, "all VAX", 0), + _ENTRY(VAX, VAX780, "VAX-780", 0), + _ENTRY(VAX, VAX785, "VAX-785", 0), + _ENTRY(VAX, VAX750, "VAX-750", 0), + _ENTRY(VAX, VAX730, "VAX-730", 0), + _ENTRY(VAX, UVAXI, "UVAX-I", 0), + _ENTRY(VAX, UVAXII, "UVAX-II", 0), + _ENTRY(VAX, VAX8200, "VAX-8200", 0), + _ENTRY(VAX, VAX8500, "VAX-8500", 0), + _ENTRY(VAX, VAX8600, "VAX-8600", 0), + _ENTRY(VAX, VAX8650, "VAX-8650", 0), + _ENTRY(VAX, VAX8800, "VAX-8800", 0), + _ENTRY(VAX, UVAXIII, "UVAX-III", 0), + { .name = NULL }, +}; +static const struct macho_cpu_subentry macho_cpu_m68k_subtypes[] = { + _ENTRY(M68K, MC680X0, "all Motorola 68xxx", 0), + _ENTRY(M68K, MC68040, "Motorola 68040", 0), + _ENTRY(M68K, MC68030, "Motorola 68030", 0), + { .name = NULL }, +}; +static const struct macho_cpu_subentry macho_cpu_i386_subtypes[] = { + _ENTRY(I386, ALL, "all Intel/AMD", 0), + _ENTRY(I386, 386, "Intel 386", 0), + _ENTRY(I386, 486, "Intel 486", 0), + _ENTRY(I386, 486SX, "Intel 486SX", 0), + _ENTRY(I386, 586, "Intel 586", 0), + _ENTRY(I386, PENTIUM, "Intel Pentium", 0), + _ENTRY(I386, PPRO, "Intel Pentium Pro", 0), + _ENTRY(I386, PENTIUM2_M3, "Intel Pentium II M3", 0), + _ENTRY(I386, PENTIUM2_M5, "Intel Pentium II M5", 0), + _ENTRY(I386, CELERON, "Intel Celeron", 0), + _ENTRY(I386, CELERON_M, "Intel Celeron/M", 0), + _ENTRY(I386, PENTIUM3, "Intel Pentium III", 0), + _ENTRY(I386, PENTIUM3_M, "Intel Pentium III M", 0), + _ENTRY(I386, PENTIUM3_XEON, "Intel Pentium III Xeon", 0), + _ENTRY(I386, PENTIUM_M, "Intel Pentium/M", 0), + _ENTRY(I386, PENTIUM4, "Intel Pentium IV", 0), + _ENTRY(I386, PENTIUM4_M, "Intel Pentium IV/M", 0), + _ENTRY(I386, ITANIUM, "Intel Itanium", 0), + _ENTRY(I386, ITANIUM2, "Intel Itanium 2", 0), + _ENTRY(I386, XEON, "Intel Xeon", 0), + _ENTRY(I386, XEON_MP, "Intel Xeon SMP", 0), + { .name = NULL }, +}; +static const struct macho_cpu_subentry macho_cpu_mips_subtypes[] = { + _ENTRY(MIPS, ALL, "all MIPS", 0), + _ENTRY(MIPS, R2300, "MIPS r2300", 0), + _ENTRY(MIPS, R2600, "MIPS r2600", 0), + _ENTRY(MIPS, R2800, "MIPS r2800", 0), + _ENTRY(MIPS, R2000A, "MIPS r2000a", 0), + _ENTRY(MIPS, R2000, "MIPS r2000", 0), + _ENTRY(MIPS, R3000A, "MIPS r3000a", 0), + _ENTRY(MIPS, R3000, "MIPS r3000", 0), + { .name = NULL }, +}; +static const struct macho_cpu_subentry macho_cpu_m98k_subtypes[] = { + _ENTRY(M98K, ALL, "all Motorola 98xxx", 0), + _ENTRY(M98K, MC98601, "Motorola 98601", 0), + { .name = NULL }, +}; +static const struct macho_cpu_subentry macho_cpu_parisc_subtypes[] = { + _ENTRY(PARISC, ALL, "all HPPA/PaRISC", 0), + _ENTRY(PARISC, 7100LC, "HPPA 7100LC", 0), + { .name = NULL }, +}; +static const struct macho_cpu_subentry macho_cpu_m88k_subtypes[] = { + _ENTRY(M88K, ALL, "All Motorola 88xxx", 0), + _ENTRY(M88K, MC88100, "Motorola 88100", 0), + _ENTRY(M88K, MC88110, "Motorola 88110", 0), + { .name = NULL }, +}; +static const struct macho_cpu_subentry macho_cpu_sparc_subtypes[] = { + _ENTRY(SPARC, ALL, "all Sparc", 0), + { .name = NULL }, +}; +static const struct macho_cpu_subentry macho_cpu_i860_subtypes[] = { + _ENTRY(I860, ALL, "all i860", 0), + _ENTRY(I860, 860, "i860", 0), + { .name = NULL }, +}; +static const struct macho_cpu_subentry macho_cpu_ppc32_subtypes[] = { + _ENTRY(PPC32, ALL, "all PowerPC", 1), + _ENTRY(PPC32, 601, "PowerPC 601", 2), + _ENTRY(PPC32, 602, "PowerPC 602", 3), + _ENTRY(PPC32, 603, "PowerPC 603", 4), + _ENTRY(PPC32, 603E, "PowerPC 603e", 5), + _ENTRY(PPC32, 603EV, "PowerPC 603ev", 6), + _ENTRY(PPC32, 604, "PowerPC 604", 7), + _ENTRY(PPC32, 604E, "PowerPC 604e", 8), + _ENTRY(PPC32, 620, "PowerPC 620", 9), + _ENTRY(PPC32, 750, "PowerPC 750", 10), + _ENTRY(PPC32, 7400, "PowerPC 7400", 11), + _ENTRY(PPC32, 7450, "PowerPC 7450", 12), + _ENTRY(PPC32, 970, "PowerPC 970", 13), + { .name = NULL }, +}; +static const struct macho_cpu_subentry macho_cpu_ppc64_subtypes[] = { + _ENTRY(PPC64, ALL, "all PowerPC64", 14), + /*_ENTRY(PPC64, 970, "PowerPC 970", 1),*/ + { .name = NULL }, +}; +#undef _ENTRY + +/* + * A CPU type mapping table with human-readable strings + */ +struct macho_cpu_entry { + const char *name; + macho_cpu_type_t type; + const struct macho_cpu_subentry *subtypes; +}; +static const struct macho_cpu_entry macho_cpu_types[] = { +#define _ENTRY(TYPE, SUBTYPES, NAME) { \ + .name = NAME, \ + .type = MACHO_CPU_TYPE_ ## TYPE, \ + .subtypes = SUBTYPES \ + } + _ENTRY(PPC32, macho_cpu_ppc32_subtypes, "PowerPC" ), + _ENTRY(PPC64, macho_cpu_ppc64_subtypes, "PowerPC64" ), + _ENTRY(I386, macho_cpu_i386_subtypes, "Intel x86" ), + _ENTRY(VAX, macho_cpu_vax_subtypes, "VAX" ), + _ENTRY(M68K, macho_cpu_m68k_subtypes, "Motorola 68xxx"), + _ENTRY(MIPS, macho_cpu_mips_subtypes, "MIPS" ), + _ENTRY(M98K, macho_cpu_m98k_subtypes, "Motorola 98xxx"), + _ENTRY(PARISC, macho_cpu_parisc_subtypes, "HPPA/PaRISC" ), + _ENTRY(ARM, NULL, "ARM" ), + _ENTRY(M88K, macho_cpu_m88k_subtypes, "Motorola 88xxx"), + _ENTRY(SPARC, macho_cpu_sparc_subtypes, "Sparc" ), + _ENTRY(I860, macho_cpu_i860_subtypes, "i860" ), + _ENTRY(ALPHA, NULL, "Alpha" ), + _ENTRY(ANY, NULL, "unknown" ), + { .name = NULL }, +#undef _ENTRY +}; + +static unsigned int macho_check_cpu(macho_cpu_type_t type, + macho_cpu_subtype_t subtype) +{ + const struct macho_cpu_subentry *entry = NULL; + unsigned long i; + + /* Iterate over all the CPU types */ + for (i = 0; macho_cpu_types[i].name; i++) + if (type == macho_cpu_types[i].type) + break; + + /* Invalid CPU if we didn't find a match */ + if (!macho_cpu_types[i].name) { + macho_dbg("Unknown CPU type (%u)\n", type); + return 0; + } + + entry = macho_cpu_types[i].subtypes; + + /* Iterate over all the CPU subtypes (if any) */ + for (; entry && entry->name; entry++) + if (type == entry->type && subtype == entry->subtype) + break; + + /* Invalid CPU if we didn't find a match */ + if (!entry) { + macho_dbg("Unknown %s subtype (%u)\n", + macho_cpu_types[i].name, subtype); + return 0; + } + + macho_dbg("Found binary image for %s\n", entry->name); + + /* Return the preference level for this code */ + return entry->preference; +} + +#endif /* not _MACHO_CPUS_H */ diff --git a/fs/mach-o/debug.h b/fs/mach-o/debug.h new file mode 100644 index 0000000..205cbfe --- /dev/null +++ b/fs/mach-o/debug.h @@ -0,0 +1,9 @@ +#ifndef _MACHO_DEBUG_H +# define _MACHO_DEBUG_H 1 + +# include /* For printk() */ + +# define macho_dbg(x, args...) \ + printk(KERN_DEBUG "binfmt_mach-o: " x,##args) + +#endif /* not _MACHO_DEBUG_H */ diff --git a/fs/mach-o/files.h b/fs/mach-o/files.h new file mode 100644 index 0000000..17253d9 --- /dev/null +++ b/fs/mach-o/files.h @@ -0,0 +1,139 @@ +#ifndef _MACHO_FILES_H +# define _MACHO_FILES_H 1 + +# include "debug.h" +# include /* For __u32 */ + +/* + * Mach-O file types, borrowed from Darwin + */ +typedef __u32 __bitwise macho_file_type_t; +# define _ENTRY(type, num) \ + MACHO_FILE_TYPE_##type = ((__force macho_file_type_t)num) +enum { + _ENTRY(OBJECT, 1), + _ENTRY(EXECUTE, 2), + _ENTRY(FVMLIB, 3), + _ENTRY(CORE, 4), + _ENTRY(PRELOAD, 5), + _ENTRY(DYLIB, 6), + _ENTRY(DYLINKER, 7), + _ENTRY(BUNDLE, 8), + _ENTRY(DYLIB_STUB, 9), +}; +#undef _ENTRY + +/* + * A file type mapping table with human-readable strings + */ +struct macho_file_type_entry { + const char *name; + macho_file_type_t type; + unsigned int runnable; +}; + +static const struct macho_file_type_entry macho_file_types[] = { +#define _ENTRY(TYPE, NAME, RUNNABLE) { \ + .name = NAME, \ + .type = MACHO_FILE_TYPE_ ## TYPE, \ + .runnable = RUNNABLE \ + } + _ENTRY(OBJECT, "relocatable object", 1), + _ENTRY(EXECUTE, "demand-paged executable", 1), + _ENTRY(FVMLIB, "fixed-virtual-memory shared library", 0), + _ENTRY(CORE, "coredump", 0), + _ENTRY(PRELOAD, "preloaded executable", 1), + _ENTRY(DYLIB, "dynamically linked shared library", 0), + _ENTRY(DYLINKER, "dynamic link editor", 0), + _ENTRY(BUNDLE, "dynamically linked module", 0), + _ENTRY(DYLIB_STUB, "shared library stub for static link", 0), + { .name = NULL, } +#undef _ENTRY +}; + +/* + * Mach-O file flags, borrowed from Darwin + */ +enum macho_file_flag { + MACHO_FILE_FLAG_NO_UNDEF = 0, + MACHO_FILE_FLAG_INCR_LINK = 1, + MACHO_FILE_FLAG_DYN_LINK = 2, + MACHO_FILE_FLAG_BIND_AT_LOAD = 3, + MACHO_FILE_FLAG_PREBOUND = 4, + MACHO_FILE_FLAG_SPLIT_SEGS = 5, + MACHO_FILE_FLAG_LAZY_INIT = 6, + MACHO_FILE_FLAG_TWO_LEVEL = 7, + MACHO_FILE_FLAG_FORCE_FLAT = 8, + MACHO_FILE_FLAG_NO_MULT_DEFS = 9, + MACHO_FILE_FLAG_NO_FIX_PREBIND = 10, + MACHO_FILE_FLAG_PREBINDABLE = 11, + MACHO_FILE_FLAG_ALL_MODS_BOUND = 12, + MACHO_FILE_FLAG_SUBSECT_VIA_SYM = 13, + MACHO_FILE_FLAG_CANONICAL = 14, + MACHO_FILE_FLAG_WEAK_DEFINES = 15, + MACHO_FILE_FLAG_BINDS_TO_WEAK = 16, + MACHO_FILE_FLAG_EXECSTACK = 17, +}; + +/* + * A file flag mapping table with human-readable strings + */ +static const char *macho_file_flags[] = { +#define _ENTRY(FLAG, NAME) [MACHO_FILE_FLAG_ ## FLAG] = NAME + _ENTRY( NO_UNDEF, "has no undefined references" ), + _ENTRY( INCR_LINK, "was incrementally linked" ), + _ENTRY( DYN_LINK, "was dynamically linked" ), + _ENTRY( BIND_AT_LOAD, "will bind undefined refs during load" ), + _ENTRY( PREBOUND, "is prebound" ), + _ENTRY( SPLIT_SEGS, "has split RO and R/W segments" ), + _ENTRY( LAZY_INIT, "is lazily initialized" ), + _ENTRY( TWO_LEVEL, "uses two-level namespace bindings" ), + _ENTRY( FORCE_FLAT, "forces flat namespace bindings" ), + _ENTRY( NO_MULT_DEFS, "doesn't have multiply defined symbols" ), + _ENTRY( NO_FIX_PREBIND, "won't notify the prebinding agent" ), + _ENTRY( PREBINDABLE, "can be prebound" ), + _ENTRY( ALL_MODS_BOUND, "is fully bound to two-level namespaces"), + _ENTRY( SUBSECT_VIA_SYM,"can be divided via symbols" ), + _ENTRY( CANONICAL, "is canonicalized by un-prebinding" ), + _ENTRY( WEAK_DEFINES, "exports weak symbols" ), + _ENTRY( BINDS_TO_WEAK, "imports weak symbols" ), + _ENTRY( EXECSTACK, "requires executable stack" ), + NULL +}; + +static int macho_check_file(macho_file_type_t type, __u32 flags) +{ + enum macho_file_flag flag = /* 0 */ MACHO_FILE_FLAG_NO_UNDEF; + unsigned long i; + + /* Iterate over the list of file types */ + for (i = 0; macho_file_types[i].name; i++) + if (macho_file_types[i].type == type) + break; + + /* If we didn't find the file type then it's not executable */ + if (!macho_file_types[i].name) { + macho_dbg("Unknown filetype (%u)\n", type); + return 0; + } + + macho_dbg("Mach-O %s (%sexecutable):\n", macho_file_types[i].name, + macho_file_types[i].runnable?"":"not "); + + /* Check every flag */ + while (flags && macho_file_flags[flag]) { + if (flags & 1) + macho_dbg(" %s\n", macho_file_flags[flag]); + + flag++; + flags >>= 1; + } + + if (flags) + macho_dbg("Unknown file flag bits: 0x%08lx\n", + (unsigned long)(flags << flag)); + + return macho_file_types[i].runnable; +} + +#endif /* not _MACHO_FILES_H */ diff --git a/fs/mach-o/headers.h b/fs/mach-o/headers.h new file mode 100644 index 0000000..17f019d --- /dev/null +++ b/fs/mach-o/headers.h @@ -0,0 +1,49 @@ +#ifndef _MACHO_HEADERS_H +# define _MACHO_HEADERS_H 1 + +# include +# include "cpus.h" + +/* Mach-O universal binary header */ +# define MACHO_FAT_MAGIC (__constant_cpu_to_be32(0xcafebabe)) +struct macho_fat_header { + __be32 magic; + __be32 arch_count; +} __attribute__((__packed__)); + +struct macho_fat_arch { + __be32 cpu_type; + __be32 cpu_subtype; + __be32 offset; + __be32 size; + __be32 align; +} __attribute__((__packed__)); + +/* Mach-O 32-bit arch-specific binary header */ +# define MACHO_MACH32_MAGIC (0xfeedface) +# define MACHO_MACH32_CIGAM (___constant_swab32(MACHO_MACH32_MAGIC)) +struct macho_mach32_header { + __u32 magic; + macho_cpu_type_t cpu_type; + macho_cpu_subtype_t cpu_subtype; + __u32 filetype; + __u32 cmd_count; + __u32 cmd_size; + __u32 flags; +} __attribute__((__packed__)); + +/* Mach-O 64-bit arch-specific binary header */ +# define MACHO_MACH64_MAGIC (0xfeedfacf) +# define MACHO_MACH64_CIGAM (___constant_swab32(MACHO_MACH64_MAGIC)) +struct macho_mach64_header { + __u32 magic; + macho_cpu_type_t cpu_type; + macho_cpu_subtype_t cpu_subtype; + __u32 filetype; + __u32 cmd_count; + __u32 cmd_size; + __u32 flags; + __u32 reserved; +} __attribute__((__packed__)); + +#endif /* not _MACHO_HEADERS_H */