]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Add Locker friend class to SBuf for protection against memory issues
authorAmos Jeffries <squid3@treenet.co.nz>
Thu, 29 Oct 2015 18:53:48 +0000 (11:53 -0700)
committerAmos Jeffries <squid3@treenet.co.nz>
Thu, 29 Oct 2015 18:53:48 +0000 (11:53 -0700)
When appending or otherwise modifying an SBuf based on a SBuf& or char*
the parameter used may be pointing at the MemBlob memory buffer
indirectly without holding a separate ref-count lock to it.

If 'this' SBuf then requires reallocation for any reason the char* or
buffer pointer taken from the SBuf&, which is being manipulated may in
fact be left pointing at invalid memory.

Utilize a private Locker class to create relatively cheap ref-count locks
on the store_ MemBlob when this problem MAY occur. This Locker needs to
be used on all non-const SBuf methods accepting char* or SBuf& argument.

src/SBuf.cc
src/SBuf.h

index 79a04adba173640c20674316117db3945498bbb8..30ac2259a0095ebf683f65e49cd641fa7530557f 100644 (file)
@@ -161,6 +161,7 @@ SBuf&
 SBuf::assign(const char *S, size_type n)
 {
     debugs(24, 6, id << " from c-string, n=" << n << ")");
+    Locker prevent_raw_memory_madness(this, S, n);
     clear();
     return append(S, n); //bounds checked in append()
 }
@@ -213,6 +214,7 @@ SBuf::clear()
 SBuf&
 SBuf::append(const SBuf &S)
 {
+    Locker prevent_raw_memory_madness(this, S.buf(), S.length());
     return lowAppend(S.buf(), S.length());
 }
 
@@ -224,6 +226,7 @@ SBuf::append(const char * S, size_type Ssize)
     if (Ssize == SBuf::npos)
         Ssize = strlen(S);
     debugs(24, 7, "from c-string to id " << id);
+    Locker prevent_raw_memory_madness(this, S, Ssize);
     // coverity[access_dbuff_in_call]
     return lowAppend(S, Ssize);
 }
@@ -237,6 +240,10 @@ SBuf::append(const char c)
 SBuf&
 SBuf::Printf(const char *fmt, ...)
 {
+    // with printf() an arg might be a dangerous char*
+    // NP: cant rely on vappendf() Locker because of clear()
+    Locker prevent_raw_memory_madness(this, buf(), length());
+
     va_list args;
     va_start(args, fmt);
     clear();
@@ -263,6 +270,9 @@ SBuf::vappendf(const char *fmt, va_list vargs)
     //reserve twice the format-string size, it's a likely heuristic
     size_type requiredSpaceEstimate = strlen(fmt)*2;
 
+    // with appendf() an arg might be a dangerous char*
+    Locker prevent_raw_memory_madness(this, buf(), length());
+
     char *space = rawSpace(requiredSpaceEstimate);
 #ifdef VA_COPY
     va_list ap;
index dcbe587720adcbe526f602e8a64779239c2f7ac5..7258b828c8754b76ce6d9170e8ae5e25d6828553 100644 (file)
@@ -667,6 +667,20 @@ public:
     // TODO: possibly implement a replace() call
 private:
 
+    class Locker
+    {
+    public:
+        Locker(SBuf *parent, const char *Q, size_t len) : locket(nullptr) {
+            // lock if Q intersects the parents buffer area
+            const MemBlob *P = parent->store_.getRaw();
+            if ( (Q+len) >= P->mem && Q <= (P->mem + P->capacity) )
+                locket = P;
+        }
+    private:
+        MemBlob::Pointer locket;
+    };
+    friend class Locker;
+
     MemBlob::Pointer store_; ///< memory block, possibly shared with other SBufs
     size_type off_; ///< our content start offset from the beginning of shared store_
     size_type len_; ///< number of our content bytes in shared store_