Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Security: add kernel address space layout randomization (KASLR) #2004

Merged
merged 5 commits into from
Mar 7, 2024

Conversation

francescolavra
Copy link
Member

This change set adds a security feature that randomizes the virtual address ranges where the kernel and klib binaries are mapped. The range from which random addresses are generated spans 2GB, and the only restriction on generated addresses is 4KB alignment, therefore the number of possible addresses is 2^19.

In a future commit the kernel will be linked as a
position-independent executable. This change makes the LDFLAGS for
the x86_64 bootloader independent from the kernel LDFLAGS, so that
the bootloader will not be linked as a PIE.
This change makes read_kernel_syms() a static function in kernel/
init.c, while introducing a platform-specific kern_get_elf()
function which returns the physical address range where the kernel
ELF is located in memory.
This change adds the random_early_u64() function, which allows
generating random numbers in the early boot stage (before the
platform clock is registered and before kernel contexts are
initialized). The hw_get_seed() function has been moved to
platform-independent code and calls the platform-specific
machine_random_seed() function to retrieve a random seed; if
machine_random_seed() is unable to generate a seed, hw_get_seed()
falls back to using other sources of entropy.
This change will be needed to implement KASLR.
This change consolidates the code for applying dynamic relocations
so that elf_dyn_relocate() contains arch-independent code, while
arch_elf_relocate() contains arch-specific code.
elf_dyn_relocate() now takes 4 parameters:
- the base adddress, used to retrieve the relocation table and the
  addresses where relocations have to be applied
- the relocation offset
- the ELF dynamic section
- the ELF symbol table
elf_dyn_relocate() supports retrieving the number of relocation
entries via the DT_RELACOUNT tag (ld v2.26.1 for x86_64 sets the
value of the DT_RELASZ tag to 0), and expects relocation entries to
be Elf64_Rela (i.e. 24 bytes each).
This change set adds a security feature that randomizes the
virtual address ranges where the kernel and klib binaries are
mapped. The range from which random addresses are generated spans
2GB, and the only restriction on generated addresses is 4KB
alignment, therefore the number of possible addresses is 2^19.

The kernel binary is now created as a PIE (position-independent
executable), and during boot the kernel applies dynamic relocations
to its code when moving to a random address. The dynamic section
is specified in the linker scripts as part of the read-only data
section (thereby preventing the default linker behavior that places
the dynamic section in the read-write data section), so that it's
mapped with read-only permissions.
Platform-specific code that maps the kernel to its final virtual
address has been removed, since the final virtual address is now
generated when doing KASLR.
The initial mappings set up during early boot by the hypervisor or
bootloader or kernel platform-specific code are removed in the
reclaim_regions() function (or earlier in the boot process).
In the x86_64 code, the assembly initialization code has been moved
to a new init.s file, and is now bound to the .start linker section
so that its load address is known at compile time; this prevents
the assembler from creating static relocation entries that cannot
be used when making a PIE. The initial pages area is now identity-
mapped instead of using the PAGES_BASE virtual address; this allows
removing the `bootstrapping` global variable from the generic page
table code.
In the aarch64 linker script, the vvar section has been moved after
the data sections, so that it's correctly mapped with read-write
permissions when doing KASLR.
The RISC-V assembly initialization code has been moved to a new
init.S file, which is compiled as non-position-independent code, so
that it can use the build-time address of the dynamic linker
section to apply the initial relocations that are needed to access
global variables. In the RISC-V linker script, sections have been
moved around in order to ensure that read-write data is located
between the READONLY_END and bss_start linker symbols.
@francescolavra francescolavra merged commit e94c466 into master Mar 7, 2024
5 checks passed
@francescolavra francescolavra deleted the feature/kaslr branch March 7, 2024 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant