Commit 1650f8d3 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.14

parent 98606bdd
VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 13
SUBLEVEL = 14
all: Version zImage
......
......@@ -17,7 +17,9 @@ if [ "$CONFIG_NET" = "y" ]; then
comment 'Networking options'
bool 'TCP/IP networking' CONFIG_INET y
if [ "$CONFIG_INET" "=" "y" ]; then
bool 'IP forwarding/gatewaying' CONFIG_IP_FORWARD n
comment '(it is safe to leave these untouched)'
bool 'PC/TCP compatibility mode' CONFIG_INET_PCTCP n
bool 'Reverse ARP' CONFIG_INET_RARP n
bool 'Assume subnets are local' CONFIG_INET_SNARL y
bool 'Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n
......@@ -26,11 +28,6 @@ bool 'The IPX protocol' CONFIG_IPX y
#bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n
fi
comment 'Program binary formats'
bool 'Elf executables' CONFIG_BINFMT_ELF y
bool 'COFF executables' CONFIG_BINFMT_COFF y
comment 'SCSI support'
bool 'SCSI support?' CONFIG_SCSI n
......@@ -78,7 +75,7 @@ if [ "$CONFIG_SLIP" = "y" ]; then
bool ' CSLIP compressed headers' SL_COMPRESSED y
# bool ' SLIP debugging on' SL_DUMP y
fi
#bool 'PPP (point-to-point) support' CONFIG_PPP n
bool 'PPP (point-to-point) support' CONFIG_PPP n
bool 'Load balancing support (very experimental)' CONFIG_SLAVE_BALANCING n
bool 'PLIP (parallel port) support' CONFIG_PLIP n
bool 'NE2000/NE1000 support' CONFIG_NE2000 n
......
......@@ -881,9 +881,9 @@ mcd_init(unsigned long mem_start, unsigned long mem_end)
/* don't get the IRQ until we know for sure the drive is there */
if (irqaction(MCD_INTR_NR, &mcd_sigaction))
if (irqaction(mcd_irq, &mcd_sigaction))
{
printk("mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", MCD_INTR_NR);
printk("mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
return mem_start;
}
snarf_region(mcd_port, 4);
......
......@@ -123,7 +123,6 @@
#include <linux/signal.h>
#endif SBPCD_USE_IRQ
#include <linux/ddi.h>
#include <linux/major.h>
#include <asm/system.h>
......@@ -142,6 +141,11 @@
#error "SBPCD: \"make config\" again. File system iso9660 is necessary."
#endif
/*
* This may come back some day..
*/
#define DDIOCSDBG 0x9000
/*
* still testing around...
*/
......
......@@ -40,13 +40,6 @@ ifdef CONFIG_HPFS_FS
FS_SUBDIRS := $(FS_SUBDIRS) hpfs
endif
ifdef CONFIG_BINFMT_ELF
BINFMTS := $(BINFMTS) binfmt_elf.o
endif
ifdef CONFIG_BINFMT_COFF
BINFMTS := $(BINFMTS) binfmt_coff.o
endif
.c.s:
$(CC) $(CFLAGS) -S $<
.c.o:
......
......@@ -53,6 +53,47 @@ asmlinkage int sys_brk(unsigned long);
extern void shm_exit (void);
static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
static int load_aout_library(int fd);
/*
* Here are the actual binaries that will be accepted:
* add more with "register_binfmt()"..
*/
static struct linux_binfmt aout_format = { NULL, load_aout_binary, load_aout_library };
static struct linux_binfmt *formats = &aout_format;
int register_binfmt(struct linux_binfmt * fmt)
{
struct linux_binfmt ** tmp = &formats;
if (!fmt)
return -EINVAL;
if (fmt->next)
return -EBUSY;
while (*tmp) {
if (fmt == *tmp)
return -EBUSY;
tmp = &(*tmp)->next;
}
*tmp = fmt;
return 0;
}
int unregister_binfmt(struct linux_binfmt * fmt)
{
struct linux_binfmt ** tmp = &formats;
while (*tmp) {
if (fmt == *tmp) {
*tmp = fmt->next;
return 0;
}
tmp = &(*tmp)->next;
}
return -EINVAL;
}
int open_inode(struct inode * inode, int mode)
{
int error, fd;
......@@ -247,14 +288,14 @@ asmlinkage int sys_uselib(const char * library)
file = current->files->fd[fd];
retval = -ENOEXEC;
if (file && file->f_inode && file->f_op && file->f_op->read) {
fmt = formats;
do {
for (fmt = formats ; fmt ; fmt = fmt->next) {
int (*fn)(int) = fmt->load_shlib;
if (!fn)
break;
retval = fn(fd);
fmt++;
} while (retval == -ENOEXEC);
if (retval != -ENOEXEC)
break;
}
}
sys_close(fd);
return retval;
......@@ -530,13 +571,13 @@ void flush_old_exec(struct linux_binprm * bprm)
if (last_task_used_math == current)
last_task_used_math = NULL;
current->used_math = 0;
current->elf_executable = 0;
current->personality = 0;
}
/*
* sys_execve() executes a new program.
*/
static int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
{
struct linux_binprm bprm;
struct linux_binfmt * fmt;
......@@ -684,8 +725,7 @@ static int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs
}
bprm.sh_bang = sh_bang;
fmt = formats;
do {
for (fmt = formats ; fmt ; fmt = fmt->next) {
int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
if (!fn)
break;
......@@ -695,8 +735,9 @@ static int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs
current->did_exec = 1;
return 0;
}
fmt++;
} while (retval == -ENOEXEC);
if (retval != -ENOEXEC)
break;
}
exec_error2:
iput(bprm.inode);
exec_error1:
......@@ -721,39 +762,6 @@ asmlinkage int sys_execve(struct pt_regs regs)
return error;
}
/*
* These are the prototypes for the functions in the dispatch table, as
* well as the dispatch table itself.
*/
extern int load_aout_binary(struct linux_binprm *,
struct pt_regs * regs);
extern int load_aout_library(int fd);
#ifdef CONFIG_BINFMT_ELF
extern int load_elf_binary(struct linux_binprm *,
struct pt_regs * regs);
extern int load_elf_library(int fd);
#endif
#ifdef CONFIG_BINFMT_COFF
extern int load_coff_binary(struct linux_binprm *,
struct pt_regs * regs);
extern int load_coff_library(int fd);
#endif
/* Here are the actual binaries that will be accepted */
struct linux_binfmt formats[] = {
{load_aout_binary, load_aout_library},
#ifdef CONFIG_BINFMT_ELF
{load_elf_binary, load_elf_library},
#endif
#ifdef CONFIG_BINFMT_COFF
{load_coff_binary, load_coff_library},
#endif
{NULL, NULL}
};
static void set_brk(unsigned long start, unsigned long end)
{
start = PAGE_ALIGN(start);
......@@ -770,7 +778,7 @@ static void set_brk(unsigned long start, unsigned long end)
* libraries. There is no binary dependent code anywhere else.
*/
int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
struct exec ex;
struct file * file;
......@@ -868,7 +876,7 @@ int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
}
int load_aout_library(int fd)
static int load_aout_library(int fd)
{
struct file * file;
struct exec ex;
......
......@@ -280,6 +280,8 @@ static int proc_readnet(struct inode * inode, struct file * file,
* the start pointer and we know the length..
*/
if (length <= 0)
break;
/*
* Copy the bytes
*/
......
......@@ -3,6 +3,11 @@
*
* Created for Linux based loosely upon Mathius Lattner's minix
* patches by Peter MacDonald. Heavily edited by Linus.
*
* 4 February 1994
* COFF/ELF binary emulation. If the process has the STICKY_TIMEOUTS
* flag set in its personality we do *not* modify the given timeout
* parameter to reflect time remaining.
*/
#include <linux/types.h>
......@@ -14,6 +19,7 @@
#include <linux/stat.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/personality.h>
#include <asm/segment.h>
#include <asm/system.h>
......@@ -235,7 +241,7 @@ asmlinkage int sys_select( unsigned long *buffer )
else
timeout = 0;
current->timeout = 0;
if (tvp) {
if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
timeout %= HZ;
timeout *= (1000000/HZ);
......
/*
* These are the functions used to load COFF IBSC style executables.
* Information on COFF format may be obtained in either the Intel Binary
* Compatibility Specification 2 or O'Rilley's book on COFF. The shared
* libraries are defined only the in the Intel book.
*
* This file is based upon code written by Eric Youndale for the ELF object
* file format.
*
* Author: Al Longyear (longyear@sii.com)
*
* Latest Revision:
* 3 Feburary 1994
* Al Longyear (longyear@sii.com)
* Cleared first page of bss section using put_fs_byte.
*/
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/a.out.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/binfmts.h>
#include <asm/segment.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/coff.h>
#include <linux/malloc.h>
asmlinkage int sys_exit (int exit_code);
asmlinkage int sys_close (unsigned fd);
asmlinkage int sys_open (const char *, int, int);
asmlinkage int sys_uselib(const char * library);
static int preload_library (struct linux_binprm *exe_bprm,
COFF_SCNHDR * sect,
struct file *fp);
static int load_object (struct linux_binprm *bprm,
struct pt_regs *regs,
int lib_ok);
/*
* Small procedure to test for the proper file alignment.
*/
static inline int
is_properly_aligned (COFF_SCNHDR *sect)
{
long scnptr = COFF_LONG (sect->s_scnptr);
long vaddr = COFF_LONG (sect->s_vaddr);
/*
* Print the section information if needed
*/
#ifdef COFF_DEBUG
printk ("%s, scnptr = %d, vaddr = %d\n",
sect->s_name,
scnptr, vaddr);
#endif
/*
* Return the error code if the section is not properly aligned.
*/
#ifdef COFF_DEBUG
if (((vaddr - scnptr) & ~PAGE_MASK) != 0)
printk ("bad alignment in %s\n", sect->s_name);
#endif
return ((((vaddr - scnptr) & ~PAGE_MASK) != 0) ? -ENOEXEC : 0);
}
/*
* Clear the bytes in the last page of data.
*/
static
int clear_memory (unsigned long addr, unsigned long size)
{
int status;
size = (PAGE_SIZE - (addr & ~PAGE_MASK)) & ~PAGE_MASK;
if (size == 0)
status = 0;
else {
#ifdef COFF_DEBUG
printk ("un-initialized storage in last page %d\n", size);
#endif
status = verify_area (VERIFY_WRITE,
(void *) addr, size);
#ifdef COFF_DEBUG
printk ("result from verify_area = %d\n", status);
#endif
if (status >= 0)
while (size-- != 0)
put_fs_byte (0, addr++);
}
return status;
}
/*
* Helper function to process the load operation.
*/
static int
load_object (struct linux_binprm * bprm, struct pt_regs *regs, int lib_ok)
{
COFF_FILHDR *coff_hdr = (COFF_FILHDR *) bprm->buf; /* COFF Header */
COFF_SCNHDR *sect_bufr; /* Pointer to section table */
COFF_SCNHDR *text_sect; /* Pointer to the text section */
COFF_SCNHDR *data_sect; /* Pointer to the data section */
COFF_SCNHDR *bss_sect; /* Pointer to the bss section */
int text_count; /* Number of text sections */
int data_count; /* Number of data sections */
int bss_count; /* Number of bss sections */
int lib_count; /* Number of lib sections */
unsigned int start_addr = 0;/* Starting location for program */
int status = 0; /* Result status register */
int fd = -1; /* Open file descriptor */
struct file *fp = NULL; /* Pointer to the file at "fd" */
short int sections = 0; /* Number of sections in the file */
short int aout_size = 0; /* Size of the a.out header area */
short int flags; /* Flag bits from the COFF header */
#ifdef COFF_DEBUG
printk ("binfmt_coff entry: %s\n", bprm->filename);
#endif
/*
* Validate the magic value for the object file.
*/
do {
if (COFF_I386BADMAG (*coff_hdr)) {
#ifdef COFF_DEBUG
printk ("bad filehdr magic\n");
#endif
status = -ENOEXEC;
break;
}
/*
* The object file should have 32 BIT little endian format. Do not allow
* it to have the 16 bit object file flag set as Linux is not able to run
* on the 80286/80186/8086.
*/
flags = COFF_SHORT (coff_hdr->f_flags);
if ((flags & (COFF_F_AR32WR | COFF_F_AR16WR)) != COFF_F_AR32WR) {
#ifdef COFF_DEBUG
printk ("invalid f_flags bits\n");
#endif
status = -ENOEXEC;
break;
}
/*
* Extract the header information which we need.
*/
sections = COFF_SHORT (coff_hdr->f_nscns); /* Number of sections */
aout_size = COFF_SHORT (coff_hdr->f_opthdr); /* Size of opt. headr */
/*
* If the file is not executable then reject the exectution. This means
* that there must not be external references.
*/
if ((flags & COFF_F_EXEC) == 0) {
#ifdef COFF_DEBUG
printk ("not executable bit\n");
#endif
status = -ENOEXEC;
break;
}
/*
* There must be atleast one section.
*/
if (sections == 0) {
#ifdef COFF_DEBUG
printk ("no sections\n");
#endif
status = -ENOEXEC;
break;
}
/*
* Do some additional consistency checks.
* The system requires mapping for this loader. If you try
* to use a file system with no mapping, the format is not valid.
*/
if (!bprm->inode->i_op ||
!bprm->inode->i_op->default_file_ops->mmap) {
#ifdef COFF_DEBUG
printk ("no mmap in fs\n");
#endif
status = -ENOEXEC;
}
}
while (0);
/*
* Allocate a buffer to hold the entire coff section list.
*/
if (status >= 0) {
int nbytes = sections * COFF_SCNHSZ;
sect_bufr = (COFF_SCNHDR *) kmalloc (nbytes, GFP_KERNEL);
if (0 == sect_bufr) {
#ifdef COFF_DEBUG
printk ("kmalloc failed\n");
#endif
status = -ENOEXEC;
}
/*
* Read the section list from the disk file.
*/
else {
int old_fs = get_fs ();
set_fs (get_ds ()); /* Make it point to the proper location */
status = read_exec (bprm->inode, /* INODE for file */
aout_size + COFF_FILHSZ, /* Offset in the file */
(char *) sect_bufr, /* Buffer for read */
nbytes); /* Byte count reqd. */
set_fs (old_fs); /* Restore the selector */
#ifdef COFF_DEBUG
if (status < 0)
printk ("read aout hdr, status = %d\n", status);
#endif
}
}
else
sect_bufr = NULL; /* Errors do not have a section buffer */
/*
* Count the number of sections for the required types and store the location
* of the last section for the three primary types.
*/
text_count = 0;
data_count = 0;
bss_count = 0;
lib_count = 0;
text_sect = NULL;
data_sect = NULL;
bss_sect = NULL;
/*
* Loop through the sections and find the various types
*/
if (status >= 0) {
int nIndex;
COFF_SCNHDR *sect_ptr = sect_bufr;
for (nIndex = 0; nIndex < sections; ++nIndex) {
long int sect_flags = COFF_LONG (sect_ptr->s_flags);
switch (sect_flags) {
case COFF_STYP_TEXT:
text_sect = sect_ptr;
++text_count;
status = is_properly_aligned (sect_ptr);
break;
case COFF_STYP_DATA:
data_sect = sect_ptr;
++data_count;
status = is_properly_aligned (sect_ptr);
break;
case COFF_STYP_BSS:
bss_sect = sect_ptr;
++bss_count;
break;
case COFF_STYP_LIB:
#ifdef COFF_DEBUG
printk (".lib section found\n");
#endif
++lib_count;
break;
default:
break;
}
sect_ptr = (COFF_SCNHDR *) & ((char *) sect_ptr)[COFF_SCNHSZ];
}
/*
* Ensure that there are the required sections. There must be one text
* sections and one each of the data and bss sections for an executable.
* A library may or may not have a data / bss section.
*/
if (text_count != 1) {
status = -ENOEXEC;
#ifdef COFF_DEBUG
printk ("no text sections\n");
#endif
}
else {
if (lib_ok) {
if (data_count != 1 || bss_count != 1) {
status = -ENOEXEC;
#ifdef COFF_DEBUG
printk ("no .data nor .bss sections\n");
#endif
}
}
}
}
/*
* If there is no additional header then assume the file starts at
* the first byte of the text section. This may not be the proper place,
* so the best solution is to include the optional header. A shared library
* __MUST__ have an optional header to indicate that it is a shared library.
*/
if (status >= 0) {
if (aout_size == 0) {
if (!lib_ok) {
status = -ENOEXEC;
#ifdef COFF_DEBUG
printk ("no header in library\n");
#endif
}
start_addr = COFF_LONG (text_sect->s_vaddr);
}
/*
* There is some header. Ensure that it is sufficient.
*/
else {
if (aout_size < COFF_AOUTSZ) {
status = -ENOEXEC;
#ifdef COFF_DEBUG
printk ("header too small\n");
#endif
}
else {
COFF_AOUTHDR *aout_hdr = /* Pointer to a.out header */
(COFF_AOUTHDR *) & ((char *) coff_hdr)[COFF_FILHSZ];
short int aout_magic = COFF_SHORT (aout_hdr->magic); /* id */
/*
* Validate the magic number in the a.out header. If it is valid then
* update the starting symbol location. Do not accept these file formats
* when loading a shared library.
*/
switch (aout_magic) {
case COFF_OMAGIC:
case COFF_ZMAGIC:
case COFF_STMAGIC:
if (!lib_ok) {
status = -ENOEXEC;
#ifdef COFF_DEBUG
printk ("wrong a.out header magic\n");
#endif
}
start_addr = (unsigned int) COFF_LONG (aout_hdr->entry);
break;
/*
* Magic value for a shared library. This is valid only when loading a
* shared library. (There is no need for a start_addr. It won't be used.)
*/
case COFF_SHMAGIC:
if (lib_ok) {
#ifdef COFF_DEBUG
printk ("wrong a.out header magic\n");
#endif
status = -ENOEXEC;
}
break;
default:
#ifdef COFF_DEBUG
printk ("wrong a.out header magic\n");
#endif
status = -ENOEXEC;
break;
}
}
}
}
/*
* Fetch a file pointer to the executable.
*/
if (status >= 0) {
fd = open_inode (bprm->inode, O_RDONLY);
if (fd < 0) {
#ifdef COFF_DEBUG
printk ("can not open inode, result = %d\n", fd);
#endif
status = fd;
}
else
fp = current->files->fd[fd];
}
else
fd = -1; /* Invalidate the open file descriptor */
/*
* Generate the proper values for the text fields
*
* THIS IS THE POINT OF NO RETURN. THE NEW PROCESS WILL TRAP OUT SHOULD
* SOMETHING FAIL IN THE LOAD SEQUENCE FROM THIS POINT ONWARD.
*/
if (status >= 0) {
long text_scnptr = COFF_LONG (text_sect->s_scnptr);
long text_size = COFF_LONG (text_sect->s_size);
long text_vaddr = COFF_LONG (text_sect->s_vaddr);
long data_scnptr;
long data_size;
long data_vaddr;
long bss_size;
long bss_vaddr;
/*
* Generate the proper values for the data fields
*/
if (data_sect != NULL) {
data_scnptr = COFF_LONG (data_sect->s_scnptr);
data_size = COFF_LONG (data_sect->s_size);
data_vaddr = COFF_LONG (data_sect->s_vaddr);
}
else {
data_scnptr = 0;
data_size = 0;
data_vaddr = 0;
}
/*
* Generate the proper values for the bss fields
*/
if (bss_sect != NULL) {
bss_size = COFF_LONG (bss_sect->s_size);
bss_vaddr = COFF_LONG (bss_sect->s_vaddr);
}
else {
bss_size = 0;
bss_vaddr = 0;
}
/*
* Flush the executable from memory. At this point the executable is
* committed to being defined or a segmentation violation will occur.
*/
if (lib_ok) {
#ifdef COFF_DEBUG
printk ("flushing executable\n");
#endif
flush_old_exec (bprm);
/*
* Define the initial locations for the various items in the new process
*/
current->mm->mmap = NULL;
current->mm->rss = 0;
/*
* Construct the parameter and environment string table entries.
*/
bprm->p += change_ldt (0, bprm->page);
bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
bprm->p = (unsigned long) create_tables ((char *) bprm->p,
bprm->argc,
bprm->envc,
1);
/*
* Do the end processing once the stack has been constructed
*/
current->mm->start_code = text_vaddr & PAGE_MASK;
current->mm->end_code = text_vaddr + text_size;
current->mm->end_data = data_vaddr + data_size;
current->mm->start_brk =
current->mm->brk = bss_vaddr + bss_size;
current->suid =
current->euid = bprm->e_uid;
current->sgid =
current->egid = bprm->e_gid;
current->executable = bprm->inode; /* Store inode for file */
++bprm->inode->i_count; /* Count the open inode */
regs->eip = start_addr; /* Current EIP register */
regs->esp =
current->mm->start_stack = bprm->p;
}
/*
* Map the text pages
*/
#ifdef COFF_DEBUG
printk (".text: vaddr = %d, size = %d, scnptr = %d\n",
text_vaddr,
text_size,
text_scnptr);
#endif
status = do_mmap (fp,
text_vaddr & PAGE_MASK,
text_size + (text_vaddr & ~PAGE_MASK),
PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_SHARED,
text_scnptr & PAGE_MASK);
status = (status == (text_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC;
/*
* Map the data pages
*/
if (status >= 0 && data_size != 0) {
#ifdef COFF_DEBUG
printk (".data: vaddr = %d, size = %d, scnptr = %d\n",
data_vaddr,
data_size,
data_scnptr);
#endif
status = do_mmap (fp,
data_vaddr & PAGE_MASK,
data_size + (data_vaddr & ~PAGE_MASK),
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE,
data_scnptr & PAGE_MASK);
status = (status == (data_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC;
}
/*
* Construct the bss data for the process. The bss ranges from the
* end of the data (which may not be on a page boundry) to the end
* of the bss section. Allocate any necessary pages for the data.
*/
if (status >= 0 && bss_size != 0) {
#ifdef COFF_DEBUG
printk (".bss: vaddr = %d, size = %d\n",
bss_vaddr,
bss_size);
#endif
zeromap_page_range (PAGE_ALIGN (bss_vaddr),
PAGE_ALIGN (bss_size),
PAGE_COPY);
status = clear_memory (bss_vaddr, bss_size);
}
/*
* Load any shared library for the executable.
*/
if (status >= 0 && lib_ok && lib_count != 0) {
int nIndex;
COFF_SCNHDR *sect_ptr = sect_bufr;
/*
* Find the library sections. (There should be atleast one. It was counted
* earlier.) This will evenutally recurse to our code and load the shared
* library with our own procedures.
*/
for (nIndex = 0; nIndex < sections; ++nIndex) {
long int sect_flags = COFF_LONG (sect_ptr->s_flags);
if (sect_flags == COFF_STYP_LIB) {
status = preload_library (bprm, sect_ptr, fp);
if (status != 0)
break;
}
sect_ptr = (COFF_SCNHDR *) &((char *) sect_ptr) [COFF_SCNHSZ];
}
}
/*
* Generate any needed trap for this process. If an error occured then
* generate a segmentation violation. If the process is being debugged
* then generate the load trap. (Note: If this is a library load then
* do not generate the trap here. Pass the error to the caller who
* will do it for the process in the outer lay of this procedure call.)
*/
if (lib_ok) {
if (status < 0)
send_sig (SIGSEGV, current, 0); /* Generate the error trap */
else {
if (current->flags & PF_PTRACED)
send_sig (SIGTRAP, current, 0);
}
status = 0; /* We are committed. It can't fail */
}
}
/*
* Do any cleanup processing
*/
if (fd >= 0)
sys_close (fd); /* Close unused code file */
if (sect_bufr != NULL)
kfree (sect_bufr); /* Release section list buffer */
/*
* Return the completion status.
*/
#ifdef COFF_DEBUG
printk ("binfmt_coff: result = %d\n", status);
#endif
return (status);
}
/*
* This procedure will load the library listed in the file name given
* as the paramter. The result will be non-zero should something fail
* to load.
*/
static int
preload_this_library (struct linux_binprm *exe_bprm, char *lib_name)
{
int status;
int old_fs = get_fs();
/*
* If debugging then print "we have arrived"
*/
#ifdef COFF_DEBUG
printk ("%s loading shared library %s\n",
exe_bprm->filename,
lib_name);
#endif
/*
* Change the FS register to the proper kernel address space and attempt
* to load the library. The library name is allocated from the kernel
* pool.
*/
set_fs (get_ds ());
status = sys_uselib (lib_name);
set_fs (old_fs);
/*
* Return the success/failure to the caller.
*/
return (status);
}
/*
* This procedure is called to load a library section. The various
* libraries are loaded from the list given in the section data.
*/
static int
preload_library (struct linux_binprm *exe_bprm,
COFF_SCNHDR * sect, struct file *fp)
{
int status = 0; /* Completion status */
long nbytes; /* Count of bytes in the header area */
/*
* Fetch the size of the section. There must be enough room for atleast
* one entry.
*/
nbytes = COFF_LONG (sect->s_size);
if (nbytes < COFF_SLIBSZ) {
status = -ENOEXEC;
#ifdef COFF_DEBUG
printk ("library section too small\n");
#endif
}
/*
* Allocate a buffer to hold the section data
*/
else {
COFF_SLIBHD *phdr;
char *buffer = (char *) kmalloc (nbytes, GFP_KERNEL);
if (0 == buffer) {
status = -ENOEXEC;
#ifdef COFF_DEBUG
printk ("kmalloc failed\n");
#endif
}
else {
int old_fs = get_fs ();
/*
* Read the section data from the disk file.
*/
set_fs (get_ds ()); /* Make it point to the proper location */
status = read_exec (exe_bprm->inode, /* INODE for file */
COFF_LONG (sect->s_scnptr), /* Disk location */
buffer, /* Buffer for read */
nbytes); /* Byte count reqd. */
set_fs (old_fs); /* Restore the selector */
/*
* Check the result. The value returned is the byte count actaully read.
*/
if (status >= 0 && status != nbytes) {
#ifdef COFF_DEBUG
printk ("read of lib section was short\n");
#endif
status = -ENOEXEC;
}
}
/*
* At this point, go through the list of libraries in the data area.
*/
phdr = (COFF_SLIBHD *) buffer;
while (status >= 0 && nbytes > COFF_SLIBSZ) {
int entry_size = COFF_LONG (phdr->sl_entsz) * sizeof (long);
int header_size = COFF_LONG (phdr->sl_pathndx) * sizeof (long);
/*
* Validate the sizes of the various items. I don't trust the linker!!
*/
if ((unsigned) header_size >= (unsigned) nbytes ||
entry_size <= 0 ||
(unsigned) entry_size <= (unsigned) header_size) {
status = -ENOEXEC;
#ifdef COFF_DEBUG
printk ("header count is invalid\n");
#endif
}
/*
* Load the library. Stop the load process on the first error.
*/
else {
status = preload_this_library (exe_bprm,
&((char *) phdr)[header_size]);
#ifdef COFF_DEBUG
printk ("preload_this_library result = %d\n", status);
#endif
}
/*
* Point to the next library in the section data.
*/
nbytes -= entry_size;
phdr = (COFF_SLIBHD *) &((char *) phdr)[entry_size];
}
/*
* Release the space for the library list.
*/
if (buffer != NULL)
kfree (buffer);
}
/*
* Return the resulting status to the caller.
*/
return (status);
}
/*
* This procedure is called by the main load sequence. It will load
* the executable and prepare it for execution. It provides the additional
* parameters used by the recursive coff loader and tells the loader that
* this is the main executable. How simple it is . . . .
*/
int
load_coff_binary (struct linux_binprm *bprm, struct pt_regs *regs)
{
return (load_object (bprm, regs, 1));
}
/*
* Load the image for any shared library.
*
* This is called when we need to load a library based upon a file name.
*/
int
load_coff_library (int fd)
{
struct linux_binprm *bprm; /* Parameters for the load operation */
int status; /* Status of the request */
/*
* Read the first portion of the file.
*/
bprm = (struct linux_binprm *) kmalloc (sizeof (struct linux_binprm),
GFP_KERNEL);
if (0 == bprm) {
#ifdef COFF_DEBUG
printk ("kmalloc failed\n");
#endif
status = -ENOEXEC;
}
else {
struct file *file; /* Pointer to the file table */
struct pt_regs regs; /* Register work area */
int old_fs = get_fs (); /* Previous FS register value */
memset (bprm, '\0', sizeof (struct linux_binprm));
file = current->files->fd[fd];
bprm->inode = file->f_inode; /* The only item _really_ needed */
bprm->filename = ""; /* Make it a legal string */
/*
* Read the section list from the disk file.
*/
set_fs (get_ds ()); /* Make it point to the proper location */
status = read_exec (bprm->inode, /* INODE for file */
0L, /* Offset in the file */
bprm->buf, /* Buffer for read */
sizeof (bprm->buf)); /* Size of the buffer */
set_fs (old_fs); /* Restore the selector */
/*
* Try to load the library.
*/
status = load_object (bprm, &regs, 0);
/*
* Release the work buffer and return the result.
*/
kfree (bprm); /* Release the buffer area */
}
/*
* Return the result of the load operation
*/
return (status);
}
/*
* linux/fs/binfmt_elf.c
*/
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/a.out.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/binfmts.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/malloc.h>
#include <linux/shm.h>
#include <asm/segment.h>
asmlinkage int sys_exit(int exit_code);
asmlinkage int sys_close(unsigned fd);
asmlinkage int sys_open(const char *, int, int);
asmlinkage int sys_brk(unsigned long);
#define DLINFO_ITEMS 8
#include <linux/elf.h>
/* 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 void padzero(int elf_bss){
unsigned int fpnt, nbyte;
if(elf_bss & 0xfff) {
nbyte = (PAGE_SIZE - (elf_bss & 0xfff)) & 0xfff;
if(nbyte){
verify_area(VERIFY_WRITE, (void *) elf_bss, nbyte);
fpnt = elf_bss;
while(fpnt & 0xfff) put_fs_byte(0, fpnt++);
};
};
}
unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, int ibcs)
{
unsigned long *argv,*envp, *dlinfo;
unsigned long * sp;
struct vm_area_struct *mpnt;
mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
if (mpnt) {
mpnt->vm_task = current;
mpnt->vm_start = PAGE_MASK & (unsigned long) p;
mpnt->vm_end = TASK_SIZE;
mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
mpnt->vm_share = NULL;
mpnt->vm_inode = NULL;
mpnt->vm_offset = 0;
mpnt->vm_ops = NULL;
insert_vm_struct(current, mpnt);
current->mm->stk_vma = mpnt;
}
sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
if(exec) sp -= DLINFO_ITEMS*2;
dlinfo = sp;
sp -= envc+1;
envp = sp;
sp -= argc+1;
argv = sp;
if (!ibcs) {
put_fs_long((unsigned long)envp,--sp);
put_fs_long((unsigned long)argv,--sp);
}
/* The constant numbers (0-9) that we are writing here are
described in the header file sys/auxv.h on at least
some versions of SVr4 */
if(exec) { /* Put this here for an ELF program interpreter */
struct elf_phdr * eppnt;
eppnt = (struct elf_phdr *) exec->e_phoff;
put_fs_long(3,dlinfo++); put_fs_long(load_addr + exec->e_phoff,dlinfo++);
put_fs_long(4,dlinfo++); put_fs_long(sizeof(struct elf_phdr),dlinfo++);
put_fs_long(5,dlinfo++); put_fs_long(exec->e_phnum,dlinfo++);
put_fs_long(9,dlinfo++); put_fs_long((unsigned long) exec->e_entry,dlinfo++);
put_fs_long(7,dlinfo++); put_fs_long(SHM_RANGE_START,dlinfo++);
put_fs_long(8,dlinfo++); put_fs_long(0,dlinfo++);
put_fs_long(6,dlinfo++); put_fs_long(PAGE_SIZE,dlinfo++);
put_fs_long(0,dlinfo++); put_fs_long(0,dlinfo++);
};
put_fs_long((unsigned long)argc,--sp);
current->mm->arg_start = (unsigned long) p;
while (argc-->0) {
put_fs_long((unsigned long) p,argv++);
while (get_fs_byte(p++)) /* nothing */ ;
}
put_fs_long(0,argv);
current->mm->arg_end = current->mm->env_start = (unsigned long) p;
while (envc-->0) {
put_fs_long((unsigned long) p,envp++);
while (get_fs_byte(p++)) /* nothing */ ;
}
put_fs_long(0,envp);
current->mm->env_end = (unsigned long) p;
return sp;
}
/* This is much more generalized than the library routine read function,
so we keep this separate. Techincally the library read function
is only provided so that we can read a.out libraries that have
an ELF header */
static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
struct inode * interpreter_inode)
{
struct file * file;
struct elf_phdr *elf_phdata = NULL;
struct elf_phdr *eppnt;
unsigned int len;
unsigned int load_addr;
int elf_exec_fileno;
int elf_bss;
int old_fs, retval;
unsigned int last_bss;
int error;
int i, k;
elf_bss = 0;
last_bss = 0;
error = load_addr = 0;
/* First of all, some simple consistency checks */
if((interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN) ||
(interp_elf_ex->e_machine != EM_386 && interp_elf_ex->e_machine != EM_486) ||
(!interpreter_inode->i_op || !interpreter_inode->i_op->bmap ||
!interpreter_inode->i_op->default_file_ops->mmap)){
return 0xffffffff;
};
/* Now read in all of the header information */
if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
return 0xffffffff;
elf_phdata = (struct elf_phdr *)
kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL);
if(!elf_phdata) return 0xffffffff;
old_fs = get_fs();
set_fs(get_ds());
retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata,
sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
set_fs(old_fs);
elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
if (elf_exec_fileno < 0) return 0xffffffff;
file = current->files->fd[elf_exec_fileno];
eppnt = elf_phdata;
for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
if(eppnt->p_type == PT_LOAD) {
error = do_mmap(file,
eppnt->p_vaddr & 0xfffff000,
eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | (interp_elf_ex->e_type == ET_EXEC ? MAP_FIXED : 0),
eppnt->p_offset & 0xfffff000);
if(!load_addr && interp_elf_ex->e_type == ET_DYN)
load_addr = error;
k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
if(k > elf_bss) elf_bss = k;
if(error < 0 && error > -1024) break; /* Real error */
k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
if(k > last_bss) last_bss = k;
}
/* Now use mmap to map the library into memory. */
sys_close(elf_exec_fileno);
if(error < 0 && error > -1024) {
kfree(elf_phdata);
return 0xffffffff;
}
padzero(elf_bss);
len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */
/* Map the last of the bss segment */
if (last_bss > len)
do_mmap(NULL, len, last_bss-len,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
kfree(elf_phdata);
return ((unsigned int) interp_elf_ex->e_entry) + load_addr;
}
static unsigned int load_aout_interp(struct exec * interp_ex,
struct inode * interpreter_inode)
{
int retval;
unsigned int elf_entry;
current->mm->brk = interp_ex->a_bss +
(current->mm->end_data = interp_ex->a_data +
(current->mm->end_code = interp_ex->a_text));
elf_entry = interp_ex->a_entry;
if (N_MAGIC(*interp_ex) == OMAGIC) {
do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
retval = read_exec(interpreter_inode, 32, (char *) 0,
interp_ex->a_text+interp_ex->a_data);
} else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
retval = read_exec(interpreter_inode,
N_TXTOFF(*interp_ex) ,
(char *) N_TXTADDR(*interp_ex),
interp_ex->a_text+interp_ex->a_data);
} else
retval = -1;
if(retval >= 0)
do_mmap(NULL, (interp_ex->a_text + interp_ex->a_data + 0xfff) &
0xfffff000, interp_ex->a_bss,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
if(retval < 0) return 0xffffffff;
return elf_entry;
}
/*
* These are the functions used to load ELF style executables and shared
* libraries. There is no binary dependent code anywhere else.
*/
#define INTERPRETER_NONE 0
#define INTERPRETER_AOUT 1
#define INTERPRETER_ELF 2
int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex;
struct file * file;
struct exec interp_ex;
struct inode *interpreter_inode;
unsigned int load_addr;
unsigned int interpreter_type = INTERPRETER_NONE;
int i;
int old_fs;
int error;
struct elf_phdr * elf_ppnt, *elf_phdata;
int elf_exec_fileno;
unsigned int elf_bss, k, elf_brk;
int retval;
char * elf_interpreter;
unsigned int elf_entry;
int status;
unsigned int start_code, end_code, end_data;
unsigned int elf_stack;
char passed_fileno[6];
status = 0;
load_addr = 0;
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
if (elf_ex.e_ident[0] != 0x7f ||
strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
return -ENOEXEC;
/* First of all, some simple consistency checks */
if(elf_ex.e_type != ET_EXEC ||
(elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
(!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
!bprm->inode->i_op->default_file_ops->mmap)){
return -ENOEXEC;
};
/* Now read in all of the header information */
elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
elf_ex.e_phnum, GFP_KERNEL);
old_fs = get_fs();
set_fs(get_ds());
retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
elf_ex.e_phentsize * elf_ex.e_phnum);
set_fs(old_fs);
if (retval < 0) {
kfree (elf_phdata);
return retval;
}
elf_ppnt = elf_phdata;
elf_bss = 0;
elf_brk = 0;
elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
if (elf_exec_fileno < 0) {
kfree (elf_phdata);
return elf_exec_fileno;
}
file = current->files->fd[elf_exec_fileno];
elf_stack = 0xffffffff;
elf_interpreter = NULL;
start_code = 0;
end_code = 0;
end_data = 0;
old_fs = get_fs();
set_fs(get_ds());
for(i=0;i < elf_ex.e_phnum; i++){
if(elf_ppnt->p_type == PT_INTERP) {
/* This is the program interpreter used for shared libraries -
for now assume that this is an a.out format binary */
elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
GFP_KERNEL);
retval = read_exec(bprm->inode,elf_ppnt->p_offset,elf_interpreter,
elf_ppnt->p_filesz);
#if 0
printk("Using ELF interpreter %s\n", elf_interpreter);
#endif
if(retval >= 0)
retval = namei(elf_interpreter, &interpreter_inode);
if(retval >= 0)
retval = read_exec(interpreter_inode,0,bprm->buf,128);
if(retval >= 0){
interp_ex = *((struct exec *) bprm->buf); /* exec-header */
interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
};
if(retval < 0) {
kfree (elf_phdata);
kfree(elf_interpreter);
return retval;
};
};
elf_ppnt++;
};
set_fs(old_fs);
/* Some simple consistency checks for the interpreter */
if(elf_interpreter){
interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
if(retval < 0) {
kfree(elf_interpreter);
kfree(elf_phdata);
return -ELIBACC;
};
/* Now figure out which format our binary is */
if((N_MAGIC(interp_ex) != OMAGIC) &&
(N_MAGIC(interp_ex) != ZMAGIC) &&
(N_MAGIC(interp_ex) != QMAGIC))
interpreter_type = INTERPRETER_ELF;
if (interp_elf_ex.e_ident[0] != 0x7f ||
strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
interpreter_type &= ~INTERPRETER_ELF;
if(!interpreter_type)
{
kfree(elf_interpreter);
kfree(elf_phdata);
return -ELIBBAD;
};
}
/* OK, we are done with that, now set up the arg stuff,
and then start this sucker up */
if (!bprm->sh_bang) {
char * passed_p;
if(interpreter_type == INTERPRETER_AOUT) {
sprintf(passed_fileno, "%d", elf_exec_fileno);
passed_p = passed_fileno;
if(elf_interpreter) {
bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
bprm->argc++;
};
};
if (!bprm->p) {
if(elf_interpreter) {
kfree(elf_interpreter);
}
kfree (elf_phdata);
return -E2BIG;
}
}
/* OK, This is the point of no return */
flush_old_exec(bprm);
current->mm->end_data = 0;
current->mm->end_code = 0;
current->mm->start_mmap = ELF_START_MMAP;
current->mm->mmap = NULL;
elf_entry = (unsigned int) elf_ex.e_entry;
/* Do this so that we can load the interpreter, if need be. We will
change some of these later */
current->mm->rss = 0;
bprm->p += change_ldt(0, bprm->page);
current->mm->start_stack = bprm->p;
/* Now we do a little grungy work by mmaping the ELF image into
the correct location in memory. At this point, we assume that
the image should be loaded at fixed address, not at a variable
address. */
old_fs = get_fs();
set_fs(get_ds());
elf_ppnt = elf_phdata;
for(i=0;i < elf_ex.e_phnum; i++){
if(elf_ppnt->p_type == PT_INTERP) {
/* Set these up so that we are able to load the interpreter */
/* Now load the interpreter into user address space */
set_fs(old_fs);
if(interpreter_type & 1) elf_entry =
load_aout_interp(&interp_ex, interpreter_inode);
if(interpreter_type & 2) elf_entry =
load_elf_interp(&interp_elf_ex, interpreter_inode);
old_fs = get_fs();
set_fs(get_ds());
iput(interpreter_inode);
kfree(elf_interpreter);
if(elf_entry == 0xffffffff) {
printk("Unable to load interpreter\n");
kfree(elf_phdata);
send_sig(SIGSEGV, current, 0);
return 0;
};
};
if(elf_ppnt->p_type == PT_LOAD) {
error = do_mmap(file,
elf_ppnt->p_vaddr & 0xfffff000,
elf_ppnt->p_filesz + (elf_ppnt->p_vaddr & 0xfff),
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE,
elf_ppnt->p_offset & 0xfffff000);
#ifdef LOW_ELF_STACK
if(elf_ppnt->p_vaddr & 0xfffff000 < elf_stack)
elf_stack = elf_ppnt->p_vaddr & 0xfffff000;
#endif
if(!load_addr)
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
k = elf_ppnt->p_vaddr;
if(k > start_code) start_code = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
if(k > elf_bss) elf_bss = k;
if((elf_ppnt->p_flags | PROT_WRITE) && end_code < k)
end_code = k;
if(end_data < k) end_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
if(k > elf_brk) elf_brk = k;
};
elf_ppnt++;
};
set_fs(old_fs);
kfree(elf_phdata);
if(!elf_interpreter) sys_close(elf_exec_fileno);
current->elf_executable = 1;
current->executable = bprm->inode;
bprm->inode->i_count++;
#ifdef LOW_ELF_STACK
current->start_stack = p = elf_stack - 4;
#endif
bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
bprm->p = (unsigned long)
create_elf_tables((char *)bprm->p,
bprm->argc,
bprm->envc,
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
load_addr,
(interpreter_type == INTERPRETER_AOUT ? 0 : 1));
if(interpreter_type == INTERPRETER_AOUT)
current->mm->arg_start += strlen(passed_fileno) + 1;
current->mm->start_brk = current->mm->brk = elf_brk;
current->mm->end_code = end_code;
current->mm->start_code = start_code;
current->mm->end_data = end_data;
current->mm->start_stack = bprm->p;
current->suid = current->euid = bprm->e_uid;
current->sgid = current->egid = bprm->e_gid;
/* Calling sys_brk effectively mmaps the pages that we need for the bss and break
sections */
current->mm->brk = (elf_bss + 0xfff) & 0xfffff000;
sys_brk((elf_brk + 0xfff) & 0xfffff000);
padzero(elf_bss);
/* Why this, you ask??? Well SVr4 maps page 0 as read-only,
and some applications "depend" upon this behavior.
Since we do not have the power to recompile these, we
emulate the SVr4 behavior. Sigh. */
error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE, 0);
regs->eip = elf_entry; /* eip, magic happens :-) */
regs->esp = bprm->p; /* stack pointer */
if (current->flags & PF_PTRACED)
send_sig(SIGTRAP, current, 0);
return 0;
}
/* This is really simpleminded and specialized - we are loading an
a.out library that is given an ELF header. */
int load_elf_library(int fd){
struct file * file;
struct elfhdr elf_ex;
struct elf_phdr *elf_phdata = NULL;
struct inode * inode;
unsigned int len;
int elf_bss;
int old_fs, retval;
unsigned int bss;
int error;
int i,j, k;
len = 0;
file = current->files->fd[fd];
inode = file->f_inode;
elf_bss = 0;
set_fs(KERNEL_DS);
if (file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex)) != sizeof(elf_ex)) {
sys_close(fd);
return -EACCES;
}
set_fs(USER_DS);
if (elf_ex.e_ident[0] != 0x7f ||
strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
return -ENOEXEC;
/* First of all, some simple consistency checks */
if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
(elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
(!inode->i_op || !inode->i_op->bmap ||
!inode->i_op->default_file_ops->mmap)){
return -ENOEXEC;
};
/* Now read in all of the header information */
if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
return -ENOEXEC;
elf_phdata = (struct elf_phdr *)
kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
old_fs = get_fs();
set_fs(get_ds());
retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
sizeof(struct elf_phdr) * elf_ex.e_phnum);
set_fs(old_fs);
j = 0;
for(i=0; i<elf_ex.e_phnum; i++)
if((elf_phdata + i)->p_type == PT_LOAD) j++;
if(j != 1) {
kfree(elf_phdata);
return -ENOEXEC;
};
while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
/* Now use mmap to map the library into memory. */
error = do_mmap(file,
elf_phdata->p_vaddr & 0xfffff000,
elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff),
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE,
elf_phdata->p_offset & 0xfffff000);
k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
if(k > elf_bss) elf_bss = k;
sys_close(fd);
if (error != elf_phdata->p_vaddr & 0xfffff000) {
kfree(elf_phdata);
return error;
}
padzero(elf_bss);
len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
if (bss > len)
do_mmap(NULL, len, bss-len,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
kfree(elf_phdata);
return 0;
}
......@@ -24,15 +24,18 @@ struct linux_binprm{
char * filename; /* Name of binary */
};
/* This structure defines the functions that are used to load the binary formats that
* linux accepts. */
struct linux_binfmt{
/*
* This structure defines the functions that are used to load the binary formats that
* linux accepts.
*/
struct linux_binfmt {
struct linux_binfmt * next;
int (*load_binary)(struct linux_binprm *, struct pt_regs * regs);
int (*load_shlib)(int fd);
};
extern struct linux_binfmt formats[];
extern int register_binfmt(struct linux_binfmt *);
extern int unregister_binfmt(struct linux_binfmt *);
extern int read_exec(struct inode *inode, unsigned long offset,
char * addr, unsigned long count);
......
/* Flags for bug emulation. These occupy the top three bytes. */
#define STICKY_TIMEOUTS 0x8000000
#define WHOLE_SECONDS 0x4000000
/* Personality types. These go in the low byte. */
#define PER_MASK (0x00ff)
#define PER_LINUX (0x0000)
#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS)
#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS)
#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)
#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS)
#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS)
......@@ -254,10 +254,12 @@ struct task_struct {
/* various fields */
struct task_struct *next_task, *prev_task;
struct sigaction sigaction[32];
unsigned long * signal_map;
unsigned long * signal_invmap;
unsigned long saved_kernel_stack;
unsigned long kernel_stack_page;
int exit_code, exit_signal;
int elf_executable:1;
unsigned long personality;
int dumpable:1;
int did_exec:1;
int pid,pgrp,session,leader;
......@@ -323,7 +325,7 @@ struct task_struct {
/* state etc */ { 0,15,15,0,0,0,0, \
/* debugregs */ { 0, }, \
/* schedlink */ &init_task,&init_task, \
/* signals */ {{ 0, },}, \
/* signals */ {{ 0, },}, ident_map, ident_map, \
/* stack */ 0,(unsigned long) &init_kernel_stack, \
/* ec,brk... */ 0,0,0,0,0, \
/* pid etc.. */ 0,0,0,0, \
......
......@@ -282,10 +282,12 @@ int kill_proc(int pid, int sig, int priv)
* POSIX specifies that kill(-1,sig) is unspecified, but what we have
* is probably wrong. Should make it like BSD or SYSV.
*/
asmlinkage int sys_kill(int pid,int sig)
asmlinkage int sys_kill(int pid, unsigned int sig)
{
int err, retval = 0, count = 0;
if (sig > 32)
return -EINVAL;
if (!pid)
return(kill_pg(current->pgrp,sig,0));
if (pid == -1) {
......
......@@ -15,6 +15,7 @@
#include <linux/sys.h>
#include <linux/utsname.h>
#include <linux/interrupt.h>
#include <linux/binfmts.h>
#ifdef CONFIG_INET
#include <linux/netdevice.h>
#endif
......@@ -28,20 +29,16 @@ extern char * ftape_big_buffer;
extern void (*do_floppy)(void);
#endif
#ifdef CONFIG_BINFMT_IBCS
extern int do_execve(char * filename, char ** argv, char ** envp,
struct pt_regs * regs);
extern void flush_old_exec(struct linux_binprm * bprm);
extern int open_inode(struct inode * inode, int mode);
extern int read_exec(struct inode *inode, unsigned long offset,
char * addr, unsigned long count);
extern void check_pending(int signum);
extern int do_signal(unsigned long oldmask, struct pt_regs * regs);
extern int (*ibcs_invmapsig)(int);
extern void (* iABI_hook)(struct pt_regs * regs);
#endif
#ifdef CONFIG_INET
extern int register_netdev(struct device *);
extern void unregister_netdev(struct device *);
......@@ -67,6 +64,8 @@ struct {
X(__verify_write),
X(do_mmap),
X(do_munmap),
X(insert_vm_struct),
X(zeromap_page_range),
/* internal kernel memory management */
X(__get_free_pages),
......@@ -94,6 +93,10 @@ struct {
X(register_filesystem),
X(unregister_filesystem),
/* executable format registration */
X(register_binfmt),
X(unregister_binfmt),
/* interrupt handling */
X(request_irq),
X(free_irq),
......@@ -115,24 +118,8 @@ struct {
X(system_utsname),
X(sys_call_table),
#ifdef CONFIG_FTAPE
/* The next labels are needed for ftape driver. */
X(ftape_big_buffer),
X(do_floppy),
#endif
#ifdef CONFIG_BINFMT_IBCS
/*
* The following are needed if iBCS support is modular rather than
* compiled in.
*/
/* Emulator hooks. */
X(iABI_hook),
X(ibcs_invmapsig),
/* Signal interfaces */
X(do_signal),
X(check_pending),
X(send_sig),
/* Program loader interfaces */
......@@ -141,16 +128,17 @@ struct {
X(create_tables),
X(do_execve),
X(flush_old_exec),
X(formats),
X(insert_vm_struct),
X(open_inode),
X(read_exec),
X(zeromap_page_range),
/* Miscellaneous access points */
X(si_meminfo),
#endif
#ifdef CONFIG_FTAPE
/* The next labels are needed for ftape driver. */
X(ftape_big_buffer),
X(do_floppy),
#endif
#ifdef CONFIG_INET
/* support for loadable net drivers */
X(register_netdev),
......
......@@ -87,6 +87,16 @@ extern void mem_use(void);
extern int timer_interrupt(void);
asmlinkage int system_call(void);
/*
* signal mapping: this is the default identity mapping used for normal
* linux binaries (it's both the reverse and the normal map, of course)
*/
static unsigned long ident_map[33] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32
};
static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
struct task_struct init_task = INIT_TASK;
......
......@@ -135,7 +135,9 @@ asmlinkage int sys_signal(int signum, unsigned long handler)
{
struct sigaction tmp;
if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
if (signum<1 || signum>32)
return -EINVAL;
if (signum==SIGKILL || signum==SIGSTOP)
return -EINVAL;
if (handler >= TASK_SIZE)
return -EFAULT;
......@@ -154,7 +156,9 @@ asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
{
struct sigaction new_sa, *p;
if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
if (signum<1 || signum>32)
return -EINVAL;
if (signum==SIGKILL || signum==SIGSTOP)
return -EINVAL;
p = signum - 1 + current->sigaction;
if (action) {
......@@ -242,7 +246,7 @@ static void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned lon
do_exit(SIGSEGV);
/* set up the "normal" stack seen by the signal handler (iBCS2) */
put_fs_long(__CODE,frame);
put_fs_long(signr, frame+1);
put_fs_long(current->signal_invmap[signr], frame+1);
put_fs_long(regs->gs, frame+2);
put_fs_long(regs->fs, frame+3);
put_fs_long(regs->es, frame+4);
......
......@@ -3,7 +3,6 @@
#include "datalink.h"
#include <linux/mm.h>
#include <linux/in.h>
#include <linux/ddi.h>
static struct datalink_proto *p8022_list = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment