09c434b8a0047 (Thomas Gleixner 2019-05-19 13:08:20 +0100 1) // SPDX-License-Identifier: GPL-2.0-only
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 3) * linux/fs/binfmt_em86.c
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 4) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 5) * Based on linux/fs/binfmt_script.c
96de0e252cedf (Jan Engelhardt 2007-10-19 23:21:04 +0200 6) * Copyright (C) 1996 Martin von Löwis
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 7) * original #!-checking implemented by tytso.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 8) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 9) * em86 changes Copyright (C) 1997 Jim Paradis
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 10) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 11)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 12) #include <linux/module.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 13) #include <linux/string.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 14) #include <linux/stat.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 15) #include <linux/binfmts.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 16) #include <linux/elf.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 17) #include <linux/init.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 18) #include <linux/fs.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 19) #include <linux/file.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 20) #include <linux/errno.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 21)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 22)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 23) #define EM86_INTERP "/usr/bin/em86"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 24) #define EM86_I_NAME "em86"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 25)
71613c3b871c5 (Al Viro 2012-10-20 22:00:48 -0400 26) static int load_em86(struct linux_binprm *bprm)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 27) {
a310dcb7a43f9 (Daniel Wagner 2016-08-02 14:04:57 -0700 28) const char *i_name, *i_arg;
a310dcb7a43f9 (Daniel Wagner 2016-08-02 14:04:57 -0700 29) char *interp;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 30) struct file * file;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 31) int retval;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 32) struct elfhdr elf_ex;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 33)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 34) /* Make sure this is a Linux/Intel ELF executable... */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 35) elf_ex = *((struct elfhdr *)bprm->buf);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 36)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 37) if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 38) return -ENOEXEC;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 39)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 40) /* First of all, some simple consistency checks */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 41) if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 42) (!((elf_ex.e_machine == EM_386) || (elf_ex.e_machine == EM_486))) ||
72c2d53192004 (Al Viro 2013-09-22 16:27:52 -0400 43) !bprm->file->f_op->mmap) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 44) return -ENOEXEC;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 45) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 46)
51f39a1f0cea1 (David Drysdale 2014-12-12 16:57:29 -0800 47) /* Need to be able to load the file after exec */
51f39a1f0cea1 (David Drysdale 2014-12-12 16:57:29 -0800 48) if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE)
51f39a1f0cea1 (David Drysdale 2014-12-12 16:57:29 -0800 49) return -ENOENT;
51f39a1f0cea1 (David Drysdale 2014-12-12 16:57:29 -0800 50)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 51) /* Unlike in the script case, we don't have to do any hairy
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 52) * parsing to find our interpreter... it's hardcoded!
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 53) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 54) interp = EM86_INTERP;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 55) i_name = EM86_I_NAME;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 56) i_arg = NULL; /* We reserve the right to add an arg later */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 57)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 58) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 59) * Splice in (1) the interpreter's name for argv[0]
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 60) * (2) (optional) argument to interpreter
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 61) * (3) filename of emulated file (replace argv[0])
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 62) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 63) * This is done in reverse order, because of how the
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 64) * user environment and arguments are stored.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 65) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 66) remove_arg_zero(bprm);
986db2d14a6dc (Christoph Hellwig 2020-06-04 16:51:14 -0700 67) retval = copy_string_kernel(bprm->filename, bprm);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 68) if (retval < 0) return retval;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 69) bprm->argc++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 70) if (i_arg) {
986db2d14a6dc (Christoph Hellwig 2020-06-04 16:51:14 -0700 71) retval = copy_string_kernel(i_arg, bprm);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72) if (retval < 0) return retval;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73) bprm->argc++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) }
986db2d14a6dc (Christoph Hellwig 2020-06-04 16:51:14 -0700 75) retval = copy_string_kernel(i_name, bprm);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 76) if (retval < 0) return retval;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 77) bprm->argc++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 78)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 79) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 80) * OK, now restart the process with the interpreter's inode.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 81) * Note that we use open_exec() as the name is now in kernel
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 82) * space, and we don't need to copy it.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 83) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 84) file = open_exec(interp);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 85) if (IS_ERR(file))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 86) return PTR_ERR(file);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 87)
bc2bf338d54b7 (Eric W. Biederman 2020-05-18 18:43:20 -0500 88) bprm->interpreter = file;
bc2bf338d54b7 (Eric W. Biederman 2020-05-18 18:43:20 -0500 89) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 90) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 91)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 92) static struct linux_binfmt em86_format = {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 93) .module = THIS_MODULE,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 94) .load_binary = load_em86,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 95) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 96)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 97) static int __init init_em86_binfmt(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 98) {
8fc3dc5a3a17a (Al Viro 2012-03-17 03:05:16 -0400 99) register_binfmt(&em86_format);
8fc3dc5a3a17a (Al Viro 2012-03-17 03:05:16 -0400 100) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 101) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 102)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 103) static void __exit exit_em86_binfmt(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 104) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 105) unregister_binfmt(&em86_format);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 106) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 107)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 108) core_initcall(init_em86_binfmt);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 109) module_exit(exit_em86_binfmt);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 110) MODULE_LICENSE("GPL");