@@ -473,12 +473,16 @@ void CoreUserInputHandler::handleMsg(const BufferInfo &bufferInfo, const QString
         return;

     QString target = msg.section(' ', 0, 0);
-    QByteArray encMsg = userEncode(target, msg.section(' ', 1));
+    QString msgSection = msg.section(' ', 1);
+
+    std::function<QByteArray(const QString &, const QString &)> encodeFunc = [this] (const QString &target, const QString &message) -> QByteArray {
+        return userEncode(target, message);
+    };

 #ifdef HAVE_QCA2
-    putPrivmsg(serverEncode(target), encMsg, network()->cipher(target));
+    putPrivmsg(target, msgSection, encodeFunc, network()->cipher(target));
 #else
-    putPrivmsg(serverEncode(target), encMsg);
+    putPrivmsg(target, msgSection, encodeFunc);
 #endif
 }

@@ -594,11 +598,14 @@ void CoreUserInputHandler::handleSay(const BufferInfo &bufferInfo, const QString
     if (bufferInfo.bufferName().isEmpty() || !bufferInfo.acceptsRegularMessages())
         return;  // server buffer

-    QByteArray encMsg = channelEncode(bufferInfo.bufferName(), msg);
+    std::function<QByteArray(const QString &, const QString &)> encodeFunc = [this] (const QString &target, const QString &message) -> QByteArray {
+        return channelEncode(target, message);
+    };
+
 #ifdef HAVE_QCA2
-    putPrivmsg(serverEncode(bufferInfo.bufferName()), encMsg, network()->cipher(bufferInfo.bufferName()));
+    putPrivmsg(bufferInfo.bufferName(), msg, encodeFunc, network()->cipher(bufferInfo.bufferName()));
 #else
-    putPrivmsg(serverEncode(bufferInfo.bufferName()), encMsg);
+    putPrivmsg(bufferInfo.bufferName(), msg, encodeFunc);
 #endif
     emit displayMsg(Message::Plain, bufferInfo.type(), bufferInfo.bufferName(), msg, network()->myNick(), Message::Self);
 }
@@ -763,56 +770,23 @@ void CoreUserInputHandler::defaultHandler(QString cmd, const BufferInfo &bufferI
 }

-void CoreUserInputHandler::putPrivmsg(const QByteArray &target, const QByteArray &message, Cipher *cipher)
+void CoreUserInputHandler::putPrivmsg(const QString &target, const QString &message, std::function<QByteArray(const QString &, const QString &)> encodeFunc, Cipher *cipher)
 {
-    // Encrypted messages need special care. There's no clear relation between cleartext and encrypted message length,
-    // so we can't just compute the maxSplitPos. Instead, we need to loop through the splitpoints until the crypted
-    // version is short enough...
-    // TODO: check out how the various possible encryption methods behave length-wise and make
-    //       this clean by predicting the length of the crypted msg.
-    //       For example, blowfish-ebc seems to create 8-char chunks.
+    QString cmd("PRIVMSG");
+    QByteArray targetEnc = serverEncode(target);

-    static const char *cmd = "PRIVMSG";
-    static const char *splitter = " .,-!?";
+    std::function<QList<QByteArray>(QString &)> cmdGenerator = [&] (QString &splitMsg) -> QList<QByteArray> {
+        QByteArray splitMsgEnc = encodeFunc(target, splitMsg);

-    int maxSplitPos = message.count();
-    int splitPos = maxSplitPos;
-    forever {
-        QByteArray crypted = message.left(splitPos);
-        bool isEncrypted = false;
 #ifdef HAVE_QCA2
-        if (cipher && !cipher->key().isEmpty() && !message.isEmpty()) {
-            isEncrypted = cipher->encrypt(crypted);
+        if (cipher && !cipher->key().isEmpty() && !splitMsg.isEmpty()) {
+            cipher->encrypt(splitMsgEnc);
         }
 #endif
-        int overrun = lastParamOverrun(cmd, QList<QByteArray>() << target << crypted);
-        if (overrun) {
-            // In case this is not an encrypted msg, we can just cut off at the end
-            if (!isEncrypted)
-                maxSplitPos = message.count() - overrun;
-
-            splitPos = -1;
-            for (const char *splitChar = splitter; *splitChar != 0; splitChar++) {
-                splitPos = qMax(splitPos, message.lastIndexOf(*splitChar, maxSplitPos) + 1); // keep split char on old line
-            }
-            if (splitPos <= 0 || splitPos > maxSplitPos)
-                splitPos = maxSplitPos;
-
-            maxSplitPos = splitPos - 1;
-            if (maxSplitPos <= 0) { // this should never happen, but who knows...
-                qWarning() << tr("[Error] Could not encrypt your message: %1").arg(message.data());
-                return;
-            }
-            continue; // we never come back here for !encrypted!
-        }
-
-        // now we have found a valid splitpos (or didn't need to split to begin with)
-        putCmd(cmd, QList<QByteArray>() << target << crypted);
-        if (splitPos < message.count())
-            putPrivmsg(target, message.mid(splitPos), cipher);
+        return QList<QByteArray>() << targetEnc << splitMsgEnc;
+    };

-        return;
-    }
+    putCmd(cmd, network()->splitMessage(cmd, message, cmdGenerator));
 }


Merge pull request #101 from hintjens/master

Problem: issue #1273, protocol downgrade attack

@@ -323,6 +323,14 @@ int zmq::session_base_t::zap_connect ()
     return 0;
 }

+bool zmq::session_base_t::zap_enabled ()
+{
+    return (
+         options.mechanism != ZMQ_NULL ||
+        (options.mechanism == ZMQ_NULL && options.zap_domain.length() > 0)
+    );
+}
+
 void zmq::session_base_t::process_attach (i_engine *engine_)
 {
     zmq_assert (engine_ != NULL);


KaxBlockInternal: check EBML lace sizes against available buffer space

@@ -529,6 +529,8 @@ filepos_t KaxInternalBlock::ReadData(IOCallback & input, ScopeMode ReadFully)
           case LACING_EBML:
             SizeRead = LastBufferSize;
             FrameSize = ReadCodedSizeValue(BufferStart + Mem.GetPosition(), SizeRead, SizeUnknown);
+            if (!FrameSize || (static_cast<uint32>(FrameSize + SizeRead) > LastBufferSize))
+              throw SafeReadIOCallback::EndOfStreamX(SizeRead);
             SizeList[0] = FrameSize;
             Mem.Skip(SizeRead);
             LastBufferSize -= FrameSize + SizeRead;
@@ -537,6 +539,8 @@ filepos_t KaxInternalBlock::ReadData(IOCallback & input, ScopeMode ReadFully)
               // get the size of the frame
               SizeRead = LastBufferSize;
               FrameSize += ReadCodedSizeSignedValue(BufferStart + Mem.GetPosition(), SizeRead, SizeUnknown);
+              if (!FrameSize || (static_cast<uint32>(FrameSize + SizeRead) > LastBufferSize))
+                throw SafeReadIOCallback::EndOfStreamX(SizeRead);
               SizeList[Index] = FrameSize;
               Mem.Skip(SizeRead);
               LastBufferSize -= FrameSize + SizeRead;


@@ -0,0 +1,39 @@
+/*
+* Safe(r) Integer Handling
+* (C) 2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_UTILS_SAFE_INT_H__
+#define BOTAN_UTILS_SAFE_INT_H__
+
+#include <botan/exceptn.h>
+#include <string>
+
+namespace Botan {
+
+class Integer_Overflow_Detected : public Exception
+   {
+   public:
+      Integer_Overflow_Detected(const std::string& file, int line) :
+         Exception("Integer overflow detected at " + file + ":" + std::to_string(line))
+         {}
+   };
+
+inline size_t checked_add(size_t x, size_t y, const char* file, int line)
+   {
+   // TODO: use __builtin_x_overflow on GCC and Clang
+   size_t z = x + y;
+   if(z < x)
+      {
+      throw Integer_Overflow_Detected(file, line);
+      }
+   return z;
+   }
+
+#define BOTAN_CHECKED_ADD(x,y) checked_add(x,y,__FILE__,__LINE__)
+
+}
+
+#endif


Fixed memory leak when creating nested exceptions in Magick++.

@@ -852,12 +852,18 @@ MagickPPExport void Magick::throwException(ExceptionInfo *exception_,
             exception_->description) != 0))
           {
             if (nestedException == (Exception *) NULL)
-              nestedException=createException(p);
+              {
+                nestedException=createException(p);
+                q=nestedException;
+              }
             else
               {
-                q=createException(p);
-                nestedException->nested(q);
-                nestedException=q;
+                Exception
+                  *r;
+
+                r=createException(p);
+                q->nested(r);
+                q=r;
               }
           }
       }


DNP3: fix reachable assertion and buffer over-read/overflow.

A DNP3 packet using a link layer header that specifies a zero length can
trigger an assertion failure if assertions are enabled.  Assertions are
enabled unless Bro is compiled with the NDEBUG preprocessor macro
defined.  The default configuration of Bro will define this macro and so
disables assertions, but using the --enable-debug option in the
configure script will enable assertions.  When assertions are disabled,
or also for certain length values, the DNP3 parser may attempt to pass a
negative value as the third argument to memcpy (number of bytes to copy)
and result in a buffer over-read or overflow.

Reported by Travis Emmert.

@@ -138,9 +138,14 @@ bool DNP3_Base::ProcessData(int len, const u_char* data, bool orig)
 		if ( endp->in_hdr )
 			{
 			// We're parsing the DNP3 header and link layer, get that in full.
-			if ( ! AddToBuffer(endp, PSEUDO_APP_LAYER_INDEX, &data, &len) )
+			int res = AddToBuffer(endp, PSEUDO_APP_LAYER_INDEX, &data, &len);
+
+			if ( res == 0 )
 				return true;

+			if ( res < 0 )
+				return false;
+
 			// The first two bytes must always be 0x0564.
 			if( endp->buffer[0] != 0x05 || endp->buffer[1] != 0x64 )
 				{
@@ -186,7 +191,11 @@ bool DNP3_Base::ProcessData(int len, const u_char* data, bool orig)

 		if ( ! endp->in_hdr )
 			{
-			assert(endp->pkt_length);
+			if ( endp->pkt_length <= 0 )
+				{
+				analyzer->Weird("dnp3_negative_or_zero_length_link_layer");
+				return false;
+				}

 			// We're parsing the DNP3 application layer, get that
 			// in full now as well. We calculate the number of
@@ -197,9 +206,14 @@ bool DNP3_Base::ProcessData(int len, const u_char* data, bool orig)
 			int n = PSEUDO_APP_LAYER_INDEX + (endp->pkt_length - 5) + ((endp->pkt_length - 5) / 16) * 2
 					+ 2 * ( ((endp->pkt_length - 5) % 16 == 0) ? 0 : 1) - 1 ;

-			if ( ! AddToBuffer(endp, n, &data, &len) )
+			int res = AddToBuffer(endp, n, &data, &len);
+
+			if ( res == 0 )
 				return true;

+			if ( res < 0 )
+				return false;
+
 			// Parse the the application layer data.
 			if ( ! ParseAppLayer(endp) )
 				return false;
@@ -213,19 +227,42 @@ bool DNP3_Base::ProcessData(int len, const u_char* data, bool orig)
 	return true;
 	}

-bool DNP3_Base::AddToBuffer(Endpoint* endp, int target_len, const u_char** data, int* len)
+int DNP3_Base::AddToBuffer(Endpoint* endp, int target_len, const u_char** data, int* len)
 	{
 	if ( ! target_len )
-		return true;
+		return 1;
+
+	if ( *len < 0 )
+		{
+		reporter->AnalyzerError(analyzer, "dnp3 negative input length: %d", *len);
+		return -1;
+		}
+
+	if ( target_len < endp->buffer_len )
+		{
+		reporter->AnalyzerError(analyzer, "dnp3 invalid target length: %d - %d",
+		                        target_len, endp->buffer_len);
+		return -1;
+		}

 	int to_copy = min(*len, target_len - endp->buffer_len);

+	if ( endp->buffer_len + to_copy > MAX_BUFFER_SIZE )
+		{
+		reporter->AnalyzerError(analyzer, "dnp3 buffer length exceeded: %d + %d",
+		                        endp->buffer_len, to_copy);
+		return -1;
+		}
+
 	memcpy(endp->buffer + endp->buffer_len, *data, to_copy);
 	*data += to_copy;
 	*len -= to_copy;
 	endp->buffer_len += to_copy;

-	return endp->buffer_len == target_len;
+	if ( endp->buffer_len == target_len )
+		return 1;
+
+	return 0;
 	}

 bool DNP3_Base::ParseAppLayer(Endpoint* endp)
@@ -256,8 +293,15 @@ bool DNP3_Base::ParseAppLayer(Endpoint* endp)
 		if ( ! CheckCRC(n, data, data + n, "app_chunk") )
 			return false;

+		if ( data + n >= endp->buffer + endp->buffer_len )
+			{
+			reporter->AnalyzerError(analyzer,
+			                        "dnp3 app layer parsing overflow %d - %d",
+			                        endp->buffer_len, n);
+			return false;
+			}
+
 		// Pass on to BinPAC.
-		assert(data + n < endp->buffer + endp->buffer_len);
 		flow->flow_buffer()->BufferData(data + transport, data + n);
 		transport = 0;


Secunia SA75000 advisory: several buffer overruns

@@ -12870,6 +12870,10 @@ int CLASS parse_tiff_ifd(int base)
         load_raw = &CLASS sony_arw_load_raw;
         data_offset = get4() + base;
         ifd++;
+#ifdef LIBRAW_LIBRARY_BUILD
+	if (ifd >= sizeof tiff_ifd / sizeof tiff_ifd[0])
+	  throw LIBRAW_EXCEPTION_IO_CORRUPT;
+#endif
         break;
       }
 #ifdef LIBRAW_LIBRARY_BUILD
@@ -13177,7 +13181,7 @@ int CLASS parse_tiff_ifd(int base)
       break;
     case 50454: /* Sinar tag */
     case 50455:
-      if (len > 2560000 || !(cbuf = (char *)malloc(len)))
+      if (len < 1 || len > 2560000 || !(cbuf = (char *)malloc(len)))
         break;
 #ifndef LIBRAW_LIBRARY_BUILD
       fread(cbuf, 1, len, ifp);
@@ -14795,7 +14799,11 @@ int CLASS parse_jpeg(int offset)
     }
     order = get2();
     hlen = get4();
-    if (get4() == 0x48454150) /* "HEAP" */
+    if (get4() == 0x48454150
+#ifdef LIBRAW_LIBRARY_BUILD
+	&& (save+hlen) >= 0 && (save+hlen)<=ifp->size()
+#endif
+	) /* "HEAP" */
     {
 #ifdef LIBRAW_LIBRARY_BUILD
       imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens;


SECURITY: Integer overflow in pointer validation.

Details: https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2014-03-02-0-c++-integer-overflow.md

@@ -685,7 +685,8 @@ struct WireHelpers {
               return result;
             }

-            KJ_REQUIRE(elementTag->structRef.wordSize() / ELEMENTS * count <= wordCount,
+            KJ_REQUIRE(elementTag->structRef.wordSize() / ELEMENTS *
+                       ElementCount64(count) <= wordCount,
                        "Struct list pointer's elements overran size.") {
               return result;
             }
@@ -1663,7 +1664,7 @@ struct WireHelpers {
           ElementCount elementCount = tag->inlineCompositeListElementCount();
           auto wordsPerElement = tag->structRef.wordSize() / ELEMENTS;

-          KJ_REQUIRE(wordsPerElement * elementCount <= wordCount,
+          KJ_REQUIRE(wordsPerElement * ElementCount64(elementCount) <= wordCount,
                      "INLINE_COMPOSITE list's elements overrun its word count.") {
             goto useDefault;
           }
@@ -1919,7 +1920,7 @@ struct WireHelpers {
       size = tag->inlineCompositeListElementCount();
       wordsPerElement = tag->structRef.wordSize() / ELEMENTS;

-      KJ_REQUIRE(size * wordsPerElement <= wordCount,
+      KJ_REQUIRE(ElementCount64(size) * wordsPerElement <= wordCount,
                  "INLINE_COMPOSITE list's elements overrun its word count.") {
         goto useDefault;
       }


@@ -140,8 +140,10 @@ AP4_AtomSampleTable::GetSample(AP4_Ordinal index,
     AP4_UI32 cts_offset = 0;
     AP4_UI64 dts        = 0;
     AP4_UI32 duration   = 0;
-    result = m_SttsAtom->GetDts(index, dts, &duration);
-    if (AP4_FAILED(result)) return result;
+    if (m_SttsAtom) {
+        result = m_SttsAtom->GetDts(index, dts, &duration);
+        if (AP4_FAILED(result)) return result;
+    }
     sample.SetDuration(duration);
     sample.SetDts(dts);
     if (m_CttsAtom == NULL) {


Work around shell code in podcast names (#598)

@@ -130,7 +130,7 @@ std::string queueloader::get_filename(const std::string& str) {
 		strftime(lbuf, sizeof(lbuf), "%Y-%b-%d-%H%M%S.unknown", localtime(&t));
 		fn.append(lbuf);
 	} else {
-		fn.append(base);
+		fn.append(utils::replace_all(base, "'", "%27"));
 	}
 	return fn;
 }


fixed possible crashes on malformed inputs.

@@ -270,7 +270,7 @@ AP4_AvccAtom::InspectFields(AP4_AtomInspector& inspector)
     for (unsigned int i=0; i<m_SequenceParameters.ItemCount(); i++) {
         inspector.AddField("Sequence Parameter", m_SequenceParameters[i].GetData(), m_SequenceParameters[i].GetDataSize());
     }
-    for (unsigned int i=0; i<m_SequenceParameters.ItemCount(); i++) {
+    for (unsigned int i=0; i<m_PictureParameters.ItemCount(); i++) {
         inspector.AddField("Picture Parameter", m_PictureParameters[i].GetData(), m_PictureParameters[i].GetDataSize());
     }
     return AP4_SUCCESS;


@@ -37,7 +37,7 @@
 /**
  * Version number of the SDK
  */
-#define AP4_VERSION        0x01050000
-#define AP4_VERSION_STRING "1.5.0.0"
+#define AP4_VERSION        0x01050001
+#define AP4_VERSION_STRING "1.5.0.1"

 #endif // _AP4_VERSION_H_


Pad keys to avoid memory errors (fixes #147)

@@ -479,6 +479,8 @@ compute_O_value(std::string const& user_password,

     char upass[key_bytes];
     pad_or_truncate_password_V4(user_password, upass);
+    std::string k1(reinterpret_cast<char*>(O_key), OU_key_bytes_V4);
+    pad_short_parameter(k1, data.getLengthBytes());
     iterate_rc4(QUtil::unsigned_char_pointer(upass), key_bytes,
 		O_key, data.getLengthBytes(),
                 (data.getR() >= 3) ? 20 : 1, false);
@@ -495,6 +497,7 @@ compute_U_value_R2(std::string const& user_password,
     std::string k1 = QPDF::compute_encryption_key(user_password, data);
     char udata[key_bytes];
     pad_or_truncate_password_V4("", udata);
+    pad_short_parameter(k1, data.getLengthBytes());
     iterate_rc4(QUtil::unsigned_char_pointer(udata), key_bytes,
 		QUtil::unsigned_char_pointer(k1),
                 data.getLengthBytes(), 1, false);
@@ -516,6 +519,7 @@ compute_U_value_R3(std::string const& user_password,
                                 data.getId1().length());
     MD5::Digest digest;
     md5.digest(digest);
+    pad_short_parameter(k1, data.getLengthBytes());
     iterate_rc4(digest, sizeof(MD5::Digest),
 		QUtil::unsigned_char_pointer(k1),
                 data.getLengthBytes(), 20, false);
@@ -591,7 +595,10 @@ check_owner_password_V4(std::string& user_password,
     compute_O_rc4_key(user_password, owner_password, data, key);
     unsigned char O_data[key_bytes];
     memcpy(O_data, QUtil::unsigned_char_pointer(data.getO()), key_bytes);
-    iterate_rc4(O_data, key_bytes, key, data.getLengthBytes(),
+    std::string k1(reinterpret_cast<char*>(key), OU_key_bytes_V4);
+    pad_short_parameter(k1, data.getLengthBytes());
+    iterate_rc4(O_data, key_bytes, QUtil::unsigned_char_pointer(k1),
+                data.getLengthBytes(),
                 (data.getR() >= 3) ? 20 : 1, true);
     std::string new_user_password =
         std::string(reinterpret_cast<char*>(O_data), key_bytes);
@@ -886,6 +893,7 @@ QPDF::initializeEncryption()

     if (V < 5)
     {
+        // These must be exactly the right number of bytes.
         pad_short_parameter(O, key_bytes);
         pad_short_parameter(U, key_bytes);
         if (! ((O.length() == key_bytes) && (U.length() == key_bytes)))
@@ -913,24 +921,12 @@ QPDF::initializeEncryption()
         UE = encryption_dict.getKey("/UE").getStringValue();
         Perms = encryption_dict.getKey("/Perms").getStringValue();

+        // These may be longer than the minimum number of bytes.
         pad_short_parameter(O, OU_key_bytes_V5);
         pad_short_parameter(U, OU_key_bytes_V5);
         pad_short_parameter(OE, OUE_key_bytes_V5);
         pad_short_parameter(UE, OUE_key_bytes_V5);
         pad_short_parameter(Perms, Perms_key_bytes_V5);
-        if ((O.length() < OU_key_bytes_V5) ||
-            (U.length() < OU_key_bytes_V5) ||
-            (OE.length() < OUE_key_bytes_V5) ||
-            (UE.length() < OUE_key_bytes_V5) ||
-            (Perms.length() < Perms_key_bytes_V5))
-        {
-            throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
-                          "encryption dictionary",
-                          this->m->file->getLastOffset(),
-                          "incorrect length for some of"
-                          " /O, /U, /OE, /UE, or /Perms in"
-                          " encryption dictionary");
-        }
     }

     int Length = 40;


@@ -121,8 +121,6 @@ typedef struct x3f_property_s {
   /* Computed */
   utf16_t *name;		/* 0x0000 terminated UTF 16 */
   utf16_t *value;               /* 0x0000 terminated UTF 16 */
-  char *name_utf8;		/* converted to UTF 8 */
-  char *value_utf8;          /* converted to UTF 8 */
 } x3f_property_t;

 typedef struct x3f_property_table_s {
@@ -516,7 +514,6 @@ unsigned x3f_get4(LibRaw_abstract_datastream *f)
 		int _cur = _file->_func(_buffer,1,_left);	\
 		if (_cur == 0) {							\
 			throw LIBRAW_EXCEPTION_IO_CORRUPT;		\
-			exit(1);								\
 		}											\
 		_left -= _cur;								\
 	}												\
@@ -912,11 +909,6 @@ static void free_camf_entry(camf_entry_t *entry)
 			if (PL)
 			{
 				int i;
-
-				for (i = 0; i < PL->property_table.size; i++) {
-					FREE(PL->property_table.element[i].name_utf8);
-					FREE(PL->property_table.element[i].value_utf8);
-				}
 			}
 			FREE(PL->property_table.element);
 			FREE(PL->data);
@@ -1624,14 +1616,14 @@ static void x3f_load_property_list(x3f_info_t *I, x3f_directory_entry_t *DE)

 	if (!PL->data_size)
 		PL->data_size = read_data_block(&PL->data, I, DE, 0);
+	uint32_t maxoffset = PL->data_size/sizeof(utf16_t)-2; // at least 2 chars, value + terminating 0x0000

 	for (i=0; i<PL->num_properties; i++) {
 		x3f_property_t *P = &PL->property_table.element[i];
-
+		if(P->name_offset > maxoffset || P->value_offset > maxoffset)
+			throw LIBRAW_EXCEPTION_IO_CORRUPT;
 		P->name = ((utf16_t *)PL->data + P->name_offset);
 		P->value = ((utf16_t *)PL->data + P->value_offset);
-		P->name_utf8 = 0;// utf16le_to_utf8(P->name);
-		P->value_utf8 = 0;//utf16le_to_utf8(P->value);
 	}
 }


Merge remote-tracking branch 'private/wip-mon-snap-caps'

@@ -76,6 +76,9 @@
 #include "include/str_map.h"
 #include "include/scope_guard.h"

+#include "auth/cephx/CephxKeyServer.h"
+#include "osd/OSDCap.h"
+
 #include "json_spirit/json_spirit_reader.h"

 #include <boost/algorithm/string/predicate.hpp>
@@ -91,6 +94,87 @@ const uint32_t MAX_POOL_APPLICATIONS = 4;
 const uint32_t MAX_POOL_APPLICATION_KEYS = 64;
 const uint32_t MAX_POOL_APPLICATION_LENGTH = 128;

+bool is_osd_writable(const OSDCapGrant& grant, const std::string* pool_name) {
+  // Note: this doesn't include support for the application tag match
+  if ((grant.spec.allow & OSD_CAP_W) != 0) {
+    auto& match = grant.match;
+    if (match.is_match_all()) {
+      return true;
+    } else if (pool_name != nullptr && match.auid < 0 &&
+               !match.pool_namespace.pool_name.empty() &&
+               match.pool_namespace.pool_name == *pool_name) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool is_unmanaged_snap_op_permitted(CephContext* cct,
+                                    const KeyServer& key_server,
+                                    const EntityName& entity_name,
+                                    const MonCap& mon_caps,
+                                    const std::string* pool_name)
+{
+  typedef std::map<std::string, std::string> CommandArgs;
+
+  if (mon_caps.is_capable(cct, CEPH_ENTITY_TYPE_MON,
+                               entity_name, "osd",
+                               "osd pool op unmanaged-snap",
+                               (pool_name == nullptr ?
+                                  CommandArgs{} /* pool DNE, require unrestricted cap */ :
+                                  CommandArgs{{"poolname", *pool_name}}),
+                                false, true, false)) {
+    return true;
+  }
+
+  AuthCapsInfo caps_info;
+  if (!key_server.get_service_caps(entity_name, CEPH_ENTITY_TYPE_OSD,
+                                   caps_info)) {
+    dout(10) << "unable to locate OSD cap data for " << entity_name
+             << " in auth db" << dendl;
+    return false;
+  }
+
+  string caps_str;
+  if (caps_info.caps.length() > 0) {
+    auto p = caps_info.caps.cbegin();
+    try {
+      decode(caps_str, p);
+    } catch (const buffer::error &err) {
+      derr << "corrupt OSD cap data for " << entity_name << " in auth db"
+           << dendl;
+      return false;
+    }
+  }
+
+  OSDCap osd_cap;
+  if (!osd_cap.parse(caps_str, nullptr)) {
+    dout(10) << "unable to parse OSD cap data for " << entity_name
+             << " in auth db" << dendl;
+    return false;
+  }
+
+  // if the entity has write permissions in one or all pools, permit
+  // usage of unmanaged-snapshots
+  if (osd_cap.allow_all()) {
+    return true;
+  }
+
+  for (auto& grant : osd_cap.grants) {
+    if (grant.profile.is_valid()) {
+      for (auto& profile_grant : grant.profile_grants) {
+        if (is_osd_writable(profile_grant, pool_name)) {
+          return true;
+        }
+      }
+    } else if (is_osd_writable(grant, pool_name)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 } // anonymous namespace

 void LastEpochClean::Lec::report(ps_t ps, epoch_t last_epoch_clean)
@@ -11707,11 +11791,61 @@ bool OSDMonitor::prepare_command_impl(MonOpRequestRef op,
   return true;
 }

-bool OSDMonitor::preprocess_pool_op(MonOpRequestRef op)
+bool OSDMonitor::enforce_pool_op_caps(MonOpRequestRef op)
 {
   op->mark_osdmon_event(__func__);
+
   MPoolOp *m = static_cast<MPoolOp*>(op->get_req());
-
+  MonSession *session = m->get_session();
+  if (!session) {
+    _pool_op_reply(op, -EPERM, osdmap.get_epoch());
+    return true;
+  }
+
+  switch (m->op) {
+  case POOL_OP_CREATE_UNMANAGED_SNAP:
+  case POOL_OP_DELETE_UNMANAGED_SNAP:
+    {
+      const std::string* pool_name = nullptr;
+      const pg_pool_t *pg_pool = osdmap.get_pg_pool(m->pool);
+      if (pg_pool != nullptr) {
+        pool_name = &osdmap.get_pool_name(m->pool);
+      }
+
+      if (!is_unmanaged_snap_op_permitted(cct, mon->key_server,
+                                          session->entity_name, session->caps,
+                                          pool_name)) {
+        dout(0) << "got unmanaged-snap pool op from entity with insufficient "
+                << "privileges. message: " << *m  << std::endl
+                << "caps: " << session->caps << dendl;
+        _pool_op_reply(op, -EPERM, osdmap.get_epoch());
+        return true;
+      }
+    }
+    break;
+  default:
+    if (!session->is_capable("osd", MON_CAP_W)) {
+      dout(0) << "got pool op from entity with insufficient privileges. "
+              << "message: " << *m  << std::endl
+              << "caps: " << session->caps << dendl;
+      _pool_op_reply(op, -EPERM, osdmap.get_epoch());
+      return true;
+    }
+    break;
+  }
+
+  return false;
+}
+
+bool OSDMonitor::preprocess_pool_op(MonOpRequestRef op)
+{
+  op->mark_osdmon_event(__func__);
+  MPoolOp *m = static_cast<MPoolOp*>(op->get_req());
+
+  if (enforce_pool_op_caps(op)) {
+    return true;
+  }
+
   if (m->fsid != mon->monmap->fsid) {
     dout(0) << __func__ << " drop message on fsid " << m->fsid
             << " != " << mon->monmap->fsid << " for " << *m << dendl;
@@ -11795,19 +11929,6 @@ bool OSDMonitor::preprocess_pool_op_create(MonOpRequestRef op)
 {
   op->mark_osdmon_event(__func__);
   MPoolOp *m = static_cast<MPoolOp*>(op->get_req());
-  MonSession *session = m->get_session();
-  if (!session) {
-    _pool_op_reply(op, -EPERM, osdmap.get_epoch());
-    return true;
-  }
-  if (!session->is_capable("osd", MON_CAP_W)) {
-    dout(5) << "attempt to create new pool without sufficient auid privileges!"
-	    << "message: " << *m  << std::endl
-	    << "caps: " << session->caps << dendl;
-    _pool_op_reply(op, -EPERM, osdmap.get_epoch());
-    return true;
-  }
-
   int64_t pool = osdmap.lookup_pg_pool_name(m->name.c_str());
   if (pool >= 0) {
     _pool_op_reply(op, 0, osdmap.get_epoch());


Check that a secondary auth manager is set before dereferencing.

Summary: CVE-2018-6343

Reviewed By: mingtaoy

Differential Revision: D12994423

fbshipit-source-id: 9229ec11da8085f1fa153595e8e5353e19d06fb7

@@ -1349,6 +1349,10 @@ void HTTPSession::onCertificateRequest(uint16_t requestId,
   DestructorGuard dg(this);
   VLOG(4) << "CERTIFICATE_REQUEST on" << *this << ", requestId=" << requestId;

+  if (!secondAuthManager_) {
+    return;
+  }
+
   std::pair<uint16_t, std::unique_ptr<folly::IOBuf>> authenticator;
   auto fizzBase = getTransport()->getUnderlyingTransport<AsyncFizzBase>();
   if (fizzBase) {
@@ -1382,6 +1386,10 @@ void HTTPSession::onCertificate(uint16_t certId,
   DestructorGuard dg(this);
   VLOG(4) << "CERTIFICATE on" << *this << ", certId=" << certId;

+  if (!secondAuthManager_) {
+    return;
+  }
+
   bool isValid = false;
   auto fizzBase = getTransport()->getUnderlyingTransport<AsyncFizzBase>();
   if (fizzBase) {


@@ -1340,6 +1340,10 @@ void CLASS nikon_load_raw()

 void CLASS nikon_yuv_load_raw()
 {
+#ifdef LIBRAW_LIBRARY_BUILD
+  if(!image)
+    throw LIBRAW_EXCEPTION_IO_CORRUPT;
+#endif
   int row, col, yuv[4], rgb[3], b, c;
   UINT64 bitbuf=0;
   float cmul[4];
@@ -2156,6 +2160,10 @@ void CLASS sinar_4shot_load_raw()
     unpacked_load_raw();
     return;
   }
+#ifdef LIBRAW_LIBRARY_BUILD
+  else if(!image)
+    throw LIBRAW_EXCEPTION_IO_CORRUPT;
+#endif
   pixel = (ushort *) calloc (raw_width, sizeof *pixel);
   merror (pixel, "sinar_4shot_load_raw()");
 #ifdef LIBRAW_LIBRARY_BUILD
@@ -2675,6 +2683,11 @@ void CLASS quicktake_100_load_raw()

 void CLASS kodak_radc_load_raw()
 {
+#ifdef LIBRAW_LIBRARY_BUILD
+  // All kodak radc images are 768x512
+  if(width>768 || raw_width>768 || height > 512 || raw_height>512 )
+    throw LIBRAW_EXCEPTION_IO_CORRUPT;
+#endif
   static const signed char src[] = {
     1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8,
     1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8,
@@ -2926,6 +2939,10 @@ void CLASS gamma_curve (double pwr, double ts, int mode, int imax);

 void CLASS lossy_dng_load_raw()
 {
+#ifdef LIBRAW_LIBRARY_BUILD
+  if(!image)
+    throw LIBRAW_EXCEPTION_IO_CORRUPT;
+#endif
   struct jpeg_decompress_struct cinfo;
   struct jpeg_error_mgr jerr;
   JSAMPARRAY buf;
@@ -3057,6 +3074,10 @@ void CLASS eight_bit_load_raw()

 void CLASS kodak_c330_load_raw()
 {
+#ifdef LIBRAW_LIBRARY_BUILD
+  if(!image)
+    throw LIBRAW_EXCEPTION_IO_CORRUPT;
+#endif
   uchar *pixel;
   int row, col, y, cb, cr, rgb[3], c;

@@ -3094,6 +3115,10 @@ void CLASS kodak_c330_load_raw()

 void CLASS kodak_c603_load_raw()
 {
+#ifdef LIBRAW_LIBRARY_BUILD
+  if(!image)
+    throw LIBRAW_EXCEPTION_IO_CORRUPT;
+#endif
   uchar *pixel;
   int row, col, y, cb, cr, rgb[3], c;

@@ -3257,6 +3282,10 @@ void CLASS kodak_65000_load_raw()

 void CLASS kodak_ycbcr_load_raw()
 {
+#ifdef LIBRAW_LIBRARY_BUILD
+  if(!image)
+    throw LIBRAW_EXCEPTION_IO_CORRUPT;
+#endif
   short buf[384], *bp;
   int row, col, len, c, i, j, k, y[2][2], cb, cr, rgb[3];
   ushort *ip;
@@ -3291,6 +3320,10 @@ void CLASS kodak_ycbcr_load_raw()

 void CLASS kodak_rgb_load_raw()
 {
+#ifdef LIBRAW_LIBRARY_BUILD
+  if(!image)
+    throw LIBRAW_EXCEPTION_IO_CORRUPT;
+#endif
   short buf[768], *bp;
   int row, col, len, c, i, rgb[3],ret;
   ushort *ip=image[0];
@@ -3319,6 +3352,10 @@ void CLASS kodak_rgb_load_raw()

 void CLASS kodak_thumb_load_raw()
 {
+#ifdef LIBRAW_LIBRARY_BUILD
+  if(!image)
+    throw LIBRAW_EXCEPTION_IO_CORRUPT;
+#endif
   int row, col;
   colors = thumb_misc >> 5;
   for (row=0; row < height; row++)


Secunia 76000 #2: xtrans allhex not initialized

@@ -7045,6 +7045,8 @@ void CLASS xtrans_interpolate(int passes)
 #endif

 #ifdef LIBRAW_LIBRARY_BUILD
+  if(width < TS || height < TS)
+	  throw LIBRAW_EXCEPTION_IO_CORRUPT; // too small image
 /* Check against right pattern */
   for (row = 0; row < 6; row++)
 	  for (col = 0; col < 6; col++)
@@ -7053,6 +7055,13 @@ void CLASS xtrans_interpolate(int passes)
   if(cstat[0] < 6 || cstat[0]>10 || cstat[1]< 16
     || cstat[1]>24 || cstat[2]< 6 || cstat[2]>10 || cstat[3])
 	  throw LIBRAW_EXCEPTION_IO_CORRUPT;
+
+ // Init allhex table to unreasonable values
+ for(int i = 0; i < 3; i++)
+  for(int j = 0; j < 3; j++)
+   for(int k = 0; k < 2; k++)
+    for(int l = 0; l < 8; l++)
+     allhex[i][j][k][l]=32700;
 #endif
   cielab(0, 0);
   ndir = 4 << (passes > 1);
@@ -7063,6 +7072,7 @@ void CLASS xtrans_interpolate(int passes)
   drv = (float(*)[TS][TS])(buffer + TS * TS * (ndir * 6 + 6));
   homo = (char(*)[TS][TS])(buffer + TS * TS * (ndir * 10 + 6));

+  int minv=0,maxv=0,minh=0,maxh=0;
   /* Map a green hexagon around each non-green pixel and vice versa:	*/
   for (row = 0; row < 3; row++)
     for (col = 0; col < 3; col++)
@@ -7083,11 +7093,25 @@ void CLASS xtrans_interpolate(int passes)
           {
             v = orth[d] * patt[g][c * 2] + orth[d + 1] * patt[g][c * 2 + 1];
             h = orth[d + 2] * patt[g][c * 2] + orth[d + 3] * patt[g][c * 2 + 1];
+	    minv=MIN(v,minv);
+	    maxv=MAX(v,maxv);
+	    minh=MIN(v,minh);
+   	    maxh=MAX(v,maxh);
             allhex[row][col][0][c ^ (g * 2 & d)] = h + v * width;
             allhex[row][col][1][c ^ (g * 2 & d)] = h + v * TS;
           }
       }

+#ifdef LIBRAW_LIBRARY_BUILD
+   // Check allhex table initialization
+  for(int i = 0; i < 3; i++)
+    for(int j = 0; j < 3; j++)
+      for(int k = 0; k < 2; k++)
+        for(int l = 0; l < 8; l++)
+	  if(allhex[i][j][k][l]>maxh+maxv*width+1 || allhex[i][j][k][l]<minh+minv*width-1)
+	  throw LIBRAW_EXCEPTION_IO_CORRUPT;
+  int retrycount = 0;
+#endif
   /* Set green1 and green3 to the minimum and maximum allowed values:	*/
   for (row = 2; row < height - 2; row++)
     for (min = ~(max = 0), col = 2; col < width - 2; col++)
@@ -7118,7 +7142,13 @@ void CLASS xtrans_interpolate(int passes)
         break;
       case 2:
         if ((min = ~(max = 0)) && (col += 2) < width - 3 && row > 2)
-          row--;
+	{
+           row--;
+#ifdef LIBRAW_LIBRARY_BUILD
+	  if(retrycount++ > width*height)
+	  	throw LIBRAW_EXCEPTION_IO_CORRUPT;
+#endif
+	}
       }
     }


@@ -22,7 +22,7 @@ it under the terms of the one of two licenses as you choose:

 #define LIBRAW_MAJOR_VERSION  0
 #define LIBRAW_MINOR_VERSION  18
-#define LIBRAW_PATCH_VERSION  7
+#define LIBRAW_PATCH_VERSION  8
 #define LIBRAW_VERSION_TAIL   Release

 #define LIBRAW_SHLIB_CURRENT  	16


Secunia 81800#1: samsumg_load_raw

Secunia 81800#2: find_green

Secunia 81800#3: rollei_load_raw

remove_trailing_spaces: isspace() does not works right with signed non-latin chars

Secunia 81800#5/6: nikon_coolscan_load_raw

Secunia 81800#4: rollei_load_raw

@@ -251,6 +251,7 @@ static float fMAX(float a, float b)
 	3 G R G R G R	3 B G B G B G	3 R G R G R G	3 G B G B G B
  */

+#define RAWINDEX(row, col) ((row)*raw_width + (col))
 #define RAW(row,col) \
 	raw_image[(row)*raw_width+(col)]
 //@end DEFINES
@@ -1511,9 +1512,14 @@ void CLASS pentax_load_raw()

 void CLASS nikon_coolscan_load_raw()
 {
-  int bufsize = width*3*tiff_bps/8;
-  if(tiff_bps <= 8)
-    gamma_curve(1.0/imgdata.params.coolscan_nef_gamma,0.,1,255);
+  if(!image)
+    throw LIBRAW_EXCEPTION_IO_CORRUPT;
+
+  int bypp = tiff_bps <= 8 ? 1 : 2;
+  int bufsize = width * 3 * bypp;
+
+  if (tiff_bps <= 8)
+    gamma_curve(1.0 / imgdata.params.coolscan_nef_gamma, 0., 1, 255);
   else
     gamma_curve(1.0/imgdata.params.coolscan_nef_gamma,0.,1,65535);
   fseek (ifp, data_offset, SEEK_SET);
@@ -1794,7 +1800,12 @@ void CLASS rollei_thumb()
 void CLASS rollei_load_raw()
 {
   uchar pixel[10];
-  unsigned iten=0, isix, i, buffer=0, todo[16];
+  unsigned iten = 0, isix, i, buffer = 0, todo[16];
+#ifdef LIBRAW_LIBRARY_BUILD
+  if(raw_width > 32767 || raw_height > 32767)
+    throw LIBRAW_EXCEPTION_IO_BADFILE;
+#endif
+  unsigned maxpixel = raw_width*(raw_height+7);

   isix = raw_width * raw_height * 5 / 8;
   while (fread (pixel, 1, 10, ifp) == 10) {
@@ -1810,8 +1821,11 @@ void CLASS rollei_load_raw()
       todo[i]   = isix++;
       todo[i+1] = buffer >> (14-i)*5;
     }
-    for (i=0; i < 16; i+=2)
-      raw_image[todo[i]] = (todo[i+1] & 0x3ff);
+    for (i = 0; i < 16; i += 2)
+      if(todo[i] < maxpixel)
+        raw_image[todo[i]] = (todo[i + 1] & 0x3ff);
+      else
+        derror();
   }
   maximum = 0x3ff;
 }
@@ -3857,6 +3871,11 @@ void CLASS sony_arw2_load_raw()
 void CLASS samsung_load_raw()
 {
   int row, col, c, i, dir, op[4], len[4];
+#ifdef LIBRAW_LIBRARY_BUILD
+  if(raw_width> 32768 || raw_height > 32768)  // definitely too much for old samsung
+    throw LIBRAW_EXCEPTION_IO_BADFILE;
+#endif
+  unsigned maxpixels = raw_width*(raw_height+7);

   order = 0x4949;
   for (row=0; row < raw_height; row++) {
@@ -3875,11 +3894,17 @@ void CLASS samsung_load_raw()
 	case 2: len[c]--;		break;
 	case 1: len[c]++;
       }
-      for (c=0; c < 16; c+=2) {
-	i = len[((c & 1) << 1) | (c >> 3)];
-        RAW(row,col+c) = ((signed) ph1_bits(i) << (32-i) >> (32-i)) +
-	  (dir ? RAW(row+(~c | -2),col+c) : col ? RAW(row,col+(c | -2)) : 128);
-	if (c == 14) c = -1;
+      for (c = 0; c < 16; c += 2)
+      {
+        i = len[((c & 1) << 1) | (c >> 3)];
+	unsigned idest = RAWINDEX(row, col + c);
+	unsigned isrc = (dir ? RAWINDEX(row + (~c | -2), col + c) : col ? RAWINDEX(row, col + (c | -2)) : 0);
+	if(idest < maxpixels && isrc < maxpixels) // less than zero is handled by unsigned conversion
+  	RAW(row, col + c) = ((signed)ph1_bits(i) << (32 - i) >> (32 - i)) + 			                (dir ? RAW(row + (~c | -2), col + c) : col ? RAW(row, col + (c | -2)) : 128);
+	else
+  	  derror();
+        if (c == 14)
+          c = -1;
       }
     }
   }
@@ -11081,37 +11106,68 @@ void CLASS parse_exif (int base)
        if (((make[0] == '\0') && (!strncmp(model, "ov5647",6))) ||
            ((!strncmp(make, "RaspberryPi",11)) && (!strncmp(model, "RP_OV5647",9))) ||
            ((!strncmp(make, "RaspberryPi",11)) && (!strncmp(model, "RP_imx219",9)))) {
-         char mn_text[512];
-         char* pos;
-         char ccms[512];
-         ushort l;
-         float num;
-
-         fgets(mn_text, len, ifp);
-         pos = strstr(mn_text, "gain_r=");
-         if (pos) cam_mul[0] = atof(pos+7);
-         pos = strstr(mn_text, "gain_b=");
-         if (pos) cam_mul[2] = atof(pos+7);
-         if ((cam_mul[0] > 0.001f) && (cam_mul[2] > 0.001f)) cam_mul[1] = cam_mul[3] = 1.0f;
-         else cam_mul[0] = cam_mul[2] = 0.0f;
-
-         pos = strstr(mn_text, "ccm=") + 4;
-         l = strstr(pos, " ") - pos;
-         memcpy (ccms, pos, l);
-         ccms[l] = '\0';
-
-         pos = strtok (ccms, ",");
-         for (l=0; l<4; l++) {
-           num = 0.0;
-           for (c=0; c<3; c++) {
-             imgdata.color.ccm[l][c] = (float)atoi(pos);
-             num += imgdata.color.ccm[l][c];
-             pos = strtok (NULL, ",");
-           }
-           if (num > 0.01) FORC3 imgdata.color.ccm[l][c] = imgdata.color.ccm[l][c] / num;
-         }
+        char mn_text[512];
+        char *pos;
+        char ccms[512];
+        ushort l;
+        float num;
+
+	fgets(mn_text, MIN(len,511), ifp);
+        mn_text[511] = 0;
+
+        pos = strstr(mn_text, "gain_r=");
+        if (pos)
+          cam_mul[0] = atof(pos + 7);
+        pos = strstr(mn_text, "gain_b=");
+        if (pos)
+          cam_mul[2] = atof(pos + 7);
+        if ((cam_mul[0] > 0.001f) && (cam_mul[2] > 0.001f))
+          cam_mul[1] = cam_mul[3] = 1.0f;
+        else
+          cam_mul[0] = cam_mul[2] = 0.0f;
+
+        pos = strstr(mn_text, "ccm=");
+        if(pos)
+        {
+         pos +=4;
+         char *pos2 = strstr(pos, " ");
+         if(pos2)
+         {
+           l = pos2 - pos;
+           memcpy(ccms, pos, l);
+           ccms[l] = '\0';
+#if defined WIN32 || defined(__MINGW32__)
+           // Win32 strtok is already thread-safe
+          pos = strtok(ccms, ",");
+#else
+          char *last=0;
+          pos = strtok_r(ccms, ",",&last);
+#endif
+          if(pos)
+          {
+            for (l = 0; l < 4; l++)
+            {
+              num = 0.0;
+              for (c = 0; c < 3; c++)
+              {
+                imgdata.color.ccm[l][c] = (float)atoi(pos);
+                num += imgdata.color.ccm[l][c];
+#if defined WIN32 || defined(__MINGW32__)
+                pos = strtok(NULL, ",");
+#else
+                pos = strtok_r(NULL, ",",&last);
+#endif
+                if(!pos) goto end; // broken
+              }
+              if (num > 0.01)
+                FORC3 imgdata.color.ccm[l][c] = imgdata.color.ccm[l][c] / num;
+            }
+          }
+        }
        }
-       else
+      end:;
+      }
+      else
 #endif
         parse_makernote (base, 0);
        break;
@@ -15077,7 +15133,8 @@ float CLASS find_green (int bps, int bite, int off0, int off1)
   UINT64 bitbuf=0;
   int vbits, col, i, c;
   ushort img[2][2064];
-  double sum[]={0,0};
+  double sum[] = {0, 0};
+  if(width > 2064) return 0.f; // too wide

   FORC(2) {
     fseek (ifp, c ? off1:off0, SEEK_SET);
@@ -15100,14 +15157,16 @@ float CLASS find_green (int bps, int bite, int off0, int off1)
 #ifdef LIBRAW_LIBRARY_BUILD
 static void remove_trailing_spaces(char *string, size_t len)
 {
-  if(len<1) return; // not needed, b/c sizeof of make/model is 64
-  string[len-1]=0;
-  if(len<3) return; // also not needed
-  len = strnlen(string,len-1);
-  for(int i=len-1; i>=0; i--)
+  if (len < 1)
+    return; // not needed, b/c sizeof of make/model is 64
+  string[len - 1] = 0;
+  if (len < 3)
+    return; // also not needed
+  len = strnlen(string, len - 1);
+  for (int i = len - 1; i >= 0; i--)
   {
-    if(isspace(string[i]))
-      string[i]=0;
+    if (isspace((unsigned char)string[i]))
+      string[i] = 0;
     else
       break;
   }


@@ -1228,9 +1228,14 @@ void CLASS pentax_load_raw()

 void CLASS nikon_coolscan_load_raw()
 {
-  int bufsize = width*3*tiff_bps/8;
-  if(tiff_bps <= 8)
-    gamma_curve(1.0/imgdata.params.coolscan_nef_gamma,0.,1,255);
+  if(!image)
+    throw LIBRAW_EXCEPTION_IO_CORRUPT;
+
+  int bypp = tiff_bps <= 8 ? 1 : 2;
+  int bufsize = width * 3 * bypp;
+
+  if (tiff_bps <= 8)
+    gamma_curve(1.0 / imgdata.params.coolscan_nef_gamma, 0., 1, 255);
   else
     gamma_curve(1.0/imgdata.params.coolscan_nef_gamma,0.,1,65535);
   fseek (ifp, data_offset, SEEK_SET);
@@ -1506,7 +1511,12 @@ void CLASS rollei_thumb()
 void CLASS rollei_load_raw()
 {
   uchar pixel[10];
-  unsigned iten=0, isix, i, buffer=0, todo[16];
+  unsigned iten = 0, isix, i, buffer = 0, todo[16];
+#ifdef LIBRAW_LIBRARY_BUILD
+  if(raw_width > 32767 || raw_height > 32767)
+    throw LIBRAW_EXCEPTION_IO_BADFILE;
+#endif
+  unsigned maxpixel = raw_width*(raw_height+7);

   isix = raw_width * raw_height * 5 / 8;
   while (fread (pixel, 1, 10, ifp) == 10) {
@@ -1522,8 +1532,11 @@ void CLASS rollei_load_raw()
       todo[i]   = isix++;
       todo[i+1] = buffer >> (14-i)*5;
     }
-    for (i=0; i < 16; i+=2)
-      raw_image[todo[i]] = (todo[i+1] & 0x3ff);
+    for (i = 0; i < 16; i += 2)
+      if(todo[i] < maxpixel)
+        raw_image[todo[i]] = (todo[i + 1] & 0x3ff);
+      else
+        derror();
   }
   maximum = 0x3ff;
 }
@@ -3569,6 +3582,11 @@ void CLASS sony_arw2_load_raw()
 void CLASS samsung_load_raw()
 {
   int row, col, c, i, dir, op[4], len[4];
+#ifdef LIBRAW_LIBRARY_BUILD
+  if(raw_width> 32768 || raw_height > 32768)  // definitely too much for old samsung
+    throw LIBRAW_EXCEPTION_IO_BADFILE;
+#endif
+  unsigned maxpixels = raw_width*(raw_height+7);

   order = 0x4949;
   for (row=0; row < raw_height; row++) {
@@ -3587,11 +3605,17 @@ void CLASS samsung_load_raw()
 	case 2: len[c]--;		break;
 	case 1: len[c]++;
       }
-      for (c=0; c < 16; c+=2) {
-	i = len[((c & 1) << 1) | (c >> 3)];
-        RAW(row,col+c) = ((signed) ph1_bits(i) << (32-i) >> (32-i)) +
-	  (dir ? RAW(row+(~c | -2),col+c) : col ? RAW(row,col+(c | -2)) : 128);
-	if (c == 14) c = -1;
+      for (c = 0; c < 16; c += 2)
+      {
+        i = len[((c & 1) << 1) | (c >> 3)];
+	unsigned idest = RAWINDEX(row, col + c);
+	unsigned isrc = (dir ? RAWINDEX(row + (~c | -2), col + c) : col ? RAWINDEX(row, col + (c | -2)) : 0);
+	if(idest < maxpixels && isrc < maxpixels) // less than zero is handled by unsigned conversion
+  	RAW(row, col + c) = ((signed)ph1_bits(i) << (32 - i) >> (32 - i)) + 			                (dir ? RAW(row + (~c | -2), col + c) : col ? RAW(row, col + (c | -2)) : 128);
+	else
+  	  derror();
+        if (c == 14)
+          c = -1;
       }
     }
   }
@@ -9890,37 +9914,68 @@ void CLASS parse_exif (int base)
        if (((make[0] == '\0') && (!strncmp(model, "ov5647",6))) ||
            ((!strncmp(make, "RaspberryPi",11)) && (!strncmp(model, "RP_OV5647",9))) ||
            ((!strncmp(make, "RaspberryPi",11)) && (!strncmp(model, "RP_imx219",9)))) {
-         char mn_text[512];
-         char* pos;
-         char ccms[512];
-         ushort l;
-         float num;
-
-         fgets(mn_text, len, ifp);
-         pos = strstr(mn_text, "gain_r=");
-         if (pos) cam_mul[0] = atof(pos+7);
-         pos = strstr(mn_text, "gain_b=");
-         if (pos) cam_mul[2] = atof(pos+7);
-         if ((cam_mul[0] > 0.001f) && (cam_mul[2] > 0.001f)) cam_mul[1] = cam_mul[3] = 1.0f;
-         else cam_mul[0] = cam_mul[2] = 0.0f;
-
-         pos = strstr(mn_text, "ccm=") + 4;
-         l = strstr(pos, " ") - pos;
-         memcpy (ccms, pos, l);
-         ccms[l] = '\0';
-
-         pos = strtok (ccms, ",");
-         for (l=0; l<4; l++) {
-           num = 0.0;
-           for (c=0; c<3; c++) {
-             imgdata.color.ccm[l][c] = (float)atoi(pos);
-             num += imgdata.color.ccm[l][c];
-             pos = strtok (NULL, ",");
-           }
-           if (num > 0.01) FORC3 imgdata.color.ccm[l][c] = imgdata.color.ccm[l][c] / num;
-         }
+        char mn_text[512];
+        char *pos;
+        char ccms[512];
+        ushort l;
+        float num;
+
+	fgets(mn_text, MIN(len,511), ifp);
+        mn_text[511] = 0;
+
+        pos = strstr(mn_text, "gain_r=");
+        if (pos)
+          cam_mul[0] = atof(pos + 7);
+        pos = strstr(mn_text, "gain_b=");
+        if (pos)
+          cam_mul[2] = atof(pos + 7);
+        if ((cam_mul[0] > 0.001f) && (cam_mul[2] > 0.001f))
+          cam_mul[1] = cam_mul[3] = 1.0f;
+        else
+          cam_mul[0] = cam_mul[2] = 0.0f;
+
+        pos = strstr(mn_text, "ccm=");
+        if(pos)
+        {
+         pos +=4;
+         char *pos2 = strstr(pos, " ");
+         if(pos2)
+         {
+           l = pos2 - pos;
+           memcpy(ccms, pos, l);
+           ccms[l] = '\0';
+#if defined WIN32 || defined(__MINGW32__)
+           // Win32 strtok is already thread-safe
+          pos = strtok(ccms, ",");
+#else
+          char *last=0;
+          pos = strtok_r(ccms, ",",&last);
+#endif
+          if(pos)
+          {
+            for (l = 0; l < 4; l++)
+            {
+              num = 0.0;
+              for (c = 0; c < 3; c++)
+              {
+                imgdata.color.ccm[l][c] = (float)atoi(pos);
+                num += imgdata.color.ccm[l][c];
+#if defined WIN32 || defined(__MINGW32__)
+                pos = strtok(NULL, ",");
+#else
+                pos = strtok_r(NULL, ",",&last);
+#endif
+                if(!pos) goto end; // broken
+              }
+              if (num > 0.01)
+                FORC3 imgdata.color.ccm[l][c] = imgdata.color.ccm[l][c] / num;
+            }
+          }
+        }
        }
-       else
+      end:;
+      }
+      else
 #endif
         parse_makernote (base, 0);
        break;
@@ -13739,7 +13794,8 @@ float CLASS find_green (int bps, int bite, int off0, int off1)
   UINT64 bitbuf=0;
   int vbits, col, i, c;
   ushort img[2][2064];
-  double sum[]={0,0};
+  double sum[] = {0, 0};
+  if(width > 2064) return 0.f; // too wide

   FORC(2) {
     fseek (ifp, c ? off1:off0, SEEK_SET);
@@ -13762,14 +13818,16 @@ float CLASS find_green (int bps, int bite, int off0, int off1)
 #ifdef LIBRAW_LIBRARY_BUILD
 static void remove_trailing_spaces(char *string, size_t len)
 {
-  if(len<1) return; // not needed, b/c sizeof of make/model is 64
-  string[len-1]=0;
-  if(len<3) return; // also not needed
-  len = strnlen(string,len-1);
-  for(int i=len-1; i>=0; i--)
+  if (len < 1)
+    return; // not needed, b/c sizeof of make/model is 64
+  string[len - 1] = 0;
+  if (len < 3)
+    return; // also not needed
+  len = strnlen(string, len - 1);
+  for (int i = len - 1; i >= 0; i--)
   {
-    if(isspace(string[i]))
-      string[i]=0;
+    if (isspace((unsigned char)string[i]))
+      string[i] = 0;
     else
       break;
   }


Bug 1675: Prevent SCP server sending files that were not requested

https://winscp.net/tracker/1675

Source commit: 4aa587620973bf793fb6e783052277c0f7be4b55

@@ -2361,6 +2361,10 @@ void __fastcall TSCPFileSystem::SCPSink(const UnicodeString TargetDir,
           {
             FTerminal->LogEvent(FORMAT(L"Warning: Remote host set a compound pathname '%s'", (Line)));
           }
+          if ((Level == 0) && (OnlyFileName != UnixExtractFileName(FileName)))
+          {
+            SCPError(LoadStr(UNREQUESTED_FILE), False);
+          }

           FullFileName = SourceDir + OnlyFileName;
           OperationProgress->SetFile(FullFileName);


[Extensions] Have URLPattern::Contains() properly check schemes

Have URLPattern::Contains() properly check the schemes of the patterns
when evaluating if one pattern contains another. This is important in
order to prevent extensions from requesting chrome:-scheme permissions
via the permissions API when <all_urls> is specified as an optional
permission.

Bug: 859600,918470

Change-Id: If04d945ad0c939e84a80d83502c0f84b6ef0923d
Reviewed-on: https://chromium-review.googlesource.com/c/1396561
Commit-Queue: Devlin <rdevlin.cronin@chromium.org>
Reviewed-by: Karan Bhatia <karandeepb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#621410}

@@ -19,13 +19,17 @@
 #include "components/crx_file/id_util.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/extension_features.h"
+#include "extensions/common/manifest_handlers/permissions_parser.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"

 namespace extensions {

 namespace {

+constexpr char kNotInManifestError[] =
+    "Only permissions specified in the manifest may be requested.";
+
 using permissions_test_util::GetPatternsAsStrings;

 scoped_refptr<const Extension> CreateExtensionWithPermissions(
@@ -556,7 +560,7 @@ TEST_F(PermissionsAPIUnitTest, RequestingPermissionsNotSpecifiedInManifest) {
   auto function = base::MakeRefCounted<PermissionsRequestFunction>();
   function->set_user_gesture(true);
   function->set_extension(extension.get());
-  EXPECT_EQ("Only permissions specified in the manifest may be requested.",
+  EXPECT_EQ(kNotInManifestError,
             extension_function_test_utils::RunFunctionAndReturnError(
                 function.get(),
                 R"([{
@@ -617,4 +621,52 @@ TEST_F(PermissionsAPIUnitTest, RequestingAlreadyGrantedWithheldPermissions) {
           kGoogleCom));
 }

+// Test that requesting chrome:-scheme URLs is disallowed in the permissions
+// API.
+TEST_F(PermissionsAPIUnitTest, RequestingChromeURLs) {
+  scoped_refptr<const Extension> extension =
+      ExtensionBuilder("extension")
+          .SetManifestKey("optional_permissions",
+                          ListBuilder().Append("<all_urls>").Build())
+          .Build();
+  AddExtensionAndGrantPermissions(*extension);
+
+  const GURL chrome_url("chrome://settings");
+
+  // By default, the extension should not have access to chrome://settings.
+  EXPECT_FALSE(extension->permissions_data()->HasHostPermission(chrome_url));
+  // The optional permissions should also omit the chrome:-scheme for the
+  // <all_urls> pattern.
+  EXPECT_FALSE(PermissionsParser::GetOptionalPermissions(extension.get())
+                   .explicit_hosts()
+                   .MatchesURL(chrome_url));
+
+  {
+    // Trying to request "chrome://settings/*" should fail, since it's not in
+    // the optional permissions.
+    auto function = base::MakeRefCounted<PermissionsRequestFunction>();
+    function->set_user_gesture(true);
+    function->set_extension(extension.get());
+    std::string error =
+        extension_function_test_utils::RunFunctionAndReturnError(
+            function.get(), R"([{"origins": ["chrome://settings/*"]}])",
+            browser(), api_test_utils::NONE);
+    EXPECT_EQ(kNotInManifestError, error);
+  }
+  // chrome://settings should still be restricted.
+  EXPECT_FALSE(extension->permissions_data()->HasHostPermission(chrome_url));
+
+  // The extension can request <all_urls>, but it should not grant access to the
+  // chrome:-scheme.
+  std::unique_ptr<const PermissionSet> prompted_permissions;
+  RunRequestFunction(*extension, browser(), R"([{"origins": ["<all_urls>"]}])",
+                     &prompted_permissions);
+  EXPECT_THAT(GetPatternsAsStrings(prompted_permissions->effective_hosts()),
+              testing::UnorderedElementsAre("<all_urls>"));
+
+  EXPECT_FALSE(extension->permissions_data()->HasHostPermission(chrome_url));
+  EXPECT_TRUE(extension->permissions_data()->HasHostPermission(
+      GURL("https://example.com")));
+}
+
 }  // namespace extensions


[runtime] Reduce spread/apply call max arguments

Bug: chromium:906043
Change-Id: I308b29af0644c318d73926b27e65a94913c760c7
Reviewed-on: https://chromium-review.googlesource.com/c/1346115
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57731}

@@ -184,6 +184,8 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
     Goto(&if_done);
   }

+  Label too_many_args(this, Label::kDeferred);
+
   // Tail call to the appropriate builtin (depending on whether we have
   // a {new_target} passed).
   BIND(&if_done);
@@ -194,6 +196,8 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
     TNode<Int32T> length = var_length.value();
     {
       Label normalize_done(this);
+      GotoIf(Int32GreaterThan(length, Int32Constant(Code::kMaxArguments)),
+             &too_many_args);
       GotoIfNot(Word32Equal(length, Int32Constant(0)), &normalize_done);
       // Make sure we don't accidentally pass along the
       // empty_fixed_double_array since the tailed-called stubs cannot handle
@@ -228,6 +232,9 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
                                    Int32Constant(HOLEY_DOUBLE_ELEMENTS));
     }
   }
+
+  BIND(&too_many_args);
+  ThrowRangeError(context, MessageTemplate::kTooManyArguments);
 }

 // Takes a FixedArray of doubles and creates a new FixedArray with those doubles
@@ -239,6 +246,11 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructDoubleVarargs(
     TNode<Int32T> args_count, TNode<Context> context, TNode<Int32T> kind) {
   const ElementsKind new_kind = PACKED_ELEMENTS;
   const WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER;
+
+  Label too_many_args(this, Label::kDeferred);
+  GotoIf(Int32GreaterThan(length, Int32Constant(Code::kMaxArguments)),
+         &too_many_args);
+
   TNode<IntPtrT> intptr_length = ChangeInt32ToIntPtr(length);
   CSA_ASSERT(this, WordNotEqual(intptr_length, IntPtrConstant(0)));

@@ -258,13 +270,16 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructDoubleVarargs(
     TailCallStub(callable, context, target, new_target, args_count, length,
                  new_elements);
   }
+
+  BIND(&too_many_args);
+  ThrowRangeError(context, MessageTemplate::kTooManyArguments);
 }

 void CallOrConstructBuiltinsAssembler::CallOrConstructWithSpread(
     TNode<Object> target, TNode<Object> new_target, TNode<Object> spread,
     TNode<Int32T> args_count, TNode<Context> context) {
   Label if_smiorobject(this), if_double(this),
-      if_generic(this, Label::kDeferred);
+      if_generic(this, Label::kDeferred), too_many_args(this, Label::kDeferred);

   TVARIABLE(Int32T, var_length);
   TVARIABLE(FixedArrayBase, var_elements);
@@ -330,6 +345,9 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithSpread(
     TNode<FixedArrayBase> elements = var_elements.value();
     TNode<Int32T> length = var_length.value();

+    GotoIf(Int32GreaterThan(length, Int32Constant(Code::kMaxArguments)),
+           &too_many_args);
+
     if (new_target == nullptr) {
       Callable callable = CodeFactory::CallVarargs(isolate());
       TailCallStub(callable, context, target, args_count, length, elements);
@@ -347,6 +365,9 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithSpread(
                                  var_length.value(), args_count, context,
                                  var_elements_kind.value());
   }
+
+  BIND(&too_many_args);
+  ThrowRangeError(context, MessageTemplate::kTooManyArguments);
 }

 TF_BUILTIN(CallWithArrayLike, CallOrConstructBuiltinsAssembler) {


Peek for \n in LineBasedFrameDecoder.

Summary:
Previously this could underflow if there was not a following \n.

CVE-2019-3563

Reviewed By: siyengar

Differential Revision: D14935715

fbshipit-source-id: 25c3eecf373f89efa1232456aeeb092f13b7fa06

@@ -606,3 +606,37 @@ TEST(LineBasedFrameDecoder, CarriageNewLineOnly) {
   pipeline->read(q);
   EXPECT_EQ(called, 1);
 }
+
+TEST(LineBasedFrameDecoder, CarriageOnly) {
+  auto pipeline = Pipeline<IOBufQueue&, std::unique_ptr<IOBuf>>::create();
+
+  (*pipeline)
+      .addBack(LineBasedFrameDecoder(
+          10, true, LineBasedFrameDecoder::TerminatorType::CARRIAGENEWLINE))
+      .addBack(test::FrameTester([&](std::unique_ptr<IOBuf>) { FAIL(); }))
+      .finalize();
+
+  IOBufQueue q(IOBufQueue::cacheChainLength());
+  q.append(IOBuf::copyBuffer("\raa"));
+  pipeline->read(q);
+}
+
+TEST(LineBasedFrameDecoder, DoubleCarriage) {
+  auto pipeline = Pipeline<IOBufQueue&, std::unique_ptr<IOBuf>>::create();
+  int called = 0;
+
+  (*pipeline)
+      .addBack(LineBasedFrameDecoder(
+          10, true, LineBasedFrameDecoder::TerminatorType::CARRIAGENEWLINE))
+      .addBack(test::FrameTester([&](std::unique_ptr<IOBuf> buf) {
+        auto sz = buf->computeChainDataLength();
+        called++;
+        EXPECT_EQ(sz, 1);
+      }))
+      .finalize();
+
+  IOBufQueue q(IOBufQueue::cacheChainLength());
+  q.append(IOBuf::copyBuffer("\r\r\na\r\n"));
+  pipeline->read(q);
+  EXPECT_EQ(called, 2);
+}


Show an error page if a URL redirects to a javascript: URL.

BUG=935175

Change-Id: Id4a9198d5dff823bc3d324b9de9bff2ee86dc499
Reviewed-on: https://chromium-review.googlesource.com/c/1488152
Commit-Queue: Charlie Reis <creis@chromium.org>
Reviewed-by: Arthur Sonzogni <arthursonzogni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#635848}

@@ -894,8 +894,13 @@ void NavigationRequest::OnRequestRedirected(
           redirect_info.new_url)) {
     DVLOG(1) << "Denied redirect for "
              << redirect_info.new_url.possibly_invalid_spec();
-    navigation_handle_->set_net_error_code(net::ERR_UNSAFE_REDIRECT);
-    frame_tree_node_->ResetNavigationRequest(false, true);
+    // Show an error page rather than leaving the previous page in place.
+    OnRequestFailedInternal(
+        network::URLLoaderCompletionStatus(net::ERR_UNSAFE_REDIRECT),
+        false /* skip_throttles */, base::nullopt /* error_page_content */,
+        false /* collapse_frame */);
+    // DO NOT ADD CODE after this. The previous call to OnRequestFailedInternal
+    // has destroyed the NavigationRequest.
     return;
   }

@@ -908,8 +913,13 @@ void NavigationRequest::OnRequestRedirected(
           redirect_info.new_url)) {
     DVLOG(1) << "Denied unauthorized redirect for "
              << redirect_info.new_url.possibly_invalid_spec();
-    navigation_handle_->set_net_error_code(net::ERR_UNSAFE_REDIRECT);
-    frame_tree_node_->ResetNavigationRequest(false, true);
+    // Show an error page rather than leaving the previous page in place.
+    OnRequestFailedInternal(
+        network::URLLoaderCompletionStatus(net::ERR_UNSAFE_REDIRECT),
+        false /* skip_throttles */, base::nullopt /* error_page_content */,
+        false /* collapse_frame */);
+    // DO NOT ADD CODE after this. The previous call to OnRequestFailedInternal
+    // has destroyed the NavigationRequest.
     return;
   }


Inherit the navigation initiator when navigating instead of the parent/opener

Spec PR: https://github.com/w3c/webappsec-csp/pull/358

Bug: 905301, 894228, 836148
Change-Id: I43ada2266d42d1cd56dbe3c6dd89d115e878a83a
Reviewed-on: https://chromium-review.googlesource.com/c/1314633
Commit-Queue: Andy Paicu <andypaicu@chromium.org>
Reviewed-by: Mike West <mkwst@chromium.org>
Cr-Commit-Position: refs/heads/master@{#610850}

@@ -660,22 +660,6 @@ bool ContentSecurityPolicy::AllowPluginTypeForDocument(
           type, type_attribute, url, reporting_policy))
     return false;

-  // CSP says that a plugin document in a nested browsing context should
-  // inherit the plugin-types of its parent.
-  //
-  // FIXME: The plugin-types directive should be pushed down into the
-  // current document instead of reaching up to the parent for it here.
-  LocalFrame* frame = document.GetFrame();
-  if (frame && frame->Tree().Parent() && document.IsPluginDocument()) {
-    ContentSecurityPolicy* parent_csp = frame->Tree()
-                                            .Parent()
-                                            ->GetSecurityContext()
-                                            ->GetContentSecurityPolicy();
-    if (parent_csp && !parent_csp->AllowPluginType(type, type_attribute, url,
-                                                   reporting_policy))
-      return false;
-  }
-
   return true;
 }


Throw on bad types during skipping data

Summary:
The current code silently returns on bad types. In case when we have an invalid data, we may get a container of a large size with a bad type, this would lead to us running long loop doing nothing (though we already can say that the data is invalid).

The new code would throw an exception as soon as we try to skip a value of invalid type.

Fixes CVE-2019-3552

Reviewed By: yfeldblum, stevegury

Differential Revision: D8344920

fbshipit-source-id: f12e8f3442f7ad5e1a81d822380701e929b80f0d

@@ -57,4 +57,12 @@ namespace apache { namespace thrift { namespace protocol {
           "Attempt to interpret value {} as bool, probably the data is corrupted",
           value));
 }
+
+[[noreturn]] void TProtocolException::throwInvalidSkipType(TType type) {
+  throw TProtocolException(
+      TProtocolException::INVALID_DATA,
+      folly::sformat(
+          "Encountered invalid field/element type ({}) during skipping",
+          static_cast<uint8_t>(type)));
+}
 }}}


Call CanCaptureVisiblePage in page capture API.

Currently the pageCapture permission allows access
to arbitrary local files and chrome:// pages which
can be a security concern. In order to address this,
the page capture API needs to be changed similar to
the captureVisibleTab API. The API will now only allow
extensions to capture otherwise-restricted URLs if the
user has granted activeTab. In addition, file:// URLs are
only capturable with the "Allow on file URLs" option enabled.

Bug: 893087

Change-Id: I6d6225a3efb70fc033e2e1c031c633869afac624
Reviewed-on: https://chromium-review.googlesource.com/c/1330689
Commit-Queue: Bettina Dea <bdea@chromium.org>
Reviewed-by: Devlin <rdevlin.cronin@chromium.org>
Reviewed-by: Varun Khaneja <vakh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#615248}

@@ -5,21 +5,34 @@
 #include "base/base_switches.h"
 #include "base/command_line.h"
 #include "base/threading/thread_restrictions.h"
+#include "chrome/browser/extensions/active_tab_permission_granter.h"
 #include "chrome/browser/extensions/api/page_capture/page_capture_api.h"
+#include "chrome/browser/extensions/extension_action_runner.h"
 #include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "chromeos/login/scoped_test_public_session_login_state.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/extension_dialog_auto_confirm.h"
+#include "extensions/common/permissions/permission_set.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "extensions/common/url_pattern_set.h"
+#include "extensions/test/extension_test_message_listener.h"
+#include "extensions/test/result_catcher.h"
 #include "net/dns/mock_host_resolver.h"

 #if defined(OS_CHROMEOS)
 #include "chromeos/login/login_state.h"
 #endif  // defined(OS_CHROMEOS)

+using extensions::Extension;
+using extensions::ExtensionActionRunner;
 using extensions::PageCaptureSaveAsMHTMLFunction;
+using extensions::ResultCatcher;
 using extensions::ScopedTestDialogAutoConfirm;

 class ExtensionPageCaptureApiTest : public extensions::ExtensionApiTest {
@@ -55,6 +68,24 @@ class PageCaptureSaveAsMHTMLDelegate
 IN_PROC_BROWSER_TEST_F(ExtensionPageCaptureApiTest, SaveAsMHTML) {
   ASSERT_TRUE(StartEmbeddedTestServer());
   PageCaptureSaveAsMHTMLDelegate delegate;
+  ASSERT_TRUE(RunExtensionTestWithFlagsAndArg(
+      "page_capture", "ONLY_PAGE_CAPTURE_PERMISSION", kFlagNone))
+      << message_;
+  // Make sure the MHTML data gets written to the temporary file.
+  ASSERT_FALSE(delegate.temp_file_.empty());
+  // Flush the message loops to make sure the delete happens.
+  content::RunAllTasksUntilIdle();
+  content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
+  // Make sure the temporary file is destroyed once the javascript side reads
+  // the contents.
+  base::ScopedAllowBlockingForTesting allow_blocking;
+  ASSERT_FALSE(base::PathExists(delegate.temp_file_));
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionPageCaptureApiTest,
+                       SaveAsMHTMLWithActiveTabWithFileAccess) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  PageCaptureSaveAsMHTMLDelegate delegate;
   ASSERT_TRUE(RunExtensionTest("page_capture")) << message_;
   // Make sure the MHTML data gets written to the temporary file.
   ASSERT_FALSE(delegate.temp_file_.empty());


[url] Make path URL parsing more lax

Parsing the path component of a non-special URL like javascript or data
should not fail for invalid URL characters like \uFFFF. See this bit
in the spec:
https://url.spec.whatwg.org/#cannot-be-a-base-url-path-state

Note: some failing WPTs are added which are because url parsing
replaces invalid characters (e.g. \uFFFF) with the replacement char
\uFFFD, when that isn't in the spec.

Bug: 925614
Change-Id: I450495bfdfa68dc70334ebed16a3ecc0d5737e88
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1551917
Reviewed-by: Mike West <mkwst@chromium.org>
Commit-Queue: Charlie Harrison <csharrison@chromium.org>
Cr-Commit-Position: refs/heads/master@{#648155}

@@ -1873,9 +1873,13 @@ TEST(URLCanonTest, CanonicalizePathURL) {
     const char* input;
     const char* expected;
   } path_cases[] = {
-    {"javascript:", "javascript:"},
-    {"JavaScript:Foo", "javascript:Foo"},
-    {"Foo:\":This /is interesting;?#", "foo:\":This /is interesting;?#"},
+      {"javascript:", "javascript:"},
+      {"JavaScript:Foo", "javascript:Foo"},
+      {"Foo:\":This /is interesting;?#", "foo:\":This /is interesting;?#"},
+
+      // Validation errors should not cause failure. See
+      // https://crbug.com/925614.
+      {"javascript:\uFFFF", "javascript:%EF%BF%BD"},
   };

   for (size_t i = 0; i < base::size(path_cases); i++) {


Prevent WindowClient.navigate() from cancelling a browser-initiated navigation.

Otherwise, a service worker can prevent you from navigating where you
want to go via the omnibox.

Note: this is similar to WebContentsImpl::OnGoToEntryAtOffset() for
renderer-initiated history navigations.

Bug: 930154
Change-Id: I3a687ccc8ba4420d2369adb24f63c2702bdeeff1
Reviewed-on: https://chromium-review.googlesource.com/c/1477454
Commit-Queue: Matt Falkenhagen <falken@chromium.org>
Commit-Queue: Arthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: Arthur Sonzogni <arthursonzogni@chromium.org>
Auto-Submit: Matt Falkenhagen <falken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#633231}

@@ -258,6 +258,36 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerClientsApiBrowserTest,
   EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
 }

+// Tests a WindowClient.navigate() call during a browser-initiated navigation.
+// Regression test for https://crbug.com/930154.
+IN_PROC_BROWSER_TEST_F(ServiceWorkerClientsApiBrowserTest,
+                       NavigateDuringBrowserNavigation) {
+  // Load a page that registers a service worker.
+  EXPECT_TRUE(NavigateToURL(shell(),
+                            embedded_test_server()->GetURL(
+                                "/service_worker/create_service_worker.html")));
+  EXPECT_EQ("DONE", EvalJs(shell(), "register('client_api_worker.js');"));
+
+  // Load the test page.
+  EXPECT_TRUE(NavigateToURL(
+      shell(),
+      embedded_test_server()->GetURL("/service_worker/request_navigate.html")));
+
+  // Start a browser-initiated navigation.
+  GURL url(embedded_test_server()->GetURL("/title1.html"));
+  TestNavigationManager navigation(shell()->web_contents(), url);
+  shell()->LoadURL(url);
+  EXPECT_TRUE(navigation.WaitForRequestStart());
+
+  // Have the service worker call client.navigate() to try to go to another
+  // URL. It should fail.
+  EXPECT_EQ("navigate failed", EvalJs(shell(), "requestToNavigate();"));
+
+  // The browser-initiated navigation should finish.
+  navigation.WaitForNavigationFinished();  // Resume navigation.
+  EXPECT_TRUE(navigation.was_successful());
+}
+
 // Tests a successful Clients.openWindow() call.
 IN_PROC_BROWSER_TEST_F(ServiceWorkerClientsApiBrowserTest, OpenWindow) {
   ActivatedServiceWorkerObserver observer;


Fix remote code execution and privilege escalation vulnerability.

To trigger this, need to have a user already.

Thanks for Jeriko One <jeriko.one@gmx.us> for finding and reporting this.

CVE-2019-12816

@@ -1600,6 +1600,7 @@ class CModules : public std::vector<CModule*>, private CCoreTranslationMixin {
   private:
     static ModHandle OpenModule(const CString& sModule, const CString& sModPath,
                                 CModInfo& Info, CString& sRetMsg);
+    static bool ValidateModuleName(const CString& sModule, CString& sRetMsg);

   protected:
     CUser* m_pUser;


Replace copied scrypt implementation with call to libsodium

Summary:
libsodium actually uses the same implementation; using libsodium means we don't
need to maintain a copy ourselves.

Keep the `pickparams` implementation though, as that's not exposed in libsodium.

We should deprecate this extension, and strongly encourage directly using `ext_sodium` instead from Hack code; stored hashes from `ext_scrypt` can be verified like this:

```
$enc = scrypt_enc('foo', random_bytes(SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES));

list($_, $algo, $n, $r, $p, $salt, $out) = explode('$', $enc);
invariant($algo === 's', 'did not get an scrypt result');
$salt = base64_decode($salt);
$out = base64_decode($out);

$opslimit = (1 << $n) * $r * $p * 4;
$memlimit = (1 << $n) * $r * 128;
$sodium = sodium_crypto_pwhash_scryptsalsa208sha256(strlen($out), 'foo', $salt, $opslimit, $memlimit);
\var_dump($sodium === $out);
```

This also makes the scrypt extension depend on libsodium; this is fine, libsodium's going to be a hard dependency for HHVM  anyway when the proxygen pin is next updated.

Reviewed By: alexeyt

Differential Revision: D15702142

fbshipit-source-id: 2dcad7c6cb273d4ce4b3479ffa445841fa2d1107

@@ -1,418 +0,0 @@
-/*-
- * Copyright 2005,2007,2009 Colin Percival
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <sys/types.h>
-
-#include <stdint.h>
-#include <string.h>
-
-#include <folly/Bits.h>
-
-#include "sha256.h" // nolint
-
-/*
- * Encode a length len/4 vector of (uint32_t) into a length len vector of
- * (unsigned char) in big-endian form.  Assumes len is a multiple of 4.
- */
-static void
-be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len)
-{
-  size_t i;
-  uint32_t *d;
-
-  for (i = 0; i < len / 4; i++) {
-    d = (uint32_t *) (dst + i * 4);
-    *d = folly::Endian::big32(src[i]);
-  }
-}
-
-/*
- * Decode a big-endian length len vector of (unsigned char) into a length
- * len/4 vector of (uint32_t).  Assumes len is a multiple of 4.
- */
-static void
-be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len)
-{
-  size_t i;
-  uint32_t *s;
-
-  for (i = 0; i < len / 4; i++) {
-    s = (uint32_t *) (src + i * 4);
-    dst[i] = folly::Endian::big32(*s);
-  }
-}
-
-/* Elementary functions used by SHA256 */
-#define Ch(x, y, z) ((x & (y ^ z)) ^ z)
-#define Maj(x, y, z)  ((x & (y | z)) | (y & z))
-#define SHR(x, n) (x >> n)
-#define ROTR(x, n)  ((x >> n) | (x << (32 - n)))
-#define S0(x)   (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
-#define S1(x)   (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
-#define s0(x)   (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
-#define s1(x)   (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
-
-/* SHA256 round function */
-#define RND(a, b, c, d, e, f, g, h, k)      \
-  t0 = h + S1(e) + Ch(e, f, g) + k;   \
-  t1 = S0(a) + Maj(a, b, c);      \
-  d += t0;          \
-  h  = t0 + t1;
-
-/* Adjusted round function for rotating state */
-#define RNDr(S, W, i, k)      \
-  RND(S[(64 - i) % 8], S[(65 - i) % 8], \
-      S[(66 - i) % 8], S[(67 - i) % 8], \
-      S[(68 - i) % 8], S[(69 - i) % 8], \
-      S[(70 - i) % 8], S[(71 - i) % 8], \
-      W[i] + k)
-
-/*
- * SHA256 block compression function.  The 256-bit state is transformed via
- * the 512-bit input block to produce a new state.
- */
-static void
-SHA256_Transform(uint32_t * state, const unsigned char block[64])
-{
-  uint32_t W[64];
-  uint32_t S[8];
-  uint32_t t0, t1;
-  int i;
-
-  /* 1. Prepare message schedule W. */
-  be32dec_vect(W, block, 64);
-  for (i = 16; i < 64; i++)
-    W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
-
-  /* 2. Initialize working variables. */
-  memcpy(S, state, 32);
-
-  /* 3. Mix. */
-  RNDr(S, W, 0, 0x428a2f98);
-  RNDr(S, W, 1, 0x71374491);
-  RNDr(S, W, 2, 0xb5c0fbcf);
-  RNDr(S, W, 3, 0xe9b5dba5);
-  RNDr(S, W, 4, 0x3956c25b);
-  RNDr(S, W, 5, 0x59f111f1);
-  RNDr(S, W, 6, 0x923f82a4);
-  RNDr(S, W, 7, 0xab1c5ed5);
-  RNDr(S, W, 8, 0xd807aa98);
-  RNDr(S, W, 9, 0x12835b01);
-  RNDr(S, W, 10, 0x243185be);
-  RNDr(S, W, 11, 0x550c7dc3);
-  RNDr(S, W, 12, 0x72be5d74);
-  RNDr(S, W, 13, 0x80deb1fe);
-  RNDr(S, W, 14, 0x9bdc06a7);
-  RNDr(S, W, 15, 0xc19bf174);
-  RNDr(S, W, 16, 0xe49b69c1);
-  RNDr(S, W, 17, 0xefbe4786);
-  RNDr(S, W, 18, 0x0fc19dc6);
-  RNDr(S, W, 19, 0x240ca1cc);
-  RNDr(S, W, 20, 0x2de92c6f);
-  RNDr(S, W, 21, 0x4a7484aa);
-  RNDr(S, W, 22, 0x5cb0a9dc);
-  RNDr(S, W, 23, 0x76f988da);
-  RNDr(S, W, 24, 0x983e5152);
-  RNDr(S, W, 25, 0xa831c66d);
-  RNDr(S, W, 26, 0xb00327c8);
-  RNDr(S, W, 27, 0xbf597fc7);
-  RNDr(S, W, 28, 0xc6e00bf3);
-  RNDr(S, W, 29, 0xd5a79147);
-  RNDr(S, W, 30, 0x06ca6351);
-  RNDr(S, W, 31, 0x14292967);
-  RNDr(S, W, 32, 0x27b70a85);
-  RNDr(S, W, 33, 0x2e1b2138);
-  RNDr(S, W, 34, 0x4d2c6dfc);
-  RNDr(S, W, 35, 0x53380d13);
-  RNDr(S, W, 36, 0x650a7354);
-  RNDr(S, W, 37, 0x766a0abb);
-  RNDr(S, W, 38, 0x81c2c92e);
-  RNDr(S, W, 39, 0x92722c85);
-  RNDr(S, W, 40, 0xa2bfe8a1);
-  RNDr(S, W, 41, 0xa81a664b);
-  RNDr(S, W, 42, 0xc24b8b70);
-  RNDr(S, W, 43, 0xc76c51a3);
-  RNDr(S, W, 44, 0xd192e819);
-  RNDr(S, W, 45, 0xd6990624);
-  RNDr(S, W, 46, 0xf40e3585);
-  RNDr(S, W, 47, 0x106aa070);
-  RNDr(S, W, 48, 0x19a4c116);
-  RNDr(S, W, 49, 0x1e376c08);
-  RNDr(S, W, 50, 0x2748774c);
-  RNDr(S, W, 51, 0x34b0bcb5);
-  RNDr(S, W, 52, 0x391c0cb3);
-  RNDr(S, W, 53, 0x4ed8aa4a);
-  RNDr(S, W, 54, 0x5b9cca4f);
-  RNDr(S, W, 55, 0x682e6ff3);
-  RNDr(S, W, 56, 0x748f82ee);
-  RNDr(S, W, 57, 0x78a5636f);
-  RNDr(S, W, 58, 0x84c87814);
-  RNDr(S, W, 59, 0x8cc70208);
-  RNDr(S, W, 60, 0x90befffa);
-  RNDr(S, W, 61, 0xa4506ceb);
-  RNDr(S, W, 62, 0xbef9a3f7);
-  RNDr(S, W, 63, 0xc67178f2);
-
-  /* 4. Mix local working variables into global state */
-  for (i = 0; i < 8; i++)
-    state[i] += S[i];
-
-  /* Clean the stack. */
-  memset(W, 0, 256);
-  memset(S, 0, 32);
-  t0 = t1 = 0;
-}
-
-static unsigned char PAD[64] = {
-  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* Add padding and terminating bit-count. */
-static void
-SHA256_Pad(struct SHA256_CTX * ctx)
-{
-  unsigned char len[8];
-  uint32_t r, plen;
-
-  /*
-   * Convert length to a vector of bytes -- we do this now rather
-   * than later because the length will change after we pad.
-   */
-  be32enc_vect(len, ctx->count, 8);
-
-  /* Add 1--64 bytes so that the resulting length is 56 mod 64 */
-  r = (ctx->count[1] >> 3) & 0x3f;
-  plen = (r < 56) ? (56 - r) : (120 - r);
-  scrypt_SHA256_Update(ctx, PAD, (size_t)plen);
-
-  /* Add the terminating bit-count */
-  scrypt_SHA256_Update(ctx, len, 8);
-}
-
-/* SHA-256 initialization.  Begins a SHA-256 operation. */
-void
-SHA256_Init(struct SHA256_CTX * ctx)
-{
-
-  /* Zero bits processed so far */
-  ctx->count[0] = ctx->count[1] = 0;
-
-  /* Magic initialization constants */
-  ctx->state[0] = 0x6A09E667;
-  ctx->state[1] = 0xBB67AE85;
-  ctx->state[2] = 0x3C6EF372;
-  ctx->state[3] = 0xA54FF53A;
-  ctx->state[4] = 0x510E527F;
-  ctx->state[5] = 0x9B05688C;
-  ctx->state[6] = 0x1F83D9AB;
-  ctx->state[7] = 0x5BE0CD19;
-}
-
-/* Add bytes into the hash */
-void
-scrypt_SHA256_Update(struct SHA256_CTX * ctx, const void *in, size_t len)
-{
-  uint32_t bitlen[2];
-  uint32_t r;
-  const unsigned char *src = (unsigned char *) in;
-
-  /* Number of bytes left in the buffer from previous updates */
-  r = (ctx->count[1] >> 3) & 0x3f;
-
-  /* Convert the length into a number of bits */
-  bitlen[1] = ((uint32_t)len) << 3;
-  bitlen[0] = (uint32_t)(len >> 29);
-
-  /* Update number of bits */
-  if ((ctx->count[1] += bitlen[1]) < bitlen[1])
-    ctx->count[0]++;
-  ctx->count[0] += bitlen[0];
-
-  /* Handle the case where we don't need to perform any transforms */
-  if (len < 64 - r) {
-    memcpy(&ctx->buf[r], src, len);
-    return;
-  }
-
-  /* Finish the current block */
-  memcpy(&ctx->buf[r], src, 64 - r);
-  SHA256_Transform(ctx->state, ctx->buf);
-  src += 64 - r;
-  len -= 64 - r;
-
-  /* Perform complete blocks */
-  while (len >= 64) {
-    SHA256_Transform(ctx->state, src);
-    src += 64;
-    len -= 64;
-  }
-
-  /* Copy left over data into buffer */
-  memcpy(ctx->buf, src, len);
-}
-
-/*
- * SHA-256 finalization.  Pads the input data, exports the hash value,
- * and clears the context state.
- */
-void
-scrypt_SHA256_Final(unsigned char digest[32], struct SHA256_CTX * ctx)
-{
-
-  /* Add padding */
-  SHA256_Pad(ctx);
-
-  /* Write the hash */
-  be32enc_vect(digest, ctx->state, 32);
-
-  /* Clear the context state */
-  memset((void *)ctx, 0, sizeof(*ctx));
-}
-
-/* Initialize an HMAC-SHA256 operation with the given key. */
-void
-HMAC_SHA256_Init(struct HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen)
-{
-  unsigned char pad[64];
-  unsigned char khash[32];
-  const unsigned char * K = (unsigned char *) _K;
-  size_t i;
-
-  /* If Klen > 64, the key is really SHA256(K). */
-  if (Klen > 64) {
-    SHA256_Init(&ctx->ictx);
-    scrypt_SHA256_Update(&ctx->ictx, K, Klen);
-    scrypt_SHA256_Final(khash, &ctx->ictx);
-    K = khash;
-    Klen = 32;
-  }
-
-  /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
-  SHA256_Init(&ctx->ictx);
-  memset(pad, 0x36, 64);
-  for (i = 0; i < Klen; i++)
-    pad[i] ^= K[i];
-  scrypt_SHA256_Update(&ctx->ictx, pad, 64);
-
-  /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
-  SHA256_Init(&ctx->octx);
-  memset(pad, 0x5c, 64);
-  for (i = 0; i < Klen; i++)
-    pad[i] ^= K[i];
-  scrypt_SHA256_Update(&ctx->octx, pad, 64);
-
-  /* Clean the stack. */
-  memset(khash, 0, 32);
-}
-
-/* Add bytes to the HMAC-SHA256 operation. */
-void
-HMAC_SHA256_Update(struct HMAC_SHA256_CTX * ctx, const void *in, size_t len)
-{
-
-  /* Feed data to the inner SHA256 operation. */
-  scrypt_SHA256_Update(&ctx->ictx, in, len);
-}
-
-/* Finish an HMAC-SHA256 operation. */
-void
-HMAC_SHA256_Final(unsigned char digest[32], struct HMAC_SHA256_CTX * ctx)
-{
-  unsigned char ihash[32];
-
-  /* Finish the inner SHA256 operation. */
-  scrypt_SHA256_Final(ihash, &ctx->ictx);
-
-  /* Feed the inner hash to the outer SHA256 operation. */
-  scrypt_SHA256_Update(&ctx->octx, ihash, 32);
-
-  /* Finish the outer SHA256 operation. */
-  scrypt_SHA256_Final(digest, &ctx->octx);
-
-  /* Clean the stack. */
-  memset(ihash, 0, 32);
-}
-
-/**
- * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
- * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
- * write the output to buf.  The value dkLen must be at most 32 * (2^32 - 1).
- */
-void
-PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt,
-    size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen)
-{
-  struct HMAC_SHA256_CTX PShctx, hctx;
-  size_t i;
-  uint8_t ivec[4];
-  uint32_t *ivec_p;
-  uint8_t U[32];
-  uint8_t T[32];
-  uint64_t j;
-  int k;
-  size_t clen;
-
-  /* Compute HMAC state after processing P and S. */
-  HMAC_SHA256_Init(&PShctx, passwd, passwdlen);
-  HMAC_SHA256_Update(&PShctx, salt, saltlen);
-
-  /* Iterate through the blocks. */
-  ivec_p = (uint32_t *) ivec;
-  for (i = 0; i * 32 < dkLen; i++) {
-    /* Generate INT(i + 1). */
-    *ivec_p = folly::Endian::big32((uint32_t)(i + 1));
-
-    /* Compute U_1 = PRF(P, S || INT(i)). */
-    memcpy(&hctx, &PShctx, sizeof(struct HMAC_SHA256_CTX));
-    HMAC_SHA256_Update(&hctx, ivec, 4);
-    HMAC_SHA256_Final(U, &hctx);
-
-    /* T_i = U_1 ... */
-    memcpy(T, U, 32);
-
-    for (j = 2; j <= c; j++) {
-      /* Compute U_j. */
-      HMAC_SHA256_Init(&hctx, passwd, passwdlen);
-      HMAC_SHA256_Update(&hctx, U, 32);
-      HMAC_SHA256_Final(U, &hctx);
-
-      /* ... xor U_j ... */
-      for (k = 0; k < 32; k++)
-        T[k] ^= U[k];
-    }
-
-    /* Copy as many bytes as necessary into buf. */
-    clen = dkLen - i * 32;
-    if (clen > 32)
-      clen = 32;
-    memcpy(&buf[i * 32], T, clen);
-  }
-
-  /* Clean PShctx, since we never called _Final on it. */
-  memset(&PShctx, 0, sizeof(struct HMAC_SHA256_CTX));
-}


fix: Do not use the "/tmp" directory

https://github.com/linuxdeepin/deepin-clone/issues/16
https://bugzilla.opensuse.org/show_bug.cgi?id=1130388

@@ -303,9 +303,9 @@ bool DDeviceDiskInfoPrivate::openDataStream(int index)

         if (currentMode == DDiskInfo::Read) {
             const QString &executer = Helper::getPartcloneExecuter(part);
-            process->start(QStringLiteral("%1 -s %2 -o - -c -z %3 -L /tmp/partclone.log").arg(executer).arg(part.filePath()).arg(Global::bufferSize), QIODevice::ReadOnly);
+            process->start(QStringLiteral("%1 -s %2 -o - -c -z %3 -L /var/log/partclone.log").arg(executer).arg(part.filePath()).arg(Global::bufferSize), QIODevice::ReadOnly);
         } else {
-            process->start(QStringLiteral("partclone.restore -s - -o %2 -z %3 -L /tmp/partclone.log").arg(part.filePath()).arg(Global::bufferSize));
+            process->start(QStringLiteral("partclone.restore -s - -o %2 -z %3 -L /var/log/partclone.log").arg(part.filePath()).arg(Global::bufferSize));
         }

         break;


Ignore exceptions when deserializing note plaintexts

@@ -173,15 +173,21 @@ boost::optional<SaplingOutgoingPlaintext> SaplingOutgoingPlaintext::decrypt(
     }

     // Deserialize from the plaintext
-    CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
-    ss << pt.get();
+    try {
+        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+        ss << pt.get();

-    SaplingOutgoingPlaintext ret;
-    ss >> ret;
+        SaplingOutgoingPlaintext ret;
+        ss >> ret;

-    assert(ss.size() == 0);
+        assert(ss.size() == 0);

-    return ret;
+        return ret;
+    } catch (const boost::thread_interrupted&) {
+        throw;
+    } catch (...) {
+        return boost::none;
+    }
 }

 boost::optional<SaplingNotePlaintext> SaplingNotePlaintext::decrypt(
@@ -197,13 +203,17 @@ boost::optional<SaplingNotePlaintext> SaplingNotePlaintext::decrypt(
     }

     // Deserialize from the plaintext
-    CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
-    ss << pt.get();
-
     SaplingNotePlaintext ret;
-    ss >> ret;
-
-    assert(ss.size() == 0);
+    try {
+        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+        ss << pt.get();
+        ss >> ret;
+        assert(ss.size() == 0);
+    } catch (const boost::thread_interrupted&) {
+        throw;
+    } catch (...) {
+        return boost::none;
+    }

     uint256 pk_d;
     if (!librustzcash_ivk_to_pkd(ivk.begin(), ret.d.data(), pk_d.begin())) {
@@ -243,11 +253,17 @@ boost::optional<SaplingNotePlaintext> SaplingNotePlaintext::decrypt(
     }

     // Deserialize from the plaintext
-    CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
-    ss << pt.get();
-
     SaplingNotePlaintext ret;
-    ss >> ret;
+    try {
+        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+        ss << pt.get();
+        ss >> ret;
+        assert(ss.size() == 0);
+    } catch (const boost::thread_interrupted&) {
+        throw;
+    } catch (...) {
+        return boost::none;
+    }

     uint256 cmu_expected;
     if (!librustzcash_sapling_compute_cm(
@@ -265,8 +281,6 @@ boost::optional<SaplingNotePlaintext> SaplingNotePlaintext::decrypt(
         return boost::none;
     }

-    assert(ss.size() == 0);
-
     return ret;
 }


Track byteSize of HeaderMap internally.

Introduces a cached byte size updated internally in HeaderMap. The value
is stored as an optional, and is cleared whenever a non-const pointer or
reference to a HeaderEntry is accessed. The cached value can be set with
refreshByteSize() which performs an iteration over the HeaderMap to sum
the size of each key and value in the HeaderMap.

Signed-off-by: Asra Ali <asraa@google.com>

@@ -509,6 +509,10 @@ int ConnectionImpl::onFrameReceived(const nghttp2_frame* frame) {

   switch (frame->hd.type) {
   case NGHTTP2_HEADERS: {
+    // Verify that the final HeaderMap's byte size is under the limit before decoding headers.
+    // This assert iterates over the HeaderMap.
+    ASSERT(stream->headers_->byteSize().has_value() &&
+           stream->headers_->byteSize().value() == stream->headers_->byteSizeInternal());
     stream->remote_end_stream_ = frame->hd.flags & NGHTTP2_FLAG_END_STREAM;
     if (!stream->cookies_.empty()) {
       HeaderString key(Headers::get().Cookie);
@@ -620,6 +624,12 @@ int ConnectionImpl::onFrameSend(const nghttp2_frame* frame) {
   case NGHTTP2_HEADERS:
   case NGHTTP2_DATA: {
     StreamImpl* stream = getStream(frame->hd.stream_id);
+    if (stream->headers_) {
+      // Verify that the final HeaderMap's byte size is under the limit before sending frames.
+      // This assert iterates over the HeaderMap.
+      ASSERT(stream->headers_->byteSize().has_value() &&
+             stream->headers_->byteSize().value() == stream->headers_->byteSizeInternal());
+    }
     stream->local_end_stream_sent_ = frame->hd.flags & NGHTTP2_FLAG_END_STREAM;
     break;
   }
@@ -808,9 +818,10 @@ int ConnectionImpl::saveHeader(const nghttp2_frame* frame, HeaderString&& name,
     stats_.headers_cb_no_stream_.inc();
     return 0;
   }
-
   stream->saveHeader(std::move(name), std::move(value));
-  if (stream->headers_->byteSize() > max_request_headers_kb_ * 1024) {
+  // Verify that the cached value in byte size exists.
+  ASSERT(stream->headers_->byteSize().has_value());
+  if (stream->headers_->byteSize().value() > max_request_headers_kb_ * 1024) {
     // This will cause the library to reset/close the stream.
     stats_.header_overflow_.inc();
     return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;


@@ -64,6 +64,8 @@ TEST_P(Http2IntegrationTest, Retry) { testRetry(); }

 TEST_P(Http2IntegrationTest, RetryAttemptCount) { testRetryAttemptCountHeader(); }

+TEST_P(Http2IntegrationTest, LargeRequestTrailersRejected) { testLargeRequestTrailers(66, 60); }
+
 static std::string response_metadata_filter = R"EOF(
 name: response-metadata-filter
 config: {}


Restrict PixelBuffer dimensions to safe values

We do a lot of calculations based on pixel coordinates and we need
to make sure they do not overflow. Restrict the maximum dimensions
we support rather than try to switch over all calculations to use
64 bit integers.

This prevents attackers from from injecting code by specifying a
huge framebuffer size and relying on the values overflowing to
access invalid areas of the heap.

This primarily affects the client which gets both the screen
dimensions and the pixel contents from the remote side. But the
server might also be affected as a client can adjust the screen
dimensions, as can applications inside the session.

Issue found by Pavel Cheremushkin from Kaspersky Lab.

@@ -31,6 +31,14 @@ using namespace rdr;

 static LogWriter vlog("PixelBuffer");

+// We do a lot of byte offset calculations that assume the result fits
+// inside a signed 32 bit integer. Limit the maximum size of pixel
+// buffers so that these calculations never overflow.
+
+const int maxPixelBufferWidth = 16384;
+const int maxPixelBufferHeight = 16384;
+const int maxPixelBufferStride = 16384;
+

 // -=- Generic pixel buffer class

@@ -108,6 +116,11 @@ void PixelBuffer::getImage(const PixelFormat& pf, void* imageBuf,

 void PixelBuffer::setSize(int width, int height)
 {
+  if ((width < 0) || (width > maxPixelBufferWidth))
+    throw rfb::Exception("Invalid PixelBuffer width of %d pixels requested", width);
+  if ((height < 0) || (height > maxPixelBufferHeight))
+    throw rfb::Exception("Invalid PixelBuffer height of %d pixels requested", height);
+
   width_ = width;
   height_ = height;
 }
@@ -340,6 +353,15 @@ const rdr::U8* FullFramePixelBuffer::getBuffer(const Rect& r, int* stride_) cons
 void FullFramePixelBuffer::setBuffer(int width, int height,
                                      rdr::U8* data_, int stride_)
 {
+  if ((width < 0) || (width > maxPixelBufferWidth))
+    throw rfb::Exception("Invalid PixelBuffer width of %d pixels requested", width);
+  if ((height < 0) || (height > maxPixelBufferHeight))
+    throw rfb::Exception("Invalid PixelBuffer height of %d pixels requested", height);
+  if ((stride_ < 0) || (stride_ > maxPixelBufferStride) || (stride_ < width))
+    throw rfb::Exception("Invalid PixelBuffer stride of %d pixels requested", stride_);
+  if ((width != 0) && (height != 0) && (data_ == NULL))
+    throw rfb::Exception("PixelBuffer requested without a valid memory area");
+
   ModifiablePixelBuffer::setSize(width, height);
   stride = stride_;
   data = data_;


Use size_t for lengths in stream objects

Provides safety against them accidentally becoming negative because
of bugs in the calculations.

Also does the same to CharArray and friends as they were strongly
connection to the stream objects.

@@ -34,28 +34,28 @@ namespace rdr {

   public:

-    FdOutStream(int fd, bool blocking=true, int timeoutms=-1, int bufSize=0);
+    FdOutStream(int fd, bool blocking=true, int timeoutms=-1, size_t bufSize=0);
     virtual ~FdOutStream();

     void setTimeout(int timeoutms);
     void setBlocking(bool blocking);
     int getFd() { return fd; }

     void flush();
-    int length();
+    size_t length();

     int bufferUsage();

     unsigned getIdleTime();

   private:
-    int overrun(int itemSize, int nItems);
-    int writeWithTimeout(const void* data, int length, int timeoutms);
+    size_t overrun(size_t itemSize, size_t nItems);
+    size_t writeWithTimeout(const void* data, size_t length, int timeoutms);
     int fd;
     bool blocking;
     int timeoutms;
-    int bufSize;
-    int offset;
+    size_t bufSize;
+    size_t offset;
     U8* start;
     U8* sentUpTo;
     struct timeval lastWrite;


@@ -44,7 +44,7 @@ namespace rdr {
     // itemSize bytes.  Returns the number of items which fit (up to a maximum
     // of nItems).

-    inline int check(int itemSize, int nItems=1)
+    inline size_t check(size_t itemSize, size_t nItems=1)
     {
       if (ptr + itemSize * nItems > end) {
         if (ptr + itemSize > end)
@@ -76,25 +76,25 @@ namespace rdr {
       writeBytes(str, len);
     }

-    inline void pad(int bytes) {
+    inline void pad(size_t bytes) {
       while (bytes-- > 0) writeU8(0);
     }

-    inline void skip(int bytes) {
+    inline void skip(size_t bytes) {
       while (bytes > 0) {
-        int n = check(1, bytes);
+        size_t n = check(1, bytes);
         ptr += n;
         bytes -= n;
       }
     }

     // writeBytes() writes an exact number of bytes.

-    void writeBytes(const void* data, int length) {
+    void writeBytes(const void* data, size_t length) {
       const U8* dataPtr = (const U8*)data;
       const U8* dataEnd = dataPtr + length;
       while (dataPtr < dataEnd) {
-        int n = check(1, dataEnd - dataPtr);
+        size_t n = check(1, dataEnd - dataPtr);
         memcpy(ptr, dataPtr, n);
         ptr += n;
         dataPtr += n;
@@ -103,9 +103,9 @@ namespace rdr {

     // copyBytes() efficiently transfers data between streams

-    void copyBytes(InStream* is, int length) {
+    void copyBytes(InStream* is, size_t length) {
       while (length > 0) {
-        int n = check(1, length);
+        size_t n = check(1, length);
         is->readBytes(ptr, n);
         ptr += n;
         length -= n;
@@ -124,7 +124,7 @@ namespace rdr {

     // length() returns the length of the stream.

-    virtual int length() = 0;
+    virtual size_t length() = 0;

     // flush() requests that the stream be flushed.

@@ -145,7 +145,7 @@ namespace rdr {
     // the number of items which fit (up to a maximum of nItems).  itemSize is
     // supposed to be "small" (a few bytes).

-    virtual int overrun(int itemSize, int nItems) = 0;
+    virtual size_t overrun(size_t itemSize, size_t nItems) = 0;

   protected:


@@ -35,25 +35,25 @@ namespace rdr {

   public:

-    ZlibOutStream(OutStream* os=0, int bufSize=0, int compressionLevel=-1);
+    ZlibOutStream(OutStream* os=0, size_t bufSize=0, int compressionLevel=-1);
     virtual ~ZlibOutStream();

     void setUnderlying(OutStream* os);
     void setCompressionLevel(int level=-1);
     void flush();
-    int length();
+    size_t length();

   private:

-    int overrun(int itemSize, int nItems);
+    size_t overrun(size_t itemSize, size_t nItems);
     void deflate(int flush);
     void checkCompressionLevel();

     OutStream* underlying;
     int compressionLevel;
     int newLevel;
-    int bufSize;
-    int offset;
+    size_t bufSize;
+    size_t offset;
     z_stream_s* zs;
     U8* start;
   };


Handle close_notify as standard writeErr in AsyncSSLSocket.

Summary: Fixes CVE-2019-11934

Reviewed By: mingtaoy

Differential Revision: D18020613

fbshipit-source-id: db82bb250e53f0d225f1280bd67bc74abd417836

@@ -1450,9 +1450,6 @@ AsyncSocket::WriteResult AsyncSSLSocket::interpretSSLError(int rc, int error) {
         WRITE_ERROR,
         std::make_unique<SSLException>(SSLError::INVALID_RENEGOTIATION));
   } else {
-    if (zero_return(error, rc, errno)) {
-      return WriteResult(0);
-    }
     auto errError = ERR_get_error();
     VLOG(3) << "ERROR: AsyncSSLSocket(fd=" << fd_ << ", state=" << int(state_)
             << ", sslState=" << sslState_ << ", events=" << eventFlags_ << "): "
@@ -1589,10 +1586,7 @@ AsyncSocket::WriteResult AsyncSSLSocket::performWrite(
         *partialWritten = uint32_t(offset);
         return WriteResult(totalWritten);
       }
-      auto writeResult = interpretSSLError(int(bytes), error);
-      if (writeResult.writeReturn < 0) {
-        return writeResult;
-      } // else fall through to below to correctly record totalWritten
+      return interpretSSLError(int(bytes), error);
     }

     totalWritten += bytes;


Limitless Prefetching should not always schedule all action tasks

This reverts the code snipped to what it used to be before limitless was
introduced. These tasks should indeed only be scheduled during a
background task run even if limitless is enabled.

Bug: 793109
Change-Id: I0bd427cb245e0e006f560c23cf6843e29d5aac63
Reviewed-on: https://chromium-review.googlesource.com/915206
Reviewed-by: Peter Williamson <petewil@chromium.org>
Commit-Queue: Carlos Knippschild <carlosk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#536837}

@@ -195,9 +195,8 @@ void PrefetchDispatcherImpl::QueueActionTasks() {
   task_queue_.AddTask(std::move(download_archives_task));

   // The following tasks should not be run unless we are in the background task,
-  // as we need to ensure WiFi access at that time. Schedule them anyway if
-  // limitless prefetching is enabled.
-  if (!background_task_ && !offline_pages::IsLimitlessPrefetchingEnabled())
+  // as we need to ensure WiFi access at that time.
+  if (!background_task_)
     return;

   std::unique_ptr<Task> get_operation_task = std::make_unique<GetOperationTask>(


Java: Check the size of the remaining frame before deserializing a string

Summary:
In order to avoid over-allocating memory for malformed or truncated frame, we
ensure that we have enough data in the current frame.

This is a partial fix for CVE-2019-11938.

Reviewed By: vitaut

Differential Revision: D14505601

fbshipit-source-id: c90f248828b067a3a5debcc8df6a3f4e9da6d195

@@ -638,6 +638,7 @@ private byte[] readBinary(int length) throws TException {
       return new byte[0];
     }

+    ensureContainerHasEnough(length, TType.BYTE);
     byte[] buf = new byte[length];
     trans_.readAll(buf, 0, length);
     return buf;


@@ -776,10 +776,27 @@ void CLua::init_lua()
     setregistry("__clua");
 }

+static int lua_loadstring(lua_State *ls)
+{
+    const auto lua = luaL_checkstring(ls, 1);
+    if (lua[0] == 0x1b)
+        abort();
+    lua_settop(ls, 0);
+    if (luaL_loadstring(ls, lua))
+    {
+        lua_pushnil(ls);
+        lua_insert(ls, 1);
+    }
+    return lua_gettop(ls);
+}
+
 void CLua::init_libraries()
 {
     lua_stack_cleaner clean(state());

+    lua_pushcfunction(_state, lua_loadstring);
+    lua_setglobal(_state, "loadstring");
+
     // Open Crawl bindings
     cluaopen_kills(_state);
     cluaopen_you(_state);