18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/fs/binfmt_em86.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Based on linux/fs/binfmt_script.c
68c2ecf20Sopenharmony_ci *  Copyright (C) 1996  Martin von Löwis
78c2ecf20Sopenharmony_ci *  original #!-checking implemented by tytso.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *  em86 changes Copyright (C) 1997  Jim Paradis
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/string.h>
148c2ecf20Sopenharmony_ci#include <linux/stat.h>
158c2ecf20Sopenharmony_ci#include <linux/binfmts.h>
168c2ecf20Sopenharmony_ci#include <linux/elf.h>
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/fs.h>
198c2ecf20Sopenharmony_ci#include <linux/file.h>
208c2ecf20Sopenharmony_ci#include <linux/errno.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define EM86_INTERP	"/usr/bin/em86"
248c2ecf20Sopenharmony_ci#define EM86_I_NAME	"em86"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic int load_em86(struct linux_binprm *bprm)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	const char *i_name, *i_arg;
298c2ecf20Sopenharmony_ci	char *interp;
308c2ecf20Sopenharmony_ci	struct file * file;
318c2ecf20Sopenharmony_ci	int retval;
328c2ecf20Sopenharmony_ci	struct elfhdr	elf_ex;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	/* Make sure this is a Linux/Intel ELF executable... */
358c2ecf20Sopenharmony_ci	elf_ex = *((struct elfhdr *)bprm->buf);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
388c2ecf20Sopenharmony_ci		return  -ENOEXEC;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/* First of all, some simple consistency checks */
418c2ecf20Sopenharmony_ci	if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
428c2ecf20Sopenharmony_ci		(!((elf_ex.e_machine == EM_386) || (elf_ex.e_machine == EM_486))) ||
438c2ecf20Sopenharmony_ci		!bprm->file->f_op->mmap) {
448c2ecf20Sopenharmony_ci			return -ENOEXEC;
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	/* Need to be able to load the file after exec */
488c2ecf20Sopenharmony_ci	if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE)
498c2ecf20Sopenharmony_ci		return -ENOENT;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	/* Unlike in the script case, we don't have to do any hairy
528c2ecf20Sopenharmony_ci	 * parsing to find our interpreter... it's hardcoded!
538c2ecf20Sopenharmony_ci	 */
548c2ecf20Sopenharmony_ci	interp = EM86_INTERP;
558c2ecf20Sopenharmony_ci	i_name = EM86_I_NAME;
568c2ecf20Sopenharmony_ci	i_arg = NULL;		/* We reserve the right to add an arg later */
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	/*
598c2ecf20Sopenharmony_ci	 * Splice in (1) the interpreter's name for argv[0]
608c2ecf20Sopenharmony_ci	 *           (2) (optional) argument to interpreter
618c2ecf20Sopenharmony_ci	 *           (3) filename of emulated file (replace argv[0])
628c2ecf20Sopenharmony_ci	 *
638c2ecf20Sopenharmony_ci	 * This is done in reverse order, because of how the
648c2ecf20Sopenharmony_ci	 * user environment and arguments are stored.
658c2ecf20Sopenharmony_ci	 */
668c2ecf20Sopenharmony_ci	remove_arg_zero(bprm);
678c2ecf20Sopenharmony_ci	retval = copy_string_kernel(bprm->filename, bprm);
688c2ecf20Sopenharmony_ci	if (retval < 0) return retval;
698c2ecf20Sopenharmony_ci	bprm->argc++;
708c2ecf20Sopenharmony_ci	if (i_arg) {
718c2ecf20Sopenharmony_ci		retval = copy_string_kernel(i_arg, bprm);
728c2ecf20Sopenharmony_ci		if (retval < 0) return retval;
738c2ecf20Sopenharmony_ci		bprm->argc++;
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci	retval = copy_string_kernel(i_name, bprm);
768c2ecf20Sopenharmony_ci	if (retval < 0)	return retval;
778c2ecf20Sopenharmony_ci	bprm->argc++;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	/*
808c2ecf20Sopenharmony_ci	 * OK, now restart the process with the interpreter's inode.
818c2ecf20Sopenharmony_ci	 * Note that we use open_exec() as the name is now in kernel
828c2ecf20Sopenharmony_ci	 * space, and we don't need to copy it.
838c2ecf20Sopenharmony_ci	 */
848c2ecf20Sopenharmony_ci	file = open_exec(interp);
858c2ecf20Sopenharmony_ci	if (IS_ERR(file))
868c2ecf20Sopenharmony_ci		return PTR_ERR(file);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	bprm->interpreter = file;
898c2ecf20Sopenharmony_ci	return 0;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic struct linux_binfmt em86_format = {
938c2ecf20Sopenharmony_ci	.module		= THIS_MODULE,
948c2ecf20Sopenharmony_ci	.load_binary	= load_em86,
958c2ecf20Sopenharmony_ci};
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic int __init init_em86_binfmt(void)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	register_binfmt(&em86_format);
1008c2ecf20Sopenharmony_ci	return 0;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic void __exit exit_em86_binfmt(void)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	unregister_binfmt(&em86_format);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cicore_initcall(init_em86_binfmt);
1098c2ecf20Sopenharmony_cimodule_exit(exit_em86_binfmt);
1108c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
111