📄 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 intis_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. */staticint 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 intload_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 + -