nx bit
Originally created by Tails on #5835 (Redmine)
{{toc}}
Rationale and context
The NX bit helps enabling executable space protection. Most 64bits, and some 32bits, x86 CPUs support this.
On Linux, PAE must be enabled to get the NX bit enabled. We cannot blindly enable PAE, as it "causes pre-Pentium Pro (including Pentium MMX) and Celeron M and Pentium M processors without NX support to fail to boot" (Wikipedia.
So we cannot default to use PAE, and should at least provide the non-bigmem one as an alternative choice in the bootloader or wait for non-PAE systems to be rare enough so that we can stop supporting them.
As of 2.6.39, Debian –686 kernels have PAE enabled (reference: Ben’s blog, that’s why we now ship a –486 kernel.
If we don’t want to ship –486 until non-PAE systems die, and forget about NX bit until then, we have to ship both –686-pae and –486, and have the bootloader autodetect the most appropriate one depending on what the kernel supports.
Implementation
Done
The feature/multikernel
branch (merged into experimental
):
- installs two kernels (
-486
,-686-pae
) - patches the syslinux menu configuration to autoselect best kernel wrt. hardware support, and automatically jump to an arch-specific appropriate sub-menu
- tested on CPUs: 486, amd64, 686 without PAE
- successfully run the Tails USB Installer with a
-686-pae
kernel - given up shipping an amd64 kernel, due to the VirtualBox bugs about guest additions vs. 32-bit userspace + 64-bit kernel :(
- memtest with 686-pae on 4GB RAM and more was tried: worse results than with sdmem (2.5GB of the known pattern found after "wiping" with memtest, vs. 1.5GB when using sdmem), so we’re back to sdmem (54c81c1 reverted)
Next steps
done in Tails 0.14
Possibly later
Resources
ifcpu64
The ifcpu64.c32
module seems to
provide what we need, allowing to do different things for 64-bit
hardware, 32-bit hardware with PAE support and 32-bit hardware without
PAE, like this:
label boot_kernel
com32 ifcpu64.c32
append boot_kernel_64 -- boot_kernel_32pae -- boot_kernel_32
label boot_kernel_32
kernel vmlinuz_32
append ...
label boot_kernel_32pae
kernel vmlinuz_32pae
append ...
label boot_kernel_64
kernel vmlinuz_64
append ...
Unfortunately, it does not select a default kernel, but boots it right
away. So instead of booting a Linux kernel, we can boot the
vesamenu.c32
module with a different configuration file for each
kernel:
label select_menu
com32 /syslinux/ifcpu64.c32
append menu_amd64 -- menu_686-pae -- menu_486
label menu_amd64
kernel /syslinux/vesamenu.c32
append live_amd64.cfg
label menu_686-pae
kernel /syslinux/vesamenu.c32
append live_686-pae.cfg
label menu_486
kernel /syslinux/vesamenu.c32
append live_486.cfg
default select_menu
Discarded
HDT
The HDT (hardware detection tool) syslinux module (homepage, page on syslinux wiki has code that might help supporting this; it’s been shipped in mainline syslinux for a while. On the other hand does not offer any kind of feature that can be used to parameterized the boot menu.
default64 menu keyword
Debian multi-arch installer’s syslinux menu autodetects amd64-compatible
hardware and pre-selects the right default kernel. Seems like it uses
the default64
menu keyword (see debian-installer Git repository).
Unfortunately, this solution is not suitable for us because it does not
allow to select a kernel depending on PAE support, and is not part of
recent syslinux
package.
ifcpu.c32
Other COM32 modules shipped with syslinux might be better suited for our
specific needs. See especially ifcpu.c32
; according to its source
code, it can "run one command if system match some CPU features, another
if it doesn’t" and is supposed to be used e.g. like this:
label ifcpu
com32 ifcpu.c32
append pae -- boot_entry_1 -- boot_entry_2
label boot_entry_1
kernel vmlinuz_entry1
append ...
label boot_entry_2
kernel vmlinuz_entry2
append ...
… which would almost suit our needs but only allows two alternatives, while we need three.