This is an archive of the discontinued LLVM Phabricator instance.

[LLD] Implement /guard:[no]ehcont
ClosedPublic

Authored by pengfei on Mar 22 2021, 7:46 AM.

Diff Detail

Event Timeline

pengfei requested review of this revision.Mar 22 2021, 7:46 AM
pengfei created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptMar 22 2021, 7:46 AM
pengfei updated this revision to Diff 332576.Mar 23 2021, 2:19 AM

Add EHCont to load config table.

pengfei added a subscriber: rnk.Mar 23 2021, 2:30 AM

Hi @rnk , I'm implementing EHCont guard in LLD referring to your longjmp patch. Currently the binary's EHCont table always be null. I guess it results from I haven't told lld where's the place it should put the EHCont table in the load config table.
But I didn't find any related code in longjmp patch. Could you point me where the code is? Or I misunderstood something?

rnk added a comment.Mar 23 2021, 1:56 PM

Hi @rnk , I'm implementing EHCont guard in LLD referring to your longjmp patch. Currently the binary's EHCont table always be null. I guess it results from I haven't told lld where's the place it should put the EHCont table in the load config table.
But I didn't find any related code in longjmp patch. Could you point me where the code is? Or I misunderstood something?

The CRT is actually responsible for providing a struct defining the load configuration. You can see in the LLD gfids tests that they all have a blob like this:

        .section .rdata,"dr"
.globl _load_config_used
_load_config_used:
        .long 256
        .fill 124, 1, 0
        .quad __guard_fids_table
        .quad __guard_fids_count
        .long __guard_flags
        .fill 128, 1, 0

To add ehcont tests, you will need to provide a similar load config that llvm-readobj can parse. Hopefully that answers your question.

pengfei updated this revision to Diff 333000.Mar 24 2021, 8:14 AM

Solved the problems.

pengfei retitled this revision from [LLD][WIP] Implement /guard:[no]ehcont to [LLD] Implement /guard:[no]ehcont.Mar 24 2021, 8:19 AM
pengfei added reviewers: rnk, ruiu.
pengfei added subscribers: LuoYuanke, annita.zhang.
In D99078#2645963, @rnk wrote:

Hi @rnk , I'm implementing EHCont guard in LLD referring to your longjmp patch. Currently the binary's EHCont table always be null. I guess it results from I haven't told lld where's the place it should put the EHCont table in the load config table.
But I didn't find any related code in longjmp patch. Could you point me where the code is? Or I misunderstood something?

The CRT is actually responsible for providing a struct defining the load configuration. You can see in the LLD gfids tests that they all have a blob like this:

        .section .rdata,"dr"
.globl _load_config_used
_load_config_used:
        .long 256
        .fill 124, 1, 0
        .quad __guard_fids_table
        .quad __guard_fids_count
        .long __guard_flags
        .fill 128, 1, 0

To add ehcont tests, you will need to provide a similar load config that llvm-readobj can parse. Hopefully that answers your question.

Yes. It solves my problems. Thanks very much.
Now, the last question: I found it works with a given load configuration in the test (That's why I'm sure it's the right direction), but still doesn't work when using clang-cl or/and lld-link to build a cpp file. I guess it maybe related to the lld-link that doesn't use the latest CRT. Do you know how to fix this problem?

lld/test/COFF/pdb-natvis.test
17

I have no idea how this been affected by this patch.

pengfei updated this revision to Diff 333197.Mar 24 2021, 8:19 PM
  1. Remove lib dependency to make linux testing happy.
  2. Revert the change to pdb-natvis.test.
pengfei added inline comments.Mar 24 2021, 8:25 PM
lld/test/COFF/pdb-natvis.test
17

Since the change results in the build server fail, I suspect if it is my local problem. Reverted it to see if the build server happy.

rnk accepted this revision.Apr 13 2021, 3:59 PM

Looks good!

This revision is now accepted and ready to land.Apr 13 2021, 3:59 PM
In D99078#2687146, @rnk wrote:

Looks good!

Thanks for the review.

This revision was landed with ongoing or failed builds.Apr 14 2021, 12:07 AM
This revision was automatically updated to reflect the committed changes.
alvinhochun added inline comments.
lld/COFF/DriverUtils.cpp
104–114

This changed the behaviour of /guard:cf. Before this change, /guard:cf is equivalent to /guard:cf,longjmp by default, but after this change one must explicitly pass /guard:longjmp to`lld-link for it to generate the guard long jump table.

This also does not match the behaviour of MSVC's link.exe. From my quick testing, /guard:cf, /guard:longjmp and /guard:cf,longjmp all do the same thing for it to enable both CFGuard and the long jump table. Only when you pass /guard:cf,nolongjmp is the jump table not present in the final image.

Herald added a project: Restricted Project. · View Herald TranscriptAug 27 2022, 12:48 AM
Herald added a subscriber: ormris. · View Herald Transcript
pengfei added inline comments.Aug 27 2022, 3:07 AM
lld/COFF/DriverUtils.cpp
104–114

Thanks for raising the problem. I don't find any description about the longjmp option in official document. Unless there's explicit document about the relationship between /guard:cf, /guard:longjmp and /guard:cf,longjmp, I don't think we need to match the exact behavior with MSVC. The single /guard:cf has ambiguity since we are supporting ehcont. So I'm not sure if the current MSVC behavior is constant in future versions.

alvinhochun added inline comments.Aug 27 2022, 4:49 AM
lld/COFF/DriverUtils.cpp
104–114

I just think that, long jump guard seems to be a rather cheap hardening measure when control flow guard is already in use. Not enabling it by default perhaps seems a bit odd, especially since this feels like an unintentional change. But fine with me either way (I don't really use MSVC or Clang with MSVC target, just noticed the difference when investigating this LLD feature.)

pengfei added inline comments.Aug 27 2022, 5:47 AM
lld/COFF/DriverUtils.cpp
104–114

Thanks for the point. I'm not a MSVC/clang-cl user either. So I couldn't weight how cheap the long jump guard is. I designed it in the perspective of a junior user, to whom it's hard to understand the longjmp is on by default for some reason and need nolongjmp to disable it, while ehcont is on the contrary.
It would have value from the perspective of backward compatibility if we chose this way at the beginning. But the patch was merged more than one year... So let's keep it as is :)

rnk added inline comments.Aug 29 2022, 10:46 AM
lld/COFF/DriverUtils.cpp
104–114

I agree, longjump protections should be implied by /guard:cf. The nolongjump flag exists merely as a backwards compatibility escape hatch. Users should generally not specify /guard:longjump.

mstorsjo added inline comments.
lld/COFF/DriverUtils.cpp
104–114

Also, FWIW, even if the exact behaviour of Microsoft's tools isn't documented, such a detail like this would most probably not change randomly from one version to another. I also would prefer that we match link.exe's behaviour exactly on this point, instead of making up our own rules for how these flags interact.

pengfei added inline comments.Aug 29 2022, 6:12 PM
lld/COFF/DriverUtils.cpp
104–114

Thanks @rnk @mstorsjo ! That makes sense to me. I put D132901 to revert the behavior, please take a look, thanks!