Comparing PROT_EXEC-only pages on different CPUs
Alpha and IA64 are the only Linux architecture where PROT_EXEC by itself results in exec-only pages. Interestingly, the hardware of some other architectures _could_ implement exec-only pages, but they chose not to:
The PA-RISC pgtable.h says:
"We could have an execute only page using "gateway - promote to priv level 3", but that is kind of silly. So, the way things are defined now, we must always have read permission for pages with execute permission. For the fun of it we'll go ahead and support write only pages."
Richard Curnow working on the SH64 port says:
"Although the hardware is capable of distinguish R and X, the kernel always allows R if X is specified to mmap(). This is for 2 reasons :
1. jump tables for switch() get embedded into the code in 32-bit (SHmedia) mode
2. constant pools embedded in the code in 16-bit (SHcompact, i.e. SH-4 compatible) mode
so in practice an exec-only page is pretty useless to a typical userland program."
Richard raises an interesting point: exec-only pages are useless if the code needs to read jump tables and constant pools. It seems very likely Alpha and IA64 have these.
The point is: should the automatic addition of read permission be kernel policy (as on SH64 and PA-RISC), or should it be for userspace policy to get right as real code probably needs it (as on Alpha and IA64)?
Does anyone think there's a "right" behaviour which current or future Linux ports should try to conform to? Should any of the current ones be changed?
I'm just making sure all 4 know about each others behaviour before I wash my hands of this observation. :)
Cheers,
-- Jamie
Quoted 3 lines · Jamie Lokier
Richard raises an interesting point: exec-only pages are useless if the code needs to read jump tables and constant pools. It seems very likely Alpha and IA64 have these.
Only if the processor is crippled enough that mixing jump tables and constant pools in the same pages as code is considered reasonable. Anyway, that's a strawman -- it's the toolchain's job to get the bits on the pt_load segments correct.
If the pt_load segment or the mmap prot argument says execute-only, then you should honor it.
r~
Thanks for your input, Richard.
Quoted 6 lines · Richard Henderson
Quoted 3 lines
Richard raises an interesting point: exec-only pages are useless if the code needs to read jump tables and constant pools. It seems very likely Alpha and IA64 have these.
Only if the processor is crippled enough that mixing jump tables and constant pools in the same pages as code is considered reasonable.
That's a good point, if the i-cache and/or DTLB are separate from d-cache and/or DTLB. Then it makes more sense to put tables in a separate address block.
However if the caches are unified then it makes sense to put them together. Somehow I doubt if any of these 64-bit chips have unified i- and d-caches though :)
Quoted 5 lines
Anyway, that's a strawman -- it's the toolchain's job to get the bits on the
pt_loadsegments correct.If the
pt_loadsegment or the mmap prot argument says execute-only, then you should honor it.
In other words, PA-RISC and SH64 kernels _should_ create exec-only pages if requested, as the hardware can do it, right?
And the toolchain _should_ ask read permssion for code segments, if (and only if) the compiler has generated code which needs that, right?
I very much agree.
(Fwiw, Alpha does gives read permission to a write-only request, even on chips which don't need that for byte writes to work. Isn't that a similar case?)
Thanks,
-- Jamie
Hi Jamie
Quoted 9 lines · Jamie Lokier
Quoted 6 lines · Richard Henderson
Quoted 3 lines
Richard raises an interesting point: exec-only pages are useless if the code needs to read jump tables and constant pools. It seems very likely Alpha and IA64 have these.
Only if the processor is crippled enough that mixing jump tables and constant pools in the same pages as code is considered reasonable.
Quoted 7 lines
That's a good point, if the i-cache and/or DTLB are separate from d-cache and/or DTLB. Then it makes more sense to put tables in a separate address block.
However if the caches are unified then it makes sense to put them together. Somehow I doubt if any of these 64-bit chips have unified i- and d-caches though :)
For the SH-4, and the SH-5 in SHcompact mode, the insertion of constant pools in amongst the code is essential. The SH-4 instruction set has specific "load word/longword from 2N/4N bytes forward of current PC" instructions (mov.[wl] @(disp,PC),Rm) for this. It seems a reasonable enough way of handling large immediates in a 16-bit encoding.
For SH-5 in SHmedia mode, it probably isn't really necessary to put switch tables inside the .text section, but it's what the current toolchains do.
Quoted 11 lines
Quoted 5 lines
Anyway, that's a strawman -- it's the toolchain's job to get the bits on the
pt_loadsegments correct.If the
pt_loadsegment or the mmap prot argument says execute-only, then you should honor it.In other words, PA-RISC and SH64 kernels _should_ create exec-only pages if requested, as the hardware can do it, right?
And the toolchain _should_ ask read permssion for code segments, if (and only if) the compiler has generated code which needs that, right?
As it turns out, it looks like the SH-5 toolchains already do that. The kernel was forcing readability onto mappings unnecessarily. I've done some local fixes to sh64/2.6 today, and the results of the program are now coming out:
Requested PROT | --- R-- -W- RW- --X R-X -WX RWX
========================================================================
MAP_SHARED | --- r-- -w- rw- --x r-x -wx rwx MAP_PRIVATE | --- r-- -w- rw- --x r-x -wx rwx
Signature · 2 lines
Richard \\\ SH-4/SH-5 Core & Debug Architect Curnow \\\ SuperH (UK) Ltd, Bristol
Quoted 3 lines
Richard raises an interesting point: exec-only pages are useless if the code needs to read jump tables and constant pools. It seems very likely Alpha and IA64 have these.
HPPA GCC code also needs to be able to read jump tables in .text.
Dave
Signature · 2 lines
J. David Anglin [email protected] National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
Quoted 5 lines · John David Anglin
Quoted 3 lines
Richard raises an interesting point: exec-only pages are useless if the code needs to read jump tables and constant pools. It seems very likely Alpha and IA64 have these.
HPPA GCC code also needs to be able to read jump tables in .text.
As Richard Henderson points out, the toolchain should be requesting PROT_READ|PROT_EXEC if it generates code which needs data read access. ELF is particularly good for tracking generating those flags, so do HPPA code segments have the read flag set at the moment? I.e. if it does, then it would be fine to change the kernel to honour PROT_EXEC-only.
(There's also the question of whether that code needs data read
access: do jump table instructions do data reads or do they count as code reads? I don't know HPPA well enough to know).
-- Jamie
Quoted 6 lines
As Richard Henderson points out, the toolchain should be requesting PROT_READ|PROT_EXEC if it generates code which needs data read access. ELF is particularly good for tracking generating those flags, so do HPPA code segments have the read flag set at the moment? I.e. if it does, then it would be fine to change the kernel to honour PROT_EXEC-only.
The default flags for .text and other code sections are "AX" for both hppa64-hpux and hppa-linux. Thus, unless someone explicitly removes PROT_READ, there isn't a problem reading the offsets in the jump tables.
Having jump tables containing data in the code sections is relatively new on HPPA. There were problems with the previous implementation in which the jump tables contained code.
It would be possible to put the jump tables in .rodata. The reasons why the jump tables ended up in the code sections are:
1) The instruction sequence to load the start of the table is about three instructions shorter.
2) The tables contain absolute offsets. In order to put the tables in .rodata, we needed support for 32 and 64-bit pc-relative relocations in binutils. I added this support to binutils a few months ago. However, I decided that I didn't want to require an update to a non-released version of binutils in order to build and use GCC.
3) There weren't any problems putting the tables in the code sections under hpux.
Quoted 3 lines
(There's also the question of whether that code needs data read
access: do jump table instructions do data reads or do they count as code reads? I don't know HPPA well enough to know).
The jump table instructions use the standard HPPA load instructions (i.e., there is no difference in a read to .text or .data aside from the protection flags that have been set for the page).
The tool chain only controls the setting of SHF_ALLOC, SHF_EXECINSTR, SHF_WRITE, ... There isn't any control over whether a section can be read or not as far as I can tell.
Dave
Signature · 2 lines
J. David Anglin [email protected] National Research Council of Canada (613) 990-0752 (FAX: 952-6602)