-
Notifications
You must be signed in to change notification settings - Fork 8k
arch: riscv: reset global pointer on exception #81155
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
Conversation
cc @cwshu |
Add macros to read / write hardware registers. Signed-off-by: Yong Cong Sin <[email protected]> Signed-off-by: Yong Cong Sin <[email protected]>
Reset the gp on exception entry from u-mode to protect the kernel against a possible rogue user thread. Signed-off-by: Yong Cong Sin <[email protected]> Signed-off-by: Yong Cong Sin <[email protected]>
Add a test to make sure that the `gp` global pointer register used for relative addressing when `CONFIG_RISCV_GP` is enabled can't be corrupted by a rogue user thread. Signed-off-by: Yong Cong Sin <[email protected]> Signed-off-by: Yong Cong Sin <[email protected]>
Added test |
Chris Friedt wrote:
Is the point here to illustrate that we _can_ use it from within uninterruptible context?
If `CONFIG_RISCV_GP` is set then gp is used by all the code compiled by gcc to reference global variables.
I let you imagine how futile the security model is if user threads may mess with it.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And yes, this should definitely be tagged as a security fix.
Just curious if we back up / restore GP already? If not, we may want to consider doing so. |
On Tue, 12 Nov 2024, Chris Friedt wrote:
@npitre, let me know if this aligns with your suggestion as well. I
understand it's adding one more register to push / pop, but it's maybe
worth it?
No it is not.
The gp, when so instructed by the build system, is relied upon by the
linker to produce tighter code for addressing global variables. In such
case it stands for "Global Pointer" and not "General Purpose". It is
then used potentially everywhere a relocation is involved: isr, thread
context, user context, etc. It is assumed by the linker to hold the same
value everywhere, be set once and never modified afterwards. You cannot
just accidentally "corrupt it (you're likely to crash right away). Even
the assembler needs this norelax mode to touch it otherwise it complains
with an error.
Please see
https://www.sifive.com/blog/all-aboard-part-3-linker-relaxation-in-riscv-toolchain
for more details.
So _preserving_ the gp is completely useless and wasteful. Restoring it
is also wasteful _unless_ untrusted code may be involved. That untrusted
code could potentially create a privilege elevation attack with a
carefully chosen gp value and syscall combination to trick the
privileged kernel code into updating the wrong global variable. That's
the reason why exiting user mode must re-set the gp value.
Now if we had an hypervisor switching between different OSes then
obviously that hypervisor would have to save and restore the gp value as
it is going to differ between different systems. But within a given
environment it is not meant to change.
|
Agree ! this should be merged ASAP imho. |
Why is there no backport to v3.6 for the patch provided? |
3.6 isn't my focus so I probably forgot about it last time - I'd suggest anyone still on v3.6 to use v3.7 as the latter is LTS |
Reset the gp on exception entry from u-mode to protect the kernel against a possible rogue user thread when global pointer (GP) relative addressing is enabled (
CONFIG_RISCV_GP=y
).Fixes #81372