From ff36bd3d8589bb9f86b1ce2caef17c1e9cb54b81 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Tue, 19 Oct 2021 23:00:45 +0000 Subject: [PATCH 1/3] build: Support the Fedora LLVM 11 package Fedora is on LLVM 12, and the backward compatibility package has a non-standard name for llvm-config. --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index fa07ec689..23fb7be66 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,8 @@ ifeq ($(OS), Linux) LLVM_CONFIG=llvm-config-11 ifneq ($(shell which llvm-config-11 2>/dev/null),) LLVM_CONFIG=llvm-config-11 + else ifneq ($(shell which llvm-config-11-64 2>/dev/null),) + LLVM_CONFIG=llvm-config-11-64 else ifneq ($(shell llvm-config --version | grep '^11\.'),) LLVM_CONFIG=llvm-config From 796a0c3968243f540e68e584283d862f60bf3f26 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Sun, 31 Oct 2021 21:37:22 +0000 Subject: [PATCH 2/3] core/intrinsics: Add mem_zero_volatile --- core/intrinsics/intrinsics.odin | 1 + src/check_builtin.cpp | 1 + src/checker_builtin_procs.hpp | 2 ++ src/llvm_backend_proc.cpp | 13 ++++++++++++- src/llvm_backend_utility.cpp | 6 +++--- 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 67ac22c8b..2da7a7439 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -39,6 +39,7 @@ sqrt :: proc(x: $T) -> T where type_is_float(T) --- mem_copy :: proc(dst, src: rawptr, len: int) --- mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) --- mem_zero :: proc(ptr: rawptr, len: int) --- +mem_zero_volatile :: proc(ptr: rawptr, len: int) --- fixed_point_mul :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 2373317c3..482813792 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2598,6 +2598,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; case BuiltinProc_mem_zero: + case BuiltinProc_mem_zero_volatile: { operand->mode = Addressing_NoValue; operand->type = t_invalid; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 3ab85f31b..abd9fc6ca 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -70,6 +70,7 @@ enum BuiltinProcId { BuiltinProc_mem_copy, BuiltinProc_mem_copy_non_overlapping, BuiltinProc_mem_zero, + BuiltinProc_mem_zero_volatile, BuiltinProc_ptr_offset, BuiltinProc_ptr_sub, @@ -322,6 +323,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("mem_copy"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("mem_copy_non_overlapping"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("mem_zero"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("mem_zero_volatile"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("ptr_offset"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("ptr_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 29f7b6655..e1edfcac7 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1560,7 +1560,18 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, len = lb_emit_conv(p, len, t_int); unsigned alignment = 1; - lb_mem_zero_ptr_internal(p, ptr.value, len.value, alignment); + lb_mem_zero_ptr_internal(p, ptr.value, len.value, alignment, false); + return {}; + } + case BuiltinProc_mem_zero_volatile: + { + lbValue ptr = lb_build_expr(p, ce->args[0]); + lbValue len = lb_build_expr(p, ce->args[1]); + ptr = lb_emit_conv(p, ptr, t_rawptr); + len = lb_emit_conv(p, len, t_int); + + unsigned alignment = 1; + lb_mem_zero_ptr_internal(p, ptr.value, len.value, alignment, true); return {}; } diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index b58f07d49..709106bc4 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -48,7 +48,7 @@ lbValue lb_correct_endianness(lbProcedure *p, lbValue value) { return value; } -void lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment) { +void lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) { bool is_inlinable = false; i64 const_len = 0; @@ -77,7 +77,7 @@ void lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], ""); args[1] = LLVMConstInt(LLVMInt8TypeInContext(p->module->ctx), 0, false); args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, ""); - args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, false); // is_volatile parameter + args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), is_volatile, false); LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); } @@ -93,7 +93,7 @@ void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alig { // NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too i32 sz = cast(i32)type_size_of(type); - lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment); + lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment, false); } break; default: From 672fc9fc4d20d06810a66aa6133a94a0565eae05 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Sun, 31 Oct 2021 21:41:39 +0000 Subject: [PATCH 3/3] core/mem: Add zero_explicit This call is intended to provide the ability to securely scrub memory without compiler interference, in a similar manner to explicit_bzero, memset_s, SecureZeroMemory. The approach taken is a volatile memset followed by a seqentially consistent memory fence, to prevent the call from being optimized away by DSE, and from being reordered. An identical approach is currently being used by the zeroize Rust crate, and is effective in practice. LLVM IR output: ``` ; Function Attrs: nounwind define internal i8* @mem.zero_explicit(i8* %0, i64 %1) #0 { decls: call void @llvm.memset.p0i8.i64(i8* %0, i8 0, i64 %1, i1 true) fence seq_cst ret i8* %0 } ``` --- core/mem/mem.odin | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/mem/mem.odin b/core/mem/mem.odin index 29d124e42..8eb877e75 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -10,6 +10,15 @@ zero :: proc "contextless" (data: rawptr, len: int) -> rawptr { intrinsics.mem_zero(data, len) return data } +zero_explicit :: proc "contextless" (data: rawptr, len: int) -> rawptr { + // This routine tries to avoid the compiler optimizing away the call, + // so that it is always executed. It is intended to provided + // equivalent semantics to those provided by the C11 Annex K 3.7.4.1 + // memset_s call. + intrinsics.mem_zero_volatile(data, len) // Use the volatile mem_zero + intrinsics.atomic_fence() // Prevent reordering + return data +} zero_item :: proc "contextless" (item: $P/^$T) { intrinsics.mem_zero(item, size_of(T)) }