[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-05-13 Thread Nikita Popov via Phabricator via cfe-commits
nikic added a comment.

In D75936#2032090 , @craig.topper 
wrote:

> In D75936#2032078 , @sconstab wrote:
>
> > In D75936#2032027 , @nikic wrote:
> >
> > > This change causes a 0.8% compile-time regression for unoptimized builds 
> > > .
> > >  Based on the pipeline test diffs, I expect this is because the new pass 
> > > requests a bunch of analyses, which it most likely (LVI load hardening 
> > > disabled) will not need. Would it be possible to compute the analyses 
> > > only if LVI load hardening is actually enabled?
> >
> >
> > @craig.topper Do you have any ideas on how this could be done?
>
>
> Unfortunately due to LTO the need for LVI hardening is carried as a function 
> attribute. The pass manager system doesn't allow for running different passes 
> per function. So I don't have any good ideas of how to do that.


Hm, I see. One possibility would be to make those analyses lazy, but that's a 
larger change.

Possibly a pragmatic choice would be to not support this feature at O0? It does 
not seem relevant for non-production binaries. The relative impact of a couple 
unnecessary analysis passes is much higher at `O0` than it is at `O3`.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-05-12 Thread Matthew Riley via Phabricator via cfe-commits
mattdr added a comment.

I'm no expert in the pass manager, but given the very targeted applicability of 
LVI it definitely seems like our goal should be 0% impact for the vast majority 
of compilations that don't concern themselves with it.

Is there a way to require the pass be enabled for the compiler invocation as 
well as for the subtarget? If there's a mismatch (where LVI is desired but the 
required analyses weren't done) we can fail the compile.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-05-12 Thread Craig Topper via Phabricator via cfe-commits
craig.topper added inline comments.



Comment at: llvm/test/CodeGen/X86/O3-pipeline.ll:147
+; CHECK-NEXT:   X86 Load Value Injection (LVI) Load Hardening
 ; CHECK-NEXT:   Fixup Statepoint Caller Saved
 ; CHECK-NEXT:   PostRA Machine Sink

I'm curious what happens if we add AU.setPreservesCFG() to getAnalysisUsage in 
FixupStatepointCallerSaved.cpp  From a quick look through that pass it doesn't 
look like it changes the Machine CFG.

PostRA Machine Sink already preserves CFG. So I think that should remove the 
dominator tree construction after PostRA machine sink.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-05-12 Thread Craig Topper via Phabricator via cfe-commits
craig.topper added a comment.

In D75936#2032078 , @sconstab wrote:

> In D75936#2032027 , @nikic wrote:
>
> > This change causes a 0.8% compile-time regression for unoptimized builds 
> > .
> >  Based on the pipeline test diffs, I expect this is because the new pass 
> > requests a bunch of analyses, which it most likely (LVI load hardening 
> > disabled) will not need. Would it be possible to compute the analyses only 
> > if LVI load hardening is actually enabled?
>
>
> @craig.topper Do you have any ideas on how this could be done?


Unfortunately due to LTO the need for LVI hardening is carried as a function 
attribute. The pass manager system doesn't allow for running different passes 
per function. So I don't have any good ideas of how to do that.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-05-12 Thread Scott Constable via Phabricator via cfe-commits
sconstab added a comment.

In D75936#2032027 , @nikic wrote:

> This change causes a 0.8% compile-time regression for unoptimized builds 
> .
>  Based on the pipeline test diffs, I expect this is because the new pass 
> requests a bunch of analyses, which it most likely (LVI load hardening 
> disabled) will not need. Would it be possible to compute the analyses only if 
> LVI load hardening is actually enabled?


@craig.topper Do you have any ideas on how this could be done?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-05-12 Thread Nikita Popov via Phabricator via cfe-commits
nikic added a comment.

This change causes a 0.8% compile-time regression for unoptimized builds 
.
 Based on the pipeline test diffs, I expect this is because the new pass 
requests a bunch of analyses, which it most likely (LVI load hardening 
disabled) will not need. Would it be possible to compute the analyses only if 
LVI load hardening is actually enabled?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-05-11 Thread Craig Topper via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGe97a3e5d9d42: [X86] Add a Pass that builds a Condensed CFG 
for Load Value Injection (LVI)… (authored by sconstab, committed by 
craig.topper).

Changed prior to commit:
  https://reviews.llvm.org/D75936?vs=262816=263262#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-05-08 Thread Matthew Riley via Phabricator via cfe-commits
mattdr accepted this revision.
mattdr marked 2 inline comments as done.
mattdr added a comment.

The extra comments and the new variable name are all helpful. Thanks again.




Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:321-322
+  for (auto UseID : Uses) {
+if (!UsesVisited.insert(UseID).second)
+  continue; // Already visited this use of the current def
+

sconstab wrote:
> mattdr wrote:
> > "current def" is a bit ambiguous here. I _believe_ it means `AnalyzeDef`'s 
> > `Def` argument? At least, that's the interpretation that makes the comment 
> > make sense since `UsesVisited` is in `AnalyzeDef`'s scope.
> I am now trying to be clearer by using capital-d "Def" to refer specifically 
> to the def that is being analyzed, and lower-case-d "def" to refer to any 
> other defs. Do you think this is better? Good enough?
Much better. Thank you for the change!



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:341
+  if (UseMI.mayLoad())
+continue; // Found a transmitting load, stop traversing defs
+}

sconstab wrote:
> mattdr wrote:
> > The comment doesn't match the loop, which is traversing over `Uses`. More 
> > importantly, though: why are we allowed to stop traversing through `Uses` 
> > here? This `Def` won't be analyzed again, so this is our only chance to 
> > enumerate all transmitters to make sure we have all the necessary source -> 
> > sink edges in the gadget graph.
> @mattdr I think that the code is correct, and I added more to the comment in 
> an attempt to clarify. Let me know if you still think that this is an issue.
I definitely misread `continue` as `break` here. Thanks for the extra clarity 
and sorry for the noise.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-05-08 Thread Scott Constable via Phabricator via cfe-commits
sconstab updated this revision to Diff 262816.
sconstab marked 9 inline comments as done.
sconstab added a comment.

Addressed comments by @mattdr.

Several comments in the code have been updated, but the code has not changed.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-05-08 Thread Scott Constable via Phabricator via cfe-commits
sconstab added inline comments.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:295
+std::function)> AnalyzeDefUseChain =
+[&](NodeAddr Def) {
+  if (Transmitters.find(Def.Id) != Transmitters.end())

mattdr wrote:
> fwiw, this code would be easier to understand if we didn't shadow `Def` with 
> another variable named `Def`.
Changed the outer def to `SourceDef`, which also seems to make the code after 
the lambda a lot clearer.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:321-322
+  for (auto UseID : Uses) {
+if (!UsesVisited.insert(UseID).second)
+  continue; // Already visited this use of the current def
+

mattdr wrote:
> "current def" is a bit ambiguous here. I _believe_ it means `AnalyzeDef`'s 
> `Def` argument? At least, that's the interpretation that makes the comment 
> make sense since `UsesVisited` is in `AnalyzeDef`'s scope.
I am now trying to be clearer by using capital-d "Def" to refer specifically to 
the def that is being analyzed, and lower-case-d "def" to refer to any other 
defs. Do you think this is better? Good enough?



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:331
+// We naively assume that an instruction propagates any loaded
+// Uses to all Defs, unless the instruction is a call.
+if (UseMI.isCall())

mattdr wrote:
> Copying a comment from a previous iteration:
> 
> > Why is it okay to assume that a call doesn't propagate its uses to defs? Is 
> > it because we can assume the CFI transform is already inserting an LFENCE? 
> > Whatever the reason, let's state it explicitly here
> 
Added clarification to the comment.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:341
+  if (UseMI.mayLoad())
+continue; // Found a transmitting load, stop traversing defs
+}

mattdr wrote:
> The comment doesn't match the loop, which is traversing over `Uses`. More 
> importantly, though: why are we allowed to stop traversing through `Uses` 
> here? This `Def` won't be analyzed again, so this is our only chance to 
> enumerate all transmitters to make sure we have all the necessary source -> 
> sink edges in the gadget graph.
@mattdr I think that the code is correct, and I added more to the comment in an 
attempt to clarify. Let me know if you still think that this is an issue.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:366-369
+  llvm::sort(DefTransmitters);
+  DefTransmitters.erase(
+  std::unique(DefTransmitters.begin(), DefTransmitters.end()),
+  DefTransmitters.end());

mattdr wrote:
> Should `Transmitters` map to an `llvm::SmallSet`?
In my testing, `std::vector` seems a bit faster than `llvm::SmallSet`. I also 
suspect that `llvm::SmallSet` may waste more space because many defs will have 
no transmitters.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-05-07 Thread Matthew Riley via Phabricator via cfe-commits
mattdr added a comment.

Calling special attention to the comment at line 341, since I think it affects 
the correctness of the pass.




Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:287
+  // The `Transmitters` map memoizes transmitters found for each def. If a def
+  // has not yet been analyzed, then its list of transmitters will be empty.
+  DenseMap> Transmitters;

This comment doesn't seem to match how the map is used -- it looks like the 
loop assumes a def has been analyzed iff it is present in the map. This matches 
my expectation that, if a def is present and maps to an empty list, it would 
meant the def **had** been analyzed and found not to transmit.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:295
+std::function)> AnalyzeDefUseChain =
+[&](NodeAddr Def) {
+  if (Transmitters.find(Def.Id) != Transmitters.end())

fwiw, this code would be easier to understand if we didn't shadow `Def` with 
another variable named `Def`.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:321-322
+  for (auto UseID : Uses) {
+if (!UsesVisited.insert(UseID).second)
+  continue; // Already visited this use of the current def
+

"current def" is a bit ambiguous here. I _believe_ it means `AnalyzeDef`'s 
`Def` argument? At least, that's the interpretation that makes the comment make 
sense since `UsesVisited` is in `AnalyzeDef`'s scope.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:331
+// We naively assume that an instruction propagates any loaded
+// Uses to all Defs, unless the instruction is a call.
+if (UseMI.isCall())

Copying a comment from a previous iteration:

> Why is it okay to assume that a call doesn't propagate its uses to defs? Is 
> it because we can assume the CFI transform is already inserting an LFENCE? 
> Whatever the reason, let's state it explicitly here




Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:341
+  if (UseMI.mayLoad())
+continue; // Found a transmitting load, stop traversing defs
+}

The comment doesn't match the loop, which is traversing over `Uses`. More 
importantly, though: why are we allowed to stop traversing through `Uses` here? 
This `Def` won't be analyzed again, so this is our only chance to enumerate all 
transmitters to make sure we have all the necessary source -> sink edges in the 
gadget graph.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:364-365
+
+  // Remove duplicate transmitters
+  auto  = Transmitters[Def.Id];
+  llvm::sort(DefTransmitters);

This is also the place we populate `Transmitters` (with a default-constructed 
vector) for the current def if we haven't otherwise found any transmits. That's 
good, and necessary for `Transmitters` to remember we've analyzed the current 
def. But we should leave a comment about this subtle load-bearing side-effect.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:366-369
+  llvm::sort(DefTransmitters);
+  DefTransmitters.erase(
+  std::unique(DefTransmitters.begin(), DefTransmitters.end()),
+  DefTransmitters.end());

Should `Transmitters` map to an `llvm::SmallSet`?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-05-04 Thread Scott Constable via Phabricator via cfe-commits
sconstab updated this revision to Diff 261968.
sconstab marked 9 inline comments as done.
sconstab added a comment.
Herald added a subscriber: mgrang.

Addressed the previously unaddressed comments, as pointed out by @craig.topper.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-05-04 Thread Scott Constable via Phabricator via cfe-commits
sconstab added inline comments.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:322
+  DenseSet> GadgetEdgeSet;
+  auto AnalyzeUse = [&](NodeAddr Use, MachineInstr *MI) {
+assert(!(Use.Addr->getFlags() & NodeAttrs::PhiRef));

craig.topper wrote:
> mattdr wrote:
> > Please add a comment explaining the semantics of the boolean return here. I 
> > //think// it's: `true` if we need to consider defs of this instruction 
> > tainted by this use (and therefore add them for analysis); `false` if this 
> > instruction consumes its use
> Was this comment addressed?
It had not been addressed, so thank you for pointing this out. That lambda was 
doing too many things at once, which made it more confusing than it needed to 
be. So I just inlined it in the
```
for (auto N : Uses) {
…
}
```
loop, and I added some additional clarifying comments.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:341
+GadgetBegin.first, GadgetEnd.first);
+  if (UseMI.mayLoad()) // FIXME: This should be more precise
+return false;  // stop traversing further uses of `Reg`

craig.topper wrote:
> mattdr wrote:
> > Some more detail would be useful here: precise about what? What are the 
> > likely errors?
> > 
> Was this answered somewhere?
This was referring to the use of `mayLoad()`. At the time I wrote that comment, 
I wasn't sure that `mayLoad()` was exactly what was needed there, but I now 
think that it does suffice (SLH also uses `MachineInstr::mayLoad()`).



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:409
+NodeList Defs = SA.Addr->members_if(DataFlowGraph::IsDef, DFG);
+llvm::for_each(Defs, AnalyzeDef);
+  }

craig.topper wrote:
> mattdr wrote:
> > We analyze every def from every instruction in the function, but then 
> > //also// in `AnalyzeDefUseChain` analyze every def of every instruction 
> > with an interesting use. Are we doing a lot of extra work?
> Was this answered somewhere?
Wow, big oversight on my part. @mattdr was correct that this was doing a LOT of 
extra work. I added a memoization scheme that remembers the instructions that 
may transmit for each def. The getGadgetGraph() routine now runs about 75% 
faster.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-28 Thread Craig Topper via Phabricator via cfe-commits
craig.topper added inline comments.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:322
+  DenseSet> GadgetEdgeSet;
+  auto AnalyzeUse = [&](NodeAddr Use, MachineInstr *MI) {
+assert(!(Use.Addr->getFlags() & NodeAttrs::PhiRef));

mattdr wrote:
> Please add a comment explaining the semantics of the boolean return here. I 
> //think// it's: `true` if we need to consider defs of this instruction 
> tainted by this use (and therefore add them for analysis); `false` if this 
> instruction consumes its use
Was this comment addressed?



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:341
+GadgetBegin.first, GadgetEnd.first);
+  if (UseMI.mayLoad()) // FIXME: This should be more precise
+return false;  // stop traversing further uses of `Reg`

mattdr wrote:
> Some more detail would be useful here: precise about what? What are the 
> likely errors?
> 
Was this answered somewhere?



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:409
+NodeList Defs = SA.Addr->members_if(DataFlowGraph::IsDef, DFG);
+llvm::for_each(Defs, AnalyzeDef);
+  }

mattdr wrote:
> We analyze every def from every instruction in the function, but then 
> //also// in `AnalyzeDefUseChain` analyze every def of every instruction with 
> an interesting use. Are we doing a lot of extra work?
Was this answered somewhere?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-27 Thread Scott Constable via Phabricator via cfe-commits
sconstab updated this revision to Diff 260439.
sconstab added a comment.

Removed the `-x86-lvi-no-fixed` CLI flag. This change simplifies the code flow 
quite a bit.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-14 Thread Matthew Riley via Phabricator via cfe-commits
mattdr marked an inline comment as done.
mattdr added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:366
+std::vector TrimmedNodes(TrimNodes.size());
+for (size_type I = 0; I < TrimNodes.size(); ++I) {
+  TrimmedNodes[I] = TrimmedNodesSoFar;

craig.topper wrote:
> mattdr wrote:
> > Two comments here would make the code significantly easier to understand:
> > 1. Note that we're using `.size()` here rather than `.count()`, so we're 
> > actually iterating over *all* Node indices, not just the ones to be trimmed
> > 2. The `TrimmedNodes` vector maps indices in the original NodeSet to the 
> > number of `Node`s before that index that have been trimmed by that index, 
> > to allow later code to map elements to their new position in a dense array 
> > with the trimmed items removed
> I've stopped using TrimmedNodes.size() and TrimEdges.size() in favor of the 
> size methods from the graph which should make things more obvious.
> 
> I renamed TrimmedNodes to RemappedNodeIndex and stored the new index rather 
> than the adjustment needed. I'm also changed it to walk nodes instead of 
> indices so we don't have to translate to Node to make the contains call.
> 
> I also removed the NewNumEdges count_if and the if statement around the edge 
> loop from the loop below. I don't think that provided any value and just 
> complicated the code.
Many thanks! These changes make the code much more accessible.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-14 Thread Craig Topper via Phabricator via cfe-commits
craig.topper updated this revision to Diff 257549.
craig.topper added a comment.

Merge in test case from D77431  since it 
logically belongs with these changes.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-14 Thread Craig Topper via Phabricator via cfe-commits
craig.topper updated this revision to Diff 257488.
craig.topper marked an inline comment as done.
craig.topper added a comment.

Fix some mistakes I made in the previous upload where I accidentally deleted 
the pipeline tests instead of updating them.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-14 Thread Craig Topper via Phabricator via cfe-commits
craig.topper marked 6 inline comments as done.
craig.topper added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:366
+std::vector TrimmedNodes(TrimNodes.size());
+for (size_type I = 0; I < TrimNodes.size(); ++I) {
+  TrimmedNodes[I] = TrimmedNodesSoFar;

mattdr wrote:
> Two comments here would make the code significantly easier to understand:
> 1. Note that we're using `.size()` here rather than `.count()`, so we're 
> actually iterating over *all* Node indices, not just the ones to be trimmed
> 2. The `TrimmedNodes` vector maps indices in the original NodeSet to the 
> number of `Node`s before that index that have been trimmed by that index, to 
> allow later code to map elements to their new position in a dense array with 
> the trimmed items removed
I've stopped using TrimmedNodes.size() and TrimEdges.size() in favor of the 
size methods from the graph which should make things more obvious.

I renamed TrimmedNodes to RemappedNodeIndex and stored the new index rather 
than the adjustment needed. I'm also changed it to walk nodes instead of 
indices so we don't have to translate to Node to make the contains call.

I also removed the NewNumEdges count_if and the if statement around the edge 
loop from the loop below. I don't think that provided any value and just 
complicated the code.



Comment at: llvm/lib/Target/X86/X86ISelLowering.cpp:8626
   if (!Ld || (NumElts - NumUndefElts) <= 1) {
+dbgs() << "ctopper1\n";
 APInt SplatValue, Undef;

Oops this snuck in from something else I was experimenting with in my repo 
earlier. I'll remove.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:506
+const PseudoSourceValue *PSV = MMO->getPseudoValue();
+if (PSV && PSV->kind() == K && MMO->isLoad())
+  return true;

mattdr wrote:
> It seems very weird to make this a template argument rather than just, like, 
> a regular argument.
Agreed. I've remove the template argument and made it a static function instead 
of a method since it doesn't use anything from the class.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-14 Thread Craig Topper via Phabricator via cfe-commits
craig.topper updated this revision to Diff 257465.
craig.topper added a comment.

Address some of the review comments. Primarily the ones in ImmutableGraph. I 
did de-templatize the method in X86LoadValueInjectionLoadHardening.cpp


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86ISelLowering.cpp
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-13 Thread Matthew Riley via Phabricator via cfe-commits
mattdr accepted this revision.
mattdr added a comment.
This revision is now accepted and ready to land.

Accepting modulo some comments to be addressed. Most of my review effort was 
spent on the data structure and algorithm employed as well as code style and 
readability.

I am least confident about my understanding of `instrAccessesStackSlot` and the 
other functions that make up `instrIsFixedAccess`, since each function seems to 
be pattern-matching on something very specific without a reference to why. I 
also don't know if this diff provides an exhaustive list of fixed loads, or 
indeed if it was intended to.




Comment at: llvm/lib/Target/X86/ImmutableGraph.h:103
+
+  class NodeSet {
+friend class iterator;

sconstab wrote:
> This had not occurred to me until now, but a lot of code is shared between 
> `NodeSet` and `EdgeSet`. Maybe a template could reduce the redundancy?
Ideally I agree we'd find a way to collapse these -- but for this diff, let's 
content ourselves with a FIXME comment to that effect.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:102
+
+  size_type getNodeIndex(const Node ) const {
+return std::distance(nodes_begin(), );

Worth adding a comment for this (and `getEdgeIndex`) that this will crash if 
the `Node` (`Edge`) provided is not a reference into this specific instance of 
`ImmutableGraph`.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:340
+  auto NumEdges = static_cast(AdjList[VI].second.size());
+  if (NumEdges > 0) {
+for (size_type VEI = 0; VEI < NumEdges; ++VEI, ++EI) {

This `if` is unnecessary



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:348
+}
+assert(VI == VertexSize && EI == EdgeSize && "Gadget graph malformed");
+VertexArray[VI].Edges = [EdgeSize]; // terminator node

Technically a "generic" graph, so we should leave out "Gadget" here



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:366
+std::vector TrimmedNodes(TrimNodes.size());
+for (size_type I = 0; I < TrimNodes.size(); ++I) {
+  TrimmedNodes[I] = TrimmedNodesSoFar;

Two comments here would make the code significantly easier to understand:
1. Note that we're using `.size()` here rather than `.count()`, so we're 
actually iterating over *all* Node indices, not just the ones to be trimmed
2. The `TrimmedNodes` vector maps indices in the original NodeSet to the number 
of `Node`s before that index that have been trimmed by that index, to allow 
later code to map elements to their new position in a dense array with the 
trimmed items removed



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:56
+cl::desc("Don't treat conditional branches as disclosure gadgets. This "
+ "may improve performance, at the cost of security."),
+cl::init(false), cl::Hidden);

This is another case where references to good documentation will go a long way. 
Without details about what the tradeoff is and how to reason about it, it 
doesn't seem like anyone should use this flag.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:236
+  LLVM_DEBUG(dbgs() << "Hardening data-dependent loads...\n");
+  hardenLoads(MF, false);
+  LLVM_DEBUG(dbgs() << "Hardening data-dependent loads... Done\n");

Each call to `hardenLoads` leads to a call to `buildGadgetGraph`. A *lot* of 
the work that `getGadgetGraph` does seems to be common between mitigating fixed 
and non-fixed loads -- for example, computing register dataflow and liveness 
over the entire function.

And calling `hardenLoads` twice looks to be the common case, since 
`NoFixedLoads` is `false` by default.

Could we make this pass about half as expensive by default by combining these 
two calls to `hardenLoads` into one? It would do the expensive work once, then 
either harden _all_ loads or _only_ non-fixed loads.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:322
+  DenseSet> GadgetEdgeSet;
+  auto AnalyzeUse = [&](NodeAddr Use, MachineInstr *MI) {
+assert(!(Use.Addr->getFlags() & NodeAttrs::PhiRef));

Please add a comment explaining the semantics of the boolean return here. I 
//think// it's: `true` if we need to consider defs of this instruction tainted 
by this use (and therefore add them for analysis); `false` if this instruction 
consumes its use



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:329
+// to all Defs, unless the instruction is a call
+if (UseMI.isCall())
+  return false;

Why is it okay to assume that a call doesn't propagate its uses to defs? Is it 
because we can assume the CFI transform is already inserting an LFENCE? 
Whatever the reason, let's state it explicitly here



[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-10 Thread Matthew Riley via Phabricator via cfe-commits
mattdr added a comment.

@craig.topper can you please update/rebase this stack to remove the early LVI 
CFI work that ended up landed in https://reviews.llvm.org/D76812 instead?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-09 Thread Scott Constable via Phabricator via cfe-commits
sconstab added inline comments.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:233
+  if (!STI->useLVILoadHardening() || !STI->is64Bit())
+return false; // FIXME: support 32-bit
+

craig.topper wrote:
> sconstab wrote:
> > mattdr wrote:
> > > If the user requests hardening and we can't do it, it seems better to 
> > > fail loudly so they don't accidentally deploy an unmitigated binary.
> > @craig.topper I think this is related to the discussion we were having 
> > about what would happen for SLH on unsupported subtargets. I'm not sure 
> > what the most appropriate solution would be.
> Added a fatal error. Which isn't great as it will generate a crash report in 
> clang. But it will tell the user to file a compiler bug so I guess that's 
> something.
Would it be better to have
```
report_fatal_error("LVI load hardening is only supported on 64-bit "
   "targets.", false);
```
So that the crash diagnostic is not generated?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-08 Thread Craig Topper via Phabricator via cfe-commits
craig.topper updated this revision to Diff 256106.
craig.topper added a comment.

-Put llvm:: on the for_each calls in this patch instead of D75937 



CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-08 Thread Craig Topper via Phabricator via cfe-commits
craig.topper updated this revision to Diff 256103.
craig.topper marked 5 inline comments as done.
craig.topper added a comment.

-Replace ARG_NODE and GADGET_EDGE defines with static constexpr members


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-08 Thread Craig Topper via Phabricator via cfe-commits
craig.topper marked 37 inline comments as done and an inline comment as not 
done.
craig.topper added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:41
+class ImmutableGraph {
+  using Traits = GraphTraits *>;
+  template  friend class ImmutableGraphBuilder;

sconstab wrote:
> mattdr wrote:
> > I think this self-reference to `ImmutableGraph` dropped the `SizeT` 
> > parameter.
> Yup. Good catch.
Removed the template argument



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:73
+// The end of this Node's edges is the beginning of the next node's edges.
+const Edge *edges_end() const { return (this + 1)->Edges; }
+ArrayRef edges() const {

sconstab wrote:
> mattdr wrote:
> > sconstab wrote:
> > > mattdr wrote:
> > > > Seems like you also want to add a comment here that we know we will 
> > > > never be asked for `edges_end` for the last stored node -- that is, we 
> > > > know that `this + 1` always refers to a valid Node (which is presumably 
> > > > a dummy/sentinel)
> > > Not sure I agree. I cannot think of a conventional use of this interface 
> > > that would perform an operation on the sentinel.
> > > ```
> > > G->nodes_end().edges_end(); // invalid use of any end iterator
> > > SomeNode.edges_end(); // invalid if SomeNode == G->nodes_end()
> > > ```
> > > That is, the way that we "know" that we will never be asked for 
> > > `edges_end()` for the last stored node is that the ask itself would 
> > > already violate C++ conventions.
> > I believe any operation on the last `Node` in the array will end up 
> > accessing the sentinel:
> > 
> > ```
> > Node* LastNode = G->nodes_begin() + (G->nodes_size() - 1);  // valid 
> > reference to the last node
> > LastNode->edges_end();  // uses `this+1`, accessing the sentinel value in 
> > the Nodes array
> > ```
> > 
> `G->nodes_size()` will return the size without the sentinel node, so your 
> example should actually operate on the last data node. Right?
Comment added to clarify the extra node was allocated.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:117
+NodeSet(const ImmutableGraph , bool ContainsAll = false)
+: G{G}, V{static_cast(G.nodes_size()), ContainsAll} {}
+bool insert(const Node ) {

sconstab wrote:
> mattdr wrote:
> > How do we know that a value of `size_type` (aka `SizeT`) can be cast to 
> > `unsigned` without truncation?
> Ah. We do not know that. We could have a static assert here, but maybe the 
> best thing to do would be to follow Matt's earlier advice and fix `size_type` 
> to `int`, rather than have it as a template parameter. Anything larger would 
> break the `BitVectors` and/or waste space.
Removed the template argument



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:113
+  NumFences(NumFences), NumGadgets(NumGadgets) {}
+MachineFunction () { // FIXME: This function should be cleaner
+  for (const Node  : nodes())

mattdr wrote:
> sconstab wrote:
> > mattdr wrote:
> > > Cleaner how?
> > Maybe by keeping a member reference to the associated `MachineFunction`?
> Let's put that in the comment instead.
I found a way to remove the getMF method entirely.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:233
+  if (!STI->useLVILoadHardening() || !STI->is64Bit())
+return false; // FIXME: support 32-bit
+

sconstab wrote:
> mattdr wrote:
> > If the user requests hardening and we can't do it, it seems better to fail 
> > loudly so they don't accidentally deploy an unmitigated binary.
> @craig.topper I think this is related to the discussion we were having about 
> what would happen for SLH on unsupported subtargets. I'm not sure what the 
> most appropriate solution would be.
Added a fatal error. Which isn't great as it will generate a crash report in 
clang. But it will tell the user to file a compiler bug so I guess that's 
something.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-08 Thread Craig Topper via Phabricator via cfe-commits
craig.topper marked an inline comment as done.
craig.topper added inline comments.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:83-85
+#define ARG_NODE nullptr
+#define GADGET_EDGE ((int)(-1))
+#define WEIGHT(EdgeValue) ((double)(2 * (EdgeValue) + 1))

mattdr wrote:
> Please replace these with constants or functions.
Oops forgot to do this one.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-08 Thread Craig Topper via Phabricator via cfe-commits
craig.topper updated this revision to Diff 256073.
craig.topper added a comment.

Address review comments


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-07 Thread Scott Constable via Phabricator via cfe-commits
sconstab added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:73
+// The end of this Node's edges is the beginning of the next node's edges.
+const Edge *edges_end() const { return (this + 1)->Edges; }
+ArrayRef edges() const {

mattdr wrote:
> sconstab wrote:
> > mattdr wrote:
> > > Seems like you also want to add a comment here that we know we will never 
> > > be asked for `edges_end` for the last stored node -- that is, we know 
> > > that `this + 1` always refers to a valid Node (which is presumably a 
> > > dummy/sentinel)
> > Not sure I agree. I cannot think of a conventional use of this interface 
> > that would perform an operation on the sentinel.
> > ```
> > G->nodes_end().edges_end(); // invalid use of any end iterator
> > SomeNode.edges_end(); // invalid if SomeNode == G->nodes_end()
> > ```
> > That is, the way that we "know" that we will never be asked for 
> > `edges_end()` for the last stored node is that the ask itself would already 
> > violate C++ conventions.
> I believe any operation on the last `Node` in the array will end up accessing 
> the sentinel:
> 
> ```
> Node* LastNode = G->nodes_begin() + (G->nodes_size() - 1);  // valid 
> reference to the last node
> LastNode->edges_end();  // uses `this+1`, accessing the sentinel value in the 
> Nodes array
> ```
> 
`G->nodes_size()` will return the size without the sentinel node, so your 
example should actually operate on the last data node. Right?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-07 Thread Matthew Riley via Phabricator via cfe-commits
mattdr added a comment.

I'll wait for current comments to be addressed before doing my next round here.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-07 Thread Matthew Riley via Phabricator via cfe-commits
mattdr added a comment.

Some more comments. FWIW, I'm doing rounds of review as I can in some evening 
quiet or during my son's nap. This is a huge change and it's really hard to get 
any part of it into my head at once in a reasonable amount of time.




Comment at: llvm/lib/Target/X86/ImmutableGraph.h:73
+// The end of this Node's edges is the beginning of the next node's edges.
+const Edge *edges_end() const { return (this + 1)->Edges; }
+ArrayRef edges() const {

sconstab wrote:
> mattdr wrote:
> > Seems like you also want to add a comment here that we know we will never 
> > be asked for `edges_end` for the last stored node -- that is, we know that 
> > `this + 1` always refers to a valid Node (which is presumably a 
> > dummy/sentinel)
> Not sure I agree. I cannot think of a conventional use of this interface that 
> would perform an operation on the sentinel.
> ```
> G->nodes_end().edges_end(); // invalid use of any end iterator
> SomeNode.edges_end(); // invalid if SomeNode == G->nodes_end()
> ```
> That is, the way that we "know" that we will never be asked for `edges_end()` 
> for the last stored node is that the ask itself would already violate C++ 
> conventions.
I believe any operation on the last `Node` in the array will end up accessing 
the sentinel:

```
Node* LastNode = G->nodes_begin() + (G->nodes_size() - 1);  // valid reference 
to the last node
LastNode->edges_end();  // uses `this+1`, accessing the sentinel value in the 
Nodes array
```




Comment at: llvm/lib/Target/X86/ImmutableGraph.h:79
+
+protected:
+  ImmutableGraph(std::unique_ptr Nodes, std::unique_ptr Edges,

sconstab wrote:
> mattdr wrote:
> > Why "protected" rather than "private"? Usually seeing "protected" makes me 
> > think subclassing is expected, but that doesn't seem to be the case here.
> The `MachineGadgetGraph` class actually does subclass `ImmutableGraph` to add 
> some contextual information. I did not want the constructors for 
> `ImmutableGraph` to be public, because the intent is to use the builder. So 
> `protected` seemed like the best option.
Ah, I missed that. I searched through the file for `public ImmutableGraph` and 
didn't find it because `MachineGadgetGraph` uses the default inheritance 
specifier.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:83-85
+#define ARG_NODE nullptr
+#define GADGET_EDGE ((int)(-1))
+#define WEIGHT(EdgeValue) ((double)(2 * (EdgeValue) + 1))

Please replace these with constants or functions.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:113
+  NumFences(NumFences), NumGadgets(NumGadgets) {}
+MachineFunction () { // FIXME: This function should be cleaner
+  for (const Node  : nodes())

sconstab wrote:
> mattdr wrote:
> > Cleaner how?
> Maybe by keeping a member reference to the associated `MachineFunction`?
Let's put that in the comment instead.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-07 Thread Scott Constable via Phabricator via cfe-commits
sconstab added a comment.

Summary points for @craig.topper who has commandeered this diff:

- fix the typo that Matt pointed out
- `SizeT` should not be a template parameter, and `size_type` should be fixed 
to `int`.
- Maybe have a member reference in `MachineGadgetGraph` to the associated 
`MachineFunction`.
- Determine how this pass (and other X86 machine passes) should fail on 
unsupported X86 subtargets.




Comment at: llvm/lib/Target/X86/ImmutableGraph.h:41
+class ImmutableGraph {
+  using Traits = GraphTraits *>;
+  template  friend class ImmutableGraphBuilder;

mattdr wrote:
> I think this self-reference to `ImmutableGraph` dropped the `SizeT` parameter.
Yup. Good catch.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:73
+// The end of this Node's edges is the beginning of the next node's edges.
+const Edge *edges_end() const { return (this + 1)->Edges; }
+ArrayRef edges() const {

mattdr wrote:
> Seems like you also want to add a comment here that we know we will never be 
> asked for `edges_end` for the last stored node -- that is, we know that `this 
> + 1` always refers to a valid Node (which is presumably a dummy/sentinel)
Not sure I agree. I cannot think of a conventional use of this interface that 
would perform an operation on the sentinel.
```
G->nodes_end().edges_end(); // invalid use of any end iterator
SomeNode.edges_end(); // invalid if SomeNode == G->nodes_end()
```
That is, the way that we "know" that we will never be asked for `edges_end()` 
for the last stored node is that the ask itself would already violate C++ 
conventions.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:79
+
+protected:
+  ImmutableGraph(std::unique_ptr Nodes, std::unique_ptr Edges,

mattdr wrote:
> Why "protected" rather than "private"? Usually seeing "protected" makes me 
> think subclassing is expected, but that doesn't seem to be the case here.
The `MachineGadgetGraph` class actually does subclass `ImmutableGraph` to add 
some contextual information. I did not want the constructors for 
`ImmutableGraph` to be public, because the intent is to use the builder. So 
`protected` seemed like the best option.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:117
+NodeSet(const ImmutableGraph , bool ContainsAll = false)
+: G{G}, V{static_cast(G.nodes_size()), ContainsAll} {}
+bool insert(const Node ) {

mattdr wrote:
> How do we know that a value of `size_type` (aka `SizeT`) can be cast to 
> `unsigned` without truncation?
Ah. We do not know that. We could have a static assert here, but maybe the best 
thing to do would be to follow Matt's earlier advice and fix `size_type` to 
`int`, rather than have it as a template parameter. Anything larger would break 
the `BitVectors` and/or waste space.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:113
+  NumFences(NumFences), NumGadgets(NumGadgets) {}
+MachineFunction () { // FIXME: This function should be cleaner
+  for (const Node  : nodes())

mattdr wrote:
> Cleaner how?
Maybe by keeping a member reference to the associated `MachineFunction`?



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:233
+  if (!STI->useLVILoadHardening() || !STI->is64Bit())
+return false; // FIXME: support 32-bit
+

mattdr wrote:
> If the user requests hardening and we can't do it, it seems better to fail 
> loudly so they don't accidentally deploy an unmitigated binary.
@craig.topper I think this is related to the discussion we were having about 
what would happen for SLH on unsupported subtargets. I'm not sure what the most 
appropriate solution would be.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-07 Thread Matthew Riley via Phabricator via cfe-commits
mattdr added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:318
+}
+auto *VertexArray = new Node[VertexSize + 1 /* terminator node */];
+auto *EdgeArray = new Edge[EdgeSize];

sconstab wrote:
> mattdr wrote:
> > sconstab wrote:
> > > mattdr wrote:
> > > > As a general rule `new` is a code-smell in modern C++. This should be a 
> > > > `vector`.
> > > @mattdr I do agree with the general rule. I also think that in this case 
> > > where the structure is immutable, std::vector is wasteful because it 
> > > needs to keep separate values for the current number of elements and the 
> > > current capacity. At local scope within a function the unneeded value 
> > > would likely be optimized away, but then there would be an awkward 
> > > handoff to transfer the data from the vector to the array members.
> > > 
> > > I would not want to see the array members changed to vectors, unless LLVM 
> > > provides an encapsulated array structure that does not need to grow and 
> > > shrink.
> > So, first: I'm glad you removed the unnecessary use of `new[]` here and the 
> > corresponding (and error-prone!) use of `delete[]` later. That removes a 
> > memory leak LLVM won't have to debug.
> > 
> > You suggest here that something other than `std::vector` would be more 
> > efficient. If so, would `std::array` suffice? If not, can you explain why 
> > static allocation is impossible but dynamic allocation would be too 
> > expensive?
> A statically sized array (e.g., std::array) is insufficient because the size 
> in this case is not compiler determinable; a dynamically sized and 
> dynamically resizable array (e.g., std::vector) is sufficient but overly 
> costly; a dynamically sized and dynamically //unresizable// array is 
> sufficient and has minimal cost.
I'm not sure we allocate enough of these in the course of a compilation for the 
one extra word in a `std::vector` to matter, but I won't press the point.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:17
+///implemented as a bit vector, wherein each bit corresponds to one edge in
+///the edge array. This implies a lower bound of 64x spacial improvement
+///over, e.g., an llvm::DenseSet or llvm::SmallSet. It also means that

"spatial"



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:41
+class ImmutableGraph {
+  using Traits = GraphTraits *>;
+  template  friend class ImmutableGraphBuilder;

I think this self-reference to `ImmutableGraph` dropped the `SizeT` parameter.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:73
+// The end of this Node's edges is the beginning of the next node's edges.
+const Edge *edges_end() const { return (this + 1)->Edges; }
+ArrayRef edges() const {

Seems like you also want to add a comment here that we know we will never be 
asked for `edges_end` for the last stored node -- that is, we know that `this + 
1` always refers to a valid Node (which is presumably a dummy/sentinel)



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:79
+
+protected:
+  ImmutableGraph(std::unique_ptr Nodes, std::unique_ptr Edges,

Why "protected" rather than "private"? Usually seeing "protected" makes me 
think subclassing is expected, but that doesn't seem to be the case here.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:117
+NodeSet(const ImmutableGraph , bool ContainsAll = false)
+: G{G}, V{static_cast(G.nodes_size()), ContainsAll} {}
+bool insert(const Node ) {

How do we know that a value of `size_type` (aka `SizeT`) can be cast to 
`unsigned` without truncation?



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:298
+  static_assert(
+  std::is_base_of,
+  GraphT>::value,

this will also break if a non-default `SizeT` is provided. Maybe a good 
argument to just leave out `SizeT` for now, and it can be added in the future 
as needed?



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:113
+  NumFences(NumFences), NumGadgets(NumGadgets) {}
+MachineFunction () { // FIXME: This function should be cleaner
+  for (const Node  : nodes())

Cleaner how?



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:233
+  if (!STI->useLVILoadHardening() || !STI->is64Bit())
+return false; // FIXME: support 32-bit
+

If the user requests hardening and we can't do it, it seems better to fail 
loudly so they don't accidentally deploy an unmitigated binary.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-04 Thread Craig Topper via Phabricator via cfe-commits
craig.topper updated this revision to Diff 255086.
craig.topper added a comment.

-Add methods to get the index of a Node or Edge to remove calls to 
std::distance in various places


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-04 Thread Craig Topper via Phabricator via cfe-commits
craig.topper updated this revision to Diff 255084.
craig.topper added a comment.

-Apply updates to comments.
-Use nodes()/edges() to implement nodes_begin/end and edges_begin/end to 
simplify the code a little
-Reorder fields in the Graph class.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-04 Thread Craig Topper via Phabricator via cfe-commits
craig.topper marked 2 inline comments as done.
craig.topper added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:329
+size_type VI = 0, EI = 0;
+for (; VI < static_cast(AdjList.size()); ++VI) {
+  VertexArray[VI].Value = std::move(AdjList[VI].first);

Can this be changed to VI < VertexSize?



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:369
+continue;
+  size_type NewNumEdges = std::count_if(
+  NI->edges_begin(), NI->edges_end(),

I think I'll change this to llvm::count_if.  Also there was previously a 
conditional here that made sure the distance between edges was >0, but it 
didn't seem necessary. Please let me know if there's a reason I should put that 
back


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-04 Thread Craig Topper via Phabricator via cfe-commits
craig.topper marked 2 inline comments as done.
craig.topper added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:285
+  std::unique_ptr Edges;
+  size_type EdgesSize;
+};

sconstab wrote:
> @craig.topper It now occurs to me that these fields should probably be 
> reordered to:
> ```
>   std::unique_ptr Nodes;
>   std::unique_ptr Edges;
>   size_type NodesSize;
>   size_type EdgesSize;
> ```
> The current ordering will cause internal fragmentation.
> 
> Old ordering:
> ```
> static_assert(sizeof(ImmutableGraph) == 32);
> ```
> New ordering:
> ```
> static_assert(sizeof(ImmutableGraph) == 24);
> ```
> With vectors instead of arrays:
> ```
> static_assert(sizeof(ImmutableGraph) == 48);
> ```
I noticed that too. I just didn't focus on it since we only ever one in memory 
at a time. I'll change in my next update.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:307
+public:
+  using NodeRef = size_type;
+

sconstab wrote:
> Just noticed that `ImmutableGraphBuilder` and `ImmutableGraph` have 
> non-identical types called `NodeRef`. Suggest renaming this one to 
> `BuilderNodeRef`.
NodeRef is in the Traits class not the ImmutableGraph, but I will rename the 
builder one.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-04 Thread Scott Constable via Phabricator via cfe-commits
sconstab added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:307
+public:
+  using NodeRef = size_type;
+

Just noticed that `ImmutableGraphBuilder` and `ImmutableGraph` have 
non-identical types called `NodeRef`. Suggest renaming this one to 
`BuilderNodeRef`.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-04 Thread Scott Constable via Phabricator via cfe-commits
sconstab added a comment.

Overall, the restyling by @craig.topper looks much better than what I had 
committed before. I agree that `std::unique_ptr` is the right "container" 
in this circumstance. And the addition of `ArrayRef<>` accessors is also a nice 
touch. A few extra inline comments.




Comment at: llvm/lib/Target/X86/ImmutableGraph.h:13
+/// The advantages to this implementation are two-fold:
+/// 1. Iteration and traversal operations should experience terrific caching
+///performance.

sconstab wrote:
> mattdr wrote:
> > erm, "terrific"? If there's a substantive argument w.r.t. cache locality 
> > etc., please make it explicit.
> This is valid. I will reword.
"Iteration and traversal operations benefit from cache locality."



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:16
+/// 2. Set representations and operations on nodes and edges become
+///extraordinarily efficient. For instance, a set of edges is implemented 
as
+///a bit vector, wherein each bit corresponds to one edge in the edge

sconstab wrote:
> mattdr wrote:
> > "extraordinarily" is, again, not a useful engineering categorization. 
> > Please restrict comments to describing quantifiable claims of complexity.
> AFAIK there is not a precise engineering term for "tiny O(1)." Nonetheless I 
> will reword.
"Operations on sets of nodes/edges are efficient, and representations of those 
sets in memory are compact. For instance..."



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:84
+  : Nodes(std::move(Nodes)), NodesSize(NodesSize), Edges(std::move(Edges)),
+EdgesSize(EdgesSize) {}
+  ImmutableGraph(const ImmutableGraph &) = delete;

After the members are reordered, this list must also be reordered.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:103
+
+  class NodeSet {
+friend class iterator;

This had not occurred to me until now, but a lot of code is shared between 
`NodeSet` and `EdgeSet`. Maybe a template could reduce the redundancy?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-04 Thread Scott Constable via Phabricator via cfe-commits
sconstab added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:285
+  std::unique_ptr Edges;
+  size_type EdgesSize;
+};

@craig.topper It now occurs to me that these fields should probably be 
reordered to:
```
  std::unique_ptr Nodes;
  std::unique_ptr Edges;
  size_type NodesSize;
  size_type EdgesSize;
```
The current ordering will cause internal fragmentation.

Old ordering:
```
static_assert(sizeof(ImmutableGraph) == 32);
```
New ordering:
```
static_assert(sizeof(ImmutableGraph) == 24);
```
With vectors instead of arrays:
```
static_assert(sizeof(ImmutableGraph) == 48);
```


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-04 Thread Scott Constable via Phabricator via cfe-commits
sconstab added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:318
+}
+auto *VertexArray = new Node[VertexSize + 1 /* terminator node */];
+auto *EdgeArray = new Edge[EdgeSize];

mattdr wrote:
> sconstab wrote:
> > mattdr wrote:
> > > As a general rule `new` is a code-smell in modern C++. This should be a 
> > > `vector`.
> > @mattdr I do agree with the general rule. I also think that in this case 
> > where the structure is immutable, std::vector is wasteful because it needs 
> > to keep separate values for the current number of elements and the current 
> > capacity. At local scope within a function the unneeded value would likely 
> > be optimized away, but then there would be an awkward handoff to transfer 
> > the data from the vector to the array members.
> > 
> > I would not want to see the array members changed to vectors, unless LLVM 
> > provides an encapsulated array structure that does not need to grow and 
> > shrink.
> So, first: I'm glad you removed the unnecessary use of `new[]` here and the 
> corresponding (and error-prone!) use of `delete[]` later. That removes a 
> memory leak LLVM won't have to debug.
> 
> You suggest here that something other than `std::vector` would be more 
> efficient. If so, would `std::array` suffice? If not, can you explain why 
> static allocation is impossible but dynamic allocation would be too expensive?
A statically sized array (e.g., std::array) is insufficient because the size in 
this case is not compiler determinable; a dynamically sized and dynamically 
resizable array (e.g., std::vector) is sufficient but overly costly; a 
dynamically sized and dynamically //unresizable// array is sufficient and has 
minimal cost.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:13
+/// The advantages to this implementation are two-fold:
+/// 1. Iteration and traversal operations should experience terrific caching
+///performance.

mattdr wrote:
> erm, "terrific"? If there's a substantive argument w.r.t. cache locality 
> etc., please make it explicit.
This is valid. I will reword.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:16
+/// 2. Set representations and operations on nodes and edges become
+///extraordinarily efficient. For instance, a set of edges is implemented 
as
+///a bit vector, wherein each bit corresponds to one edge in the edge

mattdr wrote:
> "extraordinarily" is, again, not a useful engineering categorization. Please 
> restrict comments to describing quantifiable claims of complexity.
AFAIK there is not a precise engineering term for "tiny O(1)." Nonetheless I 
will reword.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:40
+
+template 
+class ImmutableGraph {

mattdr wrote:
> Every template argument for a class represents combinatorial addition of 
> complexity for the resulting code. Why do each of these template arguments 
> need to exist? in particular, why does SizeT need to exist?
I suspect that there may be more uses for this data structure and that 
eventually it may migrate to ADT. I have SizeT as a template argument because I 
found it plenty sufficient to have `int` as the size parameter for the array 
bounds, but I suspect other uses may require `size_t`.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-04 Thread Craig Topper via Phabricator via cfe-commits
craig.topper updated this revision to Diff 255028.
craig.topper added a comment.

-Add edge_begin()/edge_end()/edges() to Node class. Hides the N+1 trick used to 
find the end of a Node's edges.
-Add nodes()/edges() and use range-based for loops.
-Stop using things in the traits class since it doesn't have range-based for 
loops.
-Const-correct as required since nodes()/edges() return an ArrayRef that ends 
up making the range for loops const.
-Use llvm::for_each instead of std::for_each.
-Rename Node::value()/Edge::value() to getValue() to align with llvm naming 
convention.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-04 Thread Matthew Riley via Phabricator via cfe-commits
mattdr added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:318
+}
+auto *VertexArray = new Node[VertexSize + 1 /* terminator node */];
+auto *EdgeArray = new Edge[EdgeSize];

sconstab wrote:
> mattdr wrote:
> > As a general rule `new` is a code-smell in modern C++. This should be a 
> > `vector`.
> @mattdr I do agree with the general rule. I also think that in this case 
> where the structure is immutable, std::vector is wasteful because it needs to 
> keep separate values for the current number of elements and the current 
> capacity. At local scope within a function the unneeded value would likely be 
> optimized away, but then there would be an awkward handoff to transfer the 
> data from the vector to the array members.
> 
> I would not want to see the array members changed to vectors, unless LLVM 
> provides an encapsulated array structure that does not need to grow and 
> shrink.
So, first: I'm glad you removed the unnecessary use of `new[]` here and the 
corresponding (and error-prone!) use of `delete[]` later. That removes a memory 
leak LLVM won't have to debug.

You suggest here that something other than `std::vector` would be more 
efficient. If so, would `std::array` suffice? If not, can you explain why 
static allocation is impossible but dynamic allocation would be too expensive?



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:13
+/// The advantages to this implementation are two-fold:
+/// 1. Iteration and traversal operations should experience terrific caching
+///performance.

erm, "terrific"? If there's a substantive argument w.r.t. cache locality etc., 
please make it explicit.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:16
+/// 2. Set representations and operations on nodes and edges become
+///extraordinarily efficient. For instance, a set of edges is implemented 
as
+///a bit vector, wherein each bit corresponds to one edge in the edge

"extraordinarily" is, again, not a useful engineering categorization. Please 
restrict comments to describing quantifiable claims of complexity.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:40
+
+template 
+class ImmutableGraph {

Every template argument for a class represents combinatorial addition of 
complexity for the resulting code. Why do each of these template arguments need 
to exist? in particular, why does SizeT need to exist?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-04 Thread Craig Topper via Phabricator via cfe-commits
craig.topper updated this revision to Diff 255011.
craig.topper added a comment.

Use unique_ptr::operator[] in a few places.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-04 Thread Craig Topper via Phabricator via cfe-commits
craig.topper updated this revision to Diff 255008.
craig.topper added a comment.
This revision is now accepted and ready to land.

Use std::unique_ptr for arrays in the graph. I started trying to use 
std::vector, but it kept crashing. Which initially I thought was some issue 
with the fact that we store pointers into the vectors in other places and that 
somehow std::move of the vector was breaking that. I think I now realize its 
because the array is 1 larger than the real number of nodes and my std::vector 
version didn't take that into account.  But thinking about it more, since we 
are storing pointers into the array, it probably makes more sense for it to 
just be a plain array than a vector since resizing a vector would invalidate 
those pointers. Using an array makes it more clear than we don't resize.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-03 Thread Scott Constable via Phabricator via cfe-commits
sconstab added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:318
+}
+auto *VertexArray = new Node[VertexSize + 1 /* terminator node */];
+auto *EdgeArray = new Edge[EdgeSize];

mattdr wrote:
> As a general rule `new` is a code-smell in modern C++. This should be a 
> `vector`.
@mattdr I do agree with the general rule. I also think that in this case where 
the structure is immutable, std::vector is wasteful because it needs to keep 
separate values for the current number of elements and the current capacity. At 
local scope within a function the unneeded value would likely be optimized 
away, but then there would be an awkward handoff to transfer the data from the 
vector to the array members.

I would not want to see the array members changed to vectors, unless LLVM 
provides an encapsulated array structure that does not need to grow and shrink.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:335
+VertexArray[VI].__edges = EdgeArray + EdgeSize; // terminator node
+return new GraphT{VertexArray, VertexSize, EdgeArray, EdgeSize,
+  std::forward(Args)...};

mattdr wrote:
> this should return a `unique_ptr` to signal ownership transfer
Yes, agree.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-03 Thread Craig Topper via Phabricator via cfe-commits
craig.topper updated this revision to Diff 255000.
craig.topper added a comment.

Remove underscores from names.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-03 Thread Craig Topper via Phabricator via cfe-commits
craig.topper updated this revision to Diff 254962.
craig.topper marked an inline comment as done.
craig.topper added a comment.

Fix include guard on ImmutableGraph.h


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-03 Thread Craig Topper via Phabricator via cfe-commits
craig.topper added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:46-56
+  using NodeValueT = _NodeValueT;
+  using EdgeValueT = _EdgeValueT;
+  using size_type = _SizeT;
+  class Node;
+  class Edge {
+friend class ImmutableGraph;
+template  friend class ImmutableGraphBuilder;

chandlerc wrote:
> Folks, this isn't even close to following LLVM's coding conventions or naming 
> conventions.
> 
> These violate the C++ standard.
> 
> This shouldn't have been landed as-is. Can you all back this out and actually 
> dig into the review and get this to match LLVM's actual coding style and 
> standards?
Reverted at 1d42c0db9a2b27c149c5bac373caa5a6d38d1f74


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-03 Thread Matthew Riley via Phabricator via cfe-commits
mattdr added a comment.

Adding a few early style notes for the next round, but overall echo @chandlerc 
that this seems significantly outside of normal LLVM code.




Comment at: llvm/lib/Target/X86/ImmutableGraph.h:26
+
+#ifndef IMMUTABLEGRAPH_H
+#define IMMUTABLEGRAPH_H

It's sort of surprising that the LLVM style guide doesn't call this out 
explicitly, but `#include` guards are supposed to include the full file path. 
If they just used the filename, like, this, files with the same name in 
different paths would collide.

For an example of the expected style, see an adjacent header in this directory: 
https://github.com/llvm/llvm-project/blob/ba8b3052b59ebee4311d10bee5209dac8747acea/llvm/lib/Target/X86/X86AsmPrinter.h#L10




Comment at: llvm/lib/Target/X86/ImmutableGraph.h:318
+}
+auto *VertexArray = new Node[VertexSize + 1 /* terminator node */];
+auto *EdgeArray = new Edge[EdgeSize];

As a general rule `new` is a code-smell in modern C++. This should be a 
`vector`.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:335
+VertexArray[VI].__edges = EdgeArray + EdgeSize; // terminator node
+return new GraphT{VertexArray, VertexSize, EdgeArray, EdgeSize,
+  std::forward(Args)...};

this should return a `unique_ptr` to signal ownership transfer


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-03 Thread Chandler Carruth via Phabricator via cfe-commits
chandlerc added inline comments.



Comment at: llvm/lib/Target/X86/ImmutableGraph.h:46-56
+  using NodeValueT = _NodeValueT;
+  using EdgeValueT = _EdgeValueT;
+  using size_type = _SizeT;
+  class Node;
+  class Edge {
+friend class ImmutableGraph;
+template  friend class ImmutableGraphBuilder;

Folks, this isn't even close to following LLVM's coding conventions or naming 
conventions.

These violate the C++ standard.

This shouldn't have been landed as-is. Can you all back this out and actually 
dig into the review and get this to match LLVM's actual coding style and 
standards?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-03 Thread Craig Topper via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGc74dd640fd74: [X86] Add a Pass that builds a Condensed CFG 
for Load Value Injection (LVI)… (authored by sconstab, committed by 
craig.topper).
Herald added a project: clang.

Changed prior to commit:
  https://reviews.llvm.org/D75936?vs=251242=254896#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  clang/test/Driver/x86-target-features.c
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> 

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-04-02 Thread Zola Bridges via Phabricator via cfe-commits
zbrid accepted this revision.
zbrid added a subscriber: jyknight.
zbrid added a comment.
This revision is now accepted and ready to land.

LGTM. I would prefer if an actual LLVM maintainer also gave LGTM. @jyknight, 
@george.burgess.iv, @craig.topper?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-03-18 Thread Scott Constable via Phabricator via cfe-commits
sconstab updated this revision to Diff 251242.
sconstab added a comment.

Addressed Zola's comments.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Arch/X86.cpp
  llvm/lib/Target/X86/CMakeLists.txt
  llvm/lib/Target/X86/ImmutableGraph.h
  llvm/lib/Target/X86/X86.h
  llvm/lib/Target/X86/X86.td
  llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
  llvm/lib/Target/X86/X86Subtarget.h
  llvm/lib/Target/X86/X86TargetMachine.cpp
  llvm/test/CodeGen/X86/O0-pipeline.ll
  llvm/test/CodeGen/X86/O3-pipeline.ll
  llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll

Index: llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
===
--- /dev/null
+++ llvm/test/CodeGen/X86/lvi-hardening-gadget-graph.ll
@@ -0,0 +1,129 @@
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -x86-lvi-load-dot-verify -o %t < %s | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @test(i32* %untrusted_user_ptr, i32* %secret, i32 %secret_size) #0 {
+entry:
+  %untrusted_user_ptr.addr = alloca i32*, align 8
+  %secret.addr = alloca i32*, align 8
+  %secret_size.addr = alloca i32, align 4
+  %ret_val = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32* %untrusted_user_ptr, i32** %untrusted_user_ptr.addr, align 8
+  store i32* %secret, i32** %secret.addr, align 8
+  store i32 %secret_size, i32* %secret_size.addr, align 4
+  store i32 0, i32* %ret_val, align 4
+  call void @llvm.x86.sse2.lfence()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %secret_size.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+  %2 = load i32, i32* %i, align 4
+  %rem = srem i32 %2, 2
+  %cmp1 = icmp eq i32 %rem, 0
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:  ; preds = %for.body
+  %3 = load i32*, i32** %secret.addr, align 8
+  %4 = load i32, i32* %ret_val, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %3, i64 %idxprom
+  %5 = load i32, i32* %arrayidx, align 4
+  %6 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  store i32 %5, i32* %6, align 4
+  br label %if.end
+
+if.else:  ; preds = %for.body
+  %7 = load i32*, i32** %secret.addr, align 8
+  %8 = load i32, i32* %ret_val, align 4
+  %idxprom2 = sext i32 %8 to i64
+  %arrayidx3 = getelementptr inbounds i32, i32* %7, i64 %idxprom2
+  store i32 42, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:   ; preds = %if.else, %if.then
+  %9 = load i32*, i32** %untrusted_user_ptr.addr, align 8
+  %10 = load i32, i32* %9, align 4
+  store i32 %10, i32* %ret_val, align 4
+  br label %for.inc
+
+for.inc:  ; preds = %if.end
+  %11 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %11, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:  ; preds = %for.cond
+  %12 = load i32, i32* %ret_val, align 4
+  ret i32 %12
+}
+
+; CHECK:  digraph "Speculative gadgets for \"test\" function" {
+; CHECK-NEXT: label="Speculative gadgets for \"test\" function";
+; CHECK:  Node0x{{[0-9a-f]+}} [shape=record,color = green,label="{LFENCE\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 0];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{JCC_1 %bb.6, 13, implicit killed $eflags\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{CMP32rm killed renamable $eax, %stack.2.secret_size.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (dereferenceable load 4 from %ir.secret_size.addr)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} [shape=record,label="{renamable $eax = MOV32rm %stack.4.i, 1, $noreg, 0, $noreg :: (dereferenceable load 4 from %ir.i)\n}"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[color = red, style = "dashed"];
+; CHECK-NEXT: Node0x{{[0-9a-f]+}} -> Node0x{{[0-9a-f]+}}[label = 1];

[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-03-18 Thread Scott Constable via Phabricator via cfe-commits
sconstab marked 5 inline comments as done.
sconstab added inline comments.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:271
+// Apply the mitigation to `MF`, return the number of fences inserted.
+// If `FixedLoads` is `true`, then the mitigation will be applied to both fixed
+// and non-fixed loads; otherwise, only non-fixed loads.

zbrid wrote:
> Am I misunderstanding this comment? It sounds like if FixedLoads is true then 
> BOTH fixed loads and non-fixed loads will be mitigated. Since 
> runOnMachineFunction would call hardenLoads twice for non-fixed loads, would 
> that result in double mitigation for non-fixed loads in the case where we 
> also harden fixed loads? Unfortunately I'm having trouble reasoning through 
> this myself, so I'd appreciate some clarification.
The comment was incorrect.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75936: Add a Pass to X86 that builds a Condensed CFG for Load Value Injection (LVI) Gadgets [4/6]

2020-03-18 Thread Zola Bridges via Phabricator via cfe-commits
zbrid added a comment.

Thanks for putting this up! Here are a few comments.




Comment at: llvm/lib/Target/X86/ImmutableGraph.h:1
+//==-- ImmutableGraph.h - A fast DAG implementation 
-=//
+//

Might be useful if you add a comment about what makes this a fast DAG impl in 
case someone may want to use it later.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:254
+
+  LLVM_DEBUG(dbgs() << "* " << getPassName() << " : " << MF.getName()
+<< " *\n");

I think this should go at the top of the function.



Comment at: llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp:271
+// Apply the mitigation to `MF`, return the number of fences inserted.
+// If `FixedLoads` is `true`, then the mitigation will be applied to both fixed
+// and non-fixed loads; otherwise, only non-fixed loads.

Am I misunderstanding this comment? It sounds like if FixedLoads is true then 
BOTH fixed loads and non-fixed loads will be mitigated. Since 
runOnMachineFunction would call hardenLoads twice for non-fixed loads, would 
that result in double mitigation for non-fixed loads in the case where we also 
harden fixed loads? Unfortunately I'm having trouble reasoning through this 
myself, so I'd appreciate some clarification.



Comment at: llvm/test/CodeGen/X86/O0-pipeline.ll:61
+; CHECK-NEXT:   Machine Dominance Frontier Construction
+; CHECK-NEXT:   X86 Load Value Injection (LVI) Load Hardening Pass
 ; CHECK-NEXT:   Lazy Machine Block Frequency Analysis

Remove pass from name since that's typically the convention.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75936/new/

https://reviews.llvm.org/D75936



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits