[PATCH] D69265: [scudo][standalone] Consolidate lists

Kostya Kortchinsky via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 25 08:34:14 PDT 2019


cryptoad marked 16 inline comments as done.
cryptoad added a comment.

Mitch, thanks for the review! You made excellent points.



================
Comment at: lib/scudo/standalone/list.h:17
+// Intrusive POD singly and doubly linked list.
 // An object with all zero fields should represent a valid empty list. clear()
 // should be called on all non-zero-initialized objects before using.
----------------
hctim wrote:
> Why does the requirements to call `clear()` exist for non-zero-inited objects? For globally zero-init'ed instances of this object, we don't encounter a perf overhead of having `Size`, `First`, and `Last` be initialised to zero. For non-global instances, we have to call `clear()`, which seems easy to forget, and moving this initialisation into the c'tor doesn't cause any additional overhead (and I'd assume the call is elided, making it faster).
> 
> It also feels easy to forget to call `clear()`, and if any global objects are moved into static scopage, it may be incredibly hard to patch any instances where `clear()` isn't called.
Part of the issue, even with `constexpr explicit` constructors is that `__thread` can't seem to deal with them (as opposed to `thread_local`) and complains about it needing "dynamic initialization". It circles back to the choices made with `init` & `initLinkerInitialized`.
While your point makes sense, I don't think I can do it, unless I am missing something which is also very possible.


================
Comment at: lib/scudo/standalone/list.h:121
     DCHECK_NE(X, nullptr);
-    DCHECK_EQ(Prev->Next, X);
+    CHECK_EQ(Prev->Next, X);
     Prev->Next = X->Next;
----------------
hctim wrote:
> Why `/s/DCHECK/CHECK` here? This shouldn't fail in normal program execution, right?
You are right. I initially thought that it would be important to ensure consistency, but extract is only called with X being Prev->Next, and while someone could attempt to TOCTOU it, I don't see that happening with a meaningful success chance.


================
Comment at: lib/scudo/standalone/list.h:151
+    if (this->empty()) {
+      X->Next = nullptr;
+      First = Last = X;
----------------
hctim wrote:
> Isn't there an invariant held that if `empty() == true`, then `First == nullptr`? In which case, can't we hoist the `X->Next = First;` out from this conditional?
Good point thank you!


================
Comment at: lib/scudo/standalone/list.h:163
+  void insert(T *X, T *Y) {
+    if (Y == First) {
+      CHECK_EQ(Y->Prev, nullptr);
----------------
hctim wrote:
> Would the specialisation:
> 
> ```
> if (Y == First)
>   return push_front(X);
> ```
> be more performant?
> 
> You should then be able to remove the `if (Prev)` check below, as assumedly there's an invariant that if `Y` isn't the first element, it has a `Prev`.
Good point again, thanks!


================
Comment at: lib/scudo/standalone/list.h:164
+    if (Y == First) {
+      CHECK_EQ(Y->Prev, nullptr);
+      First = X;
----------------
hctim wrote:
> DCHECK?
Removed as part of the previously suggested change.


================
Comment at: lib/scudo/standalone/list.h:206
+    if (Prev) {
+      CHECK_EQ(Prev->Next, X);
+      Prev->Next = Next;
----------------
hctim wrote:
> DCHECK? (and throughout this function)
On this one I don't want to change the CHECKs to DCHECKs because doubly-lists unlinking is often the source of a mirrored write-4 primitive for exploitation.
Some examples can be found in http://xcon.xfocus.org/XCon2004/archives/14_Reliable%20Windows%20Heap%20Exploits_BY_SHOK.pdf.
Since it's being used in a large block header, I can't rule out that this could be targeted.
I can probably relax the nullptr CHECKs as they are probably less relevant to prevent further exploitation.


Repository:
  rCRT Compiler Runtime

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

https://reviews.llvm.org/D69265





More information about the llvm-commits mailing list