?? binfmt_coff.c
字號:
/*
* 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->filp[fd];
}
else
fd = -1; /* Invalidate the open file descriptor */
/*
* Generate the proper values for the text fields
*
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -