[patch] remove MNT_NOEXEC check for PROT_EXEC MAP_PRIVATE mmaps

From: Stas Sergeev
Date: Wed Sep 27 2006 - 15:15:50 EST


Hi Andrew.

It looks like in a course of a discussion people
agreed that at least for MAP_PRIVATE the MNT_NOEXEC
check makes no sense (no one spoke up otherwise, at least).

The attached patch removes the check for MAP_PRIVATE but
leaves for MAP_SHARED for now, as this was not agreed on.

Reasons:
- MAP_PRIVATE should not behave like that, "ro" and PROT_WRITE
is a witness ("ro" doesn't deny PROT_WRITE for MAP_PRIVATE).
- This is not a security check - file-backed MAP_PRIVATE mmaps
can just be replaced with MAP_PRIVATE | MAP_ANONYMOUS
mmap and read().
- The programs (like AFAIK wine) use MAP_PRIVATE mmaps to
access the windows dlls, which are usually on a "noexec"
fat or ntfs partitions. Wine might be smart enough not to
break but fallback to read(), but this is slower and more
memory-consuming. Some other program may not be that smart
and break. So there is clearly a need for MAP_PRIVATE with
PROT_EXEC on the noexec partitions.

Sign-off: Stas Sergeev <stsp@xxxxxxxx> --- a/mm/mmap.c 2006-01-25 15:02:24.000000000 +0300
+++ b/mm/mmap.c 2006-09-21 13:19:15.000000000 +0400
@@ -900,7 +900,7 @@
if (!file->f_op || !file->f_op->mmap)
return -ENODEV;

- if ((prot & PROT_EXEC) &&
+ if ((flags & MAP_SHARED) && (prot & PROT_EXEC) &&
(file->f_vfsmnt->mnt_flags & MNT_NOEXEC))
return -EPERM;
}
@@ -911,7 +911,8 @@
* mounted, in which case we dont add PROT_EXEC.)
*/
if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
- if (!(file && (file->f_vfsmnt->mnt_flags & MNT_NOEXEC)))
+ if (!(file && (flags & MAP_SHARED) &&
+ (file->f_vfsmnt->mnt_flags & MNT_NOEXEC)))
prot |= PROT_EXEC;

if (!len)
--- a/mm/nommu.c 2006-04-12 09:37:34.000000000 +0400
+++ b/mm/nommu.c 2006-09-21 13:21:32.000000000 +0400
@@ -495,7 +495,7 @@

/* handle executable mappings and implied executable
* mappings */
- if (file->f_vfsmnt->mnt_flags & MNT_NOEXEC) {
+ if ((flags & MAP_SHARED) && file->f_vfsmnt->mnt_flags & MNT_NOEXEC) {
if (prot & PROT_EXEC)
return -EPERM;
}