Re: [PATCH] x86: Remove a.out support

James Jones
2022-03-12T17:54:46Z

> From: Borislav Petkov <bp@suse.de>
>
> Commit
>
> eac616557050 ("x86: Deprecate a.out support")
>
> deprecated a.out support with the promise to remove it a couple of
> releases later. That commit landed in v5.1.
>
> Now it is more than a couple of releases later, no one has complained so
> remove it.

Sorry for taking so long to complain, but I have been meaning to note
that I and a few others are still using a.out. I saw it go by in my
morning Google news skim that this went in, and figured it was now or
never. The use case is running an old set of tools to build programs for
the Atari Jaguar. Namely, Atari's assembler (mac) and linker (aln). The
alternative is running windows versions in dosbox, or using some
replacements that have been developed based on an even older,
less-featureful version of the source code for mac and aln, but which
still haven't managed to add back in all the features needed to build
some programs or use the Atari debugging tools (Also available in a.out
only).

I've been running with a few local patches to fix the a.out build and
add the Kconfig options back for the last year or so to enable this on a
few of my machines, and it's been working fine. I know of at least one
other person doing this. If the code itself and supporting
syscalls/other code go away though, it'll probably become impractical.
If others are open to it, I can share my small local patches along with
a revert of this change. I'd also like to ask whether much is gained by
deleting this code as far as reducing maintenance burden. It has
survived nearly untouched since the deprecation notice and still works
modulo a broken preprocessor macro in fs/exec.c.

For the curious, or if anyone wants proof I'm not making this up and
really do spend time on these things, my amalgamation of Jaguar tools &
docs, including copies of the old mac and aln a.out binaries, is
available here:

https://github.com/cubanismo/jaguar-sdk

Thanks,
-James

> Signed-off-by: Borislav Petkov <bp@suse.de>
> ---
> arch/x86/Kconfig | 7 -
> arch/x86/ia32/Makefile | 2 -
> arch/x86/ia32/ia32_aout.c | 325 --------------------------------------
> 3 files changed, 334 deletions(-)
> delete mode 100644 arch/x86/ia32/ia32_aout.c
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 976dd6b532bf..6f3d63dbbddf 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -2835,13 +2835,6 @@ config IA32_EMULATION
> 64-bit kernel. You should likely turn this on, unless you're
> 100% sure that you don't have any 32-bit programs left.
>
> -config IA32_AOUT
> - tristate "IA32 a.out support"
> - depends on IA32_EMULATION
> - depends on BROKEN
> - help
> - Support old a.out binaries in the 32bit emulation.
> -
> config X86_X32
> bool "x32 ABI for 64-bit mode"
> depends on X86_64
> diff --git a/arch/x86/ia32/Makefile b/arch/x86/ia32/Makefile
> index 8e4d0391ff6c..e481056698de 100644
> --- a/arch/x86/ia32/Makefile
> +++ b/arch/x86/ia32/Makefile
> @@ -5,7 +5,5 @@
>
> obj-$(CONFIG_IA32_EMULATION) := ia32_signal.o
>
> -obj-$(CONFIG_IA32_AOUT) += ia32_aout.o
> -
> audit-class-$(CONFIG_AUDIT) := audit.o
> obj-$(CONFIG_IA32_EMULATION) += $(audit-class-y)
> diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
> deleted file mode 100644
> index 9bd15241fadb..000000000000
> --- a/arch/x86/ia32/ia32_aout.c
> +++ /dev/null
> @@ -1,325 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-only
> -/*
> - * a.out loader for x86-64
> - *
> - * Copyright (C) 1991, 1992, 1996 Linus Torvalds
> - * Hacked together by Andi Kleen
> - */
> -
> -#include <linux/module.h>
> -
> -#include <linux/time.h>
> -#include <linux/kernel.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/fs.h>
> -#include <linux/file.h>
> -#include <linux/stat.h>
> -#include <linux/fcntl.h>
> -#include <linux/ptrace.h>
> -#include <linux/user.h>
> -#include <linux/binfmts.h>
> -#include <linux/personality.h>
> -#include <linux/init.h>
> -#include <linux/jiffies.h>
> -#include <linux/perf_event.h>
> -#include <linux/sched/task_stack.h>
> -
> -#include <linux/uaccess.h>
> -#include <asm/cacheflush.h>
> -#include <asm/user32.h>
> -#include <asm/ia32.h>
> -
> -#undef WARN_OLD
> -
> -static int load_aout_binary(struct linux_binprm *);
> -static int load_aout_library(struct file *);
> -
> -static struct linux_binfmt aout_format = {
> - .module = THIS_MODULE,
> - .load_binary = load_aout_binary,
> - .load_shlib = load_aout_library,
> -};
> -
> -static int set_brk(unsigned long start, unsigned long end)
> -{
> - start = PAGE_ALIGN(start);
> - end = PAGE_ALIGN(end);
> - if (end <= start)
> - return 0;
> - return vm_brk(start, end - start);
> -}
> -
> -
> -/*
> - * create_aout_tables() parses the env- and arg-strings in new user
> - * memory and creates the pointer tables from them, and puts their
> - * addresses on the "stack", returning the new stack pointer value.
> - */
> -static u32 __user *create_aout_tables(char __user *p, struct linux_binprm *bprm)
> -{
> - u32 __user *argv, *envp, *sp;
> - int argc = bprm->argc, envc = bprm->envc;
> -
> - sp = (u32 __user *) ((-(unsigned long)sizeof(u32)) & (unsigned long) p);
> - sp -= envc+1;
> - envp = sp;
> - sp -= argc+1;
> - argv = sp;
> - put_user((unsigned long) envp, --sp);
> - put_user((unsigned long) argv, --sp);
> - put_user(argc, --sp);
> - current->mm->arg_start = (unsigned long) p;
> - while (argc-- > 0) {
> - char c;
> -
> - put_user((u32)(unsigned long)p, argv++);
> - do {
> - get_user(c, p++);
> - } while (c);
> - }
> - put_user(0, argv);
> - current->mm->arg_end = current->mm->env_start = (unsigned long) p;
> - while (envc-- > 0) {
> - char c;
> -
> - put_user((u32)(unsigned long)p, envp++);
> - do {
> - get_user(c, p++);
> - } while (c);
> - }
> - put_user(0, envp);
> - current->mm->env_end = (unsigned long) p;
> - return sp;
> -}
> -
> -/*
> - * These are the functions used to load a.out style executables and shared
> - * libraries. There is no binary dependent code anywhere else.
> - */
> -static int load_aout_binary(struct linux_binprm *bprm)
> -{
> - unsigned long error, fd_offset, rlim;
> - struct pt_regs *regs = current_pt_regs();
> - struct exec ex;
> - int retval;
> -
> - ex = *((struct exec *) bprm->buf); /* exec-header */
> - if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
> - N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
> - N_TRSIZE(ex) || N_DRSIZE(ex) ||
> - i_size_read(file_inode(bprm->file)) <
> - ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
> - return -ENOEXEC;
> - }
> -
> - fd_offset = N_TXTOFF(ex);
> -
> - /* Check initial limits. This avoids letting people circumvent
> - * size limits imposed on them by creating programs with large
> - * arrays in the data or bss.
> - */
> - rlim = rlimit(RLIMIT_DATA);
> - if (rlim >= RLIM_INFINITY)
> - rlim = ~0;
> - if (ex.a_data + ex.a_bss > rlim)
> - return -ENOMEM;
> -
> - /* Flush all traces of the currently running executable */
> - retval = begin_new_exec(bprm);
> - if (retval)
> - return retval;
> -
> - /* OK, This is the point of no return */
> - set_personality(PER_LINUX);
> - set_personality_ia32(false);
> -
> - setup_new_exec(bprm);
> -
> - regs->cs = __USER32_CS;
> - regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 =
> - regs->r13 = regs->r14 = regs->r15 = 0;
> -
> - current->mm->end_code = ex.a_text +
> - (current->mm->start_code = N_TXTADDR(ex));
> - current->mm->end_data = ex.a_data +
> - (current->mm->start_data = N_DATADDR(ex));
> - current->mm->brk = ex.a_bss +
> - (current->mm->start_brk = N_BSSADDR(ex));
> -
> - retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
> - if (retval < 0)
> - return retval;
> -
> - if (N_MAGIC(ex) == OMAGIC) {
> - unsigned long text_addr, map_size;
> -
> - text_addr = N_TXTADDR(ex);
> - map_size = ex.a_text+ex.a_data;
> -
> - error = vm_brk(text_addr & PAGE_MASK, map_size);
> -
> - if (error)
> - return error;
> -
> - error = read_code(bprm->file, text_addr, 32,
> - ex.a_text + ex.a_data);
> - if ((signed long)error < 0)
> - return error;
> - } else {
> -#ifdef WARN_OLD
> - static unsigned long error_time, error_time2;
> - if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
> - (N_MAGIC(ex) != NMAGIC) &&
> - time_after(jiffies, error_time2 + 5*HZ)) {
> - printk(KERN_NOTICE "executable not page aligned\n");
> - error_time2 = jiffies;
> - }
> -
> - if ((fd_offset & ~PAGE_MASK) != 0 &&
> - time_after(jiffies, error_time + 5*HZ)) {
> - printk(KERN_WARNING
> - "fd_offset is not page aligned. Please convert "
> - "program: %pD\n",
> - bprm->file);
> - error_time = jiffies;
> - }
> -#endif
> -
> - if (!bprm->file->f_op->mmap || (fd_offset & ~PAGE_MASK) != 0) {
> - error = vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
> - if (error)
> - return error;
> -
> - read_code(bprm->file, N_TXTADDR(ex), fd_offset,
> - ex.a_text+ex.a_data);
> - goto beyond_if;
> - }
> -
> - error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
> - PROT_READ | PROT_EXEC,
> - MAP_FIXED | MAP_PRIVATE | MAP_32BIT,
> - fd_offset);
> -
> - if (error != N_TXTADDR(ex))
> - return error;
> -
> - error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
> - PROT_READ | PROT_WRITE | PROT_EXEC,
> - MAP_FIXED | MAP_PRIVATE | MAP_32BIT,
> - fd_offset + ex.a_text);
> - if (error != N_DATADDR(ex))
> - return error;
> - }
> -
> -beyond_if:
> - error = set_brk(current->mm->start_brk, current->mm->brk);
> - if (error)
> - return error;
> -
> - set_binfmt(&aout_format);
> -
> - current->mm->start_stack =
> - (unsigned long)create_aout_tables((char __user *)bprm->p, bprm);
> - /* start thread */
> - loadsegment(fs, 0);
> - loadsegment(ds, __USER32_DS);
> - loadsegment(es, __USER32_DS);
> - load_gs_index(0);
> - (regs)->ip = ex.a_entry;
> - (regs)->sp = current->mm->start_stack;
> - (regs)->flags = 0x200;
> - (regs)->cs = __USER32_CS;
> - (regs)->ss = __USER32_DS;
> - regs->r8 = regs->r9 = regs->r10 = regs->r11 =
> - regs->r12 = regs->r13 = regs->r14 = regs->r15 = 0;
> - return 0;
> -}
> -
> -static int load_aout_library(struct file *file)
> -{
> - unsigned long bss, start_addr, len, error;
> - int retval;
> - struct exec ex;
> - loff_t pos = 0;
> -
> - retval = -ENOEXEC;
> - error = kernel_read(file, &ex, sizeof(ex), &pos);
> - if (error != sizeof(ex))
> - goto out;
> -
> - /* We come in here for the regular a.out style of shared libraries */
> - if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
> - N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
> - i_size_read(file_inode(file)) <
> - ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
> - goto out;
> - }
> -
> - if (N_FLAGS(ex))
> - goto out;
> -
> - /* For QMAGIC, the starting address is 0x20 into the page. We mask
> - this off to get the starting address for the page */
> -
> - start_addr = ex.a_entry & 0xfffff000;
> -
> - if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
> -#ifdef WARN_OLD
> - static unsigned long error_time;
> - if (time_after(jiffies, error_time + 5*HZ)) {
> - printk(KERN_WARNING
> - "N_TXTOFF is not page aligned. Please convert "
> - "library: %pD\n",
> - file);
> - error_time = jiffies;
> - }
> -#endif
> - retval = vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
> - if (retval)
> - goto out;
> -
> - read_code(file, start_addr, N_TXTOFF(ex),
> - ex.a_text + ex.a_data);
> - retval = 0;
> - goto out;
> - }
> - /* Now use mmap to map the library into memory. */
> - error = vm_mmap(file, start_addr, ex.a_text + ex.a_data,
> - PROT_READ | PROT_WRITE | PROT_EXEC,
> - MAP_FIXED | MAP_PRIVATE | MAP_32BIT,
> - N_TXTOFF(ex));
> - retval = error;
> - if (error != start_addr)
> - goto out;
> -
> - len = PAGE_ALIGN(ex.a_text + ex.a_data);
> - bss = ex.a_text + ex.a_data + ex.a_bss;
> - if (bss > len) {
> - retval = vm_brk(start_addr + len, bss - len);
> - if (retval)
> - goto out;
> - }
> - retval = 0;
> -out:
> - return retval;
> -}
> -
> -static int __init init_aout_binfmt(void)
> -{
> - register_binfmt(&aout_format);
> - return 0;
> -}
> -
> -static void __exit exit_aout_binfmt(void)
> -{
> - unregister_binfmt(&aout_format);
> -}
> -
> -module_init(init_aout_binfmt);
> -module_exit(exit_aout_binfmt);
> -MODULE_LICENSE("GPL");
> --
> 2.29.2