linux/fs/binfmt_elf.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * linux/fs/binfmt_elf.c
 *
 * These are the functions used to load ELF format executables as used
 * on SVr4 machines.  Information on the format may be found in the book
 * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support
 * Tools".
 *
 * Copyright 1993, 1994: Eric Youngdale ([email protected]).
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/log2.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/binfmts.h>
#include <linux/string.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/personality.h>
#include <linux/elfcore.h>
#include <linux/init.h>
#include <linux/highuid.h>
#include <linux/compiler.h>
#include <linux/highmem.h>
#include <linux/hugetlb.h>
#include <linux/pagemap.h>
#include <linux/vmalloc.h>
#include <linux/security.h>
#include <linux/random.h>
#include <linux/elf.h>
#include <linux/elf-randomize.h>
#include <linux/utsname.h>
#include <linux/coredump.h>
#include <linux/sched.h>
#include <linux/sched/coredump.h>
#include <linux/sched/task_stack.h>
#include <linux/sched/cputime.h>
#include <linux/sizes.h>
#include <linux/types.h>
#include <linux/cred.h>
#include <linux/dax.h>
#include <linux/uaccess.h>
#include <linux/rseq.h>
#include <asm/param.h>
#include <asm/page.h>

#ifndef ELF_COMPAT
#define ELF_COMPAT
#endif

#ifndef user_long_t
#define user_long_t
#endif
#ifndef user_siginfo_t
#define user_siginfo_t
#endif

/* That's for binfmt_elf_fdpic to deal with */
#ifndef elf_check_fdpic
#define elf_check_fdpic(ex)
#endif

static int load_elf_binary(struct linux_binprm *bprm);

#ifdef CONFIG_USELIB
static int load_elf_library(struct file *);
#else
#define load_elf_library
#endif

/*
 * If we don't support core dumping, then supply a NULL so we
 * don't even try.
 */
#ifdef CONFIG_ELF_CORE
static int elf_core_dump(struct coredump_params *cprm);
#else
#define elf_core_dump
#endif

#if ELF_EXEC_PAGESIZE > PAGE_SIZE
#define ELF_MIN_ALIGN
#else
#define ELF_MIN_ALIGN
#endif

#ifndef ELF_CORE_EFLAGS
#define ELF_CORE_EFLAGS
#endif

#define ELF_PAGESTART(_v)
#define ELF_PAGEOFFSET(_v)
#define ELF_PAGEALIGN(_v)

static struct linux_binfmt elf_format =;

#define BAD_ADDR(x)

/*
 * We need to explicitly zero any trailing portion of the page that follows
 * p_filesz when it ends before the page ends (e.g. bss), otherwise this
 * memory will contain the junk from the file that should not be present.
 */
static int padzero(unsigned long address)
{}

/* Let's use some macros to make this stack manipulation a little clearer */
#ifdef CONFIG_STACK_GROWSUP
#define STACK_ADD
#define STACK_ROUND
#define STACK_ALLOC
#else
#define STACK_ADD(sp, items)
#define STACK_ROUND(sp, items)
#define STACK_ALLOC(sp, len)
#endif

#ifndef ELF_BASE_PLATFORM
/*
 * AT_BASE_PLATFORM indicates the "real" hardware/microarchitecture.
 * If the arch defines ELF_BASE_PLATFORM (in asm/elf.h), the value
 * will be copied to the user stack in the same manner as AT_PLATFORM.
 */
#define ELF_BASE_PLATFORM
#endif

static int
create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec,
		unsigned long interp_load_addr,
		unsigned long e_entry, unsigned long phdr_addr)
{}

/*
 * Map "eppnt->p_filesz" bytes from "filep" offset "eppnt->p_offset"
 * into memory at "addr". (Note that p_filesz is rounded up to the
 * next page, so any extra bytes from the file must be wiped.)
 */
static unsigned long elf_map(struct file *filep, unsigned long addr,
		const struct elf_phdr *eppnt, int prot, int type,
		unsigned long total_size)
{}

/*
 * Map "eppnt->p_filesz" bytes from "filep" offset "eppnt->p_offset"
 * into memory at "addr". Memory from "p_filesz" through "p_memsz"
 * rounded up to the next page is zeroed.
 */
static unsigned long elf_load(struct file *filep, unsigned long addr,
		const struct elf_phdr *eppnt, int prot, int type,
		unsigned long total_size)
{}


static unsigned long total_mapping_size(const struct elf_phdr *phdr, int nr)
{}

static int elf_read(struct file *file, void *buf, size_t len, loff_t pos)
{}

static unsigned long maximum_alignment(struct elf_phdr *cmds, int nr)
{}

/**
 * load_elf_phdrs() - load ELF program headers
 * @elf_ex:   ELF header of the binary whose program headers should be loaded
 * @elf_file: the opened ELF binary file
 *
 * Loads ELF program headers from the binary file elf_file, which has the ELF
 * header pointed to by elf_ex, into a newly allocated array. The caller is
 * responsible for freeing the allocated data. Returns NULL upon failure.
 */
static struct elf_phdr *load_elf_phdrs(const struct elfhdr *elf_ex,
				       struct file *elf_file)
{}

#ifndef CONFIG_ARCH_BINFMT_ELF_STATE

/**
 * struct arch_elf_state - arch-specific ELF loading state
 *
 * This structure is used to preserve architecture specific data during
 * the loading of an ELF file, throughout the checking of architecture
 * specific ELF headers & through to the point where the ELF load is
 * known to be proceeding (ie. SET_PERSONALITY).
 *
 * This implementation is a dummy for architectures which require no
 * specific state.
 */
struct arch_elf_state {};

#define INIT_ARCH_ELF_STATE

/**
 * arch_elf_pt_proc() - check a PT_LOPROC..PT_HIPROC ELF program header
 * @ehdr:	The main ELF header
 * @phdr:	The program header to check
 * @elf:	The open ELF file
 * @is_interp:	True if the phdr is from the interpreter of the ELF being
 *		loaded, else false.
 * @state:	Architecture-specific state preserved throughout the process
 *		of loading the ELF.
 *
 * Inspects the program header phdr to validate its correctness and/or
 * suitability for the system. Called once per ELF program header in the
 * range PT_LOPROC to PT_HIPROC, for both the ELF being loaded and its
 * interpreter.
 *
 * Return: Zero to proceed with the ELF load, non-zero to fail the ELF load
 *         with that return code.
 */
static inline int arch_elf_pt_proc(struct elfhdr *ehdr,
				   struct elf_phdr *phdr,
				   struct file *elf, bool is_interp,
				   struct arch_elf_state *state)
{}

/**
 * arch_check_elf() - check an ELF executable
 * @ehdr:	The main ELF header
 * @has_interp:	True if the ELF has an interpreter, else false.
 * @interp_ehdr: The interpreter's ELF header
 * @state:	Architecture-specific state preserved throughout the process
 *		of loading the ELF.
 *
 * Provides a final opportunity for architecture code to reject the loading
 * of the ELF & cause an exec syscall to return an error. This is called after
 * all program headers to be checked by arch_elf_pt_proc have been.
 *
 * Return: Zero to proceed with the ELF load, non-zero to fail the ELF load
 *         with that return code.
 */
static inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp,
				 struct elfhdr *interp_ehdr,
				 struct arch_elf_state *state)
{}

#endif /* !CONFIG_ARCH_BINFMT_ELF_STATE */

static inline int make_prot(u32 p_flags, struct arch_elf_state *arch_state,
			    bool has_interp, bool is_interp)
{}

/* This is much more generalized than the library routine read function,
   so we keep this separate.  Technically the library read function
   is only provided so that we can read a.out libraries that have
   an ELF header */

static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
		struct file *interpreter,
		unsigned long no_base, struct elf_phdr *interp_elf_phdata,
		struct arch_elf_state *arch_state)
{}

/*
 * These are the functions used to load ELF style executables and shared
 * libraries.  There is no binary dependent code anywhere else.
 */

static int parse_elf_property(const char *data, size_t *off, size_t datasz,
			      struct arch_elf_state *arch,
			      bool have_prev_type, u32 *prev_type)
{}

#define NOTE_DATA_SZ
#define GNU_PROPERTY_TYPE_0_NAME
#define NOTE_NAME_SZ

static int parse_elf_properties(struct file *f, const struct elf_phdr *phdr,
				struct arch_elf_state *arch)
{}

static int load_elf_binary(struct linux_binprm *bprm)
{}

#ifdef CONFIG_USELIB
/* This is really simpleminded and specialized - we are loading an
   a.out library that is given an ELF header. */
static int load_elf_library(struct file *file)
{}
#endif /* #ifdef CONFIG_USELIB */

#ifdef CONFIG_ELF_CORE
/*
 * ELF core dumper
 *
 * Modelled on fs/exec.c:aout_core_dump()
 * Jeremy Fitzhardinge <[email protected]>
 */

/* An ELF note in memory */
struct memelfnote
{};

static int notesize(struct memelfnote *en)
{}

static int writenote(struct memelfnote *men, struct coredump_params *cprm)
{}

static void fill_elf_header(struct elfhdr *elf, int segs,
			    u16 machine, u32 flags)
{}

static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset)
{}

static void fill_note(struct memelfnote *note, const char *name, int type,
		unsigned int sz, void *data)
{}

/*
 * fill up all the fields in prstatus from the given task struct, except
 * registers which need to be filled up separately.
 */
static void fill_prstatus(struct elf_prstatus_common *prstatus,
		struct task_struct *p, long signr)
{}

static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
		       struct mm_struct *mm)
{}

static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm)
{}

static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
		const kernel_siginfo_t *siginfo)
{}

/*
 * Format of NT_FILE note:
 *
 * long count     -- how many files are mapped
 * long page_size -- units for file_ofs
 * array of [COUNT] elements of
 *   long start
 *   long end
 *   long file_ofs
 * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...
 */
static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm)
{}

#include <linux/regset.h>

struct elf_thread_core_info {};

struct elf_note_info {};

#ifdef CORE_DUMP_USE_REGSET
/*
 * When a regset has a writeback hook, we call it on each thread before
 * dumping user memory.  On register window machines, this makes sure the
 * user memory backing the register data is up to date before we read it.
 */
static void do_thread_regset_writeback(struct task_struct *task,
				       const struct user_regset *regset)
{}

#ifndef PRSTATUS_SIZE
#define PRSTATUS_SIZE
#endif

#ifndef SET_PR_FPVALID
#define SET_PR_FPVALID(S)
#endif

static int fill_thread_core_info(struct elf_thread_core_info *t,
				 const struct user_regset_view *view,
				 long signr, struct elf_note_info *info)
{}
#else
static int fill_thread_core_info(struct elf_thread_core_info *t,
				 const struct user_regset_view *view,
				 long signr, struct elf_note_info *info)
{
	struct task_struct *p = t->task;
	elf_fpregset_t *fpu;

	fill_prstatus(&t->prstatus.common, p, signr);
	elf_core_copy_task_regs(p, &t->prstatus.pr_reg);

	fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus),
		  &(t->prstatus));
	info->size += notesize(&t->notes[0]);

	fpu = kzalloc(sizeof(elf_fpregset_t), GFP_KERNEL);
	if (!fpu || !elf_core_copy_task_fpregs(p, fpu)) {
		kfree(fpu);
		return 1;
	}

	t->prstatus.pr_fpvalid = 1;
	fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(*fpu), fpu);
	info->size += notesize(&t->notes[1]);

	return 1;
}
#endif

static int fill_note_info(struct elfhdr *elf, int phdrs,
			  struct elf_note_info *info,
			  struct coredump_params *cprm)
{}

/*
 * Write all the notes for each thread.  When writing the first thread, the
 * process-wide notes are interleaved after the first thread-specific note.
 */
static int write_note_info(struct elf_note_info *info,
			   struct coredump_params *cprm)
{}

static void free_note_info(struct elf_note_info *info)
{}

static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
			     elf_addr_t e_shoff, int segs)
{}

/*
 * Actual dumper
 *
 * This is a two-pass process; first we find the offsets of the bits,
 * and then they are actually written out.  If we run out of core limit
 * we just truncate.
 */
static int elf_core_dump(struct coredump_params *cprm)
{}

#endif		/* CONFIG_ELF_CORE */

static int __init init_elf_binfmt(void)
{}

static void __exit exit_elf_binfmt(void)
{}

core_initcall(init_elf_binfmt);
module_exit(exit_elf_binfmt);

#ifdef CONFIG_BINFMT_ELF_KUNIT_TEST
#include "tests/binfmt_elf_kunit.c"
#endif