-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[lldb][Linux] Mark memory regions used for shadow stacks #117861
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
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1621,6 +1621,7 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( | |
| region_info.SetName(name.c_str()); | ||
| } else if (name == "flags") { | ||
| region_info.SetMemoryTagged(MemoryRegionInfo::eNo); | ||
| region_info.SetIsShadowStack(MemoryRegionInfo::eNo); | ||
|
|
||
| llvm::StringRef flags = value; | ||
| llvm::StringRef flag; | ||
|
|
@@ -1629,10 +1630,10 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( | |
| std::tie(flag, flags) = flags.split(' '); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. instead of tokenizing and checking cant we just use if (value.contains("ss")) |
||
| // To account for trailing whitespace | ||
| if (flag.size()) { | ||
| if (flag == "mt") { | ||
| if (flag == "mt") | ||
| region_info.SetMemoryTagged(MemoryRegionInfo::eYes); | ||
| break; | ||
| } | ||
| else if (flag == "ss") | ||
| region_info.SetIsShadowStack(MemoryRegionInfo::eYes); | ||
| } | ||
| } | ||
| } else if (name == "type") { | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| C_SOURCES := main.c | ||
|
|
||
| include Makefile.rules |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| """ | ||
| Check that lldb features work when the AArch64 Guarded Control Stack (GCS) | ||
| extension is enabled. | ||
| """ | ||
|
|
||
|
|
||
| import lldb | ||
| from lldbsuite.test.decorators import * | ||
| from lldbsuite.test.lldbtest import * | ||
| from lldbsuite.test import lldbutil | ||
|
|
||
|
|
||
| class AArch64LinuxGCSTestCase(TestBase): | ||
| NO_DEBUG_INFO_TESTCASE = True | ||
|
|
||
| @skipUnlessArch("aarch64") | ||
| @skipUnlessPlatform(["linux"]) | ||
| def test_gcs_region(self): | ||
| if not self.isAArch64GCS(): | ||
| self.skipTest("Target must support GCS.") | ||
|
|
||
| # This test assumes that we have /proc/<PID>/smaps files | ||
| # that include "VmFlags:" lines. | ||
| # AArch64 kernel config defaults to enabling smaps with | ||
| # PROC_PAGE_MONITOR and "VmFlags" was added in kernel 3.8, | ||
| # before GCS was supported at all. | ||
|
|
||
| self.build() | ||
| self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) | ||
|
|
||
| lldbutil.run_break_set_by_file_and_line( | ||
| self, | ||
| "main.c", | ||
| line_number("main.c", "// Set break point at this line."), | ||
| num_expected_locations=1, | ||
| ) | ||
|
|
||
| self.runCmd("run", RUN_SUCCEEDED) | ||
|
|
||
| if self.process().GetState() == lldb.eStateExited: | ||
| self.fail("Test program failed to run.") | ||
|
|
||
| self.expect( | ||
| "thread list", | ||
| STOPPED_DUE_TO_BREAKPOINT, | ||
| substrs=["stopped", "stop reason = breakpoint"], | ||
| ) | ||
|
|
||
| # By now either the program or the system C library enabled GCS and there | ||
| # should be one region marked for use by it (we cannot predict exactly | ||
| # where it will be). | ||
| self.runCmd("memory region --all") | ||
| found_ss = False | ||
| for line in self.res.GetOutput().splitlines(): | ||
| if line.strip() == "shadow stack: yes": | ||
| if found_ss: | ||
| self.fail("Found more than one shadow stack region.") | ||
| found_ss = True | ||
|
|
||
| self.assertTrue(found_ss, "Failed to find a shadow stack region.") | ||
|
|
||
| # Note that we must let the debugee get killed here as it cannot exit | ||
| # cleanly if GCS was manually enabled. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| #include <asm/hwcap.h> | ||
| #include <sys/auxv.h> | ||
| #include <sys/prctl.h> | ||
|
|
||
| #ifndef HWCAP2_GCS | ||
| #define HWCAP2_GCS (1UL << 63) | ||
| #endif | ||
|
|
||
| #define PR_GET_SHADOW_STACK_STATUS 74 | ||
| #define PR_SET_SHADOW_STACK_STATUS 75 | ||
| #define PR_SHADOW_STACK_ENABLE (1UL) | ||
| #define PRCTL_SYSCALL_NO 167 | ||
|
|
||
| // Once we enable GCS, we cannot return from the function that made the syscall | ||
| // to enable it. This is because the control stack is empty, there is no valid | ||
| // address for us to return to. So for the initial enable we must use inline asm | ||
| // instead of the libc's prctl wrapper function. | ||
| #define my_prctl(option, arg2, arg3, arg4, arg5) \ | ||
| ({ \ | ||
| register unsigned long x0 __asm__("x0") = option; \ | ||
| register unsigned long x1 __asm__("x1") = arg2; \ | ||
| register unsigned long x2 __asm__("x2") = arg3; \ | ||
| register unsigned long x3 __asm__("x3") = arg4; \ | ||
| register unsigned long x4 __asm__("x4") = arg5; \ | ||
| register unsigned long x8 __asm__("x8") = PRCTL_SYSCALL_NO; \ | ||
| __asm__ __volatile__("svc #0\n" \ | ||
| : "=r"(x0) \ | ||
| : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), \ | ||
| "r"(x8) \ | ||
| : "cc", "memory"); \ | ||
| }) | ||
|
|
||
| unsigned long get_gcs_status() { | ||
| unsigned long mode = 0; | ||
| prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); | ||
| return mode; | ||
| } | ||
|
|
||
| int main() { | ||
| if (!(getauxval(AT_HWCAP2) & HWCAP2_GCS)) | ||
| return 1; | ||
|
|
||
| unsigned long mode = get_gcs_status(); | ||
| if ((mode & 1) == 0) { | ||
| // If GCS wasn't already enabled by the C library, enable it. | ||
| my_prctl(PR_SET_SHADOW_STACK_STATUS, PR_SHADOW_STACK_ENABLE, 0, 0, 0); | ||
| // From this point on, we cannot return from main without faulting because | ||
| // the return address from main, and every function before that, is not on | ||
| // the guarded control stack. | ||
| } | ||
|
|
||
| // By now we should have one memory region where the GCS is stored. | ||
| return 0; // Set break point at this line. | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.