patch-2.4.0-prerelease linux/fs/exec.c

Next file: linux/fs/ext2/Makefile
Previous file: linux/fs/efs/symlink.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test12/linux/fs/exec.c linux/fs/exec.c
@@ -223,8 +223,6 @@
 					memset(kaddr+offset+len, 0, PAGE_SIZE-offset-len);
 			}
 			err = copy_from_user(kaddr + offset, str, bytes_to_copy);
-			flush_dcache_page(page);
-			flush_page_to_ram(page);
 			kunmap(page);
 
 			if (err)
@@ -281,6 +279,7 @@
 		__free_page(page);
 		return;
 	}
+	flush_dcache_page(page);
 	flush_page_to_ram(page);
 	set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY))));
 /* no need for flush_tlb */
@@ -314,9 +313,7 @@
 		mpnt->vm_pgoff = 0;
 		mpnt->vm_file = NULL;
 		mpnt->vm_private_data = (void *) 0;
-		spin_lock(&current->mm->page_table_lock);
 		insert_vm_struct(current->mm, mpnt);
-		spin_unlock(&current->mm->page_table_lock);
 		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
 	} 
 
@@ -597,7 +594,6 @@
 int prepare_binprm(struct linux_binprm *bprm)
 {
 	int mode;
-	int id_change,cap_raised;
 	struct inode * inode = bprm->file->f_dentry->d_inode;
 
 	mode = inode->i_mode;
@@ -609,25 +605,20 @@
 
 	bprm->e_uid = current->euid;
 	bprm->e_gid = current->egid;
-	id_change = cap_raised = 0;
 
-	/* Set-uid? */
-	if (mode & S_ISUID) {
-		bprm->e_uid = inode->i_uid;
-		if (bprm->e_uid != current->euid)
-			id_change = 1;
-	}
-
-	/* Set-gid? */
-	/*
-	 * If setgid is set but no group execute bit then this
-	 * is a candidate for mandatory locking, not a setgid
-	 * executable.
-	 */
-	if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
-		bprm->e_gid = inode->i_gid;
-		if (!in_group_p(bprm->e_gid))
-			id_change = 1;
+	if(!IS_NOSUID(inode)) {
+		/* Set-uid? */
+		if (mode & S_ISUID)
+			bprm->e_uid = inode->i_uid;
+
+		/* Set-gid? */
+		/*
+		 * If setgid is set but no group execute bit then this
+		 * is a candidate for mandatory locking, not a setgid
+		 * executable.
+		 */
+		if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
+			bprm->e_gid = inode->i_gid;
 	}
 
 	/* We don't have VFS support for capabilities yet */
@@ -652,39 +643,6 @@
 			cap_set_full(bprm->cap_effective);
 	}
 
-        /* Only if pP' is _not_ a subset of pP, do we consider there
-         * has been a capability related "change of capability".  In
-         * such cases, we need to check that the elevation of
-         * privilege does not go against other system constraints.
-         * The new Permitted set is defined below -- see (***). */
-	{
-		kernel_cap_t permitted, working;
-
-		permitted = cap_intersect(bprm->cap_permitted, cap_bset);
-		working = cap_intersect(bprm->cap_inheritable,
-					current->cap_inheritable);
-		working = cap_combine(permitted, working);
-		if (!cap_issubset(working, current->cap_permitted)) {
-			cap_raised = 1;
-		}
-	}
-
-	if (id_change || cap_raised) {
-		/* We can't suid-execute if we're sharing parts of the executable */
-		/* or if we're being traced (or if suid execs are not allowed)    */
-		/* (current->mm->mm_users > 1 is ok, as we'll get a new mm anyway)   */
-		if (IS_NOSUID(inode)
-		    || must_not_trace_exec(current)
-		    || (atomic_read(&current->fs->count) > 1)
-		    || (atomic_read(&current->sig->count) > 1)
-		    || (atomic_read(&current->files->count) > 1)) {
- 			if (id_change && !capable(CAP_SETUID))
- 				return -EPERM;
- 			if (cap_raised && !capable(CAP_SETPCAP))
-  				return -EPERM;
-		}
-	}
-
 	memset(bprm->buf,0,BINPRM_BUF_SIZE);
 	return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE);
 }
@@ -701,17 +659,41 @@
  *
  * I=Inheritable, P=Permitted, E=Effective // p=process, f=file
  * ' indicates post-exec(), and X is the global 'cap_bset'.
+ *
  */
 
 void compute_creds(struct linux_binprm *bprm) 
 {
 	kernel_cap_t new_permitted, working;
+	int do_unlock = 0;
 
 	new_permitted = cap_intersect(bprm->cap_permitted, cap_bset);
 	working = cap_intersect(bprm->cap_inheritable,
 				current->cap_inheritable);
 	new_permitted = cap_combine(new_permitted, working);
 
+	if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
+	    !cap_issubset(new_permitted, current->cap_permitted)) {
+                current->dumpable = 0;
+		
+		lock_kernel();
+		if (must_not_trace_exec(current)
+		    || atomic_read(&current->fs->count) > 1
+		    || atomic_read(&current->files->count) > 1
+		    || atomic_read(&current->sig->count) > 1) {
+			if(!capable(CAP_SETUID)) {
+				bprm->e_uid = current->uid;
+				bprm->e_gid = current->gid;
+			}
+			if(!capable(CAP_SETPCAP)) {
+				new_permitted = cap_intersect(new_permitted,
+							current->cap_permitted);
+			}
+		}
+		do_unlock = 1;
+	}
+
+
 	/* For init, we want to retain the capabilities set
          * in the init_task struct. Thus we skip the usual
          * capability rules */
@@ -725,10 +707,9 @@
 
         current->suid = current->euid = current->fsuid = bprm->e_uid;
         current->sgid = current->egid = current->fsgid = bprm->e_gid;
-        if (current->euid != current->uid || current->egid != current->gid ||
-	    !cap_issubset(new_permitted, current->cap_permitted))
-                current->dumpable = 0;
 
+	if(do_unlock)
+		unlock_kernel();
 	current->keep_capabilities = 0;
 }
 
@@ -768,29 +749,26 @@
 	/* handle /sbin/loader.. */
 	{
 	    struct exec * eh = (struct exec *) bprm->buf;
-	    struct linux_binprm bprm_loader;
 
 	    if (!bprm->loader && eh->fh.f_magic == 0x183 &&
 		(eh->fh.f_flags & 0x3000) == 0x3000)
 	    {
-		int i;
 		char * dynloader[] = { "/sbin/loader" };
 		struct file * file;
+		unsigned long loader;
 
 		allow_write_access(bprm->file);
 		fput(bprm->file);
 		bprm->file = NULL;
 
-	        bprm_loader.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-	        for (i = 0 ; i < MAX_ARG_PAGES ; i++)	/* clear page-table */
-                    bprm_loader.page[i] = NULL;
+	        loader = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
 
 		file = open_exec(dynloader[0]);
 		retval = PTR_ERR(file);
 		if (IS_ERR(file))
 			return retval;
 		bprm->file = file;
-		bprm->loader = bprm_loader.p;
+		bprm->loader = loader;
 		retval = prepare_binprm(bprm);
 		if (retval<0)
 			return retval;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)