Re: [RFC] "Text file busy" when overwriting libraries

Eric W. Biederman (ebiederm@xmission.com)
15 Oct 2001 04:11:20 -0600


Linus Torvalds <torvalds@transmeta.com> writes:

> On Mon, 15 Oct 2001, Alan Cox wrote:
> >
> > > We already can open an exec only file just open("file", 0).
> >
> > Wrong.

Grr. All of that munging about with the permission bits confused me.

We do allow a no permission open in open_namei (which is what
I was staring at), we just can't generate it with filp_open. So my
open_exec needs to call open_namei directly oh well. I never intended
to allow a weird case like that, or imply that I would allow it.

Since I now have the permission checks seperate between user space,
and kernel space. I have added an additional check that O_EXEC
fails if anyone has write permission to the file. So the permissions
must be r-xr-xr-x on the file.

Just to reiterate I see this as a solution to two problems
1) It adds an additional safety check that shared libraries won't
mutate under you.
2) It allows user space access to the security policy information
regarding executables. Allowing ld-linux.so to refust to
execute binaries, and shared libaries on a filesystem mounted
noexec.

And even if this doesn't get exported to user space I see this as
a small code cleanup. That simplifies MAP_DENYWRITE implementation.

My biggest unresolved issue is which numbers to choose for O_EXEC on
every platform. As the DENYWRITE code is cleaner in open than in mmap.

Eric

diff -uNrX linux-ignore-files linux-2.4.12/Documentation/Changes linux-2.4.12.eb3/Documentation/Changes
--- linux-2.4.12/Documentation/Changes Sat Oct 13 16:19:40 2001
+++ linux-2.4.12.eb3/Documentation/Changes Sun Oct 14 01:39:38 2001
@@ -126,6 +126,13 @@

32-bit UID support is now in place. Have fun!

+A new flag O_EXEC has been added to the open call. While a file
+is opened O_EXEC you get ETXTBSY errors if you attempt to write it.
+This allows shared libraries to have the same garanutee against
+changes as normal executables do. The permissions requirements
+to open a file O_EXEC are (a) no one has it open read/write and
+(b) that the open has execute permissions on the file.
+
Linux documentation for functions is transitioning to inline
documentation via specially-formatted comments near their
definitions in the source. These comments can be combined with the
diff -uNrX linux-ignore-files linux-2.4.12/arch/alpha/kernel/osf_sys.c linux-2.4.12.eb3/arch/alpha/kernel/osf_sys.c
--- linux-2.4.12/arch/alpha/kernel/osf_sys.c Sat Oct 13 16:18:56 2001
+++ linux-2.4.12.eb3/arch/alpha/kernel/osf_sys.c Sat Oct 13 17:15:04 2001
@@ -240,7 +240,7 @@
if (!file)
goto out;
}
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
down_write(&current->mm->mmap_sem);
ret = do_mmap(file, addr, len, prot, flags, off);
up_write(&current->mm->mmap_sem);
diff -uNrX linux-ignore-files linux-2.4.12/arch/arm/kernel/sys_arm.c linux-2.4.12.eb3/arch/arm/kernel/sys_arm.c
--- linux-2.4.12/arch/arm/kernel/sys_arm.c Wed Jul 25 03:08:24 2001
+++ linux-2.4.12.eb3/arch/arm/kernel/sys_arm.c Sat Oct 13 17:07:57 2001
@@ -58,7 +58,7 @@
int error = -EINVAL;
struct file * file = NULL;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);

/*
* If we are doing a fixed mapping, and address < PAGE_SIZE,
diff -uNrX linux-ignore-files linux-2.4.12/arch/cris/kernel/sys_cris.c linux-2.4.12.eb3/arch/cris/kernel/sys_cris.c
--- linux-2.4.12/arch/cris/kernel/sys_cris.c Sat Aug 11 09:50:04 2001
+++ linux-2.4.12.eb3/arch/cris/kernel/sys_cris.c Sat Oct 13 17:14:06 2001
@@ -52,7 +52,7 @@
int error = -EBADF;
struct file * file = NULL;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
diff -uNrX linux-ignore-files linux-2.4.12/arch/i386/kernel/sys_i386.c linux-2.4.12.eb3/arch/i386/kernel/sys_i386.c
--- linux-2.4.12/arch/i386/kernel/sys_i386.c Sat Apr 14 13:36:44 2001
+++ linux-2.4.12.eb3/arch/i386/kernel/sys_i386.c Sat Oct 13 17:08:07 2001
@@ -48,7 +48,7 @@
int error = -EBADF;
struct file * file = NULL;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
diff -uNrX linux-ignore-files linux-2.4.12/arch/ia64/ia32/sys_ia32.c linux-2.4.12.eb3/arch/ia64/ia32/sys_ia32.c
--- linux-2.4.12/arch/ia64/ia32/sys_ia32.c Sat Oct 13 16:18:57 2001
+++ linux-2.4.12.eb3/arch/ia64/ia32/sys_ia32.c Sat Oct 13 17:15:34 2001
@@ -282,7 +282,7 @@
long error = -EFAULT;
unsigned int poff;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
prot |= PROT_EXEC;

if ((flags & MAP_FIXED) && ((addr & ~PAGE_MASK) || (offset & ~PAGE_MASK)))
diff -uNrX linux-ignore-files linux-2.4.12/arch/ia64/kernel/sys_ia64.c linux-2.4.12.eb3/arch/ia64/kernel/sys_ia64.c
--- linux-2.4.12/arch/ia64/kernel/sys_ia64.c Sat Aug 11 09:50:05 2001
+++ linux-2.4.12.eb3/arch/ia64/kernel/sys_ia64.c Sat Oct 13 17:10:39 2001
@@ -178,7 +178,7 @@
unsigned long roff;
struct file *file = 0;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
diff -uNrX linux-ignore-files linux-2.4.12/arch/m68k/kernel/sys_m68k.c linux-2.4.12.eb3/arch/m68k/kernel/sys_m68k.c
--- linux-2.4.12/arch/m68k/kernel/sys_m68k.c Wed Jul 25 03:07:49 2001
+++ linux-2.4.12.eb3/arch/m68k/kernel/sys_m68k.c Sat Oct 13 17:11:13 2001
@@ -52,7 +52,7 @@
int error = -EBADF;
struct file * file = NULL;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
@@ -104,7 +104,7 @@
if (a.offset & ~PAGE_MASK)
goto out;

- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ a.flags &= ~(MAP_EXECUTABLE);

error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
out:
@@ -144,7 +144,7 @@
if (!file)
goto out;
}
- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ a.flags &= ~(MAP_EXECUTABLE);

down_write(&current->mm->mmap_sem);
error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff);
diff -uNrX linux-ignore-files linux-2.4.12/arch/mips/kernel/irixelf.c linux-2.4.12.eb3/arch/mips/kernel/irixelf.c
--- linux-2.4.12/arch/mips/kernel/irixelf.c Sat Apr 14 13:36:44 2001
+++ linux-2.4.12.eb3/arch/mips/kernel/irixelf.c Sun Oct 14 00:35:14 2001
@@ -298,7 +298,7 @@
eppnt = elf_phdata;
for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
if(eppnt->p_type == PT_LOAD) {
- int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+ int elf_type = MAP_PRIVATE;
int elf_prot = 0;
unsigned long vaddr = 0;
if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
@@ -479,7 +479,7 @@
return 0;
}

-#define EXEC_MAP_FLAGS (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE)
+#define EXEC_MAP_FLAGS (MAP_FIXED | MAP_PRIVATE | MAP_EXECUTABLE)

static inline void map_executable(struct file *fp, struct elf_phdr *epp, int pnum,
unsigned int *estack, unsigned int *laddr,
@@ -776,7 +776,6 @@
return retval;

out_free_dentry:
- allow_write_access(interpreter);
fput(interpreter);
out_free_interp:
if (elf_interpreter)
@@ -842,7 +841,7 @@
elf_phdata->p_vaddr & 0xfffff000,
elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff),
PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+ MAP_FIXED | MAP_PRIVATE,
elf_phdata->p_offset & 0xfffff000);
up_write(&current->mm->mmap_sem);

@@ -919,7 +918,7 @@
down_write(&current->mm->mmap_sem);
retval = do_mmap(filp, (hp->p_vaddr & 0xfffff000),
(hp->p_filesz + (hp->p_vaddr & 0xfff)),
- prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
+ prot, (MAP_FIXED | MAP_PRIVATE),
(hp->p_offset & 0xfffff000));
up_write(&current->mm->mmap_sem);

diff -uNrX linux-ignore-files linux-2.4.12/arch/mips/kernel/syscall.c linux-2.4.12.eb3/arch/mips/kernel/syscall.c
--- linux-2.4.12/arch/mips/kernel/syscall.c Wed Jul 25 03:07:50 2001
+++ linux-2.4.12.eb3/arch/mips/kernel/syscall.c Sat Oct 13 17:11:32 2001
@@ -62,7 +62,7 @@
int error = -EBADF;
struct file * file = NULL;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
diff -uNrX linux-ignore-files linux-2.4.12/arch/mips/kernel/sysirix.c linux-2.4.12.eb3/arch/mips/kernel/sysirix.c
--- linux-2.4.12/arch/mips/kernel/sysirix.c Sat Oct 13 16:18:57 2001
+++ linux-2.4.12.eb3/arch/mips/kernel/sysirix.c Sat Oct 13 17:16:16 2001
@@ -1080,7 +1080,7 @@
}
}

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);

down_write(&current->mm->mmap_sem);
retval = do_mmap(file, addr, len, prot, flags, offset);
@@ -1640,7 +1640,7 @@
}
}

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);

down_write(&current->mm->mmap_sem);
error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
diff -uNrX linux-ignore-files linux-2.4.12/arch/mips64/kernel/syscall.c linux-2.4.12.eb3/arch/mips64/kernel/syscall.c
--- linux-2.4.12/arch/mips64/kernel/syscall.c Sat Oct 13 16:19:43 2001
+++ linux-2.4.12.eb3/arch/mips64/kernel/syscall.c Sat Oct 13 17:11:45 2001
@@ -63,7 +63,7 @@
if (!file)
goto out;
}
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);

down_write(&current->mm->mmap_sem);
error = do_mmap(file, addr, len, prot, flags, offset);
diff -uNrX linux-ignore-files linux-2.4.12/arch/parisc/kernel/sys_parisc.c linux-2.4.12.eb3/arch/parisc/kernel/sys_parisc.c
--- linux-2.4.12/arch/parisc/kernel/sys_parisc.c Sat Apr 14 13:36:45 2001
+++ linux-2.4.12.eb3/arch/parisc/kernel/sys_parisc.c Sat Oct 13 17:13:55 2001
@@ -59,7 +59,7 @@
if (!file)
goto out;
}
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
error = do_mmap(file, addr, len, prot, flags, offset);
if (file != NULL)
fput(file);
diff -uNrX linux-ignore-files linux-2.4.12/arch/ppc/kernel/syscalls.c linux-2.4.12.eb3/arch/ppc/kernel/syscalls.c
--- linux-2.4.12/arch/ppc/kernel/syscalls.c Wed Jul 25 03:07:25 2001
+++ linux-2.4.12.eb3/arch/ppc/kernel/syscalls.c Sat Oct 13 17:12:01 2001
@@ -196,7 +196,7 @@
struct file * file = NULL;
int ret = -EBADF;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
if (!(flags & MAP_ANONYMOUS)) {
if (!(file = fget(fd)))
goto out;
diff -uNrX linux-ignore-files linux-2.4.12/arch/s390/kernel/sys_s390.c linux-2.4.12.eb3/arch/s390/kernel/sys_s390.c
--- linux-2.4.12/arch/s390/kernel/sys_s390.c Sat Apr 14 13:36:45 2001
+++ linux-2.4.12.eb3/arch/s390/kernel/sys_s390.c Sat Oct 13 17:13:33 2001
@@ -54,7 +54,7 @@
int error = -EBADF;
struct file * file = NULL;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
diff -uNrX linux-ignore-files linux-2.4.12/arch/s390x/kernel/linux32.c linux-2.4.12.eb3/arch/s390x/kernel/linux32.c
--- linux-2.4.12/arch/s390x/kernel/linux32.c Sat Oct 13 16:18:57 2001
+++ linux-2.4.12.eb3/arch/s390x/kernel/linux32.c Sat Oct 13 20:13:59 2001
@@ -2923,12 +2923,10 @@
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count32(argv)) < 0) {
- allow_write_access(file);
fput(file);
return bprm.argc;
}
if ((bprm.envc = count32(envp)) < 0) {
- allow_write_access(file);
fput(file);
return bprm.envc;
}
@@ -2957,7 +2955,6 @@

out:
/* Something went wrong, return the inode and free the argument pages*/
- allow_write_access(bprm.file);
if (bprm.file)
fput(bprm.file);

@@ -4179,7 +4176,7 @@
struct file * file = NULL;
unsigned long error = -EBADF;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
diff -uNrX linux-ignore-files linux-2.4.12/arch/s390x/kernel/sys_s390.c linux-2.4.12.eb3/arch/s390x/kernel/sys_s390.c
--- linux-2.4.12/arch/s390x/kernel/sys_s390.c Thu May 3 01:46:43 2001
+++ linux-2.4.12.eb3/arch/s390x/kernel/sys_s390.c Sat Oct 13 17:14:23 2001
@@ -54,7 +54,7 @@
long error = -EBADF;
struct file * file = NULL;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
diff -uNrX linux-ignore-files linux-2.4.12/arch/sh/kernel/sys_sh.c linux-2.4.12.eb3/arch/sh/kernel/sys_sh.c
--- linux-2.4.12/arch/sh/kernel/sys_sh.c Sat Oct 13 16:19:45 2001
+++ linux-2.4.12.eb3/arch/sh/kernel/sys_sh.c Sat Oct 13 17:12:17 2001
@@ -89,7 +89,7 @@
int error = -EBADF;
struct file *file = NULL;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
diff -uNrX linux-ignore-files linux-2.4.12/arch/sparc/kernel/sys_sparc.c linux-2.4.12.eb3/arch/sparc/kernel/sys_sparc.c
--- linux-2.4.12/arch/sparc/kernel/sys_sparc.c Thu May 3 01:46:43 2001
+++ linux-2.4.12.eb3/arch/sparc/kernel/sys_sparc.c Sat Oct 13 17:12:40 2001
@@ -240,7 +240,7 @@
if (len > TASK_SIZE - PAGE_SIZE || addr + len > TASK_SIZE - PAGE_SIZE)
goto out_putf;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);

down_write(&current->mm->mmap_sem);
retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
diff -uNrX linux-ignore-files linux-2.4.12/arch/sparc/kernel/sys_sunos.c linux-2.4.12.eb3/arch/sparc/kernel/sys_sunos.c
--- linux-2.4.12/arch/sparc/kernel/sys_sunos.c Sat Oct 13 16:18:57 2001
+++ linux-2.4.12.eb3/arch/sparc/kernel/sys_sunos.c Sun Oct 14 00:35:47 2001
@@ -115,7 +115,7 @@
goto out_putf;
}

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
down_write(&current->mm->mmap_sem);
retval = do_mmap(file, addr, len, prot, flags, off);
up_write(&current->mm->mmap_sem);
diff -uNrX linux-ignore-files linux-2.4.12/arch/sparc64/kernel/binfmt_aout32.c linux-2.4.12.eb3/arch/sparc64/kernel/binfmt_aout32.c
--- linux-2.4.12/arch/sparc64/kernel/binfmt_aout32.c Wed Jul 25 03:08:26 2001
+++ linux-2.4.12.eb3/arch/sparc64/kernel/binfmt_aout32.c Sun Oct 14 00:36:22 2001
@@ -280,7 +280,7 @@
down_write(&current->mm->mmap_sem);
error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
+ MAP_FIXED | MAP_PRIVATE | MAP_EXECUTABLE,
fd_offset);
up_write(&current->mm->mmap_sem);

@@ -292,7 +292,7 @@
down_write(&current->mm->mmap_sem);
error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
+ MAP_FIXED | MAP_PRIVATE | MAP_EXECUTABLE,
fd_offset + ex.a_text);
up_write(&current->mm->mmap_sem);
if (error != N_DATADDR(ex)) {
@@ -372,7 +372,7 @@
down_write(&current->mm->mmap_sem);
error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+ MAP_FIXED | MAP_PRIVATE,
N_TXTOFF(ex));
up_write(&current->mm->mmap_sem);
retval = error;
diff -uNrX linux-ignore-files linux-2.4.12/arch/sparc64/kernel/sys_sparc.c linux-2.4.12.eb3/arch/sparc64/kernel/sys_sparc.c
--- linux-2.4.12/arch/sparc64/kernel/sys_sparc.c Thu May 3 01:46:44 2001
+++ linux-2.4.12.eb3/arch/sparc64/kernel/sys_sparc.c Sat Oct 13 17:13:19 2001
@@ -277,7 +277,7 @@
if (!file)
goto out;
}
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
len = PAGE_ALIGN(len);
retval = -EINVAL;

diff -uNrX linux-ignore-files linux-2.4.12/arch/sparc64/kernel/sys_sparc32.c linux-2.4.12.eb3/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.12/arch/sparc64/kernel/sys_sparc32.c Sat Oct 13 16:21:40 2001
+++ linux-2.4.12.eb3/arch/sparc64/kernel/sys_sparc32.c Sat Oct 13 20:28:49 2001
@@ -2998,12 +2998,10 @@
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count32(argv, bprm.p / sizeof(u32))) < 0) {
- allow_write_access(file);
fput(file);
return bprm.argc;
}
if ((bprm.envc = count32(envp, bprm.p / sizeof(u32))) < 0) {
- allow_write_access(file);
fput(file);
return bprm.envc;
}
@@ -3032,7 +3030,6 @@

out:
/* Something went wrong, return the inode and free the argument pages*/
- allow_write_access(bprm.file);
if (bprm.file)
fput(bprm.file);

diff -uNrX linux-ignore-files linux-2.4.12/arch/sparc64/kernel/sys_sunos32.c linux-2.4.12.eb3/arch/sparc64/kernel/sys_sunos32.c
--- linux-2.4.12/arch/sparc64/kernel/sys_sunos32.c Sat Oct 13 16:18:58 2001
+++ linux-2.4.12.eb3/arch/sparc64/kernel/sys_sunos32.c Sat Oct 13 17:16:57 2001
@@ -99,7 +99,7 @@
ret_type = flags & _MAP_NEW;
flags &= ~_MAP_NEW;

- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
down_write(&current->mm->mmap_sem);
retval = do_mmap(file,
(unsigned long) addr, (unsigned long) len,
diff -uNrX linux-ignore-files linux-2.4.12/arch/sparc64/solaris/misc.c linux-2.4.12.eb3/arch/sparc64/solaris/misc.c
--- linux-2.4.12/arch/sparc64/solaris/misc.c Sat Oct 13 16:19:45 2001
+++ linux-2.4.12.eb3/arch/sparc64/solaris/misc.c Sat Oct 13 17:17:17 2001
@@ -93,7 +93,7 @@
flags &= ~_MAP_NEW;

down_write(&current->mm->mmap_sem);
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ flags &= ~(MAP_EXECUTABLE);
retval = do_mmap(file,
(unsigned long) addr, (unsigned long) len,
(unsigned long) prot, (unsigned long) flags, off);
Binary files linux-2.4.12/drivers/net/hamradio/soundmodem/gentbl and linux-2.4.12.eb3/drivers/net/hamradio/soundmodem/gentbl differ
diff -uNrX linux-ignore-files linux-2.4.12/fs/binfmt_aout.c linux-2.4.12.eb3/fs/binfmt_aout.c
--- linux-2.4.12/fs/binfmt_aout.c Sat Oct 13 16:21:50 2001
+++ linux-2.4.12.eb3/fs/binfmt_aout.c Sun Oct 14 00:59:39 2001
@@ -380,7 +380,7 @@
down_write(&current->mm->mmap_sem);
error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
+ MAP_FIXED | MAP_PRIVATE | MAP_EXECUTABLE,
fd_offset);
up_write(&current->mm->mmap_sem);

@@ -392,7 +392,7 @@
down_write(&current->mm->mmap_sem);
error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
+ MAP_FIXED | MAP_PRIVATE | MAP_EXECUTABLE,
fd_offset + ex.a_text);
up_write(&current->mm->mmap_sem);
if (error != N_DATADDR(ex)) {
@@ -479,7 +479,7 @@
down_write(&current->mm->mmap_sem);
error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+ MAP_FIXED | MAP_PRIVATE,
N_TXTOFF(ex));
up_write(&current->mm->mmap_sem);
retval = error;
diff -uNrX linux-ignore-files linux-2.4.12/fs/binfmt_elf.c linux-2.4.12.eb3/fs/binfmt_elf.c
--- linux-2.4.12/fs/binfmt_elf.c Sat Oct 13 16:21:50 2001
+++ linux-2.4.12.eb3/fs/binfmt_elf.c Sun Oct 14 00:38:37 2001
@@ -288,7 +288,7 @@
eppnt = elf_phdata;
for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
if (eppnt->p_type == PT_LOAD) {
- int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+ int elf_type = MAP_PRIVATE;
int elf_prot = 0;
unsigned long vaddr = 0;
unsigned long k, map_addr;
@@ -642,7 +642,7 @@
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;

- elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
+ elf_flags = MAP_PRIVATE|MAP_EXECUTABLE;

vaddr = elf_ppnt->p_vaddr;
if (elf_ex.e_type == ET_EXEC || load_addr_set) {
@@ -701,7 +701,6 @@
interpreter,
&interp_load_addr);

- allow_write_access(interpreter);
fput(interpreter);
kfree(elf_interpreter);

@@ -789,7 +788,6 @@

/* error cleanup */
out_free_dentry:
- allow_write_access(interpreter);
fput(interpreter);
out_free_interp:
if (elf_interpreter)
@@ -853,7 +851,7 @@
(elf_phdata->p_filesz +
ELF_PAGEOFFSET(elf_phdata->p_vaddr)),
PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+ MAP_FIXED | MAP_PRIVATE,
(elf_phdata->p_offset -
ELF_PAGEOFFSET(elf_phdata->p_vaddr)));
up_write(&current->mm->mmap_sem);
diff -uNrX linux-ignore-files linux-2.4.12/fs/binfmt_em86.c linux-2.4.12.eb3/fs/binfmt_em86.c
--- linux-2.4.12/fs/binfmt_em86.c Sat Mar 17 16:28:29 2001
+++ linux-2.4.12.eb3/fs/binfmt_em86.c Sat Oct 13 20:12:38 2001
@@ -44,7 +44,6 @@
}

bprm->sh_bang++; /* Well, the bang-shell is implicit... */
- allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;

diff -uNrX linux-ignore-files linux-2.4.12/fs/binfmt_misc.c linux-2.4.12.eb3/fs/binfmt_misc.c
--- linux-2.4.12/fs/binfmt_misc.c Sat Mar 17 16:28:29 2001
+++ linux-2.4.12.eb3/fs/binfmt_misc.c Sat Oct 13 20:12:46 2001
@@ -201,7 +201,6 @@
if (!fmt)
goto _ret;

- allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;

diff -uNrX linux-ignore-files linux-2.4.12/fs/binfmt_script.c linux-2.4.12.eb3/fs/binfmt_script.c
--- linux-2.4.12/fs/binfmt_script.c Sat Mar 17 16:28:29 2001
+++ linux-2.4.12.eb3/fs/binfmt_script.c Sat Oct 13 20:12:30 2001
@@ -29,7 +29,6 @@
*/

bprm->sh_bang++;
- allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;

diff -uNrX linux-ignore-files linux-2.4.12/fs/exec.c linux-2.4.12.eb3/fs/exec.c
--- linux-2.4.12/fs/exec.c Sat Oct 13 16:20:02 2001
+++ linux-2.4.12.eb3/fs/exec.c Mon Oct 15 03:46:21 2001
@@ -337,39 +337,17 @@

struct file *open_exec(const char *name)
{
+ int error;
struct nameidata nd;
- struct inode *inode;
- struct file *file;
- int err = 0;

- if (path_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
- err = path_walk(name, &nd);
- file = ERR_PTR(err);
- if (!err) {
- inode = nd.dentry->d_inode;
- file = ERR_PTR(-EACCES);
- if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&
- S_ISREG(inode->i_mode)) {
- int err = permission(inode, MAY_EXEC);
- if (!err && !(inode->i_mode & 0111))
- err = -EACCES;
- file = ERR_PTR(err);
- if (!err) {
- file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
- if (!IS_ERR(file)) {
- err = deny_write_access(file);
- if (err) {
- fput(file);
- file = ERR_PTR(err);
- }
- }
-out:
- return file;
- }
- }
- path_release(&nd);
- }
- goto out;
+ /* For a real exec we cheat. We don't do permission checks
+ * for read, but we open the file for reading anyway...
+ */
+ error = open_namei(name, O_EXEC, 0, &nd);
+ if (!error)
+ return dentry_open(nd.dentry, nd.mnt, O_EXEC | O_RDONLY);
+
+ return ERR_PTR(error);
}

int kernel_read(struct file *file, unsigned long offset,
@@ -774,7 +752,6 @@
struct file * file;
unsigned long loader;

- allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;

@@ -809,7 +786,6 @@
retval = fn(bprm, regs);
if (retval >= 0) {
put_binfmt(fmt);
- allow_write_access(bprm->file);
if (bprm->file)
fput(bprm->file);
bprm->file = NULL;
@@ -871,13 +847,11 @@
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) {
- allow_write_access(file);
fput(file);
return bprm.argc;
}

if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) {
- allow_write_access(file);
fput(file);
return bprm.envc;
}
@@ -906,7 +880,6 @@

out:
/* Something went wrong, return the inode and free the argument pages*/
- allow_write_access(bprm.file);
if (bprm.file)
fput(bprm.file);

diff -uNrX linux-ignore-files linux-2.4.12/fs/file_table.c linux-2.4.12.eb3/fs/file_table.c
--- linux-2.4.12/fs/file_table.c Sat Oct 13 16:20:02 2001
+++ linux-2.4.12.eb3/fs/file_table.c Sat Oct 13 20:00:23 2001
@@ -114,6 +114,8 @@
fops_put(file->f_op);
if (file->f_mode & FMODE_WRITE)
put_write_access(inode);
+ if (file->f_mode & FMODE_EXEC)
+ allow_write_access(inode);
file_list_lock();
file->f_dentry = NULL;
file->f_vfsmnt = NULL;
diff -uNrX linux-ignore-files linux-2.4.12/fs/namei.c linux-2.4.12.eb3/fs/namei.c
--- linux-2.4.12/fs/namei.c Sat Oct 13 16:22:01 2001
+++ linux-2.4.12.eb3/fs/namei.c Mon Oct 15 03:52:33 2001
@@ -212,10 +212,10 @@
* put_write_access() releases this write permission.
* This is used for regular files.
* We cannot support write (and maybe mmap read-write shared) accesses and
- * MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode
- * can have the following values:
- * 0: no writers, no VM_DENYWRITE mappings
- * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist
+ * O_EXEC mmappings simultaneously. The i_writecount field of an inode can have
+ * the following values:
+ * 0: no writers, no executers.
+ * < 0: (-i_writecount) users are executing the file.
* > 0: (i_writecount) users are writing to the file.
*
* Normally we operate on that counter with atomic_{inc,dec} and it's safe
@@ -974,6 +974,8 @@
int count = 0;

acc_mode = ACC_MODE(flag);
+ if (flag & O_EXEC)
+ acc_mode |= MAY_EXEC;

/*
* The simplest case - just a plain lookup.
@@ -1069,6 +1071,22 @@
error = -EISDIR;
if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
goto exit;
+
+ error = -EACCES;
+ if (flag & O_EXEC) {
+ if (flag & FMODE_WRITE)
+ goto exit;
+ if (nd->mnt->mnt_flags & MNT_NOEXEC)
+ goto exit;
+ if (!S_ISREG(inode->i_mode))
+ goto exit;
+ /* The follow check for an executable bit was taken
+ * from the old open_exec. I don't think it is either
+ * needed or makes any sense but just in case...
+ */
+ if (!(inode->i_mode & S_IXUGO))
+ goto exit;
+ }

error = permission(inode,acc_mode);
if (error)
diff -uNrX linux-ignore-files linux-2.4.12/fs/open.c linux-2.4.12.eb3/fs/open.c
--- linux-2.4.12/fs/open.c Sat Oct 13 16:21:50 2001
+++ linux-2.4.12.eb3/fs/open.c Mon Oct 15 03:45:49 2001
@@ -612,6 +612,8 @@
* 11 - read-write
* for the internal routines (ie open_namei()/follow_link() etc). 00 is
* used by symlinks.
+ *
+ * The mapping is: 00 -> 01 , 01 -> 10, 10 -> 11, 11 -> 11
*/
struct file *filp_open(const char * filename, int flags, int mode)
{
@@ -625,6 +627,11 @@
namei_flags |= 2;

error = open_namei(filename, namei_flags, mode, &nd);
+ /* For now don't allow O_EXEC from userspace when anyone can
+ * write to the file.
+ */
+ if (!error && (flags & O_EXEC) && (nd.dentry->d_inode->i_mode & S_IWUGO))
+ error = -EACCES;
if (!error)
return dentry_open(nd.dentry, nd.mnt, flags);

@@ -644,6 +651,8 @@
goto cleanup_dentry;
f->f_flags = flags;
f->f_mode = (flags+1) & O_ACCMODE;
+ if (flags & O_EXEC)
+ f->f_mode |= FMODE_EXEC;
inode = dentry->d_inode;
if (f->f_mode & FMODE_WRITE) {
error = get_write_access(inode);
@@ -673,6 +682,12 @@
goto cleanup_all;
}
f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
+
+ if (f->f_mode & FMODE_EXEC) {
+ error = deny_write_access(f);
+ if (error)
+ goto cleanup_all;
+ }

return f;

diff -uNrX linux-ignore-files linux-2.4.12/include/asm-i386/fcntl.h linux-2.4.12.eb3/include/asm-i386/fcntl.h
--- linux-2.4.12/include/asm-i386/fcntl.h Sat Oct 13 16:20:04 2001
+++ linux-2.4.12.eb3/include/asm-i386/fcntl.h Sun Oct 14 00:08:01 2001
@@ -7,6 +7,7 @@
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
+#define O_EXEC 04 /* generate ETXTBSY on writes */
#define O_CREAT 0100 /* not fcntl */
#define O_EXCL 0200 /* not fcntl */
#define O_NOCTTY 0400 /* not fcntl */
diff -uNrX linux-ignore-files linux-2.4.12/include/linux/fs.h linux-2.4.12.eb3/include/linux/fs.h
--- linux-2.4.12/include/linux/fs.h Sat Oct 13 17:26:25 2001
+++ linux-2.4.12.eb3/include/linux/fs.h Sun Oct 14 00:42:30 2001
@@ -73,6 +73,7 @@

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

#define READ 0
#define WRITE 1
diff -uNrX linux-ignore-files linux-2.4.12/kernel/fork.c linux-2.4.12.eb3/kernel/fork.c
--- linux-2.4.12/kernel/fork.c Sat Oct 13 16:20:09 2001
+++ linux-2.4.12.eb3/kernel/fork.c Sat Oct 13 20:34:56 2001
@@ -168,8 +168,6 @@
if (file) {
struct inode *inode = file->f_dentry->d_inode;
get_file(file);
- if (tmp->vm_flags & VM_DENYWRITE)
- atomic_dec(&inode->i_writecount);

/* insert tmp into the share list, just after mpnt */
spin_lock(&inode->i_mapping->i_shared_lock);
diff -uNrX linux-ignore-files linux-2.4.12/mm/mmap.c linux-2.4.12.eb3/mm/mmap.c
--- linux-2.4.12/mm/mmap.c Sat Oct 13 16:21:52 2001
+++ linux-2.4.12.eb3/mm/mmap.c Sun Oct 14 00:50:32 2001
@@ -98,9 +98,6 @@
struct file * file = vma->vm_file;

if (file) {
- struct inode *inode = file->f_dentry->d_inode;
- if (vma->vm_flags & VM_DENYWRITE)
- atomic_inc(&inode->i_writecount);
if(vma->vm_next_share)
vma->vm_next_share->vm_pprev_share = vma->vm_pprev_share;
*vma->vm_pprev_share = vma->vm_next_share;
@@ -205,7 +202,6 @@
_trans(prot, PROT_EXEC, VM_EXEC);
flag_bits =
_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN) |
- _trans(flags, MAP_DENYWRITE, VM_DENYWRITE) |
_trans(flags, MAP_EXECUTABLE, VM_EXECUTABLE);
return prot_bits | flag_bits;
#undef _trans
@@ -310,9 +306,6 @@
struct address_space *mapping = inode->i_mapping;
struct vm_area_struct **head;

- if (vma->vm_flags & VM_DENYWRITE)
- atomic_dec(&inode->i_writecount);
-
head = &mapping->i_mmap;
if (vma->vm_flags & VM_SHARED)
head = &mapping->i_mmap_shared;
@@ -395,7 +388,6 @@
struct mm_struct * mm = current->mm;
struct vm_area_struct * vma, * prev;
unsigned int vm_flags;
- int correct_wcount = 0;
int error;
rb_node_t ** rb_link, * rb_parent;

@@ -526,12 +518,6 @@
error = -EINVAL;
if (vm_flags & (VM_GROWSDOWN|VM_GROWSUP))
goto free_vma;
- if (vm_flags & VM_DENYWRITE) {
- error = deny_write_access(file);
- if (error)
- goto free_vma;
- correct_wcount = 1;
- }
vma->vm_file = file;
get_file(file);
error = file->f_op->mmap(file, vma);
@@ -551,8 +537,6 @@
addr = vma->vm_start;

vma_link(mm, vma, prev, rb_link, rb_parent);
- if (correct_wcount)
- atomic_inc(&file->f_dentry->d_inode->i_writecount);

out:
mm->total_vm += len >> PAGE_SHIFT;
@@ -563,8 +547,6 @@
return addr;

unmap_and_free_vma:
- if (correct_wcount)
- atomic_inc(&file->f_dentry->d_inode->i_writecount);
vma->vm_file = NULL;
fput(file);

@@ -946,11 +928,9 @@
* so release them, and unmap the page range..
* If the one of the segments is only being partially unmapped,
* it will put new vm_area_struct(s) into the address space.
- * In that case we have to be careful with VM_DENYWRITE.
*/
while ((mpnt = free) != NULL) {
unsigned long st, end, size;
- struct file *file = NULL;

free = free->vm_next;

@@ -959,11 +939,6 @@
end = end > mpnt->vm_end ? mpnt->vm_end : end;
size = end - st;

- if (mpnt->vm_flags & VM_DENYWRITE &&
- (st != mpnt->vm_start || end != mpnt->vm_end) &&
- (file = mpnt->vm_file) != NULL) {
- atomic_dec(&file->f_dentry->d_inode->i_writecount);
- }
remove_shared_vm_struct(mpnt);
mm->map_count--;

@@ -973,8 +948,6 @@
* Fix the mapping, and free the old area if it wasn't reused.
*/
extra = unmap_fixup(mm, mpnt, st, size, extra);
- if (file)
- atomic_inc(&file->f_dentry->d_inode->i_writecount);
}
validate_mm(mm);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/