diff options
author | Eli Bendersky <eliben@chromium.org> | 2013-07-02 08:55:49 -0700 |
---|---|---|
committer | Eli Bendersky <eliben@chromium.org> | 2013-07-02 08:55:49 -0700 |
commit | 43102ff480a59a1661a6390422835a705f199582 (patch) | |
tree | 02ccf79af79023f5e0b2b47af8b18b3f448ee692 | |
parent | 777f0e911fc0cbd0b07f9b3ae395b5361d19b270 (diff) |
Enable ABI verification check for whitelisting external symbols
BUG=https://code.google.com/p/nativeclient/issues/detail?id=3339
R=mseaborn@chromium.org
Review URL: https://codereview.chromium.org/18426002
-rw-r--r-- | lib/Analysis/NaCl/PNaClABIVerifyModule.cpp | 20 | ||||
-rw-r--r-- | test/NaCl/PNaClABI/abi-aliases.ll | 2 | ||||
-rw-r--r-- | test/NaCl/PNaClABI/abi-alignment.ll | 4 | ||||
-rw-r--r-- | test/NaCl/PNaClABI/abi-arithmetic-attributes.ll | 4 | ||||
-rw-r--r-- | test/NaCl/PNaClABI/abi-debug-info.ll | 4 | ||||
-rw-r--r-- | test/NaCl/PNaClABI/abi-externals-whitelist.ll | 24 | ||||
-rw-r--r-- | test/NaCl/PNaClABI/abi-flattened-globals.ll | 42 | ||||
-rw-r--r-- | test/NaCl/PNaClABI/abi-stripped-pointers.ll | 12 | ||||
-rw-r--r-- | test/NaCl/PNaClABI/abi-switch.ll | 4 | ||||
-rw-r--r-- | test/NaCl/PNaClABI/global-attributes.ll | 20 | ||||
-rw-r--r-- | test/NaCl/PNaClABI/instructions.ll | 28 | ||||
-rw-r--r-- | test/NaCl/PNaClABI/types.ll | 12 |
12 files changed, 109 insertions, 67 deletions
diff --git a/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp b/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp index b276e1cf2b..8bf0848fd7 100644 --- a/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp +++ b/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp @@ -68,6 +68,10 @@ class PNaClABIVerifyModule : public ModulePass { private: void checkGlobalValueCommon(const GlobalValue *GV); bool isWhitelistedMetadata(const NamedMDNode *MD); + + /// Returns whether \p GV is an allowed external symbol in stable bitcode. + bool isWhitelistedExternal(const GlobalValue *GV); + void checkGlobalIsFlattened(const GlobalVariable *GV); PNaClABIErrorReporter *Reporter; bool ReporterIsOwned; @@ -126,8 +130,13 @@ void PNaClABIVerifyModule::checkGlobalValueCommon(const GlobalValue *GV) { const char *GVTypeName = isa<GlobalVariable>(GV) ? "Variable " : "Function "; switch (GV->getLinkage()) { - // TODO(dschuff): Disallow external linkage case GlobalValue::ExternalLinkage: + if (!isWhitelistedExternal(GV)) { + Reporter->addError() + << GV->getName() + << " is not a valid external symbol (disallowed)\n"; + } + break; case GlobalValue::InternalLinkage: break; default: @@ -299,6 +308,15 @@ bool PNaClABIVerifyModule::isWhitelistedMetadata(const NamedMDNode *MD) { return MD->getName().startswith("llvm.dbg.") && PNaClABIAllowDebugMetadata; } +bool PNaClABIVerifyModule::isWhitelistedExternal(const GlobalValue *GV) { + if (const Function *Func = dyn_cast<const Function>(GV)) { + if (Func->getName().equals("_start") || Func->isIntrinsic()) { + return true; + } + } + return false; +} + static bool isPtrToIntOfGlobal(const Constant *C) { if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) { return CE->getOpcode() == Instruction::PtrToInt && diff --git a/test/NaCl/PNaClABI/abi-aliases.ll b/test/NaCl/PNaClABI/abi-aliases.ll index f245635236..0a1bf9ab11 100644 --- a/test/NaCl/PNaClABI/abi-aliases.ll +++ b/test/NaCl/PNaClABI/abi-aliases.ll @@ -1,6 +1,6 @@ ; RUN: pnacl-abicheck < %s | FileCheck %s -@aliased_var = global [1 x i8] c"x" +@aliased_var = internal global [1 x i8] c"x" ; CHECK-NOT: disallowed @alias1 = alias [1 x i8]* @aliased_var diff --git a/test/NaCl/PNaClABI/abi-alignment.ll b/test/NaCl/PNaClABI/abi-alignment.ll index 443fe44507..a31914e4be 100644 --- a/test/NaCl/PNaClABI/abi-alignment.ll +++ b/test/NaCl/PNaClABI/abi-alignment.ll @@ -10,7 +10,7 @@ declare void @llvm.memmove.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1) declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i32, i1) -define void @allowed_cases(i32 %ptr, float %f, double %d) { +define internal void @allowed_cases(i32 %ptr, float %f, double %d) { %ptr.i32 = inttoptr i32 %ptr to i32* load i32* %ptr.i32, align 1 store i32 123, i32* %ptr.i32, align 1 @@ -49,7 +49,7 @@ define void @allowed_cases(i32 %ptr, float %f, double %d) { ; CHECK-NOT: disallowed -define void @rejected_cases(i32 %ptr, float %f, double %d, i32 %align) { +define internal void @rejected_cases(i32 %ptr, float %f, double %d, i32 %align) { %ptr.i32 = inttoptr i32 %ptr to i32* load i32* %ptr.i32, align 4 store i32 123, i32* %ptr.i32, align 4 diff --git a/test/NaCl/PNaClABI/abi-arithmetic-attributes.ll b/test/NaCl/PNaClABI/abi-arithmetic-attributes.ll index 03304fb08c..c223830ac5 100644 --- a/test/NaCl/PNaClABI/abi-arithmetic-attributes.ll +++ b/test/NaCl/PNaClABI/abi-arithmetic-attributes.ll @@ -4,7 +4,7 @@ ; unsigned wrap" and "no signed wrap") and "exact" are disallowed by ; the PNaCl ABI verifier. -define void @allowed_cases() { +define internal void @allowed_cases() { %add = add i32 1, 2 %shl = shl i32 3, 4 %udiv = udiv i32 4, 2 @@ -15,7 +15,7 @@ define void @allowed_cases() { ; CHECK-NOT: disallowed -define void @rejected_cases() { +define internal void @rejected_cases() { %add = add nsw i32 1, 2 ; CHECK: disallowed: has "nsw" attribute: %add %shl1 = shl nuw i32 3, 4 diff --git a/test/NaCl/PNaClABI/abi-debug-info.ll b/test/NaCl/PNaClABI/abi-debug-info.ll index 95efa0ced7..49b31bab91 100644 --- a/test/NaCl/PNaClABI/abi-debug-info.ll +++ b/test/NaCl/PNaClABI/abi-debug-info.ll @@ -15,7 +15,7 @@ declare void @llvm.dbg.value(metadata, i64, metadata) ; CHECK: Function llvm.dbg.value is a disallowed LLVM intrinsic -define void @debug_declare(i32 %val) { +define internal void @debug_declare(i32 %val) { ; We normally expect llvm.dbg.declare to be used on an alloca. %var = alloca [4 x i8] tail call void @llvm.dbg.declare(metadata !{[4 x i8]* %var}, metadata !{}) @@ -23,7 +23,7 @@ define void @debug_declare(i32 %val) { ret void } -define void @debug_value(i32 %ptr_as_int, i32 %val) { +define internal void @debug_value(i32 %ptr_as_int, i32 %val) { %ptr = inttoptr i32 %ptr_as_int to i8* tail call void @llvm.dbg.value(metadata !{i8* %ptr}, i64 2, metadata !{}) tail call void @llvm.dbg.value(metadata !{i32 %val}, i64 1, metadata !{}) diff --git a/test/NaCl/PNaClABI/abi-externals-whitelist.ll b/test/NaCl/PNaClABI/abi-externals-whitelist.ll new file mode 100644 index 0000000000..e0ec6e896b --- /dev/null +++ b/test/NaCl/PNaClABI/abi-externals-whitelist.ll @@ -0,0 +1,24 @@ +; RUN: pnacl-abicheck < %s | FileCheck %s + +; Make sure that external symbols are properly rejected or accepted + +define void @foo() { + ret void +} + +; CHECK: foo is not a valid external symbol (disallowed) + +define external void @main() { + ret void +} +; CHECK: main is not a valid external symbol (disallowed) + +define external void @_start() { + ret void +} +; _start is whitelisted +; CHECK-NOT: _start is not a valid external symbol (disallowed) + +; Intrinsics can be external too +declare void @llvm.trap() + diff --git a/test/NaCl/PNaClABI/abi-flattened-globals.ll b/test/NaCl/PNaClABI/abi-flattened-globals.ll index c1c7235995..38f9ca8109 100644 --- a/test/NaCl/PNaClABI/abi-flattened-globals.ll +++ b/test/NaCl/PNaClABI/abi-flattened-globals.ll @@ -3,25 +3,25 @@ ; Allowed cases -@bytes = global [7 x i8] c"abcdefg" +@bytes = internal global [7 x i8] c"abcdefg" -@ptr_to_ptr = global i32 ptrtoint (i32* @ptr to i32) -@ptr_to_func = global i32 ptrtoint (void ()* @func to i32) +@ptr_to_ptr = internal global i32 ptrtoint (i32* @ptr to i32) +@ptr_to_func = internal global i32 ptrtoint (void ()* @func to i32) -@compound = global <{ [3 x i8], i32 }> +@compound = internal global <{ [3 x i8], i32 }> <{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }> -@ptr = global i32 ptrtoint ([7 x i8]* @bytes to i32) +@ptr = internal global i32 ptrtoint ([7 x i8]* @bytes to i32) -@addend_ptr = global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1) -@addend_negative = global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1) +@addend_ptr = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1) +@addend_negative = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1) -@addend_array1 = global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1) -@addend_array2 = global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7) -@addend_array3 = global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9) +@addend_array1 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1) +@addend_array2 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7) +@addend_array3 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9) -@addend_struct1 = global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1) -@addend_struct2 = global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4) +@addend_struct1 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1) +@addend_struct2 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4) ; CHECK-NOT: disallowed @@ -31,39 +31,39 @@ @bad_external = external global [1 x i8] ; CHECK: Global variable bad_external has no initializer (disallowed) -@bad_int = global i32 0 +@bad_int = internal global i32 0 ; CHECK: Global variable bad_int has non-flattened initializer (disallowed): i32 0 -@bad_size = global i64 ptrtoint ([7 x i8]* @bytes to i64) +@bad_size = internal global i64 ptrtoint ([7 x i8]* @bytes to i64) ; CHECK: Global variable bad_size has non-flattened initializer ; "null" is not allowed. -@bad_ptr = global i8* null +@bad_ptr = internal global i8* null ; CHECK: Global variable bad_ptr has non-flattened initializer -@bad_ptr2 = global i64 ptrtoint (i8* null to i64) +@bad_ptr2 = internal global i64 ptrtoint (i8* null to i64) ; CHECK: Global variable bad_ptr2 has non-flattened initializer -@bad_sub = global i32 sub (i32 ptrtoint (i32* @ptr to i32), i32 1) +@bad_sub = internal global i32 sub (i32 ptrtoint (i32* @ptr to i32), i32 1) ; CHECK: Global variable bad_sub has non-flattened initializer ; i16 not allowed here. -@bad_compound = global <{ i32, i16 }> +@bad_compound = internal global <{ i32, i16 }> <{ i32 ptrtoint (void ()* @func to i32), i16 0 }> ; CHECK: Global variable bad_compound has non-flattened initializer ; The struct type must be packed. -@non_packed_struct = global { [3 x i8], i32 } +@non_packed_struct = internal global { [3 x i8], i32 } { [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) } ; CHECK: Global variable non_packed_struct has non-flattened initializer ; The struct type must be anonymous. %struct = type <{ [3 x i8], i32 }> -@named_struct = global %struct +@named_struct = internal global %struct <{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }> ; CHECK: Global variable named_struct has non-flattened initializer -define void @func() { +define internal void @func() { ret void } diff --git a/test/NaCl/PNaClABI/abi-stripped-pointers.ll b/test/NaCl/PNaClABI/abi-stripped-pointers.ll index 07516fb290..8f23cbce16 100644 --- a/test/NaCl/PNaClABI/abi-stripped-pointers.ll +++ b/test/NaCl/PNaClABI/abi-stripped-pointers.ll @@ -10,26 +10,26 @@ declare i8* @llvm.nacl.read.tp() -define void @pointer_arg(i8* %arg) { +define internal void @pointer_arg(i8* %arg) { ret void } ; CHECK: Function pointer_arg has disallowed type -define i8* @pointer_return() { +define internal i8* @pointer_return() { unreachable } ; CHECK-NEXT: Function pointer_return has disallowed type -define void @func() { +define internal void @func() { ret void } -define void @func_with_arg(i32 %arg) { +define internal void @func_with_arg(i32 %arg) { ret void } -define void @allowed_cases(i32 %arg) { +define internal void @allowed_cases(i32 %arg) { inttoptr i32 123 to i8* ptrtoint [4 x i8]* @var to i32 @@ -75,7 +75,7 @@ define void @allowed_cases(i32 %arg) { ; CHECK-NOT: disallowed -define void @bad_cases() { +define internal void @bad_cases() { entry: ptrtoint [4 x i8]* @var to i16 ; CHECK: Function bad_cases disallowed: non-i32 ptrtoint diff --git a/test/NaCl/PNaClABI/abi-switch.ll b/test/NaCl/PNaClABI/abi-switch.ll index a3b5e631fc..c545f4e1f7 100644 --- a/test/NaCl/PNaClABI/abi-switch.ll +++ b/test/NaCl/PNaClABI/abi-switch.ll @@ -1,11 +1,11 @@ ; RUN: pnacl-abicheck < %s | FileCheck %s -@var = global [4 x i8] c"xxxx" +@var = internal global [4 x i8] c"xxxx" ; CHECK-NOT: disallowed -define void @bad_cases() { +define internal void @bad_cases() { ; ConstantExprs should be rejected here. switch i32 ptrtoint ([4 x i8]* @var to i32), label %next [i32 0, label %next] ; CHECK: disallowed: bad switch condition diff --git a/test/NaCl/PNaClABI/global-attributes.ll b/test/NaCl/PNaClABI/global-attributes.ll index c5253b3b63..45ed9c2fb6 100644 --- a/test/NaCl/PNaClABI/global-attributes.ll +++ b/test/NaCl/PNaClABI/global-attributes.ll @@ -3,16 +3,16 @@ ; Global variable attributes ; CHECK: Variable var_with_section has disallowed "section" attribute -@var_with_section = global [1 x i8] zeroinitializer, section ".some_section" +@var_with_section = internal global [1 x i8] zeroinitializer, section ".some_section" ; PNaCl programs can depend on data alignments in general, so we allow ; "align" on global variables. ; CHECK-NOT: var_with_alignment -@var_with_alignment = global [4 x i8] zeroinitializer, align 8 +@var_with_alignment = internal global [4 x i8] zeroinitializer, align 8 ; TLS variables must be expanded out by ExpandTls. ; CHECK-NEXT: Variable tls_var has disallowed "thread_local" attribute -@tls_var = thread_local global [4 x i8] zeroinitializer +@tls_var = internal thread_local global [4 x i8] zeroinitializer ; CHECK-NEXT: Variable var_with_unnamed_addr has disallowed "unnamed_addr" attribute @var_with_unnamed_addr = internal unnamed_addr constant [1 x i8] c"x" @@ -24,37 +24,37 @@ ; Function attributes ; CHECK-NEXT: Function func_with_attrs has disallowed attributes: noreturn nounwind -define void @func_with_attrs() noreturn nounwind { +define internal void @func_with_attrs() noreturn nounwind { ret void } ; CHECK-NEXT: Function func_with_arg_attrs has disallowed attributes: inreg zeroext -define void @func_with_arg_attrs(i32 inreg zeroext) { +define internal void @func_with_arg_attrs(i32 inreg zeroext) { ret void } ; CHECK-NEXT: Function func_with_callingconv has disallowed calling convention: 8 -define fastcc void @func_with_callingconv() { +define internal fastcc void @func_with_callingconv() { ret void } ; CHECK-NEXT: Function func_with_section has disallowed "section" attribute -define void @func_with_section() section ".some_section" { +define internal void @func_with_section() section ".some_section" { ret void } ; CHECK-NEXT: Function func_with_alignment has disallowed "align" attribute -define void @func_with_alignment() align 1 { +define internal void @func_with_alignment() align 1 { ret void } ; CHECK-NEXT: Function func_with_gc has disallowed "gc" attribute -define void @func_with_gc() gc "my_gc_func" { +define internal void @func_with_gc() gc "my_gc_func" { ret void } ; CHECK-NEXT: Function func_with_unnamed_addr has disallowed "unnamed_addr" attribute -define void @func_with_unnamed_addr() unnamed_addr { +define internal void @func_with_unnamed_addr() unnamed_addr { ret void } diff --git a/test/NaCl/PNaClABI/instructions.ll b/test/NaCl/PNaClABI/instructions.ll index 49e8df5126..eb659cbffb 100644 --- a/test/NaCl/PNaClABI/instructions.ll +++ b/test/NaCl/PNaClABI/instructions.ll @@ -4,7 +4,7 @@ target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:32" target triple = "le32-unknown-nacl" -define void @terminators() { +define internal void @terminators() { ; Terminator instructions terminators: ret void @@ -18,7 +18,7 @@ next2: indirectbr i8* undef, [label %next, label %next2] } -define void @binops() { +define internal void @binops() { ; Binary operations %a1 = add i32 0, 0 %a2 = sub i32 0, 0 @@ -41,7 +41,7 @@ define void @binops() { ret void } -define void @vectors() { +define internal void @vectors() { ; CHECK-NOT: disallowed ; CHECK: disallowed: bad instruction opcode: {{.*}} extractelement @@ -56,7 +56,7 @@ define void @vectors() { ret void } -define void @aggregates() { +define internal void @aggregates() { ; CHECK-NOT: disallowed ; Aggregate operations @@ -69,7 +69,7 @@ define void @aggregates() { ret void } -define void @memory() { +define internal void @memory() { ; Memory operations %a1 = alloca i8, i32 4 %ptr = inttoptr i32 0 to i32* @@ -84,7 +84,7 @@ define void @memory() { ret void } -define void @conversion() { +define internal void @conversion() { ; Conversion operations %a1 = trunc i32 undef to i8 %a2 = zext i8 undef to i32 @@ -98,7 +98,7 @@ define void @conversion() { ret void } -define void @other() { +define internal void @other() { entry: %a1 = icmp eq i32 undef, undef %a2 = fcmp oeq float undef, undef @@ -113,14 +113,14 @@ bar: ret void } -define void @throwing_func() { +define internal void @throwing_func() { ret void } -define void @personality_func() { +define internal void @personality_func() { ret void } -define void @invoke_func() { +define internal void @invoke_func() { invoke void @throwing_func() to label %ok unwind label %onerror ; CHECK-NOT: disallowed ; CHECK: disallowed: bad instruction opcode: invoke @@ -135,7 +135,7 @@ onerror: ; CHECK: disallowed: bad instruction opcode: resume } -define i32 @va_arg(i32 %va_list_as_int) { +define internal i32 @va_arg(i32 %va_list_as_int) { %va_list = inttoptr i32 %va_list_as_int to i8* %val = va_arg i8* %va_list, i32 ret i32 %val @@ -143,16 +143,16 @@ define i32 @va_arg(i32 %va_list_as_int) { ; CHECK-NOT: disallowed ; CHECK: disallowed: bad instruction opcode: {{.*}} va_arg -@global_var = global [4 x i8] zeroinitializer +@global_var = internal global [4 x i8] zeroinitializer -define void @constantexpr() { +define internal void @constantexpr() { ptrtoint i8* getelementptr ([4 x i8]* @global_var, i32 1, i32 0) to i32 ret void } ; CHECK-NOT: disallowed ; CHECK: disallowed: operand not InherentPtr: %1 = ptrtoint i8* getelementptr -define void @inline_asm() { +define internal void @inline_asm() { call void asm "foo", ""() ret void } diff --git a/test/NaCl/PNaClABI/types.ll b/test/NaCl/PNaClABI/types.ll index 2a331324dc..6b8335504e 100644 --- a/test/NaCl/PNaClABI/types.ll +++ b/test/NaCl/PNaClABI/types.ll @@ -3,21 +3,21 @@ ; CHECK: Function badReturn has disallowed type: half* () -define half* @badReturn() { +define internal half* @badReturn() { unreachable } ; CHECK: Function badArgType1 has disallowed type: void (half, i32) -define void @badArgType1(half %a, i32 %b) { +define internal void @badArgType1(half %a, i32 %b) { ret void } ; CHECK: Function badArgType2 has disallowed type: void (i32, half) -define void @badArgType2(i32 %a, half %b) { +define internal void @badArgType2(i32 %a, half %b) { ret void } -define void @func() { +define internal void @func() { entry: br label %block block: @@ -97,7 +97,7 @@ block: %struct.s1 = type { half, float} %struct.s2 = type { i32, i32} -define void @func2() { +define internal void @func2() { entry: br label %block block: @@ -121,7 +121,7 @@ block: %struct.linked = type { i32, %struct.linked * } -define void @func3() { +define internal void @func3() { entry: br label %block block: |