-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Description
Describe the bug
When the Global Pointer (GP) relative addressing is enabled (CONFIG_RISCV_GP=y), the gp reg points at 0x800 bytes past the start of the .sdata section which is then used by the linker to relax accesses to global symbols.
zephyr/include/zephyr/arch/riscv/common/linker.ld
Lines 305 to 319 in c0a0e6a
| #ifdef CONFIG_RISCV_GP | |
| /* | |
| * RISC-V architecture has 12-bit signed immediate offsets in the | |
| * instructions. If we can put the most commonly accessed globals | |
| * in a special 4K span of memory addressed by the GP register, then | |
| * we can access those values in a single instruction, saving both | |
| * codespace and runtime. | |
| * | |
| * Since these immediate offsets are signed, place gp 0x800 past the | |
| * beginning of .sdata so that we can use both positive and negative | |
| * offsets. | |
| */ | |
| . = ALIGN(8); | |
| PROVIDE (__global_pointer$ = . + 0x800); | |
| #endif |
However, the gp reg is not protected against write from userspace, this means that a rogue userspace can corrupt the gp reg, and cause the compiled instruction to access random addresses.
To Reproduce
Steps to reproduce the behavior:
- Build the
qemu_riscv64board with userspace andCONFIG_RISCV_GPenabled - Note the value of the
gpregister - Write some random value to the
gpreg from one userspace thread - Notice that the
gpreg is now changed
Expected behavior
The gp register should remain a constant.
Impact
A rogue thread can corrupt the gp reg and cause the entire system to hard fault at best, at worst, it can potentially trick the system to access another set of random global symbols.
Environment (please complete the following information):
- Toolchain (e.g Zephyr SDK, ...): 0.16.8
- Commit SHA or Version used: v3.7 branch