Re: ETXTBUSY on shared libs (revised patch)

pacman (pacman-kernel@cqc.com)
Sat, 22 Aug 1998 23:37:19 -0500 (EST)


The first patch didn't cover mprotect. This one does, keeping PROT_EXEC and
MAP_DENYWRITE tied together.

=== CUT HERE ===
diff -ruN linux-2.0.35/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- linux-2.0.35/drivers/block/amiflop.c Thu May 16 01:05:10 1996
+++ linux/drivers/block/amiflop.c Thu Aug 20 23:33:08 1998
@@ -1617,7 +1617,7 @@
if (old_dev && old_dev != inode->i_rdev)
invalidate_buffers(old_dev);

- if (filp && filp->f_mode)
+ if (filp && (filp->f_mode & 3))
check_disk_change(inode->i_rdev);

if (filp && (filp->f_flags & (O_WRONLY|O_RDWR))) {
diff -ruN linux-2.0.35/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- linux-2.0.35/drivers/cdrom/cdrom.c Wed Jun 3 17:17:47 1998
+++ linux/drivers/cdrom/cdrom.c Thu Aug 20 22:38:19 1998
@@ -19,6 +19,7 @@
#include <linux/cdrom.h>
#include <linux/ucdrom.h>

+/* FMODE_WRITE not good enough for you? */
#define FM_WRITE 0x2 /* file mode write bit */

#define VERSION "$Id: cdrom.c,v 0.8 1996/08/10 10:52:11 david Exp $"
diff -ruN linux-2.0.35/fs/exec.c linux/fs/exec.c
--- linux-2.0.35/fs/exec.c Mon Jul 13 15:47:34 1998
+++ linux/fs/exec.c Thu Aug 20 23:32:28 1998
@@ -126,7 +126,7 @@
return -ENFILE;
}
f->f_flags = mode;
- f->f_mode = (mode+1) & O_ACCMODE;
+ f->f_mode = ((mode+1) & O_ACCMODE) | FMODE_EXEC;
f->f_inode = inode;
f->f_pos = 0;
f->f_reada = 0;
diff -ruN linux-2.0.35/fs/fifo.c linux/fs/fifo.c
--- linux-2.0.35/fs/fifo.c Mon Mar 11 04:23:22 1996
+++ linux/fs/fifo.c Thu Aug 20 22:53:02 1998
@@ -15,7 +15,7 @@
int retval = 0;
unsigned long page;

- switch( filp->f_mode ) {
+ switch( filp->f_mode & 3 ) {

case 1:
/*
diff -ruN linux-2.0.35/fs/open.c linux/fs/open.c
--- linux-2.0.35/fs/open.c Sat Nov 30 05:21:19 1996
+++ linux/fs/open.c Thu Aug 20 19:18:09 1998
@@ -522,6 +522,8 @@
if (error)
goto cleanup_inode;
}
+ if (!permission(inode, MAY_EXEC))
+ f->f_mode |= FMODE_EXEC;

f->f_inode = inode;
f->f_pos = 0;
diff -ruN linux-2.0.35/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.0.35/include/linux/fs.h Mon Jul 13 15:47:39 1998
+++ linux/include/linux/fs.h Thu Aug 20 18:38:13 1998
@@ -45,6 +45,7 @@

#define FMODE_READ 1
#define FMODE_WRITE 2
+#define FMODE_EXEC 4

#define READ 0
#define WRITE 1
diff -ruN linux-2.0.35/mm/mmap.c linux/mm/mmap.c
--- linux-2.0.35/mm/mmap.c Wed Jun 3 17:17:50 1998
+++ linux/mm/mmap.c Sat Aug 22 23:16:41 1998
@@ -190,6 +191,30 @@
default:
return -EINVAL;
}
+ if (prot & PROT_EXEC) {
+/* There are 2 ways to go on this permission check: set a FMODE_EXEC flag
+ * when the fd is created, or do it now. I prefer the former but it is a bit
+ * more complicated, so I can't be sure I haven't caused any bad side
+ * effects. Switch this #if around to do it the other way.
+ *
+ * The reason I don't like calling permission() from here because it means
+ * that a chmod can revoke permissions from an existing fd, and that doesn't
+ * occur for read and write permissions, so why should it for exec? It does
+ * look like fchdir does it this way, and that should probably be fixed too.
+ *
+ * There is another test like this one below, without the #if'ed out
+ * alternative, so if you change this one, change that one too. */
+#if 1
+ if (!(file->f_mode & FMODE_EXEC))
+ return -EACCES;
+#else
+ int error;
+ error = permission(file->f_inode, MAY_EXEC);
+ if (error)
+ return error;
+#endif
+ flags |= MAP_DENYWRITE;
+ }
if (flags & MAP_DENYWRITE) {
if (file->f_inode->i_writecount > 0)
return -ETXTBSY;
@@ -247,6 +272,8 @@
if (!(file->f_mode & 2))
vma->vm_flags &= ~(VM_MAYWRITE | VM_SHARED);
}
+ if (!(file->f_mode & FMODE_EXEC))
+ vma->vm_flags &= ~(VM_MAYEXEC);
} else
vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
diff -ruN linux-2.0.35/mm/mprotect.c linux/mm/mprotect.c
--- linux-2.0.35/mm/mprotect.c Wed Sep 11 09:57:19 1996
+++ linux/mm/mprotect.c Sat Aug 22 23:24:47 1998
@@ -231,6 +231,16 @@
break;
}

+ if(newflags & PROT_EXEC) {
+ if(vma->vm_inode && vma->vm_inode->i_writecount > 0) {
+ error = -ETXTBSY;
+ break;
+ }
+ newflags |= VM_DENYWRITE;
+ } else {
+ newflags &= ~VM_DENYWRITE;
+ }
+
if (vma->vm_end >= end) {
error = mprotect_fixup(vma, nstart, end, newflags);
break;
=== CUT HERE ===

-- 
Alan Curry

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.altern.org/andrebalsa/doc/lkml-faq.html