patch-2.3.5 linux/fs/exec.c
Next file: linux/fs/file_table.c
Previous file: linux/fs/efs/symlink.c
Back to the patch index
Back to the overall index
- Lines: 213
- Date:
Wed Jun 2 13:50:07 1999
- Orig file:
v2.3.4/linux/fs/exec.c
- Orig date:
Mon May 31 22:28:06 1999
diff -u --recursive --new-file v2.3.4/linux/fs/exec.c linux/fs/exec.c
@@ -222,78 +222,64 @@
}
/*
- * 'copy_string()' copies argument/envelope strings from user
+ * 'copy_strings()' copies argument/envelope strings from user
* memory to free pages in kernel mem. These are in a format ready
* to be put directly into the top of new user memory.
- *
- * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies
- * whether the string and the string array are from user or kernel segments:
- *
- * from_kmem argv * argv **
- * 0 user space user space
- * 1 kernel space user space
- * 2 kernel space kernel space
- *
- * We do this by playing games with the fs segment register. Since it
- * is expensive to load a segment register, we try to avoid calling
- * set_fs() unless we absolutely have to.
- */
-unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
- unsigned long p, int from_kmem)
-{
- char *str;
- mm_segment_t old_fs;
-
- if (!p)
- return 0; /* bullet-proofing */
- old_fs = get_fs();
- if (from_kmem==2)
- set_fs(KERNEL_DS);
+ */
+int copy_strings(int argc,char ** argv, struct linux_binprm *bprm)
+{
while (argc-- > 0) {
+ char *str;
int len;
unsigned long pos;
- if (from_kmem == 1)
- set_fs(KERNEL_DS);
- get_user(str, argv+argc);
- if (!str)
- panic("VFS: argc is wrong");
- if (from_kmem == 1)
- set_fs(old_fs);
- len = strlen_user(str); /* includes the '\0' */
- if (p < len) { /* this shouldn't happen - 128kB */
- set_fs(old_fs);
- return 0;
- }
- p -= len;
- pos = p;
+ if (get_user(str, argv+argc) || !str || !(len = strlen_user(str)))
+ return -EFAULT;
+ if (bprm->p < len)
+ return -E2BIG;
+
+ bprm->p -= len;
+ /* XXX: add architecture specific overflow check here. */
+
+ pos = bprm->p;
while (len) {
char *pag;
int offset, bytes_to_copy;
offset = pos % PAGE_SIZE;
- if (!(pag = (char *) page[pos/PAGE_SIZE]) &&
- !(pag = (char *) page[pos/PAGE_SIZE] =
- (unsigned long *) get_free_page(GFP_USER))) {
- if (from_kmem==2)
- set_fs(old_fs);
- return 0;
- }
+ if (!(pag = (char *) bprm->page[pos/PAGE_SIZE]) &&
+ !(pag = (char *) bprm->page[pos/PAGE_SIZE] =
+ (unsigned long *) get_free_page(GFP_USER)))
+ return -ENOMEM;
+
bytes_to_copy = PAGE_SIZE - offset;
if (bytes_to_copy > len)
bytes_to_copy = len;
- copy_from_user(pag + offset, str, bytes_to_copy);
+ if (copy_from_user(pag + offset, str, bytes_to_copy))
+ return -EFAULT;
+
pos += bytes_to_copy;
str += bytes_to_copy;
len -= bytes_to_copy;
}
}
- if (from_kmem==2)
- set_fs(old_fs);
- return p;
+ return 0;
}
-unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm)
+/*
+ * Like copy_strings, but get argv and its values from kernel memory.
+ */
+int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm)
+{
+ int r;
+ mm_segment_t oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ r = copy_strings(argc, argv, bprm);
+ set_fs(oldfs);
+ return r;
+}
+
+int setup_arg_pages(struct linux_binprm *bprm)
{
unsigned long stack_base;
struct vm_area_struct *mpnt;
@@ -301,15 +287,18 @@
stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
- p += stack_base;
+ bprm->p += stack_base;
if (bprm->loader)
bprm->loader += stack_base;
bprm->exec += stack_base;
mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
- if (mpnt) {
+ if (!mpnt)
+ return -ENOMEM;
+
+ {
mpnt->vm_mm = current->mm;
- mpnt->vm_start = PAGE_MASK & (unsigned long) p;
+ mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
mpnt->vm_end = STACK_TOP;
mpnt->vm_page_prot = PAGE_COPY;
mpnt->vm_flags = VM_STACK_FLAGS;
@@ -319,7 +308,7 @@
mpnt->vm_pte = 0;
insert_vm_struct(current->mm, 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]) {
@@ -328,7 +317,8 @@
}
stack_base += PAGE_SIZE;
}
- return p;
+
+ return 0;
}
/*
@@ -804,8 +794,7 @@
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;
+ memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
dentry = open_namei(filename, 0, 0);
retval = PTR_ERR(dentry);
@@ -829,26 +818,34 @@
}
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)
+ goto out;
- if (retval >= 0)
- retval = search_binary_handler(&bprm,regs);
+ retval = copy_strings_kernel(1, &bprm.filename, &bprm);
+ if (retval < 0)
+ goto out;
+
+ bprm.exec = bprm.p;
+ retval = copy_strings(bprm.envc, envp, &bprm);
+ if (retval < 0)
+ goto out;
+
+ retval = copy_strings(bprm.argc, argv, &bprm);
+ if (retval < 0)
+ goto out;
+
+ retval = search_binary_handler(&bprm,regs);
if (retval >= 0)
/* execve success */
return retval;
+out:
/* Something went wrong, return the inode and free the argument pages*/
if (bprm.dentry)
dput(bprm.dentry);
+ /* Assumes that free_page() can take a NULL argument. */
+ /* I hope this is ok for all architectures */
for (i=0 ; i<MAX_ARG_PAGES ; i++)
free_page(bprm.page[i]);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)