/* * 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 (ericy@cais.com). */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); static int load_elf_library(struct file *); static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, int, int, unsigned long); /* * 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 NULL #endif #if ELF_EXEC_PAGESIZE > PAGE_SIZE #define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE #else #define ELF_MIN_ALIGN PAGE_SIZE #endif #ifndef ELF_CORE_EFLAGS #define ELF_CORE_EFLAGS 0 #endif #define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_MIN_ALIGN-1)) #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1)) #define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1)) static struct linux_binfmt elf_format = { .module = THIS_MODULE, .load_binary = load_elf_binary, .load_shlib = load_elf_library, .core_dump = elf_core_dump, .min_coredump = ELF_EXEC_PAGESIZE, }; #define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) static int set_brk(unsigned long start, unsigned long end) { start = ELF_PAGEALIGN(start); end = ELF_PAGEALIGN(end); if (end > start) { unsigned long addr; down_write(¤t->mm->mmap_sem); addr = do_brk(start, end - start); up_write(¤t->mm->mmap_sem); if (BAD_ADDR(addr)) return addr; } current->mm->start_brk = current->mm->brk = end; return 0; } /* We need to explicitly zero any fractional pages after the data section (i.e. bss). This would contain the junk from the file that should not be in memory */ static int padzero(unsigned long elf_bss) { unsigned long nbyte; nbyte = ELF_PAGEOFFSET(elf_bss); if (nbyte) { nbyte = ELF_MIN_ALIGN - nbyte; if (clear_user((void __user *) elf_bss, nbyte)) return -EFAULT; } return 0; } /* Let's use some macros to make this stack manipulation a little clearer */ #ifdef CONFIG_STACK_GROWSUP #define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items)) #define STACK_ROUND(sp, items) \ ((15 + (unsigned long) ((sp) + (items))) &~ 15UL) #define STACK_ALLOC(sp, len) ({ \ elf_addr_t __user *old_sp = (elf_addr_t __user *)sp; sp += len; \ old_sp; }) #else #define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) - (items)) #define STACK_ROUND(sp, items) \ (((unsigned long) (sp - items)) &~ 15UL) #define STACK_ALLOC(sp, len) ({ sp -= len ; sp; }) #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 NULL #endif static int create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, unsigned long load_addr, unsigned long interp_load_addr) { unsigned long p = bprm->p; int argc = bprm->argc; int envc = bprm->envc; elf_addr_t __user *argv; elf_addr_t __user *envp; elf_addr_t __user *sp; elf_addr_t __user *u_platform; elf_addr_t __user *u_base_platform; elf_addr_t __user *u_rand_bytes; const char *k_platform = ELF_PLATFORM; const char *k_base_platform = ELF_BASE_PLATFORM; unsigned char k_rand_bytes[16]; int items; elf_addr_t *elf_info; int ei_index = 0; const struct cred *cred = current_cred(); struct vm_area_struct *vma; /* * In some cases (e.g. Hyper-Threading), we want to avoid L1 * evictions by the processes running on the same package. One * thing we can do is to shuffle the initial stack for them. */ p = arch_align_stack(p); /* * If this architecture has a platform capability string, copy it * to userspace. In some cases (Sparc), this info is impossible * for userspace to get any other way, in others (i386) it is * merely difficult. */ u_platform = NULL; if (k_platform) { size_t len = strlen(k_platform) + 1; u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); if (__copy_to_user(u_platform, k_platform, len)) return -EFAULT; } /* * If this architecture has a "base" platform capability * string, copy it to userspace. */ u_base_platform = NULL; if (k_base_platform) { size_t len = strlen(k_base_platform) + 1; u_base_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); if (__copy_to_user(u_base_platform, k_base_platform, len)) return -EFAULT; } /* * Generate 16 random bytes for userspace PRNG seeding. */ get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes)); u_rand_bytes = (elf_addr_t __user *) STACK_ALLOC(p, sizeof(k_rand_bytes)); if (__copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes))) return -EFAULT; /* Create the ELF interpreter info */ elf_info = (elf_addr_t *)current->mm->saved_auxv; /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */ #define NEW_AUX_ENT(id, val) \ do { \ elf_info[ei_index++] = id; \ elf_info[ei_index++] = val; \ } while (0) #ifdef ARCH_DLINFO /* * ARCH_DLINFO must come first so PPC can do its special alignment of * AUXV. * update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT() in * ARCH_DLINFO changes */ ARCH_DLINFO; #endif NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); NEW_AUX_ENT(AT_BASE, interp_load_addr); NEW_AUX_ENT(AT_FLAGS, 0); NEW_AUX_ENT(AT_ENTRY, exec->e_entry); NEW_AUX_ENT(AT_UID, cred->uid); NEW_AUX_ENT(AT_EUID, cred->euid); NEW_AUX_ENT(AT_GID, cred->gid); NEW_AUX_ENT(AT_EGID, cred->egid); NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm)); NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes); NEW_AUX_ENT(AT_EXECFN, bprm->exec); if (k_platform) { NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(unsigned long)u_platform); } if (k_base_platform) { NEW_AUX_ENT(AT_BASE_PLATFORM, (elf_addr_t)(unsigned long)u_base_platform); } if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { NEW_AUX_ENT(AT_EXECFD, bprm->interp_data); } #undef NEW_AUX_ENT /* AT_NULL is zero; clear the rest too */ memset(&elf_info[ei_index], 0, sizeof current->mm->saved_auxv - ei_index * sizeof elf_info[0]); /* And advance past the AT_NULL entry. */ ei_index += 2; sp = STACK_ADD(p, ei_index); items = (argc + 1) + (envc + 1) + 1; bprm->p = STACK_ROUND(sp, items); /* Point sp at the lowest address on the stack */ #ifdef CONFIG_STACK_GROWSUP sp = (elf_addr_t __user *)bprm->p - items - ei_index; bprm->exec = (unsigned long)sp; /* XXX: PARISC HACK */ #else sp = (elf_addr_t __user *)bprm->p; #endif /* * Grow the stack manually; some architectures have a limit on how * far ahead a user-space access may be in order to grow the stack. */ vma = find_extend_vma(current->mm, bprm->p); if (!vma) return -EFAULT; /* Now, let's put argc (and argv, envp if appropriate) on the stack */ if (__put_user(argc, sp++)) return -EFAULT; argv = sp; envp = argv + argc + 1; /* Populate argv and envp */ p = current->mm->arg_end = current->mm->arg_start; while (argc-- > 0) { size_t len; if (__put_user((elf_addr_t)p, argv++)) return -EFAULT; len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); if (!len || len > MAX_ARG_STRLEN) return -EINVAL; p += len; } if (__put_user(0, argv)) return -EFAULT; current->mm->arg_end = current->mm->env_start = p; while (envc-- > 0) { size_t len; if (__put_user((elf_addr_t)p, envp++)) return -EFAULT; len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); if (!len || len > MAX_ARG_STRLEN) return -EINVAL; p += len; } if (__put_user(0, envp)) return -EFAULT; current->mm->env_end = p; /* Put the elf_info on the stack in the right place. */ sp = (elf_addr_t __user *)envp + 1; if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t))) return -EFAULT; return 0; } static unsigned long elf_map(struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type, unsigned long total_size) { unsigned long map_addr; unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr); unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr); addr = ELF_PAGESTART(addr); size = ELF_PAGEALIGN(size); /* mmap() will return -EINVAL if given a zero size, but a * segment with zero filesize is perfectly valid */ if (!size) return addr; down_write(¤t->mm->mmap_sem); /* * total_size is the size of the ELF (interpreter) image. * The _first_ mmap needs to know the full size, otherwise * randomization might put this image into an overlapping * position with the ELF binary image. (since size < total_size) * So we first map the 'big' image - and unmap the remainder at * the end. (which unmap is needed for ELF images with holes.) */ if (total_size) { total_size = ELF_PAGEALIGN(total_size); map_addr = do_mmap(filep, addr, total_size, prot, type, off); if (!BAD_ADDR(map_addr)) do_munmap(current->mm, map_addr+size, total_size-size); } else map_addr = do_mmap(filep, addr, size, prot, type, off); up_write(¤t->mm->mmap_sem); return(map_addr); } static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr) { int i, first_idx = -1, last_idx = -1; for (i = 0; i < nr; i++) { if (cmds[i].p_type == PT_LOAD) { last_idx = i; if (first_idx == -1) first_idx = i; } } if (first_idx == -1) return 0; return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz - ELF_PAGESTART(cmds[first_idx].p_vaddr); } /* This is much more gener
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef __SOUND_INFO_H
#define __SOUND_INFO_H

/*
 *  Header file for info interface
 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
 */

#include <linux/poll.h>
#include <linux/seq_file.h>
#include <sound/core.h>

/* buffer for information */
struct snd_info_buffer {
	char *buffer;		/* pointer to begin of buffer */
	unsigned int curr;	/* current position in buffer */
	unsigned int size;	/* current size */
	unsigned int len;	/* total length of buffer */
	int stop;		/* stop flag */
	int error;		/* error code */
};

#define SNDRV_INFO_CONTENT_TEXT		0
#define SNDRV_INFO_CONTENT_DATA		1

struct snd_info_entry;

struct snd_info_entry_text {
	void (*read)(struct snd_info_entry *entry,
		     struct snd_info_buffer *buffer);
	void (*write)(struct snd_info_entry *entry,
		      struct snd_info_buffer *buffer);
};

struct snd_info_entry_ops {
	int (*open)(struct snd_info_entry *entry,
		    unsigned short mode, void **file_private_data);
	int (*release)(struct snd_info_entry *entry,
		       unsigned short mode, void *file_private_data);
	ssize_t (*read)(struct snd_info_entry *entry, void *file_private_data,
			struct file *file, char __user *buf,
			size_t count, loff_t pos);
	ssize_t (*write)(struct snd_info_entry *entry, void *file_private_data,
			 struct file *file, const char __user *buf,
			 size_t count, loff_t pos);
	loff_t (*llseek)(struct snd_info_entry *entry,
			 void *file_private_data, struct file *file,
			 loff_t offset, int orig);
	__poll_t (*poll)(struct snd_info_entry *entry,
			     void *file_private_data, struct file *file,
			     poll_table *wait);
	int (*ioctl)(struct snd_info_entry *entry, void *file_private_data,
		     struct file *file, unsigned int cmd, unsigned long arg);
	int (*mmap)(struct snd_info_entry *entry, void *file_private_data,
		    struct inode *inode, struct file *file,
		    struct vm_area_struct *vma);
};

struct snd_info_entry {
	const char *name;
	umode_t mode;
	long size;
	unsigned short content;
	union {
		struct snd_info_entry_text text;
		const struct snd_info_entry_ops *ops;
	} c;
	struct snd_info_entry *parent;
	struct module *module;
	void *private_data;
	void (*private_free)(struct snd_info_entry *entry);
	struct proc_dir_entry *p;
	struct mutex access;
	struct list_head children;
	struct list_head list;
};

#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_SND_PROC_FS)
int snd_info_minor_register(void);
#else
#define snd_info_minor_register()	0
#endif


#ifdef CONFIG_SND_PROC_FS

extern struct snd_info_entry *snd_seq_root;
#ifdef CONFIG_SND_OSSEMUL
extern struct snd_info_entry *snd_oss_root;
void snd_card_info_read_oss(struct snd_info_buffer *buffer);
#else
#define snd_oss_root NULL
static inline void snd_card_info_read_oss(struct snd_info_buffer *buffer) {}
#endif

/**
 * snd_iprintf - printf on the procfs buffer
 * @buf: the procfs buffer
 * @fmt: the printf format
 *
 * Outputs the string on the procfs buffer just like printf().
 *
 * Return: zero for success, or a negative error code.
 */
#define snd_iprintf(buf, fmt, args...) \
	seq_printf((struct seq_file *)(buf)->buffer, fmt, ##args)

int snd_info_init(void);
int snd_info_done(void);

int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len);
const char *snd_info_get_str(char *dest, const char *src, int len);
struct snd_info_entry *snd_info_create_module_entry(struct module *module,
					       const char *name,
					       struct snd_info_entry *parent);
struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
					     const char *name,
					     struct snd_info_entry *parent);
void snd_info_free_entry(struct snd_info_entry *entry);
int snd_info_store_text(struct snd_info_entry *entry);
int snd_info_restore_text(struct snd_info_entry *entry);

int snd_info_card_create(struct snd_card *card);
int snd_info_card_register(struct snd_card *card);
int snd_info_card_free(struct snd_card *card);
void snd_info_card_disconnect(struct snd_card *card);
void snd_info_card_id_change(struct snd_card *card);
int snd_info_register(struct snd_info_entry *entry);

/* for card drivers */
static inline int snd_card_proc_new(struct snd_card *card, const char *name,
				    struct snd_info_entry **entryp)
{
	*entryp = snd_info_create_card_entry(card, name, card->proc_root);
	return *entryp ? 0 : -ENOMEM;
}

static inline void snd_info_set_text_ops(struct snd_info_entry *entry, 
	void *private_data,
	void (*read)(struct snd_info_entry *, struct snd_info_buffer *))
{
	entry->private_data = private_data;
	entry->c.text.read = read;
}

int snd_card_rw_proc_new(struct snd_card *card, const char *name,
			 void *private_data,
			 void (*read)(struct snd_info_entry *,
				      struct snd_info_buffer *),
			 void (*write)(struct snd_info_entry *entry,
				       struct snd_info_buffer *buffer));

int snd_info_check_reserved_words(const char *str);

#else

#define snd_seq_root NULL
#define snd_oss_root NULL

static inline int snd_iprintf(struct snd_info_buffer *buffer, char *fmt, ...) { return 0; }
static inline int snd_info_init(void) { return 0; }
static inline int snd_info_done(void) { return 0; }

static inline int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) { return 0; }
static inline char *snd_info_get_str(char *dest, char *src, int len) { return NULL; }
static inline struct snd_info_entry *snd_info_create_module_entry(struct module *module, const char *name, struct snd_info_entry *parent) { return NULL; }
static inline struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, struct snd_info_entry *parent) { return NULL; }
static inline void snd_info_free_entry(struct snd_info_entry *entry) { ; }

static inline int snd_info_card_create(struct snd_card *card) { return 0; }
static inline int snd_info_card_register(struct snd_card *card) { return 0; }
static inline int snd_info_card_free(struct snd_card *card) { return 0; }
static inline void snd_info_card_disconnect(struct snd_card *card) { }
static inline void snd_info_card_id_change(struct snd_card *card)