Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork32k
gh-128605: Add branch protections for x86_64 in asm_trampoline.S#128606
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Conversation
In the current implementation the cf-protection test for x86_64 passes but not the branch-protection test for aarch64. |
fweimer-rh commentedJan 8, 2025
You should add PAC support at the same time, using |
Rebased. The conditionals are a bit of a mess right now so I'll do some macros later on. However annobin still reports:
Btw the arm blog proposes a different styled note than what the annobin docs mention:https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/p2-enabling-pac-and-bti-on-aarch64 Also regarding x86_64. Shouldn't the note be conditionalized in the case CET is active? |
cc'ing also@pablogsal as the original author of the file. |
bedevere-bot commentedJan 13, 2025
🤖 New build scheduled with the buildbot fleet by@pablogsal for commit549b894 🤖 If you want to schedule another build, you need to add the🔨 test-with-buildbots label again. |
pablogsal left a comment• edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
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.
This will break the DWARF mode as the debug information we are adding matches exactly with the current assembly instructions and positions:
cpython/Python/perf_jit_trampoline.c
Lines 452 to 489 ind0ecbdd
/* Emit DWARF EH CIE. */ | |
DWRF_SECTION(CIE,DWRF_U32(0);/* Offset to CIE itself. */ | |
DWRF_U8(DWRF_CIE_VERSION); | |
DWRF_STR("zR");/* Augmentation. */ | |
DWRF_UV(1);/* Code alignment factor. */ | |
DWRF_SV(-(int64_t)sizeof(uintptr_t));/* Data alignment factor. */ | |
DWRF_U8(DWRF_REG_RA);/* Return address register. */ | |
DWRF_UV(1); | |
DWRF_U8(DWRF_EH_PE_pcrel |DWRF_EH_PE_sdata4);/* Augmentation data. */ | |
DWRF_U8(DWRF_CFA_def_cfa);DWRF_UV(DWRF_REG_SP);DWRF_UV(sizeof(uintptr_t)); | |
DWRF_U8(DWRF_CFA_offset|DWRF_REG_RA);DWRF_UV(1); | |
DWRF_ALIGNNOP(sizeof(uintptr_t)); | |
) | |
ctx->eh_frame_p=p; | |
/* Emit DWARF EH FDE. */ | |
DWRF_SECTION(FDE,DWRF_U32((uint32_t)(p-framep));/* Offset to CIE. */ | |
DWRF_U32(-0x30);/* Machine code offset relative to .text. */ | |
DWRF_U32(ctx->code_size);/* Machine code length. */ | |
DWRF_U8(0);/* Augmentation data. */ | |
/* Registers saved in CFRAME. */ | |
#ifdef__x86_64__ | |
DWRF_U8(DWRF_CFA_advance_loc |4); | |
DWRF_U8(DWRF_CFA_def_cfa_offset);DWRF_UV(16); | |
DWRF_U8(DWRF_CFA_advance_loc |6); | |
DWRF_U8(DWRF_CFA_def_cfa_offset);DWRF_UV(8); | |
/* Extra registers saved for JIT-compiled code. */ | |
#elif defined(__aarch64__)&& defined(__AARCH64EL__)&& !defined(__ILP32__) | |
DWRF_U8(DWRF_CFA_advance_loc |1); | |
DWRF_U8(DWRF_CFA_def_cfa_offset);DWRF_UV(16); | |
DWRF_U8(DWRF_CFA_offset |29);DWRF_UV(2); | |
DWRF_U8(DWRF_CFA_offset |30);DWRF_UV(1); | |
DWRF_U8(DWRF_CFA_advance_loc |3); | |
DWRF_U8(DWRF_CFA_offset |-(64-29)); | |
DWRF_U8(DWRF_CFA_offset |-(64-30)); | |
DWRF_U8(DWRF_CFA_def_cfa_offset); | |
DWRF_UV(0); |
I am also not sure why this is needed other than make theannocheck
tool happy so I am not sure we want to add this extra complexity.
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
The justification for this change is provided at the linked issue. |
pablogsal commentedJan 13, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I don't think that justification is enough. The only thing the issue mentioned is that we are not using a feature and that the In any case, we need to check if the DWARF needs to be updated to account for the new instructions and if GDB can still unwind across them. |
Of course. Both ubuntu and Fedora (and by extension RHEL) and I assume other distros, enable by default the Both are implemented to mitigate return-oriented programming (ROP) and Call or Jump Oriented Programming (COP/JOP) attacks. Minimum supported CPU models are Intel's Tiger lake, AMD's Zen 3, Arm 8.3 (PAC) and Arm 8.5 (BTI). With pure C code everything is fine by just using the compiler flag(s), however when an assembly file is added to the mix the instructions need to be added manually. This feature is an all-or-nothing for the hardware functionality to work. All object files are checked for the note and if it's missing on any one, the linker does not place the note to the final executable and the hardening feature is disabled in the hardware. That essentially means that for Python 3.12+ these flags have no effect anymore. |
a7408db
to6d2d4f7
CompareOk makes sense. Thanks a lot for the extra context. We need to complement the DWARF information to ensure that the Perf JIT integration still works and we need to ensure gdb can still unwind through the trampolines when this information is active. |
Are JIT compilers expected to implement this as well? Or no, since they aren't statically present in the executable? |
pablogsal commentedJan 14, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Technically this code is also not present in the executable: we copy it from memory but the region itself where we copy it from is never executed. So if the answer is "no" then we shouldn't need this either |
Providing also a more practical reproducer. On Python 3.11 on x86_64:
Both of those flags indicate that CET protection is enabled. In Python 3.12+ they are not present. Of course when building with I'll familiarize myself with the debug information and try to figure it out. |
The answer here would be possibly yes, assembly instructions emitted by JITs should implement that, however I am not familiar myself with JITs in general or the way CPython implements it to provide a definite answer. As JIT is still being developed I'd treat this as an afterthought and revisit it in the future. |
fweimer-rh commentedJan 15, 2025
@pablogsal As the DWARF needs to be updated anyway, it may make sense to add the missing frame pointer to the x86-64 assembler (if Python's policy is to have frame pointers). Or is the goal to elide the calling frame from profiling backtraces? If the latter, there should really be a comment to this effect. |
fweimer-rh commentedJan 15, 2025
@brandtbucher For JIT compilers to keep working unchanged, they need to be marked as incompatible for now. On x86-64, SHSTK is generally automatically compatible with JIT compilation unless stack unwinding code is generated. However, x86-64 IBT requires marker instructions at the target of indirect branches. On AArch64, BTI is similar (marker instructions), but PAC is not process-switched on Linux: it's determined at boot whether it is turned on or not. The presence of the extra instructions merely ensures that the JIT code does not contain any easy-to-use JOP/ROP gadgets. Whether any of this matters is of course debatable, assuming that Python does not write-protect any of its bytecode in the process image. |
One of the problems is that if you add the frame pointer to the x86-64 assembler gdb cannot unwind through this when Python is compiled without frame pointers. The current version allows unwinding with and without frame pointers. |
I'm afraid this is a bit too jargon-heavy for me to follow without doing a bunch of self-guided research on the topic. What does it mean for the JIT code to be "marked incompatible"? I take it that if the process/kernel has these hardware features enabled, JIT code that doesn't use it will probably crash? What's the typical performance overhead of enabling this, and who exactly is using it (Ubuntu and Fedora were mentioned above... is itall users of these distros who would be unable to use our JIT)? |
bedevere-bot commentedMar 17, 2025
🤖 New build scheduled with the buildbot fleet by@pablogsal for commitf6dcc96 🤖 Results will be shown at: https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F128606%2Fmerge If you want to schedule another build, you need to add the🔨 test-with-buildbots label again. |
Will run the buildbots and I will do a pass and merge |
Btw this should be fine to backport to 3.13 and, without the perf_jit_trampoline.c changes, to 3.12. |
A single buildbot worker failed:
But it's an unrelated failure:
There is the same error in the main branch:https://buildbot.python.org/#/builders/484/builds/6705 |
It's a regression introduced by commitfd545d7: issue#127705. |
Required for mitigation against return-oriented programming (ROP) and Call or Jump Oriented Programming (COP/JOP) attacksProposed upstream:python#128606See also:https://sourceware.org/annobin/annobin.html/Test-cf-protection.html
Required for mitigation against return-oriented programming (ROP) and Call or Jump Oriented Programming (COP/JOP) attacksProposed upstream:python#128606See also:https://sourceware.org/annobin/annobin.html/Test-cf-protection.html
Required for mitigation against return-oriented programming (ROP) and Call or Jump Oriented Programming (COP/JOP) attacksProposed upstream:python#128606See also:https://sourceware.org/annobin/annobin.html/Test-cf-protection.html
Required for mitigation against return-oriented programming (ROP) and Call or Jump Oriented Programming (COP/JOP) attacksProposed upstream:python#128606See also:https://sourceware.org/annobin/annobin.html/Test-cf-protection.html
Required for mitigation against return-oriented programming (ROP) and Call or Jump Oriented Programming (COP/JOP) attacksProposed upstream:python#128606See also:https://sourceware.org/annobin/annobin.html/Test-cf-protection.html
Required for mitigation against return-oriented programming (ROP) and Call or Jump Oriented Programming (COP/JOP) attacksProposed upstream:python#128606See also:https://sourceware.org/annobin/annobin.html/Test-cf-protection.html
Required for mitigation against return-oriented programming (ROP) and Call or Jump Oriented Programming (COP/JOP) attacksProposed upstream:python#128606See also:https://sourceware.org/annobin/annobin.html/Test-cf-protection.html
Required for mitigation against return-oriented programming (ROP) and Call or Jump Oriented Programming (COP/JOP) attacksManual application is required for the assembly filesSee also:https://sourceware.org/annobin/annobin.html/Test-cf-protection.html
This will break the DWARF mode as the debug information we are adding matches exactly with the current assembly instructions and positions:
@stratakis updated to the PR to also modify Python/perf_jit_trampoline.c
I am also not sure why this is needed other than make the annocheck tool happy so I am not sure we want to add this extra complexity.
@stratakis elaborated the rationale in the meanwhile.
I built Python with this PR:
Without this PR (main branch), the protections are missing which is bad for security :-(
|
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.
LGTM. I confirm usingreadelf
that the change works as expected.
@pablogsal@brandtbucher: I plan to merge this change at the beginning of next week. Tell me if you want to review it and would prefer to have more time to review it.@pablogsal wrote that he planned to merge the change in March.
This change fix a security issue, it should be backported up to Python 3.12. Python 3.11 is not affected. |
I am happy yo go ahead. Let's do a last builedbot pass in the perf builedbot just to be sure |
!buildbot perf |
bedevere-bot commentedMay 30, 2025
🤖 New build scheduled with the buildbot fleet by@pablogsal for commit431d0e5 🤖 Results will be shown at: https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F128606%2Fmerge The command will test the builders whose names match following regular expression: The builders matched are:
|
Uh oh!
There was an error while loading.Please reload this page.