Subject: More on emulations
To: None <tech-kern@NetBSD.ORG>
From: Niklas Hallqvist <niklas@appli.se>
List: tech-kern
Date: 11/14/1995 11:20:38
During my games with emulations, I've come up with a design that
separates the "executable type", the "emulation" and the "emulation
association".  In order to not confuse things too much I start with a
simple glossary:

Executable type,
	Commonly referred to as exec-type, deals mainly with object
	file layout, but also with the in-core memory layout during
	load.  The structure that models an exec-type is called
	"struct exectype".  In the kernel, exectypes is a list that
	holds all supported exec-types.

Emulation,
	This issue deals with syscall, signal and error translation as
	well as actual emulation of foreign operating systems
	(although the native OS is sometimes considered to be an
	emulation as well for symmetry).  "struct emul" is the
	relevant datatype, and there is a list, emuls, that holds all
	the supported emulations in the kernel.

Emulation association,
	or emulation assoc, or even emul-assoc.  Associates an
	exec-type with an emulation.  An exec-type can hold binaries
	that need to be differently emulated.  Also, an exec-type
	might be associated with the same emulation in slightly
	differing ways.  That's why the emul-assoc needs to be an
	object of its own that glues together the exec-type and the
	emulation.  The corresponding structure is called "struct
	emul_assoc".  A very important list, execsw (corresponds
	closely to the old array wrt provided functionality), holds
	all the emul-assocs supported.  This is the one sought when
	trying to determine what exec-type/emulation a certain
	executable is.

All of the three object types are named, using separate namespaces.
They should be configured in a way like devices or psedo-devices are
done today, ie. with a specific configuration interface.  This means
getting rid of "options COMPAT_SVR4" and the like.  Each of the three
object types should be loadable into the kernel via the LKM interface.

In order to allow execve(2) work as before we must be able to, just
like before, loop through the execsw slots to find the correct
emul-assoc.  The emul-assoc can use the associated exec-type in order
to help out at this time.

Now we need even more fine-grained control than this.  We need a
syscall that actually specifies what emul-assoc should be used (both
exec-type & emulation is uniquely determined by that).  This is called
execvee(2) and will have a signature like:

int execvee(const char		*path,
	    char *const		argv[],
	    char *const		envp[],
	    const char		*emul_assoc,
	    struct exec_opt	*optv[]);

Where exec_opt is a special structure looking like:

struct exec_opt {
	int	eo_type;
	union eo_data {
		long	eo_val;
		void	*eo_ptr;
		void	(*eo_fcn)();
	} eo_un;
};

/* Ends the optional argument list */
#define EO_NULL			0

The options enclosed in the optv structure is a way to control the
exec-type, emul-assoc or emulation in a fine-grained way.  Each slot
can contain tagged data used by any of the three objects that so
wishes.  In the execvee(2) path the options must be validated,
ie. checked that all are supported by the kernel in use.  Otherwise
set-id wrappers expecting a binary be run in a certain way, specified
by the option might trigger a security hole, if the option isn't
supported.  While on the subject of security, execvee will not support
any set-id functionality.  The reason for this is that passing bad
emulation options to such a program could potentially be a security
risk.  Instead the wrapper calling execvee can be set-id.

Regarding internal implementation, execve will remain the same
functionally, but the implementation will change due to the separation
of the three concepts.  execvee will be a clone of execve but won't do
set-id operations nor probing of the emul-assoc as it is given.
Furthermore option validation and passing on will of course occur.

Last, some sample code to show how this should be used:

#include <sys/optv.h>

int
main(argc, argv, envp)
	int		argc;
	char *const	argv[];
	char *const	envp[];
{
	optv[0].eo_type = EO_EXEC_ELF_MAP_PAGE_ZERO;
	optv[0].eo_un.eo_val = 1;
	optv[1].eo_type = EO_NULL;
	return(execvee("/emul/svr4/usr/bin/make", argv, envp,
	    "svr4_elf", optv));
}

So, do someone object to anything of what I've said?  Other comments?
I especially appreciate security considerations as I'm not really used
to that kind of thinking yet, and it is an important fact if this
reorg. will get into the tree.  I also would like proposals on how to
configure these objects.  I have had ideas like:

emul-assoc svr4_elf: svr4 elf

This would add both svr4 and elf to the list of needed modules to
attach.  A way to specify emulations and exec-types to go in the
kernel but not associated to anything should be there as well.  LKM
emul_assocs could later use such.  The easy way is to do a
pseudo-device like keyword (but without the count parameter) like
"module".

module svr4
module elf

Niklas

Niklas Hallqvist       Phone: +46-(0)31-40 75 00  Home: +46-(0)31-41 93 95
Applitron Datasystem   Fax:   +46-(0)31-83 39 50  Home: +46-(0)31-41 93 96
Molndalsvagen 95       Email: niklas@appli.se     GSM:  +46-(0)70-714 10 35
S-412 63  GOTEBORG     WWW:   Here
Sweden		       IRC:   niklas (#NetBSD)    ICB:  niklas (netbsd)