patch-1.3.71 linux/fs/exec.c
Next file: linux/fs/ncpfs/dir.c
Previous file: linux/fs/buffer.c
Back to the patch index
Back to the overall index
- Lines: 491
- Date:
Sat Mar 2 20:29:23 1996
- Orig file:
v1.3.70/linux/fs/exec.c
- Orig date:
Fri Feb 23 13:54:36 1996
diff -u --recursive --new-file v1.3.70/linux/fs/exec.c linux/fs/exec.c
@@ -70,6 +70,8 @@
#ifdef CONFIG_BINFMT_AOUT
init_aout_binfmt();
#endif
+ /* This cannot be configured out of the kernel */
+ init_script_binfmt();
}
int register_binfmt(struct linux_binfmt * fmt)
@@ -104,6 +106,11 @@
}
return -EINVAL;
}
+
+struct linux_binfmt * get_binfmt_list()
+{
+ return formats;
+}
#endif /* CONFIG_MODULES */
int open_inode(struct inode * inode, int mode)
@@ -178,74 +185,6 @@
}
/*
- * create_tables() parses the env- and arg-strings in new user
- * memory and creates the pointer tables from them, and puts their
- * addresses on the "stack", returning the new stack pointer value.
- */
-unsigned long * create_tables(char * p, struct linux_binprm * bprm, int ibcs)
-{
- unsigned long *argv,*envp;
- unsigned long * sp;
- struct vm_area_struct *mpnt;
- int argc = bprm->argc;
- int envc = bprm->envc;
-
- mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
- if (mpnt) {
- mpnt->vm_mm = current->mm;
- mpnt->vm_start = PAGE_MASK & (unsigned long) p;
- mpnt->vm_end = STACK_TOP;
- mpnt->vm_page_prot = PAGE_COPY;
- mpnt->vm_flags = VM_STACK_FLAGS;
- mpnt->vm_ops = NULL;
- mpnt->vm_offset = 0;
- mpnt->vm_inode = NULL;
- mpnt->vm_pte = 0;
- insert_vm_struct(current, mpnt);
- current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
- }
- sp = (unsigned long *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p);
-#ifdef __alpha__
-/* whee.. test-programs are so much fun. */
- put_user(0, --sp);
- put_user(0, --sp);
- if (bprm->loader) {
- put_user(0, --sp);
- put_user(0x3eb, --sp);
- put_user(bprm->loader, --sp);
- put_user(0x3ea, --sp);
- }
- put_user(bprm->exec, --sp);
- put_user(0x3e9, --sp);
-#endif
- sp -= envc+1;
- envp = sp;
- sp -= argc+1;
- argv = sp;
-#ifdef __i386__
- if (!ibcs) {
- put_user(envp,--sp);
- put_user(argv,--sp);
- }
-#endif
- put_user(argc,--sp);
- current->mm->arg_start = (unsigned long) p;
- while (argc-->0) {
- put_user(p,argv++);
- while (get_user(p++)) /* nothing */ ;
- }
- put_user(NULL,argv);
- current->mm->arg_end = current->mm->env_start = (unsigned long) p;
- while (envc-->0) {
- put_user(p,envp++);
- while (get_user(p++)) /* nothing */ ;
- }
- put_user(NULL,envp);
- current->mm->env_end = (unsigned long) p;
- return sp;
-}
-
-/*
* count() counts the number of arguments/envelopes
*
* We also do some limited EFAULT checking: this isn't complete, but
@@ -344,20 +283,42 @@
return p;
}
-unsigned long setup_arg_pages(unsigned long text_size, unsigned long * page)
+unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm)
{
- unsigned long data_base;
+ unsigned long stack_base;
+ struct vm_area_struct *mpnt;
int i;
- data_base = STACK_TOP;
- for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
- data_base -= PAGE_SIZE;
- if (page[i]) {
+ stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
+
+ p += stack_base;
+ if (bprm->loader)
+ bprm->loader += stack_base;
+ bprm->exec += stack_base;
+
+ mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
+ if (mpnt) {
+ mpnt->vm_mm = current->mm;
+ mpnt->vm_start = PAGE_MASK & (unsigned long) p;
+ mpnt->vm_end = STACK_TOP;
+ mpnt->vm_page_prot = PAGE_COPY;
+ mpnt->vm_flags = VM_STACK_FLAGS;
+ mpnt->vm_ops = NULL;
+ mpnt->vm_offset = 0;
+ mpnt->vm_inode = NULL;
+ mpnt->vm_pte = 0;
+ insert_vm_struct(current, mpnt);
+ current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
+ }
+
+ for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+ if (bprm->page[i]) {
current->mm->rss++;
- put_dirty_page(current,page[i],data_base);
+ put_dirty_page(current,bprm->page[i],stack_base);
}
+ stack_base += PAGE_SIZE;
}
- return STACK_TOP;
+ return p;
}
/*
@@ -485,195 +446,111 @@
current->used_math = 0;
}
-/*
- * sys_execve() executes a new program.
+/*
+ * Fill the binprm structure from the inode.
+ * Check permissions, then read the first 512 bytes
*/
-int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
+int prepare_binprm(struct linux_binprm *bprm)
{
- struct linux_binprm bprm;
- struct linux_binfmt * fmt;
- int i;
- int retval;
- int sh_bang = 0;
- int try;
-#ifdef __alpha__
- int loader = 0;
-#endif
-
- bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
- for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
- bprm.page[i] = 0;
- retval = open_namei(filename, 0, 0, &bprm.inode, NULL);
- if (retval)
- return retval;
- bprm.filename = filename;
- bprm.loader = 0;
- bprm.exec = 0;
- if ((bprm.argc = count(argv)) < 0)
- return bprm.argc;
- if ((bprm.envc = count(envp)) < 0)
- return bprm.envc;
-
-restart_interp:
- if (!S_ISREG(bprm.inode->i_mode)) { /* must be regular file */
- retval = -EACCES;
- goto exec_error2;
- }
- if (IS_NOEXEC(bprm.inode)) { /* FS mustn't be mounted noexec */
- retval = -EPERM;
- goto exec_error2;
- }
- if (!bprm.inode->i_sb) {
- retval = -EACCES;
- goto exec_error2;
- }
- i = bprm.inode->i_mode;
- if (IS_NOSUID(bprm.inode) && (((i & S_ISUID) && bprm.inode->i_uid != current->
- euid) || ((i & S_ISGID) && !in_group_p(bprm.inode->i_gid))) && !suser()) {
- retval = -EPERM;
- goto exec_error2;
- }
+ int retval,i;
+ if (!S_ISREG(bprm->inode->i_mode)) /* must be regular file */
+ return -EACCES;
+ if (IS_NOEXEC(bprm->inode)) /* FS mustn't be mounted noexec */
+ return -EACCES;
+ if (!bprm->inode->i_sb)
+ return -EACCES;
+ i = bprm->inode->i_mode;
+ if (IS_NOSUID(bprm->inode) &&
+ (((i & S_ISUID) && bprm->inode->i_uid != current->euid)
+ || ((i & S_ISGID) && !in_group_p(bprm->inode->i_gid))) && !suser())
+ return -EPERM;
/* make sure we don't let suid, sgid files be ptraced. */
if (current->flags & PF_PTRACED) {
- bprm.e_uid = current->euid;
- bprm.e_gid = current->egid;
+ bprm->e_uid = current->euid;
+ bprm->e_gid = current->egid;
} else {
- bprm.e_uid = (i & S_ISUID) ? bprm.inode->i_uid : current->euid;
- bprm.e_gid = (i & S_ISGID) ? bprm.inode->i_gid : current->egid;
- }
- if ((retval = permission(bprm.inode, MAY_EXEC)) != 0)
- goto exec_error2;
- if (!(bprm.inode->i_mode & 0111) && fsuser()) {
- retval = -EACCES;
- goto exec_error2;
+ bprm->e_uid = (i & S_ISUID) ? bprm->inode->i_uid : current->euid;
+ bprm->e_gid = (i & S_ISGID) ? bprm->inode->i_gid : current->egid;
}
+ if ((retval = permission(bprm->inode, MAY_EXEC)) != 0)
+ return retval;
+ if (!(bprm->inode->i_mode & 0111) && fsuser())
+ return -EACCES;
/* better not execute files which are being written to */
- if (bprm.inode->i_writecount > 0) {
- retval = -ETXTBSY;
- goto exec_error2;
- }
- memset(bprm.buf,0,sizeof(bprm.buf));
- retval = read_exec(bprm.inode,0,bprm.buf,128,1);
- if (retval < 0)
- goto exec_error2;
- if ((bprm.buf[0] == '#') && (bprm.buf[1] == '!') && (!sh_bang)) {
- /*
- * This section does the #! interpretation.
- * Sorta complicated, but hopefully it will work. -TYT
- */
+ if (bprm->inode->i_writecount > 0)
+ return -ETXTBSY;
- char *cp, *interp, *i_name, *i_arg;
+ memset(bprm->buf,0,sizeof(bprm->buf));
+ return read_exec(bprm->inode,0,bprm->buf,128,1);
+}
- iput(bprm.inode);
- bprm.buf[127] = '\0';
- if ((cp = strchr(bprm.buf, '\n')) == NULL)
- cp = bprm.buf+127;
- *cp = '\0';
- while (cp > bprm.buf) {
- cp--;
- if ((*cp == ' ') || (*cp == '\t'))
- *cp = '\0';
- else
- break;
- }
- for (cp = bprm.buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
- if (!cp || *cp == '\0') {
- retval = -ENOEXEC; /* No interpreter name found */
- goto exec_error1;
- }
- interp = i_name = cp;
- i_arg = 0;
- for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
- if (*cp == '/')
- i_name = cp+1;
- }
- while ((*cp == ' ') || (*cp == '\t'))
- *cp++ = '\0';
- if (*cp)
- i_arg = cp;
- /*
- * OK, we've parsed out the interpreter name and
- * (optional) argument.
- */
- if (sh_bang++ == 0) {
- bprm.p = copy_strings(bprm.envc, envp, bprm.page, bprm.p, 0);
- bprm.p = copy_strings(--bprm.argc, argv+1, bprm.page, bprm.p, 0);
- }
- /*
- * Splice in (1) the interpreter's name for argv[0]
- * (2) (optional) argument to interpreter
- * (3) filename of shell script
- *
- * This is done in reverse order, because of how the
- * user environment and arguments are stored.
- */
- bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2);
- bprm.argc++;
- if (i_arg) {
- bprm.p = copy_strings(1, &i_arg, bprm.page, bprm.p, 2);
- bprm.argc++;
- }
- bprm.p = copy_strings(1, &i_name, bprm.page, bprm.p, 2);
- bprm.argc++;
- if (!bprm.p) {
- retval = -E2BIG;
- goto exec_error1;
- }
- /*
- * OK, now restart the process with the interpreter's inode.
- * Note that we use open_namei() as the name is now in kernel
- * space, and we don't need to copy it.
- */
- retval = open_namei(interp, 0, 0, &bprm.inode, NULL);
- if (retval)
- goto exec_error1;
- goto restart_interp;
+void remove_arg_zero(struct linux_binprm *bprm)
+{
+ if (bprm->argc) {
+ unsigned long offset;
+ char * page;
+ offset = bprm->p % PAGE_SIZE;
+ page = (char*)bprm->page[bprm->p/PAGE_SIZE];
+ while(bprm->p++,*(page+offset++))
+ if(offset==PAGE_SIZE){
+ offset=0;
+ page = (char*)bprm->page[bprm->p/PAGE_SIZE];
+ }
+ bprm->argc--;
}
+}
+
+/*
+ * cycle the list of binary formats handler, until one recognizes the image
+ */
+int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
+{
+ int try,retval=0;
+ struct linux_binfmt *fmt;
#ifdef __alpha__
/* handle /sbin/loader.. */
{
- struct exec * eh = (struct exec *) bprm.buf;
+ struct exec * eh = (struct exec *) bprm->buf;
- if (!loader && eh->fh.f_magic == 0x183 &&
+ if (!bprm->loader && eh->fh.f_magic == 0x183 &&
(eh->fh.f_flags & 0x3000) == 0x3000)
{
char * dynloader[] = { "/sbin/loader" };
- iput(bprm.inode);
- loader = 1;
- bprm.p = copy_strings(1, dynloader, bprm.page, bprm.p, 2);
- bprm.loader = bprm.p;
- retval = open_namei(dynloader[0], 0, 0, &bprm.inode, NULL);
+ iput(bprm->inode);
+ bprm->dont_iput = 1;
+ remove_arg_zero(bprm);
+ bprm->p = copy_strings(1, dynloader, bprm->page, bprm->p, 2);
+ bprm->argc++;
+ bprm->loader = bprm->p;
+ retval = open_namei(dynloader[0], 0, 0, &bprm->inode, NULL);
if (retval)
- goto exec_error1;
- goto restart_interp;
+ return retval;
+ bprm->dont_iput = 0;
+ retval = prepare_binprm(bprm);
+ if (retval<0)
+ return retval;
+ /* should call search_binary_handler recursively here,
+ but it does not matter */
}
}
#endif
- if (!sh_bang) {
- bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2);
- bprm.exec = bprm.p;
- bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p,0);
- bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p,0);
- if (!bprm.p) {
- retval = -E2BIG;
- goto exec_error2;
- }
- }
-
- bprm.sh_bang = sh_bang;
for (try=0; try<2; try++) {
- for (fmt = formats ; fmt ; fmt = fmt->next) {
+ for (fmt = get_binfmt_list() ; fmt ; fmt = fmt->next) {
int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
if (!fn)
continue;
- retval = fn(&bprm, regs);
+ retval = fn(bprm, regs);
if (retval >= 0) {
- iput(bprm.inode);
+ if(!bprm->dont_iput)
+ iput(bprm->inode);
+ bprm->dont_iput=1;
current->did_exec = 1;
return retval;
}
if (retval != -ENOEXEC)
break;
+ if (bprm->dont_iput) /* We don't have the inode anymore*/
+ return retval;
}
if (retval != -ENOEXEC) {
break;
@@ -681,19 +558,65 @@
}else{
#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
char modname[20];
- if (printable(bprm.buf[0]) &&
- printable(bprm.buf[1]) &&
- printable(bprm.buf[2]) &&
- printable(bprm.buf[3]))
+ if (printable(bprm->buf[0]) &&
+ printable(bprm->buf[1]) &&
+ printable(bprm->buf[2]) &&
+ printable(bprm->buf[3]))
break; /* -ENOEXEC */
- sprintf(modname, "binfmt-%hd", *(short*)(&bprm.buf));
+ sprintf(modname, "binfmt-%hd", *(short*)(&bprm->buf));
request_module(modname);
#endif
}
}
-exec_error2:
- iput(bprm.inode);
-exec_error1:
+ return retval;
+}
+
+
+/*
+ * sys_execve() executes a new program.
+ */
+int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
+{
+ struct linux_binprm bprm;
+ int retval;
+ int i;
+
+ bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+ for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
+ bprm.page[i] = 0;
+ retval = open_namei(filename, 0, 0, &bprm.inode, NULL);
+ if (retval)
+ return retval;
+ bprm.filename = filename;
+ bprm.sh_bang = 0;
+ bprm.loader = 0;
+ bprm.exec = 0;
+ bprm.dont_iput = 0;
+ if ((bprm.argc = count(argv)) < 0)
+ return bprm.argc;
+ if ((bprm.envc = count(envp)) < 0)
+ return bprm.envc;
+
+ retval = prepare_binprm(&bprm);
+
+ if(retval>=0) {
+ bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2);
+ bprm.exec = bprm.p;
+ bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p,0);
+ bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p,0);
+ if (!bprm.p)
+ retval = -E2BIG;
+ }
+
+ if(retval>=0)
+ retval = search_binary_handler(&bprm,regs);
+ if(retval>=0)
+ /* execve success */
+ return retval;
+
+ /* Something went wrong, return the inode and free the argument pages*/
+ if(!bprm.dont_iput)
+ iput(bprm.inode);
for (i=0 ; i<MAX_ARG_PAGES ; i++)
free_page(bprm.page[i]);
return(retval);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this