* [RFC][PATCH 1/2] Darwinux: Minimalist Mach-O binary format support
2007-03-30 18:05 [RFC][PATCH 0/2] Darwinux: Binary compat support for Mach-O/Darwin in Linux Kyle Moffett
@ 2007-03-30 18:06 ` Kyle Moffett
2007-03-30 18:08 ` [RFC][PATCH 2/2] Darwinux: Proper support for digging through the Mach-O load-command table Kyle Moffett
1 sibling, 0 replies; 3+ messages in thread
From: Kyle Moffett @ 2007-03-30 18:06 UTC (permalink / raw)
To: Kyle Moffett
Cc: LKML Kernel, Linus Torvalds, Benjamin Herrenschmidt,
Paul Mackerras, Mathieu Desnoyers
[-- Attachment #1: Type: text/plain, Size: 814 bytes --]
Minimalist Mach-O binary format support
This code is sucessfully able to load and recognize Mach-O binary files.
It is able to sort through the FAT file headers and identify compatible
files, although it currently is hardcoded for PowerPC64 architecture.
Does not yet support load_commands or actually mapping the Mach-O files
into memory.
Signed-off-by: Kyle Moffett <mrmacman_g4@mac.com>
---
fs/Kconfig.binfmt | 14 ++
fs/Makefile | 1 +
fs/mach-o/Makefile | 8 ++
fs/mach-o/binfmt.c | 321 +++++++++++++++++++++++++++++++++++++++++++
++++++
fs/mach-o/cpus.h | 329 +++++++++++++++++++++++++++++++++++++++++++
++++++++
fs/mach-o/debug.h | 9 ++
fs/mach-o/files.h | 139 ++++++++++++++++++++++
fs/mach-o/headers.h | 49 ++++++++
8 files changed, 870 insertions(+), 0 deletions(-)
[-- Attachment #2: darwinux_01.txt --]
[-- Type: text/plain, Size: 27533 bytes --]
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 <mrmacman_g4@mac.com>
+ *
+ * Designed from public documentation and Darwin sources as well as the Linux
+ * ELF loader by Eric Youngdale (ericy@cais.com).
+ */
+
+#include <linux/module.h>
+#include <linux/binfmts.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+
+#include "debug.h"
+#include "cpus.h"
+#include "headers.h"
+#include "files.h"
+
+#if 0
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/string.h>
+#include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/shm.h>
+#include <linux/personality.h>
+#include <linux/elfcore.h>
+#include <linux/init.h>
+#include <linux/highuid.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/compiler.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/security.h>
+#include <linux/syscalls.h>
+#include <linux/random.h>
+
+#include <asm/uaccess.h>
+#include <asm/param.h>
+#include <asm/page.h>
+#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 <linux/compiler.h>
+# include <linux/types.h>
+# include <linux/err.h>
+
+/*
+ * 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 <linux/kernel.h> /* 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 <linux/types.h> /* 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 <linux/types.h>
+# 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 */
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [RFC][PATCH 2/2] Darwinux: Proper support for digging through the Mach-O load-command table
2007-03-30 18:05 [RFC][PATCH 0/2] Darwinux: Binary compat support for Mach-O/Darwin in Linux Kyle Moffett
2007-03-30 18:06 ` [RFC][PATCH 1/2] Darwinux: Minimalist Mach-O binary format support Kyle Moffett
@ 2007-03-30 18:08 ` Kyle Moffett
1 sibling, 0 replies; 3+ messages in thread
From: Kyle Moffett @ 2007-03-30 18:08 UTC (permalink / raw)
To: Kyle Moffett
Cc: LKML Kernel, Linus Torvalds, Benjamin Herrenschmidt,
Paul Mackerras, Mathieu Desnoyers
[-- Attachment #1: Type: text/plain, Size: 790 bytes --]
Proper support for digging through the Mach-O load-command table
Uses kernel_read() to carefully iterate through all the Mach-O load
commands and logs their properties to the dmesg buffer. Partial
support is
also present for VM setup, but it's lacking a necessary symbol export on
PowerPC (arch_pick_mmap_layout). The process currently receives a
SIGKILL
after reading through all the load commands; pending completion of the
memory-mapping and setup code.
Signed-off-by: Kyle Moffett <mrmacman_g4@mac.com>
---
fs/mach-o/binfmt.c | 258 +++++++++++++++++++++++----------
fs/mach-o/cpus.h | 49 ++++---
fs/mach-o/files.h | 67 +++++----
fs/mach-o/loadcmds.h | 389 ++++++++++++++++++++++++++++++++++++++++++
++++++++
4 files changed, 640 insertions(+), 123 deletions(-)
[-- Attachment #2: darwinux_02.txt --]
[-- Type: text/plain, Size: 29049 bytes --]
diff --git a/fs/mach-o/binfmt.c b/fs/mach-o/binfmt.c
index b5ea936..ea2f46e 100644
--- a/fs/mach-o/binfmt.c
+++ b/fs/mach-o/binfmt.c
@@ -14,44 +14,13 @@
#include <linux/binfmts.h>
#include <linux/fs.h>
#include <linux/err.h>
+#include <linux/personality.h>
#include "debug.h"
#include "cpus.h"
#include "headers.h"
#include "files.h"
-
-#if 0
-#include <linux/kernel.h>
-#include <linux/stat.h>
-#include <linux/time.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/string.h>
-#include <linux/file.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/shm.h>
-#include <linux/personality.h>
-#include <linux/elfcore.h>
-#include <linux/init.h>
-#include <linux/highuid.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/compiler.h>
-#include <linux/highmem.h>
-#include <linux/pagemap.h>
-#include <linux/security.h>
-#include <linux/syscalls.h>
-#include <linux/random.h>
-
-#include <asm/uaccess.h>
-#include <asm/param.h>
-#include <asm/page.h>
-#endif
+#include "loadcmds.h"
MODULE_LICENSE("GPL");
@@ -187,21 +156,25 @@ static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs)
struct macho_mach32_header mach32;
struct macho_mach64_header mach64;
} header;
-#if 0
- struct macho_loadcmd loadcmd;
-#endif
+ union macho_loadcmd loadcmd;
} *data = NULL;
- unsigned long offset;
+ unsigned long hdr_cmd_count, hdr_cmd_size;
+ unsigned long cur_offset, loadcmd_size, i;
+ unsigned long arch_offset;
long retval;
- int err;
+ int err = -ENOEXEC;
+
+ /* Make sure the file has appropriate ops */
+ if (!bprm->file->f_op || !bprm->file->f_op->mmap)
+ goto out;
/*
* 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;
+ arch_offset = get_arch_offset(bprm);
+ if (IS_ERR_VALUE(arch_offset)) {
+ err = (long)arch_offset;
goto out;
}
@@ -213,14 +186,14 @@ static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs)
}
/* Read the header data and check the magic */
- retval = kernel_read(bprm->file, offset,
+ retval = kernel_read(bprm->file, arch_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)
+ if (!arch_offset)
err = -ENOEXEC;
/* If kernel_read() returned an error, handle it */
@@ -251,7 +224,7 @@ static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs)
*/
if (data->header.magic != MACHO_MACH32_MAGIC &&
data->header.magic != MACHO_MACH64_MAGIC) {
- if (offset)
+ if (arch_offset)
macho_dbg("Corrupt embedded Mach-O object!\n");
err = -ENOEXEC;
goto out;
@@ -260,13 +233,12 @@ static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs)
/* 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.
+ * a different platform (arch_offset == 0) or the FAT Mach-O
+ * has been corrupted.
*/
- if (offset)
+ if (arch_offset)
macho_dbg("FAT Mach-O wrapper has mismatched CPU"
" types: Mach-O file corrupt?\n");
else
@@ -283,39 +255,175 @@ static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs)
goto out;
}
+ /*
+ * Get some load-command info out of the header (NOTE: Lines up
+ * between 32-bit and 64-bit Mach-O files
+ */
+ hdr_cmd_count = data->header.mach32.cmd_count;
+ hdr_cmd_size = data->header.mach32.cmd_size;
+
+ /*
+ * FIXME: Limits the total space for load commands to 1MB, but this
+ * should be made configurable somehow for embedded systems with
+ * minimal available resources. Is there an rlimit or some page
+ * accounting we can hook into? I don't think this is that critical
+ * of an issue since for the most part we only store one load-command
+ * in kernel memory at a time, however some things like unixthread
+ * and thread load-commands need to be kept around until after we've
+ * loaded the dynamic linker.
+ */
+ if (hdr_cmd_size > (1 << 20)) {
+ macho_dbg("Mach-O file has more than 1MB worth of "
+ "load-commands (%lu bytes)\n", hdr_cmd_size);
+ err = -ENOMEM;
+ 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);
+ cur_offset = arch_offset +
+ ((data->header.magic == MACHO_MACH32_MAGIC)
+ ? sizeof(struct macho_mach32_header)
+ : sizeof(struct macho_mach64_header));
+
+#if 0
+ /*
+ * Just to avoid allocating gobs of kernel memory while we parse the
+ * load-command table, we're going to go past the point of no return
+ * nice and early, so we can just start mapping things into memory
+ */
+ err = flush_old_exec(bprm);
+ if (err)
+ goto out;
+
+ /* FIXME: This needs to actually switch to the darwin personality */
+ set_personality(PER_LINUX);
+
+ /* FIXME: Set up ugly stack/brk/etc for testing, need to fix later */
+ current->mm->start_data = 0;
+ current->mm->end_data = 0;
+ current->mm->end_code = 0;
+ current->mm->mmap = NULL;
+ current->mm->def_flags = 0;
+
+ /* Make sure to clear the fork-but-not-exec bit on this process */
+ current->flags &= ~PF_FORKNOEXEC;
+
+ /*
+ * FIXME: Figure out how to do MMAP, may need to be changed to be
+ * darwinish
+ */
+ current->mm->mmap_base = TASK_UNMAPPED_BASE;
+ current->mm->get_unmapped_area = arch_get_unmapped_area;
+ current->mm->unmap_area = arch_unmap_area;
+ current->mm->free_area_cache = current->mm->mmap_base;
+ current->mm->cached_hole_size = 0;
+#endif
+
+ /* Iterate over reading the load commands */
+ loadcmd_size = 0;
+ for (i = 0; i < hdr_cmd_count; i++) {
+ unsigned long size;
+
+ /* Check that we have room for another load command */
+ if (loadcmd_size + sizeof(data->loadcmd.hdr) > hdr_cmd_size) {
+ macho_dbg("Mach-O header doesn't allocate enough "
+ "space for load-commands %lu-%lu!\n",
+ i, hdr_cmd_count-1);
+ err = -ENOEXEC;
+ goto out_noreturn;
+ }
+
+ /* First read the itty-bitty command num and size fields */
+ retval = kernel_read(bprm->file, cur_offset,
+ (void *)&data->loadcmd.hdr,
+ sizeof(data->loadcmd.hdr));
+ if (retval != sizeof(data->loadcmd.hdr)) {
+ /* If kernel_read() returned an error, handle it */
+ if (retval < 0) {
+ macho_dbg("Error while reading Mach-O load"
+ " command %lu: %li\n", i, retval);
+ err = retval;
+ } else {
+ macho_dbg("Truncated Mach-O load command "
+ "%lu: (got %lib, wanted %lub)\n", i,
+ retval, sizeof(data->loadcmd.hdr));
+ err = -ENOEXEC;
+ }
+ goto out_noreturn;
+ }
+
+ /* Check/display the load command number */
+ macho_check_loadcmd(data->loadcmd.hdr.cmd);
+ size = data->loadcmd.hdr.size;
+
+ /*
+ * Ensure the load-command size is a multiple of 4 bytes and
+ * large enough to contain the load-command header.
+ */
+ if (size & 0x3 || size < sizeof(data->loadcmd.hdr)) {
+ macho_dbg("Invalid size for load command %lu: %lu\n",
+ i, (unsigned long)data->loadcmd.hdr.size);
+ err = -ENOEXEC;
+ goto out_noreturn;
+ }
+
+ /* Check that we have room for another load command */
+ if (loadcmd_size + size > hdr_cmd_size) {
+ macho_dbg("Mach-O header doesn't allocate enough "
+ "space for load-commands %lu-%lu!\n",
+ i, hdr_cmd_count-1);
+ err = -ENOEXEC;
+ goto out_noreturn;
+ }
+
+ /* Check that it isn't too big */
+ if (size > sizeof(data->loadcmd)) {
+ macho_dbg("Load command %lu is too big (%lu > %lu): "
+ "skipped!\n", i, size, sizeof(data->loadcmd));
+ loadcmd_size += size;
+ cur_offset += size;
+ continue;
+ }
+
+ /* Read in the rest of the load-command and move past it */
+ retval = kernel_read(bprm->file, cur_offset,
+ (void *)&data->loadcmd, size);
+ if (retval != size) {
+ /* If kernel_read() returned an error, handle it */
+ if (retval < 0) {
+ macho_dbg("Error while reading Mach-O load"
+ " command %lu: %li\n", i, retval);
+ err = retval;
+ } else {
+ macho_dbg("Truncated Mach-O load command "
+ "%lu: (got %lib, wanted %lub)\n", i,
+ retval, size);
+ err = -ENOEXEC;
+ }
+ goto out_noreturn;
+ }
+ loadcmd_size += size;
+ cur_offset += size;
+
+ switch (data->loadcmd.hdr.cmd) {
+ case MACHO_LOADCMD_NUM_SEGMENT64:
+ case MACHO_LOADCMD_NUM_SEGMENT32:
+ case MACHO_LOADCMD_NUM_THREAD_NOSTACK:
+ case MACHO_LOADCMD_NUM_THREAD:
+ case MACHO_LOADCMD_NUM_REF_DYLD:
+ macho_dbg(" Load command completed!\n");
+ break;
+ }
+ /* XXX FIXME XXX: Process the load-command */
+ }
err = -EINVAL;
- goto out;
+ goto out_noreturn;
+out_noreturn:
+ send_sig(SIGKILL, current, 0);
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
index a1f2276..00fa3c0 100644
--- a/fs/mach-o/cpus.h
+++ b/fs/mach-o/cpus.h
@@ -12,20 +12,27 @@ 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),
+ /* Historical architecture codes */
+ _ENTRY(ANY, 0xffffffff), /* CPU_TYPE_ANY */
+ _ENTRY(VAX, 0x00000001), /* CPU_TYPE_VAX */
+ _ENTRY(M68K, 0x00000006), /* CPU_TYPE_MC680x0 */
+ _ENTRY(MIPS, 0x00000008), /* CPU_TYPE_MIPS */
+ _ENTRY(M98K, 0x0000000a), /* CPU_TYPE_M98000 */
+ _ENTRY(PARISC, 0x0000000b), /* CPU_TYPE_HPPA */
+ _ENTRY(ARM, 0x0000000c), /* CPU_TYPE_ARM */
+ _ENTRY(M88K, 0x0000000d), /* CPU_TYPE_M88000 */
+ _ENTRY(SPARC, 0x0000000e), /* CPU_TYPE_SPARC */
+ _ENTRY(I860, 0x0000000f), /* CPU_TYPE_I860 */
+ _ENTRY(ALPHA, 0x00000010), /* CPU_TYPE_ALPHA */
+
+ /*
+ * Modern supported architectures. Note that a "CPU_TYPE_ABI64" flag
+ * is OR-ed into the architecture code for a 64-bit architecture
+ */
+ _ENTRY(I386, 0x00000007), /* CPU_TYPE_X86 / CPU_TYPE_I386 */
+ _ENTRY(X86_64, 0x01000007), /* CPU_TYPE_X86_64 */
+ _ENTRY(PPC32, 0x00000012), /* CPU_TYPE_POWERPC */
+ _ENTRY(PPC64, 0x01000012), /* CPU_TYPE_POWERPC64 */
};
#undef _ENTRY
@@ -84,6 +91,9 @@ enum {
_ENTRY(I386_XEON, 0x0000000c),
_ENTRY(I386_XEON_MP, 0x0000001c),
+ /* AMD 64-bit subtypes */
+ _ENTRY(X86_64_ALL, 0x00000003),
+
/* MIPS subtypes */
_ENTRY(MIPS_ALL, 0x00000000),
_ENTRY(MIPS_R2300, 0x00000001),
@@ -131,7 +141,7 @@ enum {
/* Motorola/Freescale/IBM PowerPC64 subtypes */
_ENTRY(PPC64_ALL, 0x00000000),
- /*_ENTRY(PPC64_970, 0x00000001),*/
+ _ENTRY(PPC64_970, 0x00000064),
};
#undef _ENTRY
@@ -198,6 +208,10 @@ static const struct macho_cpu_subentry macho_cpu_i386_subtypes[] = {
_ENTRY(I386, XEON_MP, "Intel Xeon SMP", 0),
{ .name = NULL },
};
+static const struct macho_cpu_subentry macho_cpu_x86_64_subtypes[] = {
+ _ENTRY(X86_64, ALL, "all 64-bit AMD", 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),
@@ -252,7 +266,7 @@ static const struct macho_cpu_subentry macho_cpu_ppc32_subtypes[] = {
};
static const struct macho_cpu_subentry macho_cpu_ppc64_subtypes[] = {
_ENTRY(PPC64, ALL, "all PowerPC64", 14),
- /*_ENTRY(PPC64, 970, "PowerPC 970", 1),*/
+ _ENTRY(PPC64, 970, "PowerPC 970", 15),
{ .name = NULL },
};
#undef _ENTRY
@@ -273,7 +287,8 @@ static const struct macho_cpu_entry macho_cpu_types[] = {
}
_ENTRY(PPC32, macho_cpu_ppc32_subtypes, "PowerPC" ),
_ENTRY(PPC64, macho_cpu_ppc64_subtypes, "PowerPC64" ),
- _ENTRY(I386, macho_cpu_i386_subtypes, "Intel x86" ),
+ _ENTRY(I386, macho_cpu_i386_subtypes, "Intel/AMD x86" ),
+ _ENTRY(X86_64, macho_cpu_x86_64_subtypes, "AMD 64-bit x86"),
_ENTRY(VAX, macho_cpu_vax_subtypes, "VAX" ),
_ENTRY(M68K, macho_cpu_m68k_subtypes, "Motorola 68xxx"),
_ENTRY(MIPS, macho_cpu_mips_subtypes, "MIPS" ),
diff --git a/fs/mach-o/files.h b/fs/mach-o/files.h
index 17253d9..cdbd028 100644
--- a/fs/mach-o/files.h
+++ b/fs/mach-o/files.h
@@ -8,20 +8,21 @@
* Mach-O file types, borrowed from Darwin
*/
typedef __u32 __bitwise macho_file_type_t;
+enum {
# 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),
-};
+ _ENTRY(OBJECT, 0x01), /* MH_OBJECT */
+ _ENTRY(EXECUTE, 0x02), /* MH_EXECUTE */
+ _ENTRY(FVMLIB, 0x03), /* MH_FVMLIB */
+ _ENTRY(CORE, 0x04), /* MH_CORE */
+ _ENTRY(PRELOAD, 0x05), /* MH_PRELOAD */
+ _ENTRY(DYLIB, 0x06), /* MH_DYLIB */
+ _ENTRY(DYLD, 0x07), /* MH_DYLINKER */
+ _ENTRY(BUNDLE, 0x08), /* MH_BUNDLE */
+ _ENTRY(DYLIB_STUB, 0x09), /* MH_DYLIB_STUB */
+ _ENTRY(DEBUG_SYM, 0x0a), /* MY_DSYM */
#undef _ENTRY
+};
/*
* A file type mapping table with human-readable strings
@@ -44,9 +45,10 @@ static const struct macho_file_type_entry macho_file_types[] = {
_ENTRY(CORE, "coredump", 0),
_ENTRY(PRELOAD, "preloaded executable", 1),
_ENTRY(DYLIB, "dynamically linked shared library", 0),
- _ENTRY(DYLINKER, "dynamic link editor", 0),
+ _ENTRY(DYLD, "dynamic link editor", 0),
_ENTRY(BUNDLE, "dynamically linked module", 0),
_ENTRY(DYLIB_STUB, "shared library stub for static link", 0),
+ _ENTRY(DEBUG_SYM, "debug symbol file", 0),
{ .name = NULL, }
#undef _ENTRY
};
@@ -55,24 +57,26 @@ static const struct macho_file_type_entry macho_file_types[] = {
* 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,
+#define _ENTRY(type, num) MACHO_FILE_FLAG_##type = num
+ _ENTRY(NO_UNDEF, 0), /* MH_NOUNDEFS */
+ _ENTRY(INCR_LINK, 1), /* MH_INCRLINK */
+ _ENTRY(DYN_LINK, 2), /* MH_DYLDLINK */
+ _ENTRY(BIND_AT_LOAD, 3), /* MH_BINDATLOAD */
+ _ENTRY(PREBOUND, 4), /* MH_PREBOUND */
+ _ENTRY(SPLIT_SEGS, 5), /* MH_SPLIT_SEGS */
+ _ENTRY(LAZY_INIT, 6), /* MH_LAZY_INIT */
+ _ENTRY(TWO_LEVEL, 7), /* MH_TWOLEVEL */
+ _ENTRY(FORCE_FLAT, 8), /* MH_FORCE_FLAT */
+ _ENTRY(NO_MULT_DEFS, 9), /* MH_NOMULTIDEFS */
+ _ENTRY(NO_FIX_PREBIND, 10), /* MH_NOFIXPREBINDING */
+ _ENTRY(PREBINDABLE, 11), /* MH_PREBINDABLE */
+ _ENTRY(ALL_MODS_BOUND, 12), /* MH_ALLMODSBOUND */
+ _ENTRY(SUBSECT_VIA_SYM, 13), /* MH_SUBSECTIONS_VIA_SYMBOLS */
+ _ENTRY(CANONICAL, 14), /* MH_CANONICAL */
+ _ENTRY(WEAK_DEFINES, 15), /* MH_WEAK_DEFINES */
+ _ENTRY(BINDS_TO_WEAK, 16), /* MH_BINDS_TO_WEAK */
+ _ENTRY(EXECSTACK, 17), /* MH_ALLOW_STACK_EXECUTION */
+#undef _ENTRY
};
/*
@@ -98,7 +102,8 @@ static const char *macho_file_flags[] = {
_ENTRY( WEAK_DEFINES, "exports weak symbols" ),
_ENTRY( BINDS_TO_WEAK, "imports weak symbols" ),
_ENTRY( EXECSTACK, "requires executable stack" ),
- NULL
+ NULL,
+#undef _ENTRY
};
static int macho_check_file(macho_file_type_t type, __u32 flags)
diff --git a/fs/mach-o/loadcmds.h b/fs/mach-o/loadcmds.h
new file mode 100644
index 0000000..0ee35c3
--- /dev/null
+++ b/fs/mach-o/loadcmds.h
@@ -0,0 +1,389 @@
+#ifndef _MACHO_LOADCMDS_H
+# define _MACHO_LOADCMDS_H 1
+
+# include <linux/types.h>
+
+/*
+ * Mach-O load-command types, borrowed from Darwin
+ */
+typedef __u32 __bitwise macho_loadcmd_num_t;
+enum {
+# define _ENTRY(type, num) \
+ MACHO_LOADCMD_NUM_##type = ((__force macho_loadcmd_num_t)num)
+ _ENTRY(SEGMENT32, 0x01), /* LC_SEGMENT */
+ _ENTRY(SYMTAB_STAB, 0x02), /* LC_SYMTAB */
+ _ENTRY(SYMTAB_GDB, 0x03), /* LC_SYMSEG */
+ _ENTRY(THREAD_NOSTACK, 0x04), /* LC_THREAD */
+ _ENTRY(THREAD, 0x05), /* LC_UNIXTHREAD */
+ _ENTRY(REF_FVMLIB, 0x06), /* LC_LOADFVMLIB */
+ _ENTRY(ID_FVMLIB, 0x07), /* LC_IDFVMLIB */
+ _ENTRY(ID, 0x08), /* LC_IDENT */
+ _ENTRY(FVMFILE, 0x09), /* LC_FVMFILE */
+ _ENTRY(PREPAGE, 0x0a), /* LC_PREPAGE */
+ _ENTRY(SYMTAB_DYLD, 0x0b), /* LC_DYSYMTAB */
+ _ENTRY(REF_DYLIB, 0x0c), /* LC_LOAD_DYLIB */
+ _ENTRY(ID_DYLIB, 0x0d), /* LC_ID_DYLIB */
+ _ENTRY(REF_DYLD, 0x0e), /* LC_LOAD_DYLINKER */
+ _ENTRY(ID_DYLD, 0x0f), /* LC_ID_DYLINKER */
+ _ENTRY(PREBINDING, 0x10), /* LC_PREBOUND_DYLIB */
+ _ENTRY(INITCODE32, 0x11), /* LC_ROUTINES */
+ _ENTRY(SUB_FRAMEWORK, 0x12), /* LC_SUB_FRAMEWORK */
+ _ENTRY(SUB_UMBRELLA, 0x13), /* LC_SUB_UMBRELLA */
+ _ENTRY(SUB_CLIENT, 0x14), /* LC_SUB_CLIENT */
+ _ENTRY(SUB_LIBRARY, 0x15), /* LC_SUB_LIBRARY */
+ _ENTRY(HINTS_2LEVEL, 0x16), /* LC_TWOLEVEL_HINTS */
+ _ENTRY(PREBIND_CKSUM, 0x17), /* LC_PREBIND_CKSUM */
+ _ENTRY(WEAKREF_DYLIB, 0x18), /* LC_LOAD_DYLIB_WEAK */
+ _ENTRY(SEGMENT64, 0x19), /* LC_SEGMENT_64 */
+ _ENTRY(INITCODE64, 0x1a), /* LC_ROUTINES_64 */
+ _ENTRY(UUID, 0x1b), /* LC_UUID */
+# undef _ENTRY
+};
+
+/* Mach-O load command header */
+struct macho_loadcmd_hdr {
+ __u32 cmd;
+ __u32 size;
+} __attribute__((__packed__));
+
+/* Variable-length string in a Mach-O load command */
+struct macho_loadcmd_varstr {
+ __u32 off;
+} __attribute__((__packed__));
+
+/* Generic large load command */
+struct macho_loadcmd_unknown {
+ struct macho_loadcmd_hdr hdr;
+ __u8 data[2048 - sizeof(struct macho_loadcmd_hdr)];
+} __attribute__((__packed__));
+
+/* Mach-O memory-mapped file segment (32-bit) */
+struct macho_loadcmd_segment32 {
+ struct macho_loadcmd_hdr hdr;
+ char name[16];
+ __u32 vm_addr;
+ __u32 vm_size;
+ __u32 file_off;
+ __u32 file_size;
+ __u32 prot_max;
+ __u32 prot_init;
+ __u32 sect_count;
+ __u32 flags;
+} __attribute__((__packed__));
+
+/* Mach-O symbol table (stab) */
+struct macho_loadcmd_symtab_stab {
+ struct macho_loadcmd_hdr hdr;
+ __u32 sym_off;
+ __u32 sym_count;
+ __u32 str_off;
+ __u32 str_size;
+} __attribute__((__packed__));
+
+/* Mach-O symbol table (gdb, obsolete) */
+struct macho_loadcmd_symtab_gdb {
+ struct macho_loadcmd_hdr hdr;
+ __u32 symtab_off;
+ __u32 symtab_size;
+} __attribute__((__packed__));
+
+/* Mach-O new thread (with or without stack) */
+# define MACHO_LOADCMD_THREAD_MAX_PPC 144
+# define MACHO_LOADCMD_THREAD_MAX_X86 144
+struct macho_loadcmd_thread {
+ struct macho_loadcmd_hdr hdr;
+ __u32 threaddata[];
+} __attribute__((__packed__));
+
+/* Mach-O reference to or identity of a fixed-VM shared lib */
+struct macho_loadcmd_fvmlib {
+ struct macho_loadcmd_hdr hdr;
+ struct macho_loadcmd_varstr path;
+ __u32 vers;
+ __u32 addr;
+ __u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O identity of an object (obsolete) */
+struct macho_loadcmd_id {
+ struct macho_loadcmd_hdr hdr;
+ __u8 iddata[];
+} __attribute__((__packed__));
+
+/* Mach-O reference to a fixed VM file */
+struct macho_loadcmd_fvmfile {
+ struct macho_loadcmd_hdr hdr;
+ struct macho_loadcmd_varstr path;
+ __u32 addr;
+ __u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O unknown (LC_PREPAGE) */
+struct macho_loadcmd_prepage {
+ struct macho_loadcmd_hdr hdr;
+ __u8 prepagedata[];
+} __attribute__((__packed__));
+
+/* Mach-O symbol table (dyld) */
+struct macho_loadcmd_symtab_dyld {
+ struct macho_loadcmd_hdr hdr;
+ __u32 sym_local_off;
+ __u32 sym_local_num;
+ __u32 sym_extern_off;
+ __u32 sym_extern_num;
+ __u32 sym_undef_off;
+ __u32 sym_undef_num;
+ __u32 toc_off;
+ __u32 toc_num;
+ __u32 modtab_off;
+ __u32 modtab_num;
+ __u32 extref_off;
+ __u32 extref_num;
+ __u32 indirect_off;
+ __u32 indirect_num;
+ __u32 extrel_off;
+ __u32 extrel_num;
+ __u32 localrel_off;
+ __u32 localrel_num;
+} __attribute__((__packed__));
+
+/* Mach-O reference to or identity of a dynamic shared lib */
+struct macho_loadcmd_dylib {
+ struct macho_loadcmd_hdr hdr;
+ struct macho_loadcmd_varstr path;
+ __u32 timestamp;
+ __u32 vers_current;
+ __u32 vers_compat;
+ __u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O reference to or identity of a dynamic linker */
+struct macho_loadcmd_dyld {
+ struct macho_loadcmd_hdr hdr;
+ struct macho_loadcmd_varstr path;
+ __u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O prebinding against a dynamic shared lib */
+struct macho_loadcmd_prebinding {
+ struct macho_loadcmd_hdr hdr;
+ struct macho_loadcmd_varstr path;
+ __u32 modvec_num;
+ __u32 modvec_off;
+ __u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O shared library init routine (32-bit) */
+struct macho_loadcmd_initcode32 {
+ struct macho_loadcmd_hdr hdr;
+ __u32 init_address;
+ __u32 init_module;
+ __u32 reserved[6];
+} __attribute__((__packed__));
+
+/* Mach-O sub-framework file */
+struct macho_loadcmd_sub_framework {
+ struct macho_loadcmd_hdr hdr;
+ struct macho_loadcmd_varstr parent;
+ __u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O sub-umbrella-framework file */
+struct macho_loadcmd_sub_umbrella {
+ struct macho_loadcmd_hdr hdr;
+ struct macho_loadcmd_varstr parent;
+ __u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O sub-framework client entry */
+struct macho_loadcmd_sub_client {
+ struct macho_loadcmd_hdr hdr;
+ struct macho_loadcmd_varstr client;
+ __u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O sub-framework library */
+struct macho_loadcmd_sub_library {
+ struct macho_loadcmd_hdr hdr;
+ struct macho_loadcmd_varstr parent;
+ __u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O two-level namespace hinting table */
+struct macho_loadcmd_hints_2level {
+ struct macho_loadcmd_hdr hdr;
+ __u32 hinttable_offset;
+ __u32 hinttable_count;
+} __attribute__((__packed__));
+
+/* Mach-O prebinding checksum */
+struct macho_loadcmd_prebind_cksum {
+ struct macho_loadcmd_hdr hdr;
+ __u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O memory-mapped file segment (64-bit) */
+struct macho_loadcmd_segment64 {
+ struct macho_loadcmd_hdr hdr;
+ char name[16];
+ __u64 vm_addr;
+ __u64 vm_size;
+ __u32 file_off;
+ __u32 file_size;
+ __u32 prot_max;
+ __u32 prot_init;
+ __u32 sect_count;
+ __u32 flags;
+} __attribute__((__packed__));
+
+/* Mach-O shared library init routine (64-bit) */
+struct macho_loadcmd_initcode64 {
+ struct macho_loadcmd_hdr hdr;
+ __u64 init_address;
+ __u64 init_module;
+ __u64 reserved[6];
+} __attribute__((__packed__));
+
+/* Mach-O linked object UUID (LC_UUID) */
+struct macho_loadcmd_uuid {
+ struct macho_loadcmd_hdr hdr;
+ __u8 uuid[16];
+} __attribute__((__packed__));
+
+/* A generic Mach-O load command */
+union macho_loadcmd {
+ struct macho_loadcmd_hdr hdr;
+ struct macho_loadcmd_unknown unknown;
+ struct macho_loadcmd_segment32 segment32;
+ struct macho_loadcmd_symtab_stab symtab_stab;
+ struct macho_loadcmd_symtab_gdb symtab_gdb;
+ struct macho_loadcmd_thread thread;
+ struct macho_loadcmd_fvmlib fvmlib;
+ struct macho_loadcmd_id id;
+ struct macho_loadcmd_fvmfile fvmfile;
+ struct macho_loadcmd_prepage prepage;
+ struct macho_loadcmd_symtab_dyld symtab_dyld;
+ struct macho_loadcmd_dylib dylib;
+ struct macho_loadcmd_dyld dyld;
+ struct macho_loadcmd_prebinding prebinding;
+ struct macho_loadcmd_initcode32 initcode32;
+ struct macho_loadcmd_sub_framework sub_framework;
+ struct macho_loadcmd_sub_umbrella sub_umbrella;
+ struct macho_loadcmd_sub_client sub_client;
+ struct macho_loadcmd_sub_library sub_library;
+ struct macho_loadcmd_hints_2level hints_2level;
+ struct macho_loadcmd_prebind_cksum prebind_cksum;
+ struct macho_loadcmd_segment64 segment64;
+ struct macho_loadcmd_initcode64 initcode64;
+ struct macho_loadcmd_uuid uuid;
+} __attribute__((__packed__));
+
+/* Inernal function to check and return a load-command string */
+static inline const __u8 *macho_loadcmd_varstr_get__(
+ const struct macho_loadcmd_hdr *hdr,
+ const struct macho_loadcmd_varstr *varstr,
+ const __u8 *loadcmd_data)
+{
+ unsigned long data_offset = ((const void *)loadcmd_data) -
+ ((const void *)hdr);
+ unsigned long str_offset, i;
+
+ /* Make sure the varstr points into the data area */
+ if (varstr->off < data_offset)
+ return NULL;
+ str_offset = varstr->off - data_offset;
+
+ /*
+ * Iterate over all the characters in the variable-length string to
+ * ensure that there is a trailing 0 before the end of the data area.
+ */
+ for (i = str_offset; i < hdr->size; i++)
+ if (!loadcmd_data[i])
+ break;
+
+ /* If we quit before we hit end-of-data then it's a valid string */
+ if (i < hdr->size)
+ return &loadcmd_data[str_offset];
+
+ /* Sadly no such luck, it's a bogus Mach-O file */
+ return NULL;
+}
+
+/*
+ * Wrapper around the macho_loadcmd_varstr_get__ function above to make the
+ * calling-convention much easier.
+ *
+ * Example usage:
+ * macho_loadcmd_dyld *dyld = (...);
+ * const char *dyld_path = macho_loadcmd_varstr_get(dyld, path);
+ * if (!dyld_path)
+ * return -ENOEXEC;
+ */
+#define macho_loadcmd_varstr_get(LOADCMD, VARSTR) \
+ (macho_loadcmd_varstr_get__(&((LOADCMD)->hdr), \
+ &((LOADCMD)->VARSTR), (LOADCMD)->data))
+
+/*
+ * A Mach-O load-command mapping table with human-readable strings
+ */
+struct macho_loadcmd_entry {
+ const char *name;
+ macho_loadcmd_num_t cmd;
+ int pass;
+};
+
+static const struct macho_loadcmd_entry macho_loadcmds[] = {
+#define _ENTRY(TYPE, NAME) { \
+ .name = NAME, \
+ .cmd = MACHO_LOADCMD_NUM_ ## TYPE, \
+ }
+ _ENTRY(SEGMENT32, "memory-mapped file segment (32-bit)"),
+ _ENTRY(SYMTAB_STAB, "symbol table (stab)"),
+ _ENTRY(SYMTAB_GDB, "symbol table (gdb, obsolete)"),
+ _ENTRY(THREAD_NOSTACK, "new thread (without stack)"),
+ _ENTRY(THREAD, "new thread (with stack)"),
+ _ENTRY(REF_FVMLIB, "reference to a fixed-VM shared lib"),
+ _ENTRY(ID_FVMLIB, "identity of a fixed-VM shared lib"),
+ _ENTRY(ID, "identity of an object (obsolete)"),
+ _ENTRY(FVMFILE, "reference to a fixed VM file"),
+ _ENTRY(PREPAGE, "unknown (LC_PREPAGE)"),
+ _ENTRY(SYMTAB_DYLD, "symbol table (dyld)"),
+ _ENTRY(REF_DYLIB, "reference to a dynamic shared lib"),
+ _ENTRY(ID_DYLIB, "identity of a dynamic shared lib"),
+ _ENTRY(REF_DYLD, "reference to a dynamic linker"),
+ _ENTRY(ID_DYLD, "identity of a dynamic linker"),
+ _ENTRY(PREBINDING, "prebinding against a dynamic shared lib"),
+ _ENTRY(INITCODE32, "shared library init routine (32-bit)"),
+ _ENTRY(SUB_FRAMEWORK, "sub-framework file"),
+ _ENTRY(SUB_UMBRELLA, "sub-umbrella-framework file"),
+ _ENTRY(SUB_CLIENT, "sub-framework client entry"),
+ _ENTRY(SUB_LIBRARY, "sub-framework library"),
+ _ENTRY(HINTS_2LEVEL, "two-level namespace hinting table"),
+ _ENTRY(PREBIND_CKSUM, "prebinding checksum"),
+ _ENTRY(WEAKREF_DYLIB, "weak reference to a dynamic shared lib"),
+ _ENTRY(SEGMENT64, "memory-mapped file segment (64-bit)"),
+ _ENTRY(INITCODE64, "shared library init routine (64-bit)"),
+ _ENTRY(UUID, "linked object UUID"),
+ { .name = NULL, }
+#undef _ENTRY
+};
+
+static void macho_check_loadcmd(macho_loadcmd_num_t cmd)
+{
+ unsigned long i;
+
+ /* Iterate over the list of file types */
+ for (i = 0; macho_loadcmds[i].name; i++)
+ if (macho_loadcmds[i].cmd == cmd)
+ break;
+
+ /* If we didn't find the load command type then ignore it */
+ if (!macho_loadcmds[i].name) {
+ macho_dbg(" Mach-O load command: unknown (%u)\n", cmd);
+ return;
+ }
+
+ macho_dbg(" Mach-O load command: %s\n", macho_loadcmds[i].name);
+}
+
+#endif /* not _MACHO_LOADCMDS_H */
^ permalink raw reply [flat|nested] 3+ messages in thread