Skip to contentSkip to conversation

Table of mmap PROT_* implementations by architecture

DISCUSSION Jamie Lokier 3 participants 4 messages Jul 1, 2004 – Jul 6, 2004

lore
Share & tools
lore
#0 lore raw
Quoted 1 line

From a study of Linux 2.6.5 source code, and some patches.

This is based on studying the source, not running tests, so there may be errors.

This table shows expected page protections, for different values of PROT_READ, PROT_WRITE and PROT_EXEC passed to mmap() and mprotect().

(As noted in a recent mail from me, real behaviour isn't quite this simple. Reading from a write-only page will *sometimes* raise a signal, and sometimes not, possibly dependent on background paging decisions. Therefore some of these entries should say "!w!" instead of "rwx", and "!w-" instead of "rw-". Perhaps there are other combinations too, depending on architecture-specific fault handlers).

======================+========================================================
Requested PROT flags | --- R-- -W- RW- --X R-X -WX RWX
======================+========================================================
alpha | --- r-- rw- rw- --x r-x rwx rwx
----------------------+--------------------------------------------------------
arm | --- r-x rwx rwx r-x r-x rwx rwx
----------------------+--------------------------------------------------------
cris | --- r-x rwx rwx r-x r-x rwx rwx
----------------------+--------------------------------------------------------
h8300 | No MMU
----------------------+--------------------------------------------------------

i386 (plain)          | ---    r-x    rwx    rwx    r-x    r-x    rwx    rwx
i386 (PaX)            | ---    r--    rw-    rw-    r-x    r-x    rw-(2) rw-(2)
i386 (exec-shield)    | ---    r--(3) rw-(3) rw-(3) r-x    r-x    rwx    rwx
i386 (NX)             | ---    r--    rw-    rw-    r-x    r-x    rwx    rwx
----------------------+--------------------------------------------------------
ia64                  | ---    r--    rw-    rw-    --x(1) r-x    rwx    rwx
----------------------+--------------------------------------------------------
m68k (motorola)       | ---    r-x    rwx    rwx    r-x    r-x    rwx    rwx
m68k (sun3)           | r-x    r-x    rwx    rwx    r-x    r-x    rwx    rwx
m68k (no mmu)         | No MMU
----------------------+--------------------------------------------------------
mips                  | ---    r-x    rwx    rwx    r-x    r-x    rwx    rwx
mips64                | ---    r-x    rwx    rwx    r-x    r-x    rwx    rwx
mips (PaX) (4)        | ---    r-x    rwx    rwx    r-x    r-x    rwx    rwx
mips64 (PaX) (4)      | ---    r-x    rwx    rwx    r-x    r-x    rwx    rwx
----------------------+--------------------------------------------------------
parisc                | ---    r--    -w-    rw-    r-x    r-x    rwx    rwx
parisc (PaX)          | ---    r--    -w-    rw-    r-x    r-x    rw-(2) rw-(2)
----------------------+--------------------------------------------------------
ppc                   | ---(1) r-x    rwx(5) rwx    r-x(5) r-x    rwx(5) rwx
ppc64                 | ---(1) r-x    rwx(5) rwx    r-x(5) r-x    rwx(5) rwx

ppc (PaX) | ---(1) r-- rw- rw- r-x r-x rw-(2) rw-(2)
ppc64 (PaX for 2.6) | ---(1) r-- rw- rw- r-x r-x rw-(2) rw-(2)
----------------------+--------------------------------------------------------
s390 | --- r-x rwx rwx r-x r-x rwx rwx
----------------------+--------------------------------------------------------
sh | --- r-x rwx rwx r-x r-x rwx rwx
sh (no mmu) | No MMU
----------------------+--------------------------------------------------------

sparc (sun4)          | ---    r-x    rwx    rwx    r-x    r-x    rwx    rwx
sparc (sun4c)         | ---    r-x    rwx    rwx    r-x    r-x    rwx    rwx
sparc (SRMMU)         | ---(1) r-x(6) rwx(6) rwx(6) r-x    r-x    rwx    rwx
sparc64               | ---    r-x    rwx    rwx    r-x    r-x    rwx    rwx
sparc (Pax+SRMMU)     | ---(1) r--    rw-    rw-    r-x    r-x    rw-(2) rw-(2)
sparc64 (Pax)         | ---    r--    rw-    rw-    r-x    r-x    rw-(2) rw-(2)

----------------------+--------------------------------------------------------
um (user mode) | ---(7) r-x rwx rwx r-x r-x rwx rwx
----------------------+--------------------------------------------------------
v850 | No MMU
----------------------+--------------------------------------------------------

x86_64 (AMD NX)       | ---    r--    rw-    rw-    r-x    r-x    rwx    rwx
x86_64 (Intel no-NX)  | ---    r-x    rwx    rwx    r-x    r-x    rwx    rwx
x86_64 (Intel NX)     | ---    r--    rw-    rw-    r-x    r-x    rwx    rwx
x86_64 (PaX NX)       | ---    r--    rw-    rw-    r-x    r-x    rw-(2) rw-(2)
x86_64 (PaX no-NX) (4)| ---    r-x    rwx    rwx    r-x    r-x    rwx    rwx

----------------------+--------------------------------------------------------

(1) - In kernel, maybe these pages are readable using "write()"? In each case that is labelled, I'm not sure from reading the code. (Pages are always readable using ptrace(), that's ok, but write() and other kernel reads shouldn't be able to read PROT_NONE pages).

(2) - The PaX security patch simulates fine-grained exec permission. PaX also disallows ALL writable+executable pages as a matter of
policy: PROT_WRITE|PROT_EXEC does not make the mapping executable and mprotect() cannot change this. This feature can be switched off for marked executables, or globally.

(3) - The Exec-Shield patch, when the CPU doesn't support the NX capability or when it's not a recent enough patch, uses segmentation to *approximate* fine-grained exec permission. If this is so, code which detects that one PROT_EXEC page isn't executable cannot assume that all non-PROT_EXEC pages aren't executable.

(4) - PaX is available for MIPS, but doesn't really disable execute permissions. On x86-64, PaX assumes the AMD64 architecture with NX capability (quite rightly) and so fails to disable execute permissions on Intel IA32e chips without NX.

(5) - The PPC code looks like it "ought to" not allow exec in these cases, but other comments indicate that the _PAGE_EXEC flag is ignored anyway.

(6) - The code says SRMMU can implement no-exec, but it's not implemented.

(7) - On User Mode Linux, PROT_NONE may depend on underlying architecture. Otherwise, read and exec are always synonymous and write implies read, regardless of the underlying architecture.

Enjoy,
-- Jamie

#1 lore raw
Quoted 14 lines · Jamie Lokier

From a study of Linux 2.6.5 source code, and some patches. This is based on studying the source, not running tests, so there may be errors.
======================+========================================================
Requested PROT flags | --- R-- -W- RW- --X R-X -WX
RWX
======================+========================================================
[...]

ppc                   | ---(1) r-x    rwx(5) rwx    r-x(5) r-x    rwx(5) rwx
ppc64                 | ---(1) r-x    rwx(5) rwx    r-x(5) r-x    rwx(5) rwx

ppc (PaX) | ---(1) r-- rw- rw- r-x r-x rw-(2) rw-(2)
ppc64 (PaX for 2.6) | ---(1) r-- rw- rw- r-x r-x rw-(2) rw-(2)
[...]

Quoted 6 lines

(1) - In kernel, maybe these pages are readable using "write()"? In each case that is labelled, I'm not sure from reading the
code.
(Pages are always readable using ptrace(), that's ok, but write() and other kernel reads shouldn't be able to read PROT_NONE
pages).

This is wrong for PPC32 and PPC64, see the email written earlier today:

Quoted 10 lines · Paul Mackerras
Quoted 2 lines

Thus PROT_NONE pages aren't readable from userspace, but it appears they _are_ readable from kernel space. Is this correct?

No. Kernel accesses to pages in the user portion of the address space (0 .. TASK_SIZE-1) are done using the user permissions. On classic PPC this is implemented (in part) by setting Ks = Kp = 1 in the segment descriptors for the user segments, which tells the hardware to check the access as if it was a user access even in supervisor mode.

We do the same on ppc64 as well.

Cheers,
Kyle Moffett

#2 lore raw
Quoted 6 lines · Kyle Moffett
Quoted 4 lines

(1) - In kernel, maybe these pages are readable using "write()"? In each case that is labelled, I'm not sure from reading the code. (Pages are always readable using ptrace(), that's ok, but write() and other kernel reads shouldn't be able to read PROT_NONE pages).

This is wrong for PPC32 and PPC64, see the email written earlier today:

Ah, bollocks! I'd already updated the file from your earlier mail, but didn't propagate that change to the email before sending it.

Thanks for pointing it out,
-- Jamie

#3 lore raw
In reply to Jamie Lokier
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line · Jamie Lokier

From a study of Linux 2.6.5 source code, and some patches.

Jamie> This is based on studying the source, not running tests, so Jamie> there may be errors.

Jamie> This table shows expected page protections, for different Jamie> values of PROT_READ, PROT_WRITE and PROT_EXEC passed to Jamie> mmap() and mprotect().

Jamie> (As noted in a recent mail from me, real behaviour isn't Jamie> quite this simple. Reading from a write-only page will Jamie> *sometimes* raise a signal, and sometimes not, possibly Jamie> dependent on background paging decisions. Therefore some of Jamie> these entries should say "!w!" instead of "rwx", and "!w-" Jamie> instead of "rw-". Perhaps there are other combinations too, Jamie> depending on architecture-specific fault handlers).

  Jamie> ==============================================================
  Jamie> Requested PROT flags | --- R-- -W- RW- --X    R-X -WX RWX
  Jamie> ==============================================================
  Jamie> ia64                 | --- r-- rw- rw- --x(1) r-x rwx rwx
  Jamie> --------------------------------------------------------------

Jamie> (1) - In kernel, maybe these pages are readable using Jamie> "write()"?

That's correct for ia64. The architecture does not support an "execute-only at all privilege levels" protection per se, so this behavior is the easiest (most efficient) to implement. If we really cared about the "read execute-only at kernel-level", we could use "probe" instructions in the __access_ok() macro to verify (user-level) access permission.

	--david