2022-03-09 22:33:40

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] a.out: Stop building a.out/osf1 support on alpha and m68k

On Wed, 09 Mar 2022 14:03:42 -0600, Eric W. Biederman wrote:
> There has been repeated discussion on removing a.out support, the most
> recent was[1]. Having read through a bunch of the discussion it looks
> like no one has see any reason why we need to keep a.out support.
>
> The m68k maintainer has even come out in favor of removing a.out
> support[2].
>
> [...]

Applied to for-next/execve, thanks!

[1/1] a.out: Stop building a.out/osf1 support on alpha and m68k
https://git.kernel.org/kees/c/f451569b9da8

--
Kees Cook


2022-03-11 13:50:59

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH] x86: Remove a.out support


From: Borislav Petkov <[email protected]>
Date: Thu, 13 Jan 2022 17:01:15 +0100
Subject: [PATCH] x86: Remove a.out support

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.

Signed-off-by: Borislav Petkov <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Eric W. Biederman <[email protected]>
---

Kees can you pick this one up in for-next/execve as well?

It still applies cleanly and the actual patch seems to have gotten lost
in the conversation about what more we could do.

Thanks,
Eric


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 9f5bd41bf660..b6563d6681c1 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2827,13 +2827,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

2022-03-11 18:01:48

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Fri, Mar 11, 2022 at 12:35 AM Linus Torvalds
<[email protected]> wrote:
>
> On Thu, Mar 10, 2022 at 3:29 PM Eric W. Biederman <[email protected]> wrote:
> >
> > Kees can you pick this one up in for-next/execve as well?
> >
> > It still applies cleanly and the actual patch seems to have gotten lost
> > in the conversation about what more we could do.
>
> Side note: there are similar other turds if a.out goes away, ie on
> alpha it's OSF4_COMPAT, and it enables support for a couple of legacy
> OSF/1 system calls.
>
> I think that was also discussed in the (old) a.out deprecation thread
> back in 2019..

The only thing that actually depends on CONFIG_OSF4_COMPAT seems to be
the custom logic in readv() and writev(). Those are the two that you removed
in your patch back then[1].

For the other system calls, I fear we can only try to guess which of them
are used in Linux applications and which ones are not. These were always
available to normal Linux user space, so the ones that are similar to our
syscalls could have been used in glibc, e.g. mmap, wait4, stat.

Arnd

[1] https://lore.kernel.org/all/CAHk-=wgt7M6yA5BJCJo0nF22WgPJnN8CvViL9CAJmd+S+Civ6w@mail.gmail.com/

[2] $ git grep sys_osf arch/alpha/kernel/syscalls/syscall.tbl
7 common osf_wait4 sys_osf_wait4
17 common brk sys_osf_brk
21 common osf_mount sys_osf_mount
43 common osf_set_program_attributes sys_osf_set_program_attributes
48 common osf_sigprocmask sys_osf_sigprocmask
71 common mmap sys_osf_mmap
93 common osf_select sys_osf_select
100 common getpriority sys_osf_getpriority
112 common osf_sigstack sys_osf_sigstack
116 common osf_gettimeofday sys_osf_gettimeofday
117 common osf_getrusage sys_osf_getrusage
120 common readv sys_osf_readv
121 common writev sys_osf_writev
122 common osf_settimeofday sys_osf_settimeofday
138 common osf_utimes sys_osf_utimes
156 common sigaction sys_osf_sigaction
159 common osf_getdirentries sys_osf_getdirentries
160 common osf_statfs sys_osf_statfs
161 common osf_fstatfs sys_osf_fstatfs
165 common osf_getdomainname sys_osf_getdomainname
207 common osf_utsname sys_osf_utsname
224 common osf_stat sys_osf_stat
225 common osf_lstat sys_osf_lstat
226 common osf_fstat sys_osf_fstat
227 common osf_statfs64 sys_osf_statfs64
228 common osf_fstatfs64 sys_osf_fstatfs64
241 common osf_sysinfo sys_osf_sysinfo
244 common osf_proplist_syscall sys_osf_proplist_syscall
251 common osf_usleep_thread sys_osf_usleep_thread
256 common osf_getsysinfo sys_osf_getsysinfo
257 common osf_setsysinfo sys_osf_setsysinfo

2022-03-11 21:44:55

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Thu, Mar 10, 2022 at 05:29:13PM -0600, Eric W. Biederman wrote:
> Kees can you pick this one up in for-next/execve as well?

I can carry it through tip, no probs.

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette

2022-03-11 23:19:25

by Linus Torvalds

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Thu, Mar 10, 2022 at 3:29 PM Eric W. Biederman <[email protected]> wrote:
>
> Kees can you pick this one up in for-next/execve as well?
>
> It still applies cleanly and the actual patch seems to have gotten lost
> in the conversation about what more we could do.

Side note: there are similar other turds if a.out goes away, ie on
alpha it's OSF4_COMPAT, and it enables support for a couple of legacy
OSF/1 system calls.

I think that was also discussed in the (old) a.out deprecation thread
back in 2019..

Linus

2022-03-13 00:19:32

by James Jones

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On 3/12/22 9:54 AM, James Jones wrote:
>> From: Borislav Petkov <[email protected]>
>>
>> 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

Apologies, fixing x86 maintainer alias address.

> Thanks,
> -James
>
>> Signed-off-by: Borislav Petkov <[email protected]>
>> ---
>> 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
>

2022-03-13 19:39:56

by James Jones

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

> From: Borislav Petkov <[email protected]>
>
> 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 <[email protected]>
> ---
> 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

2022-03-14 01:37:12

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Sat, Mar 12, 2022 at 06:06:26PM +0000, James Jones wrote:
> > 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).

Ok, for my own understanding only: you want to build those tools as
a.out binaries and run them on x86, correct?

Because wikipedia says that jaguar thing has a motorola m68k system
processor and looking at your makefile, you build some ancient gcc with
--target=m68k-aout so where does x86's a.out support come into play
here?

> > 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.

I personally don't mind if you fix it up and take care of it going
forward, shouldn't be too much of a maintenance overhead - I'd just like
you to document somewhere in those files what is still using this so
that when you don't care for that project anymore or you stop needing
it for whatever reason, we can look up the URL and check whether we can
remove a.out support then.

Thx.

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette

2022-03-15 19:53:31

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Sun, Mar 13, 2022 at 06:26:31PM +0000, James Jones wrote:
> ...
> This all probably seems absurd now, but note the newest version of these
> tools was released in 1995, when Linux ELF support would have been brand
> new. I don't know when the tools first shipped on Linux, but it would
> have been a few years before that, so a.out would have been the only
> option. It seems some Atari Jaguar developers were rather early Linux
> adopters.

Ok, that explains it fine, thanks.

Please put that explanation in a text file somewhere in
Documentation/x86/ so that we know why we're keeping a.out support.

I'll zap the removing patch from the lineup now and you can send me your
fixes whenever you're ready.

If you're wondering on how to format them and what to do, we have it all
documented in Documentation/process/. I'd especially suggest reading
Documentation/process/submitting-patches.rst

HTH.

Thx.

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette

2022-03-16 16:20:49

by James Jones

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On 3/13/22 4:56 AM, Borislav Petkov wrote:
> On Sat, Mar 12, 2022 at 06:06:26PM +0000, James Jones wrote:
>>> 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).
>
> Ok, for my own understanding only: you want to build those tools as
> a.out binaries and run them on x86, correct?

The 'mac' and 'aln' tools are only available as x86 a.out binaries. I
can't build them. They're in 'jaguar/bin/linux/[aln,mac]' in the
referenced jaguar-sdk project, along with a few others.

> Because wikipedia says that jaguar thing has a motorola m68k system
> processor and looking at your makefile, you build some ancient gcc with
> --target=m68k-aout so where does x86's a.out support come into play
> here?

Sorry for not being clearer. The 'mac' and 'aln' x86 a.out binaries
generate and consume m68k a.out object files. So if you want to use some
C code in addition to assembly listings, you'd use this separate m68k
a.out build of gcc (itself an ELF executable) to compile the C code to
object files, then link everything with 'aln'.

The real value of 'mac' and 'aln' though isn't their m68k support.
binutils can assemble and link that, as can the version of 'mac' and
'aln' that source is available for. These builds of 'mac' also support
the Jaguar's custom RISC instruction set, allowing you to add this RISC
code in the same assembly listings as the m68k code using a few
directives. This version of 'aln' has a few options to support
Jaguar-specific stuff as well.

This all probably seems absurd now, but note the newest version of these
tools was released in 1995, when Linux ELF support would have been brand
new. I don't know when the tools first shipped on Linux, but it would
have been a few years before that, so a.out would have been the only
option. It seems some Atari Jaguar developers were rather early Linux
adopters.

>>> 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.
>
> I personally don't mind if you fix it up and take care of it going
> forward, shouldn't be too much of a maintenance overhead - I'd just like
> you to document somewhere in those files what is still using this so
> that when you don't care for that project anymore or you stop needing
> it for whatever reason, we can look up the URL and check whether we can
> remove a.out support then.

OK, will do. I appreciate the consideration.

-James

> Thx.
>
> --
> Regards/Gruss,
> Boris.
>
> https://people.kernel.org/tglx/notes-about-netiquette

2022-03-17 03:19:33

by David Laight

[permalink] [raw]
Subject: RE: [PATCH] x86: Remove a.out support

From: Kees Cook
> Sent: 16 March 2022 22:30
>
> On Wed, Mar 16, 2022 at 01:38:31PM +0100, Arnd Bergmann wrote:
> > is in the end, but it's likely easier than a standalone a.out loader
> > in user space, or a conversion to ELF format.
>
> Yeah, the exec format is really simple. The only tricky bit was preparing
> the stack and making sure everything landed in the right place for text
> and data. James, can you try this? aln and mac run for me, but I'm not
> actually exercising them beyond dumping argument lists, etc:

Doesn't that restrict the a.out program to the address space below
the normal base address for elf programs?
So you'll only be able to load small programs - which might be ok here.

OTOH it might be possible to link the 'loader program' to a high
address - the elf loader will probably just load it.
Best to link it static to avoid shared lib mmaps
and probably try to avoid libc calls.

I was wondering what happens when malloc() starts using
sbrk() - but I guess it sees the top of the bss for the
loaded and it all works fine.

David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

2022-03-17 03:22:21

by James Jones

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On 3/16/22 3:30 PM, Kees Cook wrote:
> On Wed, Mar 16, 2022 at 01:38:31PM +0100, Arnd Bergmann wrote:
>> is in the end, but it's likely easier than a standalone a.out loader
>> in user space, or a conversion to ELF format.
>
> Yeah, the exec format is really simple. The only tricky bit was preparing
> the stack and making sure everything landed in the right place for text
> and data. James, can you try this? aln and mac run for me, but I'm not
> actually exercising them beyond dumping argument lists, etc:
>
> https://github.com/kees/kernel-tools/tree/trunk/a.out

Yes, works perfectly, thank you. I like the idea of using this much
better than getting emailed every time someone wants to delete the a.out
code again. Consider my use case withdrawn. I've already pushed an
update to my jaguar-sdk project to use this tool instead.

-James

> $ make
> cc -Wall -m32 aout.c -o aout
> $ ./aout aln --help
> mmap: Operation not permitted
> /proc/sys/vm/mmap_min_addr is set to 65536 but QMAGIC a.out binaries must be mapped at 4096.
> To temporarily change this, run: sudo sysctl -w vm.mmap_min_addr=4096
> $ sudo sysctl -w vm.mmap_min_addr=4096
> vm.mmap_min_addr = 4096
> $ ./aout aln --help
> aln: unrecognized option `--help'
> Usage: aln [-options] <files|-x file|-i[i] <fname> <label>>
> Where options are:
> ?: print this
> a <text> <data> <bss>: output absolute file
> hex value: segment address
> r: relocatable segment
> x: contiguous segment
> ...
>
>
>
> /*
> * Execute a static QMAGIC ia32 a.out binary.
> * Copyright 2022 Kees Cook <[email protected]>
> * License: GPLv2
> */
> #include <stdint.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <fcntl.h>
> #include <unistd.h>
> #include <sys/mman.h>
> #include <string.h>
> #include <sys/time.h>
> #include <sys/resource.h>
>
> /* Locally define the stuff from a.out.h since that file may disappear. */
> struct a_out
> {
> unsigned int a_info; /* machine type, magic, etc */
> unsigned int a_text; /* text size */
> unsigned int a_data; /* data size */
> unsigned int a_bss; /* desired bss size */
> unsigned int a_syms; /* symbol table size */
> unsigned int a_entry; /* entry address */
> unsigned int a_trsize; /* text relocation size */
> unsigned int a_drsize; /* data relocation size */
> };
>
> #define Q_MAGIC_LOAD_ADDR 0x1000
> #define MMAP_MIN_ADDR_PATH "/proc/sys/vm/mmap_min_addr"
>
> #define ALIGN(x, a) ALIGN_MASK(x, (unsigned long)(a) - 1)
> #define ALIGN_MASK(x, mask) (typeof(x))(((unsigned long)(x) + (mask)) & ~(mask))
>
> static void check_mmap_min_addr(void)
> {
> unsigned long addr;
> char buf[128], *result;
> FILE *proc;
>
> proc = fopen(MMAP_MIN_ADDR_PATH, "r");
> if (!proc)
> return;
> result = fgets(buf, sizeof(buf), proc);
> fclose(proc);
> if (!result)
> return;
>
> addr = strtoul(result, NULL, 0);
> if (addr <= Q_MAGIC_LOAD_ADDR)
> return;
>
> fprintf(stderr, "%s is set to %lu but QMAGIC a.out binaries must be mapped at %u.\n",
> MMAP_MIN_ADDR_PATH, addr, Q_MAGIC_LOAD_ADDR);
> fprintf(stderr, "To temporarily change this, run: sudo sysctl -w vm.mmap_min_addr=%u\n",
> Q_MAGIC_LOAD_ADDR);
> }
>
> int main(int argc, char *argv[], char *envp[])
> {
> const unsigned long qmagic = 0x006400cc;
> struct a_out *aout;
> struct stat info;
> unsigned char *image, *image_end, *bss, *bss_end, *stack, *stack_end;
> char **p;
> unsigned long *sp;
> struct rlimit rlim;
> int pagesize;
> int fd;
> int argc_copy, envc_copy;
> char **argv_copy, **envp_copy;
>
> if (sizeof(void *) != 4) {
> fprintf(stderr, "Eek: I was compiled in 64-bit mode. Please build with -m32.\n");
> return 1;
> }
>
> if (argc < 2) {
> fprintf(stderr, "Usage: %s a.out [arg ...]\n", argv[0]);
> return 1;
> }
>
> fd = open(argv[1], O_RDONLY);
> if (fd < 0) {
> perror(argv[1]);
> return 1;
> }
>
> if (fstat(fd, &info) < 0) {
> perror(argv[1]);
> return 1;
> }
>
> if (info.st_size < sizeof(*aout)) {
> fprintf(stderr, "%s: too small to read a.out header\n", argv[1]);
> return 1;
> }
>
> /* Load file into memory at Q_MAGIC_LOAD_ADDR. */
> pagesize = getpagesize();
> image = mmap((void *)Q_MAGIC_LOAD_ADDR, info.st_size, PROT_EXEC | PROT_READ | PROT_WRITE,
> MAP_FIXED | MAP_PRIVATE, fd, 0);
> if (image == MAP_FAILED) {
> perror("mmap");
> check_mmap_min_addr();
> return 1;
> }
> image_end = ALIGN(image + info.st_size, pagesize);
>
> aout = (struct a_out *)image;
> if (aout->a_info != qmagic) {
> fprintf(stderr, "%s: not ia32 QMAGIC a.out binary (header 0x%x != expected 0x%lx)\n",
> argv[1], aout->a_info, qmagic);
> return 1;
> }
>
> if (aout->a_syms != 0) {
> fprintf(stderr, "%s: a.out header a_syms must be 0.\n", argv[1]);
> return 1;
> }
>
> if (aout->a_trsize != 0) {
> fprintf(stderr, "%s: a.out header a_trsize must be 0.\n", argv[1]);
> return 1;
> }
>
> if (aout->a_drsize != 0) {
> fprintf(stderr, "%s: a.out header a_drsize must be 0.\n", argv[1]);
> return 1;
> }
>
> /* See if .bss needs to extend beyond end of the file mmap. */
> bss = image + aout->a_text + aout->a_data;
> bss_end = bss + aout->a_bss;
> if (bss_end > image_end) {
> bss = mmap(bss, aout->a_bss, PROT_READ | PROT_WRITE,
> MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> if (bss == MAP_FAILED) {
> perror("mmap bss");
> return 1;
> }
> }
> /* Zero out .bss. */
> memset(bss, 0, ALIGN(aout->a_bss, pagesize));
>
> /* Prepare stack, based on current stack. */
> if (getrlimit(RLIMIT_STACK, &rlim) < 0) {
> perror("getrlimit");
> return 1;
> }
>
> /* Default to 8MiB */
> if (rlim.rlim_cur == RLIM_INFINITY)
> rlim.rlim_cur = 8 * 1024 * 1024;
>
> stack = mmap(NULL, rlim.rlim_cur, PROT_EXEC | PROT_READ | PROT_WRITE,
> MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> if (stack == MAP_FAILED) {
> perror("mmap stack");
> return 1;
> }
> stack_end = ALIGN(stack + rlim.rlim_cur, pagesize);
>
> /* Fill top of stack with arg/env pointers. */
> sp = (unsigned long *)stack_end;
> sp--;
>
> /* do not include argv[0] */
> argc_copy = argc - 1;
> argv++;
>
> /* count envp */
> for (envc_copy = 0, p = envp; *p; envc_copy++, p++) ;
>
> /* make room for envp pointers */
> sp -= envc_copy + 1;
> envp_copy = (char **)sp;
> /* make room for argv pointers */
> sp -= argc_copy + 1;
> argv_copy = (char **)sp;
>
> /* store pointers and argc */
> *--sp = (unsigned long)envp_copy;
> *--sp = (unsigned long)argv_copy;
> *--sp = (unsigned long)argc_copy;
>
> /* copy argv pointer (contents can stay where they already are) */
> while (argc_copy--)
> *argv_copy++ = *argv++;
> *argv_copy = 0;
>
> /* copy envp (contents can stay where they already are) */
> while (envc_copy--)
> *envp_copy++ = *envp++;
>
> /* Aim sp at argc, and jump! */
> asm volatile ("movl %0, %%esp\njmp *%1\n" : : "rm" (sp), "r"(aout->a_entry) );
>
> /* This should be unreachable. */
> fprintf(stderr, "They found me. I don't how, but they found me.\n");
> return 2;
> }
>
> --
> Kees Cook

2022-03-17 04:31:56

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Sat, Mar 12, 2022 at 06:06:26PM +0000, James Jones wrote:
> [...]
> > docs, including copies of the old mac and aln a.out binaries, is
> > available here:
> >
> > https://github.com/cubanismo/jaguar-sdk

Do these end up requiring libc4, etc? I see "uselib" syscalls in the
disassembly...

$ for i in $(objdump -b binary -D -m i386 aln mac | grep -B4 'int.*$0x80' \
| grep -E 'int|eax' | grep mov | awk '{print $8}' | cut -d, -f1 \
| cut -c2- | sort -u); do printf "%d\n" $i; done | sort -n
1 exit
3 read
4 write
5 open
6 close
10 unlink
13 time
19 lseek
20 getpid
37 kill
45 brk
54 ioctl
55 fcntl
86 uselib
89 readdir
91 munmap
106 stat
107 lstat
108 fstat
126 sigprocmask

It seems like it should be possible to create an ELF wrapper for simple
a.out binaries...

--
Kees Cook

2022-03-17 04:54:04

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Wed, Mar 16, 2022 at 01:38:31PM +0100, Arnd Bergmann wrote:
> is in the end, but it's likely easier than a standalone a.out loader
> in user space, or a conversion to ELF format.

Yeah, the exec format is really simple. The only tricky bit was preparing
the stack and making sure everything landed in the right place for text
and data. James, can you try this? aln and mac run for me, but I'm not
actually exercising them beyond dumping argument lists, etc:

https://github.com/kees/kernel-tools/tree/trunk/a.out

$ make
cc -Wall -m32 aout.c -o aout
$ ./aout aln --help
mmap: Operation not permitted
/proc/sys/vm/mmap_min_addr is set to 65536 but QMAGIC a.out binaries must be mapped at 4096.
To temporarily change this, run: sudo sysctl -w vm.mmap_min_addr=4096
$ sudo sysctl -w vm.mmap_min_addr=4096
vm.mmap_min_addr = 4096
$ ./aout aln --help
aln: unrecognized option `--help'
Usage: aln [-options] <files|-x file|-i[i] <fname> <label>>
Where options are:
?: print this
a <text> <data> <bss>: output absolute file
hex value: segment address
r: relocatable segment
x: contiguous segment
...



/*
* Execute a static QMAGIC ia32 a.out binary.
* Copyright 2022 Kees Cook <[email protected]>
* License: GPLv2
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/time.h>
#include <sys/resource.h>

/* Locally define the stuff from a.out.h since that file may disappear. */
struct a_out
{
unsigned int a_info; /* machine type, magic, etc */
unsigned int a_text; /* text size */
unsigned int a_data; /* data size */
unsigned int a_bss; /* desired bss size */
unsigned int a_syms; /* symbol table size */
unsigned int a_entry; /* entry address */
unsigned int a_trsize; /* text relocation size */
unsigned int a_drsize; /* data relocation size */
};

#define Q_MAGIC_LOAD_ADDR 0x1000
#define MMAP_MIN_ADDR_PATH "/proc/sys/vm/mmap_min_addr"

#define ALIGN(x, a) ALIGN_MASK(x, (unsigned long)(a) - 1)
#define ALIGN_MASK(x, mask) (typeof(x))(((unsigned long)(x) + (mask)) & ~(mask))

static void check_mmap_min_addr(void)
{
unsigned long addr;
char buf[128], *result;
FILE *proc;

proc = fopen(MMAP_MIN_ADDR_PATH, "r");
if (!proc)
return;
result = fgets(buf, sizeof(buf), proc);
fclose(proc);
if (!result)
return;

addr = strtoul(result, NULL, 0);
if (addr <= Q_MAGIC_LOAD_ADDR)
return;

fprintf(stderr, "%s is set to %lu but QMAGIC a.out binaries must be mapped at %u.\n",
MMAP_MIN_ADDR_PATH, addr, Q_MAGIC_LOAD_ADDR);
fprintf(stderr, "To temporarily change this, run: sudo sysctl -w vm.mmap_min_addr=%u\n",
Q_MAGIC_LOAD_ADDR);
}

int main(int argc, char *argv[], char *envp[])
{
const unsigned long qmagic = 0x006400cc;
struct a_out *aout;
struct stat info;
unsigned char *image, *image_end, *bss, *bss_end, *stack, *stack_end;
char **p;
unsigned long *sp;
struct rlimit rlim;
int pagesize;
int fd;
int argc_copy, envc_copy;
char **argv_copy, **envp_copy;

if (sizeof(void *) != 4) {
fprintf(stderr, "Eek: I was compiled in 64-bit mode. Please build with -m32.\n");
return 1;
}

if (argc < 2) {
fprintf(stderr, "Usage: %s a.out [arg ...]\n", argv[0]);
return 1;
}

fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror(argv[1]);
return 1;
}

if (fstat(fd, &info) < 0) {
perror(argv[1]);
return 1;
}

if (info.st_size < sizeof(*aout)) {
fprintf(stderr, "%s: too small to read a.out header\n", argv[1]);
return 1;
}

/* Load file into memory at Q_MAGIC_LOAD_ADDR. */
pagesize = getpagesize();
image = mmap((void *)Q_MAGIC_LOAD_ADDR, info.st_size, PROT_EXEC | PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE, fd, 0);
if (image == MAP_FAILED) {
perror("mmap");
check_mmap_min_addr();
return 1;
}
image_end = ALIGN(image + info.st_size, pagesize);

aout = (struct a_out *)image;
if (aout->a_info != qmagic) {
fprintf(stderr, "%s: not ia32 QMAGIC a.out binary (header 0x%x != expected 0x%lx)\n",
argv[1], aout->a_info, qmagic);
return 1;
}

if (aout->a_syms != 0) {
fprintf(stderr, "%s: a.out header a_syms must be 0.\n", argv[1]);
return 1;
}

if (aout->a_trsize != 0) {
fprintf(stderr, "%s: a.out header a_trsize must be 0.\n", argv[1]);
return 1;
}

if (aout->a_drsize != 0) {
fprintf(stderr, "%s: a.out header a_drsize must be 0.\n", argv[1]);
return 1;
}

/* See if .bss needs to extend beyond end of the file mmap. */
bss = image + aout->a_text + aout->a_data;
bss_end = bss + aout->a_bss;
if (bss_end > image_end) {
bss = mmap(bss, aout->a_bss, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (bss == MAP_FAILED) {
perror("mmap bss");
return 1;
}
}
/* Zero out .bss. */
memset(bss, 0, ALIGN(aout->a_bss, pagesize));

/* Prepare stack, based on current stack. */
if (getrlimit(RLIMIT_STACK, &rlim) < 0) {
perror("getrlimit");
return 1;
}

/* Default to 8MiB */
if (rlim.rlim_cur == RLIM_INFINITY)
rlim.rlim_cur = 8 * 1024 * 1024;

stack = mmap(NULL, rlim.rlim_cur, PROT_EXEC | PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (stack == MAP_FAILED) {
perror("mmap stack");
return 1;
}
stack_end = ALIGN(stack + rlim.rlim_cur, pagesize);

/* Fill top of stack with arg/env pointers. */
sp = (unsigned long *)stack_end;
sp--;

/* do not include argv[0] */
argc_copy = argc - 1;
argv++;

/* count envp */
for (envc_copy = 0, p = envp; *p; envc_copy++, p++) ;

/* make room for envp pointers */
sp -= envc_copy + 1;
envp_copy = (char **)sp;
/* make room for argv pointers */
sp -= argc_copy + 1;
argv_copy = (char **)sp;

/* store pointers and argc */
*--sp = (unsigned long)envp_copy;
*--sp = (unsigned long)argv_copy;
*--sp = (unsigned long)argc_copy;

/* copy argv pointer (contents can stay where they already are) */
while (argc_copy--)
*argv_copy++ = *argv++;
*argv_copy = 0;

/* copy envp (contents can stay where they already are) */
while (envc_copy--)
*envp_copy++ = *envp++;

/* Aim sp at argc, and jump! */
asm volatile ("movl %0, %%esp\njmp *%1\n" : : "rm" (sp), "r"(aout->a_entry) );

/* This should be unreachable. */
fprintf(stderr, "They found me. I don't how, but they found me.\n");
return 2;
}

--
Kees Cook

2022-03-17 05:12:37

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Wed, Mar 16, 2022 James Jones <[email protected]> wrote:
> On 3/15/22 12:51 PM, Kees Cook wrote:
>
> Probably getting a bit off topic, but I did spend a few hours searching
> around for any existing tools to convert a binary from a.out->ELF, and
> trying to come up with something myself by extracting the sections with
> objdump and re-combining them into an ELF using a linker script placing
> the sections at the same locations. I couldn't get it working in an
> evening or two messing with it so I moved on, but I agree something like
> this seems possible in theory. I got 'mac' converted to an ELF that
> would load up and print its input prompt if run without parameters, but
> only if run as root. As a regular user, it segfaults somewhere before it
> even starts executing in the text section AFAICT. Any actual assembling
> segfaults even when running as root. I never got 'aln' to do anything
> but segfault.
>
> I dug the scripts up in the state they were in when I gave up (September
> 2020 according to mtime), and put them on github in case anyone wants to
> have a go at it:
>
> https://github.com/cubanismo/aout-to-elf/
>
> It was an interesting problem in its own right, and I'd be curious to
> know what I missed.

I noticed that qemu-user has code to run the two other native binary
formats (elf and flat) that the kernel supports, in
https://github.com/qemu/qemu/blob/master/linux-user/linuxload.c

The qemu code is fairly close to the kernel version it is derived
from, and the a.out loader in the kernel is the simplest of those.

If performance is not overly important, I think it should be possible
to turn the Linux binfmt_aout.c code into something that works
in qemu, allowing you to run these executables through CPU
emulation on any architecture. No idea how much work this
is in the end, but it's likely easier than a standalone a.out loader
in user space, or a conversion to ELF format.

Arnd

2022-03-17 05:23:07

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Wed, Mar 16, 2022 at 05:06:10AM +0000, James Jones wrote:
> I dug the scripts up in the state they were in when I gave up (September
> 2020 according to mtime), and put them on github in case anyone wants to
> have a go at it:
>
> https://github.com/cubanismo/aout-to-elf/
>
> It was an interesting problem in its own right, and I'd be curious to
> know what I missed.

Yeah, this is a good start. I think the main problem is with how program
entry works, specifically that %esp is pointing to argc (with all the
args in memory above there), which isn't the way ELF sets %esp.

It might be possible to make a userspace loader, though. Hmm.

--
Kees Cook

2022-03-17 05:26:03

by David Laight

[permalink] [raw]
Subject: RE: [PATCH] x86: Remove a.out support

From: James Jones
> Sent: 17 March 2022 02:05
>
> On 3/16/22 3:30 PM, Kees Cook wrote:
> > On Wed, Mar 16, 2022 at 01:38:31PM +0100, Arnd Bergmann wrote:
> >> is in the end, but it's likely easier than a standalone a.out loader
> >> in user space, or a conversion to ELF format.
> >
> > Yeah, the exec format is really simple. The only tricky bit was preparing
> > the stack and making sure everything landed in the right place for text
> > and data. James, can you try this? aln and mac run for me, but I'm not
> > actually exercising them beyond dumping argument lists, etc:
> >
> > https://github.com/kees/kernel-tools/tree/trunk/a.out
>
> Yes, works perfectly, thank you. I like the idea of using this much
> better than getting emailed every time someone wants to delete the a.out
> code again. Consider my use case withdrawn. I've already pushed an
> update to my jaguar-sdk project to use this tool instead.

Just every time the someone wants to delete the associated
system calls :-)

David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

2022-03-17 06:26:15

by David Laight

[permalink] [raw]
Subject: RE: [PATCH] x86: Remove a.out support

From: Kees Cook
> Sent: 16 March 2022 16:11
>
> On Wed, Mar 16, 2022 at 05:06:10AM +0000, James Jones wrote:
> > I dug the scripts up in the state they were in when I gave up (September
> > 2020 according to mtime), and put them on github in case anyone wants to
> > have a go at it:
> >
> > https://github.com/cubanismo/aout-to-elf/
> >
> > It was an interesting problem in its own right, and I'd be curious to
> > know what I missed.
>
> Yeah, this is a good start. I think the main problem is with how program
> entry works, specifically that %esp is pointing to argc (with all the
> args in memory above there), which isn't the way ELF sets %esp.
>
> It might be possible to make a userspace loader, though. Hmm.

Could it be fixed up by a small bit of code that the elf interpreter
runs just before jumping the a.out entry point?

Depending on the elf layout it might be enough to just reset %esp.
But if the strings are the wrong side of argv[] and enpv[] the
vectors themselves might need copying further down the stack.

Should be possible to do it as PIC code.

David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

2022-03-17 06:44:58

by James Jones

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On 3/15/22 12:51 PM, Kees Cook wrote:
> On Sat, Mar 12, 2022 at 06:06:26PM +0000, James Jones wrote:
>> [...]
>>> docs, including copies of the old mac and aln a.out binaries, is
>>> available here:
>>>
>>> https://github.com/cubanismo/jaguar-sdk
>
> Do these end up requiring libc4, etc? I see "uselib" syscalls in the
> disassembly...
>
> $ for i in $(objdump -b binary -D -m i386 aln mac | grep -B4 'int.*$0x80' \
> | grep -E 'int|eax' | grep mov | awk '{print $8}' | cut -d, -f1 \
> | cut -c2- | sort -u); do printf "%d\n" $i; done | sort -n
> 1 exit
> 3 read
> 4 write
> 5 open
> 6 close
> 10 unlink
> 13 time
> 19 lseek
> 20 getpid
> 37 kill
> 45 brk
> 54 ioctl
> 55 fcntl
> 86 uselib
> 89 readdir
> 91 munmap
> 106 stat
> 107 lstat
> 108 fstat
> 126 sigprocmask
>
> It seems like it should be possible to create an ELF wrapper for simple
> a.out binaries...

I didn't need to dig up any ancient libraries to get these working. They
seem to be completely statically linked.

Probably getting a bit off topic, but I did spend a few hours searching
around for any existing tools to convert a binary from a.out->ELF, and
trying to come up with something myself by extracting the sections with
objdump and re-combining them into an ELF using a linker script placing
the sections at the same locations. I couldn't get it working in an
evening or two messing with it so I moved on, but I agree something like
this seems possible in theory. I got 'mac' converted to an ELF that
would load up and print its input prompt if run without parameters, but
only if run as root. As a regular user, it segfaults somewhere before it
even starts executing in the text section AFAICT. Any actual assembling
segfaults even when running as root. I never got 'aln' to do anything
but segfault.

I dug the scripts up in the state they were in when I gave up (September
2020 according to mtime), and put them on github in case anyone wants to
have a go at it:

https://github.com/cubanismo/aout-to-elf/

It was an interesting problem in its own right, and I'd be curious to
know what I missed.

Thanks,
-James

> --
> Kees Cook

2022-03-17 06:47:11

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Thu, Mar 17, 2022 at 02:32:29AM +0000, David Laight wrote:
> From: Kees Cook
> > Sent: 16 March 2022 22:30
> >
> > On Wed, Mar 16, 2022 at 01:38:31PM +0100, Arnd Bergmann wrote:
> > > is in the end, but it's likely easier than a standalone a.out loader
> > > in user space, or a conversion to ELF format.
> >
> > Yeah, the exec format is really simple. The only tricky bit was preparing
> > the stack and making sure everything landed in the right place for text
> > and data. James, can you try this? aln and mac run for me, but I'm not
> > actually exercising them beyond dumping argument lists, etc:
>
> Doesn't that restrict the a.out program to the address space below
> the normal base address for elf programs?
> So you'll only be able to load small programs - which might be ok here.
>
> OTOH it might be possible to link the 'loader program' to a high
> address - the elf loader will probably just load it.
> Best to link it static to avoid shared lib mmaps
> and probably try to avoid libc calls.
>
> I was wondering what happens when malloc() starts using
> sbrk() - but I guess it sees the top of the bss for the
> loaded and it all works fine.

I'll wait unless something breaks. :) Right now I just wanted to get aln
and mac working -- and that's a pretty small subset of all a.out
binaries. :)

--
Kees Cook

2022-03-17 11:58:33

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Thu, Mar 17, 2022 at 02:04:46AM +0000, James Jones wrote:
> Yes, works perfectly, thank you. I like the idea of using this much
> better than getting emailed every time someone wants to delete the a.out
> code again. Consider my use case withdrawn. I've already pushed an
> update to my jaguar-sdk project to use this tool instead.

Ok, pls do test this solution extensively and let us know if there are
other problems. I'll schedule a.out removal then for the next kernel so
you have a month or two time to experiment.

Thx.

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette

2022-03-17 20:38:30

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Thu, Mar 17, 2022 at 02:04:46AM +0000, James Jones wrote:
> On 3/16/22 3:30 PM, Kees Cook wrote:
> > On Wed, Mar 16, 2022 at 01:38:31PM +0100, Arnd Bergmann wrote:
> >> is in the end, but it's likely easier than a standalone a.out loader
> >> in user space, or a conversion to ELF format.
> >
> > Yeah, the exec format is really simple. The only tricky bit was preparing
> > the stack and making sure everything landed in the right place for text
> > and data. James, can you try this? aln and mac run for me, but I'm not
> > actually exercising them beyond dumping argument lists, etc:
> >
> > https://github.com/kees/kernel-tools/tree/trunk/a.out
>
> Yes, works perfectly, thank you. I like the idea of using this much

Hurray!

> better than getting emailed every time someone wants to delete the a.out
> code again. Consider my use case withdrawn. I've already pushed an
> update to my jaguar-sdk project to use this tool instead.

Nice; I see there are other binaries besides aln and mac that are
working with this too? *whew* I'm glad it was relatively straight
forward. :)

--
Kees Cook

2022-04-04 22:03:01

by Maciej W. Rozycki

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Wed, 16 Mar 2022, James Jones wrote:

> Probably getting a bit off topic, but I did spend a few hours searching
> around for any existing tools to convert a binary from a.out->ELF, and
> trying to come up with something myself by extracting the sections with
> objdump and re-combining them into an ELF using a linker script placing
> the sections at the same locations. I couldn't get it working in an
> evening or two messing with it so I moved on, but I agree something like
> this seems possible in theory.

Chiming in late as I'm scanning outstanding mailing list traffic: if this
is as you say all statically linked stuff, then converting from a.out to
ELF might be as easy as:

$ objcopy -I a.out-i386-linux -O elf32-i386 a.out-binary elf-binary

though you may have to build yourself suitably old i386-linux-gnu binutils
(from ftp.gnu.org), e.g. this version does support a.out:

$ objcopy --info
BFD header file version 2.15.91 20040527
elf32-i386
(header little endian, data little endian)
i386
a.out-i386-linux
(header little endian, data little endian)
i386
efi-app-ia32
(header little endian, data little endian)
i386
elf32-little
(header little endian, data little endian)
i386
elf32-big
(header big endian, data big endian)
i386
srec
(header endianness unknown, data endianness unknown)
i386
symbolsrec
(header endianness unknown, data endianness unknown)
i386
tekhex
(header endianness unknown, data endianness unknown)
i386
binary
(header endianness unknown, data endianness unknown)
i386
ihex
(header endianness unknown, data endianness unknown)
i386
trad-core
(header endianness unknown, data endianness unknown)

elf32-i386 a.out-i386-linux efi-app-ia32 elf32-little elf32-big
i386 elf32-i386 a.out-i386-linux efi-app-ia32 elf32-little elf32-big

srec symbolsrec tekhex binary ihex trad-core
i386 srec symbolsrec tekhex binary ihex ---------

The last binutils version to support a.out-i386-linux was 2.30 I believe.
Just configuring for i386-linux-gnu should do as a.out used to be included
as a secondary BFD target (you can also do `--enable-targets=all' to get
support for all kinds of the exotic and less exotic BFD targets).

HTH,

Maciej

2022-04-05 00:19:46

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Mon, Apr 04, 2022 at 05:07:11PM +0000, David Laight wrote:
> From: Maciej W. Rozycki
> > Sent: 04 April 2022 12:04
> >
> > On Sat, 2 Apr 2022, Kees Cook wrote:
> >
> > > > Chiming in late as I'm scanning outstanding mailing list traffic: if this
> > > >is as you say all statically linked stuff, then converting from a.out to
> > > >ELF might be as easy as:
> > > >
> > > >$ objcopy -I a.out-i386-linux -O elf32-i386 a.out-binary elf-binary
> > >
> > > Based on my research (and the wrapper I ended up writing), I don't think
> > > this is sufficient because entry point handling is different between ELF
> > > and a.out (specifically the stack layout and initial sp register value).
> >
> > Fair enough. I guess the exact value of %esp doesn't matter that much
> > (why would it?), but the arguments and environment may well be structured
> > differently (and indeed based on a glance over binfmt_aout.c there's extra
> > indirection involved compared to the ELF i386 psABI).
>
> You could write a custom 'elf interpreter'.
> Hacking at those isn't for the faint-hearted :-)

A thread on LWN pointed to:
https://github.com/siegfriedpammer/run-aout
which appears to be a much more complete a.out wrapper.

--
Kees Cook

2022-04-05 00:21:37

by David Laight

[permalink] [raw]
Subject: RE: [PATCH] x86: Remove a.out support

From: Maciej W. Rozycki
> Sent: 04 April 2022 12:04
>
> On Sat, 2 Apr 2022, Kees Cook wrote:
>
> > > Chiming in late as I'm scanning outstanding mailing list traffic: if this
> > >is as you say all statically linked stuff, then converting from a.out to
> > >ELF might be as easy as:
> > >
> > >$ objcopy -I a.out-i386-linux -O elf32-i386 a.out-binary elf-binary
> >
> > Based on my research (and the wrapper I ended up writing), I don't think
> > this is sufficient because entry point handling is different between ELF
> > and a.out (specifically the stack layout and initial sp register value).
>
> Fair enough. I guess the exact value of %esp doesn't matter that much
> (why would it?), but the arguments and environment may well be structured
> differently (and indeed based on a glance over binfmt_aout.c there's extra
> indirection involved compared to the ELF i386 psABI).

You could write a custom 'elf interpreter'.
Hacking at those isn't for the faint-hearted :-)

David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

2022-04-05 01:02:34

by Maciej W. Rozycki

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Sat, 2 Apr 2022, Kees Cook wrote:

> > Chiming in late as I'm scanning outstanding mailing list traffic: if this
> >is as you say all statically linked stuff, then converting from a.out to
> >ELF might be as easy as:
> >
> >$ objcopy -I a.out-i386-linux -O elf32-i386 a.out-binary elf-binary
>
> Based on my research (and the wrapper I ended up writing), I don't think
> this is sufficient because entry point handling is different between ELF
> and a.out (specifically the stack layout and initial sp register value).

Fair enough. I guess the exact value of %esp doesn't matter that much
(why would it?), but the arguments and environment may well be structured
differently (and indeed based on a glance over binfmt_aout.c there's extra
indirection involved compared to the ELF i386 psABI).

Maciej

2022-04-05 01:23:26

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support

On Sun, Apr 3, 2022 at 6:46 PM Maciej W. Rozycki <[email protected]> wrote:
> On Wed, 16 Mar 2022, James Jones wrote:
> > Probably getting a bit off topic, but I did spend a few hours searching
> > around for any existing tools to convert a binary from a.out->ELF, and
> > trying to come up with something myself by extracting the sections with
> > objdump and re-combining them into an ELF using a linker script placing
> > the sections at the same locations. I couldn't get it working in an
> > evening or two messing with it so I moved on, but I agree something like
> > this seems possible in theory.
>
> Chiming in late as I'm scanning outstanding mailing list traffic: if this
> is as you say all statically linked stuff, then converting from a.out to
> ELF might be as easy as:

Probably, as https://lwn.net/Articles/889952/ claims dynamically linked
a.out was broken in v5.1.

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2022-04-05 03:29:51

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] x86: Remove a.out support



On April 2, 2022 3:14:43 PM PDT, "Maciej W. Rozycki" <[email protected]> wrote:
>On Wed, 16 Mar 2022, James Jones wrote:
>
>> Probably getting a bit off topic, but I did spend a few hours searching
>> around for any existing tools to convert a binary from a.out->ELF, and
>> trying to come up with something myself by extracting the sections with
>> objdump and re-combining them into an ELF using a linker script placing
>> the sections at the same locations. I couldn't get it working in an
>> evening or two messing with it so I moved on, but I agree something like
>> this seems possible in theory.
>
> Chiming in late as I'm scanning outstanding mailing list traffic: if this
>is as you say all statically linked stuff, then converting from a.out to
>ELF might be as easy as:
>
>$ objcopy -I a.out-i386-linux -O elf32-i386 a.out-binary elf-binary

Based on my research (and the wrapper I ended up writing), I don't think this is sufficient because entry point handling is different between ELF and a.out (specifically the stack layout and initial sp register value).

-Kees

--
Kees Cook