Files
retrobsd/sys/kernel/kern_exec.c
Serge Vakulenko 94c02410e4 Kconfig: rename machine to architecture, ident to board.
Make timezone and maxusers parameters optional.

Enable kernel options UCB_METER, EXEC_AOUT, EXEC_ELF and EXEC_SCRIPT
by default.
2015-09-03 12:51:56 -07:00

154 lines
4.0 KiB
C

/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/map.h>
#include <sys/inode.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/namei.h>
#include <sys/fs.h>
#include <sys/mount.h>
#include <sys/file.h>
#include <sys/signalvar.h>
#include <sys/exec.h>
#include <sys/debug.h>
/*
* exec system call, with and without environments.
*/
struct execa {
char *fname;
char **argp;
char **envp;
};
/*
* This is the internal form of the exec() function.
*
* It is called with the inode of the executable
* and the exec_params structure, which is used to
* keep information during the exec.
*
* It returns the error code, and with the ip still locked.
*/
int exec_check(struct exec_params *epp)
{
int error, i, r;
DEBUG("Entering exec_check\n");
if (access (epp->ip, IEXEC))
return ENOEXEC;
if ((u.u_procp->p_flag & P_TRACED) && access (epp->ip, IREAD))
return ENOEXEC;
if ((epp->ip->i_mode & IFMT) != IFREG ||
(epp->ip->i_mode & (IEXEC | (IEXEC>>3) | (IEXEC>>6))) == 0)
return EACCES;
/*
* Read in first few bytes of file for segment sizes, magic number:
* 407 = plain executable
* Also an ASCII line beginning with #! is
* the file name of a ``interpreter'' and arguments may be prepended
* to the argument list if given here.
*
* INTERPRETER NAMES ARE LIMITED IN LENGTH.
*
* ONLY ONE ARGUMENT MAY BE PASSED TO THE INTERPRETER FROM
* THE ASCII LINE.
*/
/*
* Read the first 'SHSIZE' bytes from the file to execute
*/
DEBUG("Read header %d bytes from %d\n", sizeof(epp->hdr), 0);
epp->hdr.sh[0] = '\0'; /* for zero length files */
error = rdwri (UIO_READ, epp->ip,
(caddr_t) &epp->hdr, sizeof(epp->hdr),
(off_t)0, IO_UNIT, &r);
if (error)
return error;
epp->hdr_len = sizeof(epp->hdr) - r;
/*
* Given the first part of the image
* loop through the exec file handlers to find
* someone who can handle this file format.
*/
error = ENOEXEC;
DEBUG("Trying %d exec formats\n", nexecs);
for (i = 0; i < nexecs && error != 0; i++) {
DEBUG("Trying exec format %d : %s\n", i, execsw[i].es_name);
if (execsw[i].es_check == NULL)
continue;
error = (*execsw[i].es_check)(epp);
if (error == 0)
break;
}
return error;
}
void
execv()
{
struct execa *arg = (struct execa *)u.u_arg;
arg->envp = NULL;
execve();
}
void
execve()
{
struct execa *uap = (struct execa *)u.u_arg;
int error;
struct inode *ip;
struct nameidata nd;
register struct nameidata *ndp = &nd;
struct exec_params eparam;
DEBUG("execve ('%s', ['%s', '%s', ...])\n", uap->fname, uap->argp[0], uap->argp[1]);
NDINIT (ndp, LOOKUP, FOLLOW, uap->fname);
ip = namei (ndp);
if (ip == NULL) {
DEBUG("execve: file '%s' not found\n", uap->fname);
return;
}
/*
* The exec_param structure is used to
* keep information about the executable during exec's processing
*/
bzero(&eparam, sizeof eparam);
eparam.userfname = uap->fname;
eparam.userargp = uap->argp;
eparam.userenvp = uap->envp;
eparam.uid = u.u_uid;
eparam.gid = u.u_groups[0];
if (ip->i_fs->fs_flags & MNT_NOEXEC) {
u.u_error = EACCES;
DEBUG("EACCES\n");
goto done;
}
if ((ip->i_fs->fs_flags & MNT_NOSUID) == 0) {
if (ip->i_mode & ISUID)
eparam.uid = ip->i_uid;
if (ip->i_mode & ISGID)
eparam.gid = ip->i_gid;
}
eparam.ip = ip;
DEBUG("calling exec_check()\n");
if ((error = exec_check(&eparam)))
u.u_error = error;
DEBUG("back from exec_check()\n");
done:
exec_alloc_freeall(&eparam);
if (ip)
iput(ip);
}