Example #1
0
/*
 * Helper function to process the load operation.
 */
static int
coff_load_object(struct linux_binprm *bprm, struct pt_regs *regs, int binary)
{
	COFF_FILHDR		*coff_hdr = NULL;
	COFF_SCNHDR		*text_sect = NULL, *data_sect = NULL,
				*bss_sect = NULL, *sect_bufr = NULL,
				*sect_ptr = NULL;
	int			text_count = 0, data_count = 0,
				bss_count = 0, lib_count = 0;
	coff_section		text, data, bss;
	u_long			start_addr = 0, p = bprm->p;
	short			flags, aout_size = 0;
	int			pageable = 1, sections = 0, status = 0, i;
	int			coff_exec_fileno;
	mm_segment_t		old_fs;


	coff_hdr = (COFF_FILHDR *)bprm->buf;

	/*
	 * Validate the magic value for the object file.
	 */
	if (COFF_I386BADMAG(*coff_hdr))
		return -ENOEXEC;

	flags = COFF_SHORT(coff_hdr->f_flags);

	/*
	 * 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.
	 */
	if ((flags & (COFF_F_AR32WR | COFF_F_AR16WR)) != COFF_F_AR32WR)
		return -ENOEXEC;

	/*
	 * If the file is not executable then reject the execution. This means
	 * that there must not be external references.
	 */
	if ((flags & COFF_F_EXEC) == 0)
		return -ENOEXEC;

	/*
	 * 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 */

	/*
	 * There must be at least one section.
	 */
	if (!sections)
		return -ENOEXEC;

	if (!bprm->file->f_op->mmap)
		pageable = 0;

	if (!(sect_bufr = kmalloc(sections * COFF_SCNHSZ, GFP_KERNEL))) {
		printk(KERN_WARNING "coff: kmalloc failed\n");
		return -ENOMEM;
	}

	status = kernel_read(bprm->file, aout_size + COFF_FILHSZ,
			(char *)sect_bufr, sections * COFF_SCNHSZ);
	if (status < 0) {
		printk(KERN_WARNING "coff: unable to read\n");
		goto out_free_buf;
	}

	status = get_unused_fd();
	if (status < 0) {
		printk(KERN_WARNING "coff: unable to get free fs\n");
		goto out_free_buf;
	}

	get_file(bprm->file);
	fd_install(coff_exec_fileno = status, bprm->file);

	/*
	 *  Loop through the sections and find the various types
	 */
	sect_ptr = sect_bufr;

	for (i = 0; i < sections; i++) {
		long int sect_flags = COFF_LONG(sect_ptr->s_flags);

		switch (sect_flags) {
		case COFF_STYP_TEXT:
			status |= coff_isaligned(sect_ptr);
			text_sect = sect_ptr;
			text_count++;
			break;

		case COFF_STYP_DATA:
			status |= coff_isaligned(sect_ptr);
			data_sect = sect_ptr;
			data_count++;
			break;

		case COFF_STYP_BSS:
			bss_sect = sect_ptr;
			bss_count++;
			break;

		case COFF_STYP_LIB:
			lib_count++;
			break;

		default:
			break;
		}

		sect_ptr = (COFF_SCNHDR *) & ((char *) sect_ptr)[COFF_SCNHSZ];
	}

	/*
	 * If any of the sections weren't properly aligned we aren't
	 * going to be able to demand page this executable. Note that
	 * at this stage the *only* excuse for having status <= 0 is if
	 * the alignment test failed.
	 */
	if (status < 0)
		pageable = 0;

	/*
	 * 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;
		goto out_free_file;
	}
	if (binary && (data_count != 1 || bss_count != 1)) {
		status = -ENOEXEC;
		goto out_free_file;
	}

	/*
	 * 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 (aout_size == 0) {
		if (!binary) {
			status = -ENOEXEC;
			goto out_free_file;
		}
		start_addr = COFF_LONG(text_sect->s_vaddr);
	} else if (aout_size < (short) COFF_AOUTSZ) {
		status = -ENOEXEC;
		goto out_free_file;
	} else {
		COFF_AOUTHDR	*aout_hdr;
		short		aout_magic;

		aout_hdr = (COFF_AOUTHDR *) &((char *)coff_hdr)[COFF_FILHSZ];
		aout_magic = COFF_SHORT(aout_hdr->magic);

		/*
		 * 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 (!binary) {
				status = -ENOEXEC;
				goto out_free_file;
			}
			start_addr = (u_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 (!binary)
				break;
			/* FALLTHROUGH */
		default:
			status = -ENOEXEC;
			goto out_free_file;
		}
	}

	/*
	 *  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.
	 */

	text.scnptr = COFF_LONG(text_sect->s_scnptr);
	text.size = COFF_LONG(text_sect->s_size);
	text.vaddr = COFF_LONG(text_sect->s_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 (binary) {
		COFF_SCNHDR	*sect_ptr2 = sect_bufr;
		u_long		personality = PER_SVR3;
		int		i;

		if ((status = flush_old_exec(bprm)))
			goto out_free_file;

		/*
		 * Look for clues as to the system this binary was compiled
		 * on in the comments section(s).
		 *
		 * Only look at the main binary, not the shared libraries
		 * (or would it be better to prefer shared libraries over
		 * binaries?  Or could they be different???)
	 	 */
		for (i = 0; i < sections; i++) {
			long	sect_flags = COFF_LONG(sect_ptr2->s_flags);

			if (sect_flags == COFF_STYP_INFO &&
			   (status = coff_parse_comments(bprm->file,
						sect_ptr2, &personality)) > 0)
				goto found;

			sect_ptr2 = (COFF_SCNHDR *) &((char *)sect_ptr2)[COFF_SCNHSZ];
		}

		/*
		 * If no .comments section was found there is no way to
		 * figure out the personality. Odds on it is SCO though...
		 */
		personality = abi_defhandler_coff;

found:
		set_personality(personality);

		current->mm->start_data = 0;
		current->mm->end_data = 0;
		current->mm->end_code = 0;
		current->mm->mmap = NULL;
		current->flags &= ~PF_FORKNOEXEC;
		current->mm->_rss = 0;

		/*
		 * Construct the parameter and environment
		 * string table entries.
		 */
		if ((status = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT)) < 0)
			goto sigsegv;

		p = (u_long)coff_mktables((char *)bprm->p,
				bprm->argc, bprm->envc);

		current->mm->end_code = text.size +
		    (current->mm->start_code = text.vaddr);
		current->mm->end_data = data.size +
		    (current->mm->start_data = data.vaddr);
		current->mm->brk = bss.size +
		    (current->mm->start_brk = bss.vaddr);

		current->mm->start_stack = p;
		compute_creds(bprm);
		start_thread(regs, start_addr, p);
	}

	old_fs = get_fs();
	set_fs(get_ds());

	if (!pageable) {
		/*
		 * Read the file from disk...
		 *
		 * XXX: untested.
		 */
		loff_t pos = data.scnptr;
		status = do_brk(text.vaddr, text.size);
		bprm->file->f_op->read(bprm->file,
				(char *)data.vaddr, data.scnptr, &pos);
		status = do_brk(data.vaddr, data.size);
		bprm->file->f_op->read(bprm->file,
				(char *)text.vaddr, text.scnptr, &pos);
		status = 0;
	} else {
		/* map the text pages...*/
		status = map_coff(bprm->file, &text, PROT_READ | PROT_EXEC,
			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
			text.scnptr & PAGE_MASK);

		if (status != (text.vaddr & PAGE_MASK)) {
			status = -ENOEXEC;
			goto out_free_file;
		}

		/* map the data pages */
		if (data.size != 0) {
			status = map_coff(bprm->file, &data,
			    PROT_READ | PROT_WRITE | PROT_EXEC,
			    MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
			    data.scnptr & PAGE_MASK);

			if (status != (data.vaddr & PAGE_MASK)) {
				status = -ENOEXEC;
				goto out_free_file;
			}
		}

		status = 0;
	}

	/*
	 * Construct the bss data for the process. The bss ranges from the
	 * end of the data (which may not be on a page boundary) to the end
	 * of the bss section. Allocate any necessary pages for the data.
	 */
	if (bss.size != 0) {
		down_write(&current->mm->mmap_sem);
		do_mmap(NULL, PAGE_ALIGN(bss.vaddr),
			bss.size + bss.vaddr -
			PAGE_ALIGN(bss.vaddr),
			PROT_READ | PROT_WRITE | PROT_EXEC,
			MAP_FIXED | MAP_PRIVATE, 0);
		up_write(&current->mm->mmap_sem);

		if ((status = coff_clear_memory(bss.vaddr, bss.size)) < 0)
			goto out_free_file;
	}

	set_fs(old_fs);

	if (!binary)
		goto out_free_file;

	/*
	 * Load any shared library for the executable.
	 */
	if (lib_count)
		status = coff_preload_shlibs(bprm, sect_bufr, sections);

	set_binfmt(&coff_format);

	/*
	 * 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 (status < 0) {
sigsegv:
		printk(KERN_WARNING "coff: trapping process with SEGV\n");
		send_sig(SIGSEGV, current, 0);	/* Generate the error trap  */
	} else if (current->ptrace & PT_PTRACED)
		send_sig(SIGTRAP, current, 0);

	/* We are committed. It can't fail */
	status = 0;

out_free_file:
	sys_close(coff_exec_fileno);

out_free_buf:
	kfree(sect_bufr);
	return (status);
}
Example #2
0
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 execution. 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 at least 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 boundary) 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 at least one. It was counted
 *  earlier.) This will eventually 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 occurred 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);
}