<|start_filename|>exec_shell_imgact-4570.1.46.c<|end_filename|>
// Stolen from: https://github.com/opensource-apple/xnu/blob/xnu-4570.1.46/bsd/kern/kern_exec.c
//#include <machine/reg.h>
//#include <machine/cpu_capabilities.h>

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/filedesc.h>
#include <sys/kernel.h>
//#include <sys/proc_internal.h>
#include <sys/kauth.h>
#include <sys/user.h>
#include <sys/socketvar.h>
#include <sys/malloc.h>
#include <sys/namei.h>
//#include <sys/mount_internal.h>
//#include <sys/vnode_internal.h>		
//#include <sys/file_internal.h>
#include <sys/stat.h>
//#include <sys/uio_internal.h>
#include <sys/acct.h>
//#include <sys/exec.h>
#include <sys/kdebug.h>
#include <sys/signal.h>
//#include <sys/aio_kern.h>
//#include <sys/sysproto.h>
//#include <sys/persona.h>
//#include <sys/reason.h>
#if SYSV_SHM
#include <sys/shm_internal.h>		/* shmexec() */
#endif
//#include <sys/ubc_internal.h>		/* ubc_map() */
#include <sys/spawn.h>
//#include <sys/spawn_internal.h>
//#include <sys/process_policy.h>
//#include <sys/codesign.h>
#include <sys/random.h>
//#include <crypto/sha1.h>

#include <libkern/libkern.h>

//#include <security/audit/audit.h>

#include <ipc/ipc_types.h>

#include <mach/mach_types.h>
#include <mach/port.h>
#include <mach/task.h>
#include <mach/task_access.h>
#include <mach/thread_act.h>
#include <mach/vm_map.h>
#include <mach/mach_vm.h>
#include <mach/vm_param.h>

#include <kern/sched_prim.h> /* thread_wakeup() */
//#include <kern/affinity.h>
#include <kern/assert.h>
#include <kern/task.h>
#include <kern/coalition.h>
#include <kern/policy_internal.h>
//#include <kern/kalloc.h>

#include <os/log.h>

#if CONFIG_MACF
#include <security/mac_framework.h>
#include <security/mac_mach_internal.h>
#endif

#include <vm/vm_map.h>
#include <vm/vm_kern.h>
//#include <vm/vm_protos.h>
#include <vm/vm_kern.h>
#include <vm/vm_fault.h>
#include <vm/vm_pageout.h>

//#include <kdp/kdp_dyld.h>

//#include <machine/pal_routines.h>

#include <pexpert/pexpert.h>

#if CONFIG_MEMORYSTATUS
#include <sys/kern_memorystatus.h>
#endif

#include <kern/thread.h>
#include <kern/task.h>
//#include <kern/ast.h>
//#include <kern/mach_loader.h>
//#include <kern/mach_fat.h>
//#include <mach-o/fat.h>
//#include <mach-o/loader.h>
#include <machine/vmparam.h>
#include <sys/imgact.h>
#include <sys/vnode.h>

#include <sys/sdt.h>

#include "imgact_linux.h"

/*
 * For #! interpreter parsing
 */
#define IS_WHITESPACE(ch) ((ch == ' ') || (ch == '\t'))
//#define IS_EOL(ch) ((ch == '#') || (ch == '\n'))
#define IS_EOL(ch) (ch == '\0')

/*
 * dyld is now passed the executable path as a getenv-like variable
 * in the same fashion as the stack_guard and malloc_entropy keys.
 */
#define	EXECUTABLE_KEY "executable_path="

static int sugid_scripts = 0;
SYSCTL_INT (_kern, OID_AUTO, sugid_scripts, CTLFLAG_RW | CTLFLAG_LOCKED, &sugid_scripts, 0, "");

/*
 * exec_save_path
 *
 * To support new app package launching for Mac OS X, the dyld needs the
 * first argument to execve() stored on the user stack.
 *
 * Save the executable path name at the bottom of the strings area and set
 * the argument vector pointer to the location following that to indicate
 * the start of the argument and environment tuples, setting the remaining
 * string space count to the size of the string area minus the path length.
 *
 * Parameters;	struct image_params *		image parameter block
 *		char *				path used to invoke program
 *		int				segment from which path comes
 *
 * Returns:	int			0	Success
 *		EFAULT				Bad address
 *	copy[in]str:EFAULT			Bad address
 *	copy[in]str:ENAMETOOLONG		Filename too long
 *
 * Implicit returns:
 *		(imgp->ip_strings)		saved path
 *		(imgp->ip_strspace)		space remaining in ip_strings
 *		(imgp->ip_strendp)		start of remaining copy area
 *		(imgp->ip_argspace)		space remaining of NCARGS
 *		(imgp->ip_applec)		Initial applev[0]
 *
 * Note:	We have to do this before the initial namei() since in the
 *		path contains symbolic links, namei() will overwrite the
 *		original path buffer contents.  If the last symbolic link
 *		resolved was a relative pathname, we would lose the original
 *		"path", which could be an absolute pathname. This might be
 *		unacceptable for dyld.
 */
static int
exec_save_path(struct image_params *imgp, user_addr_t path, int seg, const char **excpath)
{
	int error;
	size_t len;
	char *kpath;

	// imgp->ip_strings can come out of a cache, so we need to obliterate the
	// old path.
	memset(imgp->ip_strings, '\0', strlen(EXECUTABLE_KEY) + MAXPATHLEN);

	len = MIN(MAXPATHLEN, imgp->ip_strspace);

	switch(seg) {
	case UIO_USERSPACE32:
	case UIO_USERSPACE64:	/* Same for copyin()... */
		error = copyinstr(path, imgp->ip_strings + strlen(EXECUTABLE_KEY), len, &len);
		break;
	case UIO_SYSSPACE:
		kpath = CAST_DOWN(char *,path);	/* SAFE */
		error = copystr(kpath, imgp->ip_strings + strlen(EXECUTABLE_KEY), len, &len);
		break;
	default:
		error = EFAULT;
		break;
	}

	if (!error) {
		bcopy(EXECUTABLE_KEY, imgp->ip_strings, strlen(EXECUTABLE_KEY));
		len += strlen(EXECUTABLE_KEY);

		imgp->ip_strendp += len;
		imgp->ip_strspace -= len;

		if (excpath) {
			*excpath = imgp->ip_strings + strlen(EXECUTABLE_KEY);
		}
	}

	return(error);
}

/*
 * exec_reset_save_path
 *
 * If we detect a shell script, we need to reset the string area
 * state so that the interpreter can be saved onto the stack.

 * Parameters;	struct image_params *		image parameter block
 *
 * Returns:	int			0	Success
 *
 * Implicit returns:
 *		(imgp->ip_strings)		saved path
 *		(imgp->ip_strspace)		space remaining in ip_strings
 *		(imgp->ip_strendp)		start of remaining copy area
 *		(imgp->ip_argspace)		space remaining of NCARGS
 *
 */
static int
exec_reset_save_path(struct image_params *imgp)
{
	imgp->ip_strendp = imgp->ip_strings;
	imgp->ip_argspace = NCARGS;
	imgp->ip_strspace = ( NCARGS + PAGE_SIZE );

	return (0);
}

/*
 * exec_shell_imgact
 *
 * Image activator for interpreter scripts.  If the image begins with
 * the characters "#!", then it is an interpreter script.  Verify the
 * length of the script line indicating the interpreter is not in
 * excess of the maximum allowed size.  If this is the case, then
 * break out the arguments, if any, which are separated by white
 * space, and copy them into the argument save area as if they were
 * provided on the command line before all other arguments.  The line
 * ends when we encounter a comment character ('#') or newline.
 *
 * Parameters;	struct image_params *	image parameter block
 *
 * Returns:	-1			not an interpreter (keep looking)
 *		-3			Success: interpreter: relookup
 *		>0			Failure: interpreter: error number
 *
 * A return value other than -1 indicates subsequent image activators should
 * not be given the opportunity to attempt to activate the image.
 */
int
my_exec_shell_imgact(struct image_params *imgp)
{
	const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->ip_vdata;
	char *vdata = interp_bufr;
	char *ihp;
	char *line_startp, *line_endp;
	char *interp;

	/*
	 * Do we have a valid ELF header ?
	 */
	if (elf_check_header(hdr) != 0 || hdr->e_type != ET_EXEC)
		return (orig_shell_imgact(imgp));

        if (kdebug_enable)
	    printf("ELF brand (OS ABI): %x\n", hdr->e_ident[EI_OSABI]);

	if (imgp->ip_origcputype != 0) {
		/* Fat header previously matched, don't allow shell script inside */
		return (-1);
	}

	imgp->ip_flags |= IMGPF_INTERPRET;

        imgp->ip_origvattr->va_mode  &= ~(VSUID | VSGID);
	imgp->ip_interp_sugid_fd = -1;
	imgp->ip_interp_buffer[0] = '\0';

	/* Check to see if SUGID scripts are permitted.  If they aren't then
	 * clear the SUGID bits.
	 * imgp->ip_vattr is known to be valid.
	 */
	if (sugid_scripts == 0) {
		imgp->ip_origvattr->va_mode &= ~(VSUID | VSGID);
	}

	/* Try to find the first non-whitespace character */
	for( ihp = &vdata[0]; ihp < &vdata[IMG_SHSIZE]; ihp++ ) {
		if (IS_EOL(*ihp)) {
			/* Did not find interpreter, "#!\n" */
			return (ENOEXEC);
		} else if (IS_WHITESPACE(*ihp)) {
			/* Whitespace, like "#!    /bin/sh\n", keep going. */
		} else {
			/* Found start of interpreter */
			break;
		}
	}

	if (ihp == &vdata[IMG_SHSIZE]) {
		/* All whitespace, like "#!           " */
		return (ENOEXEC);
	}

	line_startp = ihp;

	/* Try to find the end of the interpreter+args string */
	for ( ; ihp < &vdata[IMG_SHSIZE]; ihp++ ) {
		if (IS_EOL(*ihp)) {
			/* Got it */
			break;
		} else {
			/* Still part of interpreter or args */
		}
	}

	if (ihp == &vdata[IMG_SHSIZE]) {
		/* A long line, like "#! blah blah blah" without end */
		return (ENOEXEC);
	}

	/* Backtrack until we find the last non-whitespace */
	while (IS_EOL(*ihp) || IS_WHITESPACE(*ihp)) {
		ihp--;
	}

	/* The character after the last non-whitespace is our logical end of line */
	line_endp = ihp + 1;

	/*
	 * Now we have pointers to the usable part of:
	 *
	 * "#!  /usr/bin/int first    second   third    \n"
	 *      ^ line_startp                       ^ line_endp
	 */

	/* copy the interpreter name */
	interp = imgp->ip_interp_buffer;
	for ( ihp = line_startp; (ihp < line_endp) && !IS_WHITESPACE(*ihp); ihp++)
		*interp++ = *ihp;
	*interp = '\0';

	exec_reset_save_path(imgp);
	exec_save_path(imgp, CAST_USER_ADDR_T(imgp->ip_interp_buffer),
							UIO_SYSSPACE, NULL);

	/* Copy the entire interpreter + args for later processing into argv[] */
	interp = imgp->ip_interp_buffer;
	for ( ihp = line_startp; (ihp < line_endp); ihp++)
		*interp++ = *ihp;
	*interp = '\0';

#if !SECURE_KERNEL && 0
	/*
	 * If we have an SUID or SGID script, create a file descriptor
	 * from the vnode and pass /dev/fd/%d instead of the actual
	 * path name so that the script does not get opened twice
	 */
	if (imgp->ip_origvattr->va_mode & (VSUID | VSGID)) {
		proc_t p;
		struct fileproc *fp;
		int fd;
		int error;

		p = vfs_context_proc(imgp->ip_vfs_context);
		error = falloc(p, &fp, &fd, imgp->ip_vfs_context);
		if (error)
			return(error);

		fp->f_fglob->fg_flag = FREAD;
		fp->f_fglob->fg_ops = &vnops;
		fp->f_fglob->fg_data = (caddr_t)imgp->ip_vp;
		
		proc_fdlock(p);
		procfdtbl_releasefd(p, fd, NULL);
		fp_drop(p, fd, fp, 1);
		proc_fdunlock(p);
		vnode_ref(imgp->ip_vp);

		imgp->ip_interp_sugid_fd = fd;
	}
#endif

	return (-3);
}



<|start_filename|>Makefile<|end_filename|>
#
#  /Developer.3.26/usr/bin/xcodebuild  -target ext2_kext
#

EXTROOT = /Library/Extensions
#SDK_ROOT = /Developer.3.26
#SYSROOT = $(SDK_ROOT)/SDKs/MacOSX10.4u.sdk
#OSX_VERSION = 10.4
#SDK_ROOT = /Developer.4.6.2/Xcode.app/Contents/Developer
SDK_ROOT = /Developer
SYSROOT = $(SDK_ROOT)/SDKs/MacOSX10.6.sdk
OSX_VERSION = 10.6
XNU_VERSION = 4570.1.46

#CC = $(SDK_ROOT)/usr/bin/gcc-4.0
#LD = $(SDK_ROOT)/usr/bin/gcc-4.0
CC = $(SDK_ROOT)/usr/bin/gcc
LD = $(CC)

# detect current kernel architecture
CPU  := $(shell uname -m)
ifeq ($(CPU),i386)
ARCH = -arch i386
else
ifeq ($(CPU),x86_64)
ARCH = -m64
endif
endif

CFLAGS += -pipe -std=gnu99 -fasm-blocks -fmessage-length=0
# DEBUG
CFLAGS += -gdwarf-2 -O0 
WARNS += -Wno-trigraphs -Wmost -Wfloat-equal -Wno-four-char-constants -Wno-unknown-pragmas
CFLAGS_KERN += -fno-builtin -fno-common \
	-force_cpusubtype_ALL -finline -fno-keep-inline-functions 
CFLAGS_APP += -fpascal-strings -mdynamic-no-pic -fvisibility=hidden
DEFS +=	-DOSX -DDEBUG -DEXT2FS_DEBUG=1 -DDIAGNOSTIC -DDX_DEBUG \
	-DEXT2FS_TRACE -DAPPLE
#DEFS +=	-DBSD -DBYTE_ORDER=LITTLE_ENDIAN

DEFS_KERN += -D_KERNEL -DKERNEL -DKERNEL_PRIVATE -DDRIVER_PRIVATE -DNeXT

CFLAGS += -mmacosx-version-min=$(OSX_VERSION) -msoft-float -mkernel

KERN_INCS += -I/System/Library/Frameworks/Kernel.framework/PrivateHeaders \
	-I$(SYSROOT)/System/Library/Frameworks/Kernel.framework/Headers

INCS += -I$(SYSROOT)/usr/include \
	-I.

KEXT_OBJS = \
	exec_shell_imgact.o \
	imgact_linux.o

all: imgact_linux.kmod 

exec_shell_imgact.o: exec_shell_imgact-$(XNU_VERSION).c
	$(CC) $(ARCH) -no-cpp-precomp -nostdinc $(CFLAGS) $(CFLAGS_KERN) $(DEFS) $(DEFS_KERN) $(KERN_INCS) $(INCS) $(WARNS) -c -o exec_shell_imgact.o exec_shell_imgact-$(XNU_VERSION).c

imgact_linux.o: imgact_linux.c
	$(CC) $(ARCH) -isysroot $(SYSROOT) -no-cpp-precomp -nostdinc $(CFLAGS) $(CFLAGS_KERN) $(DEFS) $(DEFS_KERN) $(KERN_INCS) $(INCS) $(WARNS) -c -o imgact_linux.o imgact_linux.c

imgact_linux.kmod: $(KEXT_OBJS)
	$(LD) $(ARCH) \
		-mmacosx-version-min=$(OSX_VERSION) \
		-Xlinker -kext \
		-nostdlib -fno-builtin \
		-lcc_kext -o imgact_linux.kmod $(KEXT_OBJS)

Info.plist:
	./mkinfo.sh Info.plist

execsw_proxy: Proxy.plist
	# See https://github.com/slavaim/dl_kextsymboltool
	# old MacOS X placed the kernel in the root directory
	nm -gj /mach_kernel > allsymbols
	# on the lates macOS the kernel can be found at /System/Library/Kernels
	#nm -gj /System/Library/Kernels/kernel > allsymbols
	echo "_execsw" > execsw_proxy.exports
	# include any more symbols needed

	dl_kextsymboltool -arch i386 -import allsymbols  -export execsw_proxy.exports -output execsw_proxy_32
	dl_kextsymboltool -arch x86_64 -import allsymbols -export execsw_proxy.exports -output execsw_proxy_64

	cp execsw_proxy_64 execsw_proxy
	# or make a universal kext
	#lipo -create execsw_proxy_32 execsw_proxy_64 -output execsw_proxy

proxy-install: execsw_proxy
	sudo rm -rf ${EXTROOT}/execsw_proxy.kext
	sudo mkdir -p ${EXTROOT}/execsw_proxy.kext/Contents/MacOS
	sudo cp execsw_proxy ${EXTROOT}/execsw_proxy.kext/Contents/MacOS/execsw_proxy
	sudo cp Proxy.plist ${EXTROOT}/execsw_proxy.kext/Contents/Info.plist
	sudo chown -R root:wheel ${EXTROOT}/execsw_proxy.kext

install: Info.plist imgact_linux.kmod
	sudo rm -rf $(EXTROOT)/imgact_linux.kext
	sudo mkdir -p $(EXTROOT)/imgact_linux.kext/Contents/MacOS 
	sudo cp imgact_linux.kmod $(EXTROOT)/imgact_linux.kext/Contents/MacOS/imgact_linux
	sudo cp Info.plist $(EXTROOT)/imgact_linux.kext/Contents/Info.plist
	sudo chown -R root:wheel $(EXTROOT)/imgact_linux.kext

codesign:
	sudo /usr/bin/codesign --force --sign 'Self-signed certificate' \
          $(EXTROOT)/imgact_linux.kext

test: install
	sudo kextutil -d ${EXTROOT} -t -v 6 $(EXTROOT)/imgact_linux.kext

clean:
	rm -f $(KEXT_OBJS)

distclean: clean
	rm -f imgact_linux.kmod Info.plist



<|start_filename|>imgact_linux.c<|end_filename|>
#include <mach/mach_types.h>
#include <sys/errno.h>
#include <sys/systm.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/stat.h>
#include <sys/malloc.h>
#include <sys/imgact.h>
#include <sys/kdebug.h>

#include <sys/sysctl.h>

// NB: Do not support 32 bit ELF for now

#include <sys/elf_common.h>
#include <elf.h>

#include "imgact_linux.h"

extern struct execsw {
	int (*ex_imgact)(struct image_params *);
	const char *ex_name;
} execsw[];

char interp_bufr[IMG_SHSIZE];

ex_imgact_t orig_shell_imgact;

static int orig_shell_entry = -1;

SYSCTL_NODE(_kern,        // our parent
            OID_AUTO,     // automatically assign us an object ID
            imgact_linux, // our name
            CTLFLAG_RW,   // we will be creating children, therefore, read/write
            0,            // handler function (none needed)
            "imgact_linux sysctl hierarchy");

SYSCTL_STRING(
           _kern_imgact_linux,
           OID_AUTO,
           interpreter_commandline,
           CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_KERN,
           &interp_bufr,
           sizeof(interp_bufr),
           "ELF interpreter command line"
           );

int
elf_check_header(const Elf_Ehdr *hdr)
{
	if (!IS_ELF(*hdr) ||
	    hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
	    hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
	    hdr->e_ident[EI_VERSION] != EV_CURRENT)
		return ENOEXEC;

	if (!ELF_MACHINE_OK(hdr->e_machine))
		return ENOEXEC;

	if (hdr->e_version != ELF_TARG_VER)
		return ENOEXEC;

	return 0;
}

kern_return_t imgact_linux_start (kmod_info_t * ki, void * d) {
    int e;

    strlcpy(interp_bufr, INTERP_PATH, sizeof(interp_bufr));
    sysctl_register_oid(&sysctl__kern_imgact_linux);
    sysctl_register_oid(&sysctl__kern_imgact_linux_interpreter_commandline);

    if (kdebug_enable)
        printf("execsw[] located @ %llx.\n", execsw);

    for (e = 0; execsw[e].ex_name!=NULL; e++) {
        printf("%s %d\n", execsw[e].ex_name, e);
        if (!strcmp("Interpreter Script", execsw[e].ex_name)) {
            orig_shell_entry = e;
            orig_shell_imgact = execsw[e].ex_imgact;
            execsw[e].ex_imgact = my_exec_shell_imgact;
            break;
        }
    }

    if (kdebug_enable)
        printf("exec_shell_imgact() rerouted.\n");

    return KERN_SUCCESS;
}

kern_return_t imgact_linux_stop (kmod_info_t * ki, void * d) {
    sysctl_unregister_oid(&sysctl__kern_imgact_linux_interpreter_commandline);
    sysctl_unregister_oid(&sysctl__kern_imgact_linux);
    execsw[orig_shell_entry].ex_imgact = orig_shell_imgact;
	if (kdebug_enable)
        printf("Shell image activator restored.\n");
    return KERN_SUCCESS;
}


extern kern_return_t _start(kmod_info_t *ki, void *data);
extern kern_return_t _stop(kmod_info_t *ki, void *data);
KMOD_EXPLICIT_DECL(com.github.kext.imgact_linux, "0.0.1", imgact_linux_start,
		   imgact_linux_stop)
__private_extern__ kmod_start_func_t *_realmain = imgact_linux_start;
__private_extern__ kmod_stop_func_t *_antimain = imgact_linux_stop;
__private_extern__ int _kext_apple_cc = __APPLE_CC__ ;


<|start_filename|>exec_shell_imgact-1504.15.3.c<|end_filename|>
// Stolen from: https://github.com/opensource-apple/xnu/blob/xnu-1504.15.3/bsd/kern/kern_exec.c
#if 0
/*
 * exec_save_path
 *
 * To support new app package launching for Mac OS X, the dyld needs the
 * first argument to execve() stored on the user stack.
 *
 * Save the executable path name at the top of the strings area and set
 * the argument vector pointer to the location following that to indicate
 * the start of the argument and environment tuples, setting the remaining
 * string space count to the size of the string area minus the path length
 * and a reserve for two pointers.
 *
 * Parameters;	struct image_params *		image parameter block
 *		char *				path used to invoke program
 *		int				segment from which path comes
 *
 * Returns:	int			0	Success
 *		EFAULT				Bad address
 *	copy[in]str:EFAULT			Bad address
 *	copy[in]str:ENAMETOOLONG		Filename too long
 *
 * Implicit returns:
 *		(imgp->ip_strings)		saved path
 *		(imgp->ip_strspace)		space remaining in ip_strings
 *		(imgp->ip_argv)			beginning of argument list
 *		(imgp->ip_strendp)		start of remaining copy area
 *
 * Note:	We have to do this before the initial namei() since in the
 *		path contains symbolic links, namei() will overwrite the
 *		original path buffer contents.  If the last symbolic link
 *		resolved was a relative pathname, we would lose the original
 *		"path", which could be an absolute pathname. This might be
 *		unacceptable for dyld.
 */
static int
exec_save_path(struct image_params *imgp, user_addr_t path, int seg)
{
	int error;
	size_t	len;
	char *kpath = CAST_DOWN(char *,path);	/* SAFE */

	imgp->ip_strendp = imgp->ip_strings;
	imgp->ip_strspace = SIZE_IMG_STRSPACE;

	len = MIN(MAXPATHLEN, imgp->ip_strspace);

	switch(seg) {
	case UIO_USERSPACE32:
	case UIO_USERSPACE64:	/* Same for copyin()... */
		error = copyinstr(path, imgp->ip_strings, len, &len);
		break;
	case UIO_SYSSPACE:
		error = copystr(kpath, imgp->ip_strings, len, &len);
		break;
	default:
		error = EFAULT;
		break;
	}

	if (!error) {
		imgp->ip_strendp += len;
		imgp->ip_strspace -= len;
		imgp->ip_argv = imgp->ip_strendp;
	}

	return(error);
}

/*
 * exec_shell_imgact
 *
 * Image activator for interpreter scripts.  If the image begins with the
 * characters "#!", then it is an interpreter script.  Verify that we are
 * not already executing in PowerPC mode, and that the length of the script
 * line indicating the interpreter is not in excess of the maximum allowed
 * size.  If this is the case, then break out the arguments, if any, which
 * are separated by white space, and copy them into the argument save area
 * as if they were provided on the command line before all other arguments.
 * The line ends when we encounter a comment character ('#') or newline.
 *
 * Parameters;	struct image_params *	image parameter block
 *
 * Returns:	-1			not an interpreter (keep looking)
 *		-3			Success: interpreter: relookup
 *		>0			Failure: interpreter: error number
 *
 * A return value other than -1 indicates subsequent image activators should
 * not be given the opportunity to attempt to activate the image.
 */
static int
my_exec_shell_imgact(struct image_params *imgp)
{
	const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->ip_vdata;
	char *vdata = interp_bufr;
	char *ihp;
	char *line_endp;
	char *interp;
#ifdef FIXME
	char temp[16];
	proc_t p;
	struct fileproc *fp;
	int fd;
	int error;
	size_t len;
#endif


	/*
	 * Do we have a valid ELF header ?
	 */
	if (elf_check_header(hdr) != 0 || hdr->e_type != ET_EXEC)
		return (orig_shell_imgact(imgp));

        if (kdebug_enable)
	    printf("ELF brand (OS ABI): %x\n", hdr->e_ident[EI_OSABI]);

#ifdef IMGPF_POWERPC
	if ((imgp->ip_flags & IMGPF_POWERPC) != 0)
		  return (EBADARCH);
#endif	/* IMGPF_POWERPC */

	imgp->ip_flags |= IMGPF_INTERPRET;

#ifdef FIXME
        /* Check to see if SUGID scripts are permitted.  If they aren't then
	 * clear the SUGID bits.
	 * imgp->ip_vattr is known to be valid.
         */
        if (sugid_scripts == 0) {
	   imgp->ip_origvattr->va_mode &= ~(VSUID | VSGID);
	}
#endif

	/* Find the nominal end of the interpreter line */
	for( ihp = &vdata[0]; *ihp != '\0'; ihp++) {
		if (ihp >= &vdata[IMG_SHSIZE])
			return (ENOEXEC);
	}

	line_endp = ihp;
	ihp = &vdata[0];
	/* Skip over leading spaces - until the interpreter name */
	while ( ihp < line_endp && ((*ihp == ' ') || (*ihp == '\t')))
		ihp++;

	/*
	 * Find the last non-whitespace character before the end of line or
	 * the beginning of a comment; this is our new end of line.
	 */
	for (;line_endp > ihp && ((*line_endp == ' ') || (*line_endp == '\t')); line_endp--)
		continue;

	/* Empty? */
	if (line_endp == ihp)
		return (ENOEXEC);

	/* copy the interpreter name */
	interp = imgp->ip_interp_name;
	while ((ihp < line_endp) && (*ihp != ' ') && (*ihp != '\t'))
		*interp++ = *ihp++;
	*interp = '\0';

	exec_save_path(imgp, CAST_USER_ADDR_T(imgp->ip_interp_name),
							UIO_SYSSPACE);

	ihp = &vdata[0];
	while (ihp < line_endp) {
		/* Skip leading whitespace before each argument */
		while ((*ihp == ' ') || (*ihp == '\t'))
			ihp++;

		if (ihp >= line_endp)
			break;

		/* We have an argument; copy it */
		while ((ihp < line_endp) && (*ihp != ' ') && (*ihp != '\t')) {
			*imgp->ip_strendp++ = *ihp++;
			imgp->ip_strspace--;
		}
		*imgp->ip_strendp++ = 0;
		imgp->ip_strspace--;
		imgp->ip_argc++;
	}

#ifdef FIXME
	/*
	 * If we have a SUID oder SGID script, create a file descriptor
	 * from the vnode and pass /dev/fd/%d instead of the actual
	 * path name so that the script does not get opened twice
	 */
	if (imgp->ip_origvattr->va_mode & (VSUID | VSGID)) {
		p = vfs_context_proc(imgp->ip_vfs_context);
		error = falloc(p, &fp, &fd, imgp->ip_vfs_context);
		if (error)
			return(error);

		fp->f_fglob->fg_flag = FREAD;
		fp->f_fglob->fg_type = DTYPE_VNODE;
		fp->f_fglob->fg_ops = &vnops;
		fp->f_fglob->fg_data = (caddr_t)imgp->ip_vp;
		
		proc_fdlock(p);
		procfdtbl_releasefd(p, fd, NULL);
		fp_drop(p, fd, fp, 1);
		proc_fdunlock(p);
		vnode_ref(imgp->ip_vp);

		snprintf(temp, sizeof(temp), "/dev/fd/%d", fd);
		error = copyoutstr(temp, imgp->ip_user_fname, sizeof(temp), &len);
		if (error)
			return(error);
	}
#endif

	return (-3);
}


<|start_filename|>imgact_linux.h<|end_filename|>
#ifndef IMGACT_LINUX_H_INCLUDED
#define IMGACT_LINUX_H_INCLUDED

#include <sys/elf_common.h>
#include <elf.h>

/* Default path */
#define INTERP_PATH "/opt/local/libexec/noah -e -m /compat/linux -o /var/log/noah/output_%d.log -w /var/log/noah/warning_%d.log -s /var/log/noah/strace_%d.log"

typedef int (*ex_imgact_t)(struct image_params *);

extern ex_imgact_t orig_shell_imgact;

extern char interp_bufr[IMG_SHSIZE];

extern int elf_check_header(const Elf_Ehdr *hdr);

extern int my_exec_shell_imgact(struct image_params *imgp);

#endif
