Showing posts with label cpp_secure. Show all posts
Showing posts with label cpp_secure. Show all posts

Nov 3, 2024

[C++] Security in C++ - Hardening Techniques From the Trenches

Reference:
Security in C++ - Hardening Techniques From the Trenches - Louis Dionne - C++Now 2024
https://libcxx.llvm.org/Hardening.html

BCE (bounds check elimination)
https://en.wikipedia.org/wiki/Bounds-checking_elimination


Types of memory safety (as of 2024)

  • Spatial memory safety(*)
  • Temporal memory safety(*)
  • Type safety
  • Guaranteed initialization
  • Thread safety


Spatial memory safety

  •  Each memory allocation has a given size.
  •  Accessing memory out of bounds is called an out-of-bounds(OOB) access.

Temporal memory safety

  •  All memory accesses to an object should occur during the lifetime of the objects' allocation.
  •  Access to the object outside of this window is called a use-after-free

Type safety

  •  A memory allocation is used to represent an object of a particular type.
  •  Interpreting it as an object of a different type is called a type confusion.

Guaranteed initialization

  •  When memory is allocated, it contains garbage
  •  Using that undefined content can lead to information disclosure
  •  Can also be exploited if the attacker controls the 'garbage'

Thread safety

  •  concurrent accesses to memory
  •  data races

C++

  •  It turns out that most safety issues are technically UB.

Library UB

  •  UB is what happens when the standard doesn't guarantee anything.
  •  Beware of precondition.

UB is a specification tool

  •  creates a contract with the programmer
  •  allows writing simpler APIs that make sense
  •  gives freedom to the implementation

Valid strategies:

  •  do nothing.
  •  trap if precondition is violated
  •  log and continue
  •  ...

Standard library hardening

  •  turn select UB into guaranteed traps
  •  provide hardening modes with high-level semantics
  •  allow users to select hardening mode
  •  allow vendors to select the default mode
  •  Not for debugging
  •  should be shipped as it is


libc++ hardening modes

  • none
  • fast -> trap
  • extensive -> trap SIGTRAP(5)
  • debug -> abort verbosely
Hardening mode can be selected in each TU.

ABI considerations

  • Orthogonal to hardening
  • ABI is a property of the platform
  • Vendors can select the desired ABI
  • users can't control that
  • Huge simplification

  • WebKit uses hardened libc++
  • Chrome and Google Cloud network virtualization stack.



Clang++
-Wunsafe-buffer-usage





Enter Contracts

  •  enforcing existing preconditions
  •  Contracts provide a framework for expressing them

Typed memory operations

  •  Most temporal memory safety exploits require some type confusion. If memory is never reused for a different type, confusions are impossible.
  •  Segregate allocations by type!
  •  Introduced in the Darwin Kernel.
  •  Data must not alias pointers.
  •  Randomize buckets on boot.






No type info; only size of the type.


 




What about user define new operator?
Would be an ABI breaker, but...
(Hey, remember, "all problems in computer science can be solved by another level of indirection")


Type-aware allocation and deallocation functions

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2719r0.html






Sep 9, 2021

[C++] Safer Usage Of C++ note

Reference:
Safer Usage Of C++

CLang user manual:

https://clang.llvm.org/docs/UsersManual.html

https://clang.llvm.org/docs/ClangCommandLineReference.html


Enable flags:

-fno-exceptions
-ftrapv
-fwrapv
fsanitize=signed-integer-overflow
-Wdangling-gsl

-fno-delete-null-pointer-checks (named as such for historical reasons) that defines null pointer dereferences. With this flag, dereferences of null are never optimized away.


MiraclePtr:

https://youtu.be/ohlxw5kDn-k

https://docs.google.com/presentation/d/1QvfZXx5HdUl0IdkBcrx-NM0ua-PVcTi2jNx0Sf-n8Fo/edit#slide=id.gab22a695b8_0_1


scpptool 

is a command line tool to help enforce a memory and data race safe subset of C++. 

https://github.com/duneroadrunner/scpptool


"SaferCPlusPlus" is essentially a collection of safe data types intended to facilitate memory and data race safe C++ programming.

https://github.com/duneroadrunner/SaferCPlusPlus

https://github.com/duneroadrunner/SaferCPlusPlus-AutoTranslation2


StarScan

Heap scanning use-after-free prevention

https://source.chromium.org/chromium/chromium/src/+/master:base/allocator/partition_allocator/starscan/README.md


MiraclePtr aka raw_ptr aka BackupRefPtr

https://chromium.googlesource.com/chromium/src/+/ddc017f9569973a731a574be4199d8400616f5a5/base/memory/raw_ptr.md


Pointer Safety Ideas

https://docs.google.com/document/d/1qsPh8Bcrma7S-5fobbCkBkXWaAijXOnorEqvIIGKzc0/edit#


P1705R1

Enumerating Core Undefined Behavior

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1705r1.html


Automatic Reference Counting

https://en.wikipedia.org/wiki/Automatic_Reference_Counting


Blink GC API reference

https://chromium.googlesource.com/chromium/src/+/refs/heads/main/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md

https://docs.google.com/presentation/d/1XPu03ymz8W295mCftEC9KshH9Icxfq81YwIJQzQrvxo/edit#slide=id.p


2 basic types of memory safety

spatial:

The program will behave in a defined and safe way if it accesses memory outside valid bounds.

Examples include array bounds, struct and union field access, and iterator access.


temporal:

The program will behave in a defined and safe way if it accesses memory when that memory is not valid at the time of the access.

Examples include use after free (UAF), double-free, use before initialization, and use after move (UAM).


[[clang::lifetimebound]] 

https://clang.llvm.org/docs/AttributeReference.html#lifetimebound


ABSL

Use absl::variant Instead Of enums for state machines


Oct 5, 2018

[C++][Cppcon 2018] Chandler Carruth “Spectre: Secrets, Side-Channels, Sandboxes, and Security”

CppCon 2018 - Chandler Carruth "Spectre - Secrets, Side-Channels, Sandboxes,
and Security"

It's hard to take note of this intriguing talk.
Every bits is informative.



However, there's one thing mentioned by Chandler during the prolog I would consider most important is 'ethic'.

Seen people become cocky and try to sabotage company's project due to various of reasons, a colleague of my friend's company who's holding an h1b visa tried/and did this due to consider getting low paid.
This is a serious concern in USA and also against laws.
Some how the words go around and the hiring committee could spot people with this trait from being hired.


Definition:
Vulnerability: Any mechanism that can be used to make a system fail to function correctly.

Gadget: A specific pattern or construct within code that is a component of(or used by) a vulnerability.

Reference:
https://www.redhat.com/en/blog/thoughts-netspectre

Oct 4, 2018

[C++][CppCon 2017] Chandler Carruth “Going Nowhere Faster”

[2018]




Before tackling with Chandler's 2018 CppCon's talk,
review what he gave last year(2017)


CppCon 2017: Chandler Carruth “Going Nowhere Faster”

Make Code Fast:
1. Use efficient algorithms, fast data structure & idioms
2. Benchmark the code that matters, understand why
3. Use hybrid data structures to optimize allocations & cache locality

Only care about performance that you BENCHMARK.

Additional reference:
Mike Acton's 2014's talk:
Read and write considered harmful - Hubert Matthews [ACCU 2018]

Profiling:
Use counters to track cache miss rates.
Use Efficiency Sanitizer to optimize data structures.
Tools:


CPU Register reference:
Cheatsheet:

%rax: 64 bits version of %eax

Clamp loop example:

int run(int a, int b) {
    return a >= b ? a : b;
}

$ gcc -O3 -masm=intel

.LFB0:
    .cfi_startproc
    cmp edi, esi
    mov eax, esi
    cmovge  eax, edi
    ret
    .cfi_endproc

[assembly] CMOVGE command is the prologue of this talk.

Example from the talk:

void run(){
   vector<int> v;
   # init. v
   for (auto &i : v)
 i = i > 255 ? 100 : i;

}

Keep in mind, most of the time branch isn't good for performance.


The idea of this talk is about cmovge should be faster then branches, but it's not.

Why CMOVGE is slower?

x86 runs microcode instead of assembly (more high level code).

"reorder buffer" captures the microcode, which unrolls the small loop,
i.e instead if branch out, but unrolling it into continuously microcodes,
and save the result back to 'reorder buffer'.

Since microcode unrolls the loops, register conflict happens,
since the same register is been used again and again.
So, x86 has this 'register renaming' concept.

--quote:
Register renaming is a form of pipelining that deals with data dependences between instructions by renaming their register operands. An assembly language programmer or a compiler specifies these operands using architectural registers - the registers that are explicit in the instruction set architecture. Renaming replaces architectural register names by, in effect, value names, with a new value name for each instruction destination operand. This eliminates the name dependences (output dependences and antidependences) between instructions and automatically recognizes true dependences.

The recognition of true data dependences between instructions permits a more flexible life cycle for instructions. By maintaining a status bit for each value indicating whether or not it has been computed yet, it allows the execution phase of two instruction operations to be performed out of order when there are no true data dependences between them. This is called out-of-order execution.

After looking at the process of renaming operands we will look at the life cycle of an instruction in a register renaming architecture. Then we will look at a generic hardware organization for it and some possible performance enhancements. Finally, we will look at a brief history of the register renaming concept.
end quote--

Once unrolling the loop into microcode iteration sets, they can be
run 'concurrently' inside each set/forward compute from later sets,
iff there's no dependencies.
This is called "speculative execution". 

For ALUs, there could be out of order executions.




So, why CMOVGE is slow?
CMOVGE act as a binary operator, it has to evaluate Both operants, which blocks and wait.

And branches thus faster then CMOV.

The init. example from Chandler's talk shows that a simple:
i = i > 100 ? 100 : i;
can be unrolled into if i <= 100 then branches to next loop.
Which is thus faster.




Live demo with tool 'perf'

As we can see, for CMOV, there's a high percentage of backend cycle idle.
As for unrolled microcode branches, it's even higher percentage of backend cycle idle.
Why? Because for each cycle it's storing to memory, and it should be stalled every
cycle due to it's trying to store to memory. For CMOV has lower backend cycle idle
is due to it's doing calculation for the CMOV's operants and waits for CMOV.

C++20 alert :-)

[[likely]] [[unlikely]] attributes _will_ turn CMOV into JUMPS :-)

However, be aware, benchmark to see if the static attribute hints really
agrees with your logic, or the opposite.
Read:
https://vsdmars.blogspot.com/2016/01/likely-or-unlikely-easy-misleading.html

Again, std::vector is gooooooood.... push_back guarantees vector grows.

Question from the audience:

1. Why can't CMOV to be translated to the same code as branches?
It sounds to me like:
can
---
return 42 + std::async([]{sleep(10);return 42;}).get()
---
returns early without waiting .get() ?


2. How about store buffer?
From Chandler: Store buffer doesn't help us here.
Agree that SB is used as another usage.
Reference:
http://vsdmars.blogspot.com/2018/09/concurrency-c-wrap-up-2018.html


3. total store order (TSO)
https://en.wikipedia.org/wiki/Memory_ordering


4. When CMOV is useful?
When dependencies are already being required.

Tools:

Intel® Architecture Code Analyzer
https://software.intel.com/en-us/articles/intel-architecture-code-analyzer


CMDs:
$ perf stat BINARY
$ perf list
$ perf stat -e L1-icache-loads
$ perf record BINARY
$ perf report
$ clang++ -MMD -MT file.o -MF file.o.d -std=c++17 -Wall -O3 -fno-exceptions -fvisibility=hidden -qmlt -fno-omit-frame-pointer -pthread files.cpp -S -o files.s -mllvm -x86-cmov-converter-threshold=0 -stats    # -qmlt debug info.

Reference:

How Computers Work [Jakob Stoklund Olesen]

Jun 7, 2017

[C++] hijack private data member through template instantiation.


Resize string/vector without initialization

discuss:
Uses and Abuses of Access Rights

it works because explicit template instantiation ignores access restrictions, and the friend definition "leaks" the templated type out of the class, without having to write it anywhere..

code:
#include <iostream>

class A {
private:
  void f(int) { std::cout << "whoops" << std::endl; }
};

using PMember = void (A::*)(int);

void hijack(A& s, int n, char dummy = 0);

template <PMember pf, typename T>
struct Hijack {
  friend void hijack(A& s, int n, T) {
    (s.*pf)(n);
  }
};

// explicit instantiate template instance.
template struct Hijack<&A::f, char>;

int main() {
  A a;
  hijack(a, 10);
  return 0;
}