Refactored SNMP engine after vulnerabilities

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
+ * Copyright (C) 2019-2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@

 /**
  * \file
- *      An implementation of the Simple Network Management Protocol (RFC 3411-3418)
+ *      SNMP Implementation of the protocol engine
  * \author
  *      Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
  */
@@ -42,154 +42,168 @@
 #include "snmp-engine.h"
 #include "snmp-message.h"
 #include "snmp-mib.h"
-#include "snmp-oid.h"
+#include "snmp-ber.h"

 #define LOG_MODULE "SNMP [engine]"
 #define LOG_LEVEL LOG_LEVEL_SNMP

 /*---------------------------------------------------------------------------*/
-int
-snmp_engine_get(snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t varbinds_length)
+static inline int
+snmp_engine_get(snmp_header_t *header, snmp_varbind_t *varbinds)
 {
   snmp_mib_resource_t *resource;
-  uint32_t i;
+  uint8_t i;

-  for(i = 0; i < varbinds_length; i++) {
-    resource = snmp_mib_find(varbinds[i].oid);
+  i = 0;
+  while(varbinds[i].value_type != BER_DATA_TYPE_EOC && i < SNMP_MAX_NR_VALUES) {
+    resource = snmp_mib_find(&varbinds[i].oid);
     if(!resource) {
       switch(header->version) {
       case SNMP_VERSION_1:
-        header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
+        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
         /*
          * Varbinds are 1 indexed
          */
-        header->error_index_max_repetitions.error_index = i + 1;
+        header->error_index = i + 1;
         break;
       case SNMP_VERSION_2C:
-        (&varbinds[i])->value_type = SNMP_DATA_TYPE_NO_SUCH_INSTANCE;
+        (&varbinds[i])->value_type = BER_DATA_TYPE_NO_SUCH_INSTANCE;
         break;
       default:
-        header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
-        header->error_index_max_repetitions.error_index = 0;
+        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
+        header->error_index = 0;
       }
     } else {
-      resource->handler(&varbinds[i], resource->oid);
+      resource->handler(&varbinds[i], &resource->oid);
     }
+
+    i++;
   }

   return 0;
 }
 /*---------------------------------------------------------------------------*/
-int
-snmp_engine_get_next(snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t varbinds_length)
+static inline int
+snmp_engine_get_next(snmp_header_t *header, snmp_varbind_t *varbinds)
 {
   snmp_mib_resource_t *resource;
-  uint32_t i;
+  uint8_t i;

-  for(i = 0; i < varbinds_length; i++) {
-    resource = snmp_mib_find_next(varbinds[i].oid);
+  i = 0;
+  while(varbinds[i].value_type != BER_DATA_TYPE_EOC && i < SNMP_MAX_NR_VALUES) {
+    resource = snmp_mib_find_next(&varbinds[i].oid);
     if(!resource) {
       switch(header->version) {
       case SNMP_VERSION_1:
-        header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
+        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
         /*
          * Varbinds are 1 indexed
          */
-        header->error_index_max_repetitions.error_index = i + 1;
+        header->error_index = i + 1;
         break;
       case SNMP_VERSION_2C:
-        (&varbinds[i])->value_type = SNMP_DATA_TYPE_END_OF_MIB_VIEW;
+        (&varbinds[i])->value_type = BER_DATA_TYPE_END_OF_MIB_VIEW;
         break;
       default:
-        header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
-        header->error_index_max_repetitions.error_index = 0;
+        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
+        header->error_index = 0;
       }
     } else {
-      resource->handler(&varbinds[i], resource->oid);
+      resource->handler(&varbinds[i], &resource->oid);
     }
+
+    i++;
   }

   return 0;
 }
 /*---------------------------------------------------------------------------*/
-int
-snmp_engine_get_bulk(snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t *varbinds_length)
+static inline int
+snmp_engine_get_bulk(snmp_header_t *header, snmp_varbind_t *varbinds)
 {
   snmp_mib_resource_t *resource;
-  uint32_t i, j, original_varbinds_length;
-  uint32_t oid[SNMP_MAX_NR_VALUES][SNMP_MSG_OID_MAX_LEN];
+  snmp_oid_t oids[SNMP_MAX_NR_VALUES];
+  uint32_t j, original_varbinds_length;
   uint8_t repeater;
+  uint8_t i, varbinds_length;

   /*
    * A local copy of the requested oids must be kept since
    *  the varbinds are modified on the fly
    */
-  original_varbinds_length = *varbinds_length;
-  for(i = 0; i < original_varbinds_length; i++) {
-    snmp_oid_copy(oid[i], varbinds[i].oid);
+  original_varbinds_length = 0;
+  while(varbinds[original_varbinds_length].value_type != BER_DATA_TYPE_EOC && original_varbinds_length < SNMP_MAX_NR_VALUES) {
+    memcpy(&oids[original_varbinds_length], &varbinds[original_varbinds_length].oid, sizeof(snmp_oid_t));
+    original_varbinds_length++;
   }

-  *varbinds_length = 0;
+  varbinds_length = 0;
   for(i = 0; i < original_varbinds_length; i++) {
-    if(i >= header->error_status_non_repeaters.non_repeaters) {
+    if(i >= header->non_repeaters) {
       break;
     }

-    resource = snmp_mib_find_next(oid[i]);
+    resource = snmp_mib_find_next(&oids[i]);
     if(!resource) {
       switch(header->version) {
       case SNMP_VERSION_1:
-        header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
+        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
         /*
          * Varbinds are 1 indexed
          */
-        header->error_index_max_repetitions.error_index = i + 1;
+        header->error_index = i + 1;
         break;
       case SNMP_VERSION_2C:
-        (&varbinds[i])->value_type = SNMP_DATA_TYPE_END_OF_MIB_VIEW;
+        (&varbinds[i])->value_type = BER_DATA_TYPE_END_OF_MIB_VIEW;
         break;
       default:
-        header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
-        header->error_index_max_repetitions.error_index = 0;
+        header->error_status = SNMP_STATUS_NO_SUCH_NAME;
+        header->error_index = 0;
       }
     } else {
-      if(*varbinds_length < SNMP_MAX_NR_VALUES) {
-        resource->handler(&varbinds[*varbinds_length], resource->oid);
-        (*varbinds_length)++;
+      if(varbinds_length < SNMP_MAX_NR_VALUES) {
+        resource->handler(&varbinds[varbinds_length], &resource->oid);
+        (varbinds_length)++;
+      } else {
+        return -1;
       }
     }
   }

-  for(i = 0; i < header->error_index_max_repetitions.max_repetitions; i++) {
+  for(i = 0; i < header->max_repetitions; i++) {
     repeater = 0;
-    for(j = header->error_status_non_repeaters.non_repeaters; j < original_varbinds_length; j++) {
-      resource = snmp_mib_find_next(oid[j]);
+    for(j = header->non_repeaters; j < original_varbinds_length; j++) {
+      resource = snmp_mib_find_next(&oids[j]);
       if(!resource) {
         switch(header->version) {
         case SNMP_VERSION_1:
-          header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
+          header->error_status = SNMP_STATUS_NO_SUCH_NAME;
           /*
            * Varbinds are 1 indexed
            */
-          header->error_index_max_repetitions.error_index = *varbinds_length + 1;
+          header->error_index = varbinds_length + 1;
           break;
         case SNMP_VERSION_2C:
-          if(*varbinds_length < SNMP_MAX_NR_VALUES) {
-            (&varbinds[*varbinds_length])->value_type = SNMP_DATA_TYPE_END_OF_MIB_VIEW;
-            snmp_oid_copy((&varbinds[*varbinds_length])->oid, oid[j]);
-            (*varbinds_length)++;
+          if(varbinds_length < SNMP_MAX_NR_VALUES) {
+            (&varbinds[varbinds_length])->value_type = BER_DATA_TYPE_END_OF_MIB_VIEW;
+            memcpy(&varbinds[varbinds_length].oid, &oids[j], sizeof(snmp_oid_t));
+            (varbinds_length)++;
+          } else {
+            return -1;
           }
           break;
         default:
-          header->error_status_non_repeaters.error_status = SNMP_STATUS_NO_SUCH_NAME;
-          header->error_index_max_repetitions.error_index = 0;
+          header->error_status = SNMP_STATUS_NO_SUCH_NAME;
+          header->error_index = 0;
         }
       } else {
-        if(*varbinds_length < SNMP_MAX_NR_VALUES) {
-          resource->handler(&varbinds[*varbinds_length], resource->oid);
-          (*varbinds_length)++;
-          snmp_oid_copy(oid[j], resource->oid);
+        if(varbinds_length < SNMP_MAX_NR_VALUES) {
+          resource->handler(&varbinds[varbinds_length], &resource->oid);
+          (varbinds_length)++;
+          memcpy(&oids[j], &resource->oid, sizeof(snmp_oid_t));
           repeater++;
+        } else {
+          return -1;
         }
       }
     }
@@ -201,54 +215,54 @@ snmp_engine_get_bulk(snmp_header_t *header, snmp_varbind_t *varbinds, uint32_t *
   return 0;
 }
 /*---------------------------------------------------------------------------*/
-unsigned char *
-snmp_engine(unsigned char *buff, uint32_t buff_len, unsigned char *out, uint32_t *out_len)
+int
+snmp_engine(snmp_packet_t *snmp_packet)
 {
-  static snmp_header_t header;
-  static snmp_varbind_t varbinds[SNMP_MAX_NR_VALUES];
-  static uint32_t varbind_length = SNMP_MAX_NR_VALUES;
+  snmp_header_t header;
+  snmp_varbind_t varbinds[SNMP_MAX_NR_VALUES];
+
+  memset(&header, 0, sizeof(header));
+  memset(varbinds, 0, sizeof(varbinds));

-  buff = snmp_message_decode(buff, buff_len, &header, varbinds, &varbind_length);
-  if(buff == NULL) {
-    return NULL;
+  if(!snmp_message_decode(snmp_packet, &header, varbinds)) {
+    return 0;
   }

   if(header.version != SNMP_VERSION_1) {
     if(strncmp(header.community.community, SNMP_COMMUNITY, header.community.length)) {
       LOG_ERR("Request with invalid community\n");
-      return NULL;
+      return 0;
     }
   }

   /*
    * Now handle the SNMP requests depending on their type
    */
   switch(header.pdu_type) {
-  case SNMP_DATA_TYPE_PDU_GET_REQUEST:
-    if(snmp_engine_get(&header, varbinds, varbind_length) == -1) {
-      return NULL;
+  case BER_DATA_TYPE_PDU_GET_REQUEST:
+    if(snmp_engine_get(&header, varbinds) == -1) {
+      return 0;
     }
     break;

-  case SNMP_DATA_TYPE_PDU_GET_NEXT_REQUEST:
-    if(snmp_engine_get_next(&header, varbinds, varbind_length) == -1) {
-      return NULL;
+  case BER_DATA_TYPE_PDU_GET_NEXT_REQUEST:
+    if(snmp_engine_get_next(&header, varbinds) == -1) {
+      return 0;
     }
     break;

-  case SNMP_DATA_TYPE_PDU_GET_BULK:
-    if(snmp_engine_get_bulk(&header, varbinds, &varbind_length) == -1) {
-      return NULL;
+  case BER_DATA_TYPE_PDU_GET_BULK:
+    if(snmp_engine_get_bulk(&header, varbinds) == -1) {
+      return 0;
     }
     break;

   default:
     LOG_ERR("Invalid request type");
-    return NULL;
+    return 0;
   }

-  header.pdu_type = SNMP_DATA_TYPE_PDU_GET_RESPONSE;
-  out = snmp_message_encode(out, out_len, &header, varbinds, varbind_length);
+  header.pdu_type = BER_DATA_TYPE_PDU_GET_RESPONSE;

-  return ++out;
+  return snmp_message_encode(snmp_packet, &header, varbinds);
 }


patch 8.2.3487: illegal memory access if buffer name is very long

Problem:    Illegal memory access if buffer name is very long.
Solution:   Make sure not to go over the end of the buffer.

@@ -464,13 +464,13 @@ win_redr_status(win_T *wp, int ignore_pum UNUSED)
 	    *(p + len++) = ' ';
 	if (bt_help(wp->w_buffer))
 	{
-	    STRCPY(p + len, _("[Help]"));
+	    vim_snprintf((char *)p + len, MAXPATHL - len, "%s", _("[Help]"));
 	    len += (int)STRLEN(p + len);
 	}
 #ifdef FEAT_QUICKFIX
 	if (wp->w_p_pvw)
 	{
-	    STRCPY(p + len, _("[Preview]"));
+	    vim_snprintf((char *)p + len, MAXPATHL - len, "%s", _("[Preview]"));
 	    len += (int)STRLEN(p + len);
 	}
 #endif
@@ -480,12 +480,12 @@ win_redr_status(win_T *wp, int ignore_pum UNUSED)
 #endif
 		)
 	{
-	    STRCPY(p + len, "[+]");
-	    len += 3;
+	    vim_snprintf((char *)p + len, MAXPATHL - len, "%s", "[+]");
+	    len += (int)STRLEN(p + len);
 	}
 	if (wp->w_buffer->b_p_ro)
 	{
-	    STRCPY(p + len, _("[RO]"));
+	    vim_snprintf((char *)p + len, MAXPATHL - len, "%s", _("[RO]"));
 	    len += (int)STRLEN(p + len);
 	}


kdc: validate sname in TGS-REQ

In tgs_build_reply(), validate the server name in the TGS-REQ is present before
dereferencing.

@@ -1699,6 +1699,10 @@ tgs_build_reply(astgs_request_t priv,

 	s = &adtkt.cname;
 	r = adtkt.crealm;
+    } else if (s == NULL) {
+	ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+	_kdc_set_e_text(r, "No server in request");
+	goto out;
     }

     _krb5_principalname2krb5_principal(context, &sp, *s, r);


run: Don't allow unmounting filesystems

If we don't allow mounting filesystems, we shouldn't allow unmounting
either.

Partially fixes GHSA-67h7-w3jq-vh4q.

Signed-off-by: Simon McVittie <smcv@collabora.com>

@@ -2934,6 +2934,8 @@ setup_seccomp (FlatpakBwrap   *bwrap,
     {SCMP_SYS (unshare), EPERM},
     {SCMP_SYS (setns), EPERM},
     {SCMP_SYS (mount), EPERM},
+    {SCMP_SYS (umount), EPERM},
+    {SCMP_SYS (umount2), EPERM},
     {SCMP_SYS (pivot_root), EPERM},
 #if defined(__s390__) || defined(__s390x__) || defined(__CRIS__)
     /* Architectures with CONFIG_CLONE_BACKWARDS2: the child stack


Fix integer overflow in _sdsMakeRoomFor (CVE-2021-41099)

@@ -205,7 +205,7 @@ void sdsclear(sds s) {
 sds sdsMakeRoomFor(sds s, size_t addlen) {
     void *sh, *newsh;
     size_t avail = sdsavail(s);
-    size_t len, newlen;
+    size_t len, newlen, reqlen;
     char type, oldtype = s[-1] & SDS_TYPE_MASK;
     int hdrlen;

@@ -214,7 +214,7 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {

     len = sdslen(s);
     sh = (char*)s-sdsHdrSize(oldtype);
-    newlen = (len+addlen);
+    reqlen = newlen = (len+addlen);
     assert(newlen > len);   /* Catch size_t overflow */
     if (newlen < SDS_MAX_PREALLOC)
         newlen *= 2;
@@ -229,7 +229,7 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
     if (type == SDS_TYPE_5) type = SDS_TYPE_8;

     hdrlen = sdsHdrSize(type);
-    assert(hdrlen + newlen + 1 > len);  /* Catch size_t overflow */
+    assert(hdrlen + newlen + 1 > reqlen);  /* Catch size_t overflow */
     if (oldtype==type) {
         newsh = s_realloc(sh, hdrlen+newlen+1);
         if (newsh == NULL) return NULL;


Fix ziplist and listpack overflows and truncations (CVE-2021-32627, CVE-2021-32628)

- fix possible heap corruption in ziplist and listpack resulting by trying to
  allocate more than the maximum size of 4GB.
- prevent ziplist (hash and zset) from reaching size of above 1GB, will be
  converted to HT encoding, that's not a useful size.
- prevent listpack (stream) from reaching size of above 1GB.
- XADD will start a new listpack if the new record may cause the previous
  listpack to grow over 1GB.
- XADD will respond with an error if a single stream record is over 1GB
- List type (ziplist in quicklist) was truncating strings that were over 4GB,
  now it'll respond with an error.

@@ -635,7 +635,7 @@ void georadiusGeneric(client *c, int flags) {
         robj *zobj;
         zset *zs;
         int i;
-        size_t maxelelen = 0;
+        size_t maxelelen = 0, totelelen = 0;

         if (returned_items) {
             zobj = createZsetObject();
@@ -650,13 +650,14 @@ void georadiusGeneric(client *c, int flags) {
             size_t elelen = sdslen(gp->member);

             if (maxelelen < elelen) maxelelen = elelen;
+            totelelen += elelen;
             znode = zslInsert(zs->zsl,score,gp->member);
             serverAssert(dictAdd(zs->dict,gp->member,&znode->score) == DICT_OK);
             gp->member = NULL;
         }

         if (returned_items) {
-            zsetConvertToZiplistIfNeeded(zobj,maxelelen);
+            zsetConvertToZiplistIfNeeded(zobj,maxelelen,totelelen);
             setKey(c,c->db,storekey,zobj);
             decrRefCount(zobj);
             notifyKeyspaceEvent(NOTIFY_ZSET,"georadiusstore",storekey,


@@ -49,6 +49,7 @@ unsigned char *ziplistFind(unsigned char *p, unsigned char *vstr, unsigned int v
 unsigned int ziplistLen(unsigned char *zl);
 size_t ziplistBlobLen(unsigned char *zl);
 void ziplistRepr(unsigned char *zl);
+int ziplistSafeToAdd(unsigned char* zl, size_t add);

 #ifdef REDIS_TEST
 int ziplistTest(int argc, char *argv[]);


@@ -265,6 +265,17 @@
         ZIPLIST_LENGTH(zl) = intrev16ifbe(intrev16ifbe(ZIPLIST_LENGTH(zl))+incr); \
 }

+/* Don't let ziplists grow over 1GB in any case, don't wanna risk overflow in
+ * zlbytes*/
+#define ZIPLIST_MAX_SAFETY_SIZE (1<<30)
+int ziplistSafeToAdd(unsigned char* zl, size_t add) {
+    size_t len = zl? ziplistBlobLen(zl): 0;
+    if (len + add > ZIPLIST_MAX_SAFETY_SIZE)
+        return 0;
+    return 1;
+}
+
+
 /* We use this function to receive information about a ziplist entry.
  * Note that this is not how the data is actually encoded, is just what we
  * get filled by a function in order to operate more easily. */
@@ -586,7 +597,8 @@ unsigned char *ziplistNew(void) {
 }

 /* Resize the ziplist. */
-unsigned char *ziplistResize(unsigned char *zl, unsigned int len) {
+unsigned char *ziplistResize(unsigned char *zl, size_t len) {
+    assert(len < UINT32_MAX);
     zl = zrealloc(zl,len);
     ZIPLIST_BYTES(zl) = intrev32ifbe(len);
     zl[len-1] = ZIP_END;
@@ -898,6 +910,9 @@ unsigned char *ziplistMerge(unsigned char **first, unsigned char **second) {
     /* Combined zl length should be limited within UINT16_MAX */
     zllength = zllength < UINT16_MAX ? zllength : UINT16_MAX;

+    /* larger values can't be stored into ZIPLIST_BYTES */
+    assert(zlbytes < UINT32_MAX);
+
     /* Save offset positions before we start ripping memory apart. */
     size_t first_offset = intrev32ifbe(ZIPLIST_TAIL_OFFSET(*first));
     size_t second_offset = intrev32ifbe(ZIPLIST_TAIL_OFFSET(*second));


patch 8.2.3611: crash when using CTRL-W f without finding a file name

Problem:    Crash when using CTRL-W f without finding a file name.
Solution:   Bail out when the file name length is zero.

@@ -3881,8 +3881,10 @@ get_visual_text(
 	    *pp = ml_get_pos(&VIsual);
 	    *lenp = curwin->w_cursor.col - VIsual.col + 1;
 	}
-	if (has_mbyte)
-	    // Correct the length to include the whole last character.
+	if (**pp == NUL)
+	    *lenp = 0;
+	if (has_mbyte && *lenp > 0)
+	    // Correct the length to include all bytes of the last character.
 	    *lenp += (*mb_ptr2len)(*pp + (*lenp - 1)) - 1;
     }
     reset_VIsual_and_resel();


-fix via header of CANCEL request
-fix crash in case of malformed paramless request uri in From header
-fix crash in case of From header display name with last value set to « \ »

@@ -2,7 +2,7 @@
  *  This C source file was generated by $ANTLR version 3.4
  *
  *     -  From the grammar source file : ../grammars/belle_sip_message.g
- *     -                            On : 2021-05-13 15:53:11
+ *     -                            On : 2021-09-07 16:55:34
  *     -                 for the lexer : belle_sip_messageLexerLexer
  *
  * Editing it, at least manually, is not wise.


@@ -2,7 +2,7 @@
  *  This C header file was generated by $ANTLR version 3.4
  *
  *     -  From the grammar source file : ../grammars/belle_sip_message.g
- *     -                            On : 2021-05-13 15:53:10
+ *     -                            On : 2021-09-07 16:55:33
  *     -                for the parser : belle_sip_messageParserParser
  *
  * Editing it, at least manually, is not wise.


Implement client identity verification

This commit fixes two security vulnerabilities: CVE-2021-42072 and
CVE-2021-42073.

The issues have been reported by Matthias Gerstner <mgerstner@suse.de>.

@@ -21,6 +21,7 @@
 enum class ConnectionSecurityLevel {
     PLAINTEXT,
     ENCRYPTED,
+    ENCRYPTED_AUTHENTICATED
 };

 #endif // BARRIER_LIB_NET_CONNECTION_SECURITY_LEVEL_H


Merge pull request #1346 from p12tic/client-identity-verification

Implement client identity verification [SECURITY VULNERABILITIES CVE-2021-42072, CVE-2021-42073]

@@ -66,7 +66,7 @@ ZeroconfService::ZeroconfService(MainWindow* mainWindow) :
     m_ServiceRegistered(false)
 {
     silence_avahi_warning();
-    if (m_pMainWindow->barrierType() == MainWindow::barrierServer) {
+    if (m_pMainWindow->barrier_type() == BarrierType::Server) {
         if (registerService(true)) {
             m_pZeroconfBrowser = new ZeroconfBrowser(this);
             connect(m_pZeroconfBrowser, SIGNAL(


@@ -54,25 +54,24 @@ struct Ssl {
     SSL*        m_ssl;
 };

-SecureSocket::SecureSocket(
-        IEventQueue* events,
-        SocketMultiplexer* socketMultiplexer,
-        IArchNetwork::EAddressFamily family) :
+SecureSocket::SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+                           IArchNetwork::EAddressFamily family,
+                           ConnectionSecurityLevel security_level) :
     TCPSocket(events, socketMultiplexer, family),
     m_ssl(nullptr),
     m_secureReady(false),
-    m_fatal(false)
+    m_fatal(false),
+    security_level_{security_level}
 {
 }

-SecureSocket::SecureSocket(
-        IEventQueue* events,
-        SocketMultiplexer* socketMultiplexer,
-        ArchSocket socket) :
+SecureSocket::SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
+                           ArchSocket socket, ConnectionSecurityLevel security_level) :
     TCPSocket(events, socketMultiplexer, socket),
     m_ssl(nullptr),
     m_secureReady(false),
-    m_fatal(false)
+    m_fatal(false),
+    security_level_{security_level}
 {
 }

@@ -362,6 +361,11 @@ bool SecureSocket::load_certificates(const barrier::fs::path& path)
     return true;
 }

+static int cert_verify_ignore_callback(X509_STORE_CTX*, void*)
+{
+    return 1;
+}
+
 void
 SecureSocket::initContext(bool server)
 {
@@ -397,6 +401,14 @@ SecureSocket::initContext(bool server)
     if (m_ssl->m_context == NULL) {
         showError("");
     }
+
+    if (security_level_ == ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED) {
+        // We want to ask for peer certificate, but not verify it. If we don't ask for peer
+        // certificate, e.g. client won't send it.
+        SSL_CTX_set_verify(m_ssl->m_context, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+                           nullptr);
+        SSL_CTX_set_cert_verify_callback(m_ssl->m_context, cert_verify_ignore_callback, nullptr);
+    }
 }

 void
@@ -437,6 +449,24 @@ SecureSocket::secureAccept(int socket)

     // If not fatal and no retry, state is good
     if (retry == 0) {
+        if (security_level_ == ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED) {
+            if (verify_cert_fingerprint(
+                        barrier::DataDirectories::trusted_clients_ssl_fingerprints_path())) {
+                LOG((CLOG_INFO "accepted secure socket"));
+                if (!ensure_peer_certificate()) {
+                    retry = 0;
+                    disconnect();
+                    return -1;// Cert fail, error
+                }
+            }
+            else {
+                LOG((CLOG_ERR "failed to verify server certificate fingerprint"));
+                retry = 0;
+                disconnect();
+                return -1; // Fingerprint failed, error
+            }
+        }
+
         m_secureReady = true;
         LOG((CLOG_INFO "accepted secure socket"));
         if (CLOG->getFilter() >= kDEBUG1) {
@@ -462,6 +492,12 @@ SecureSocket::secureAccept(int socket)
 int
 SecureSocket::secureConnect(int socket)
 {
+    if (!load_certificates(barrier::DataDirectories::ssl_certificate_path())) {
+        LOG((CLOG_ERR "could not load client certificates"));
+        // FIXME: this is fatal error, but we current don't disconnect because whole logic in this
+        // function needs to be cleaned up
+    }
+
     createSSL();

     // attach the socket descriptor
@@ -491,9 +527,9 @@ SecureSocket::secureConnect(int socket)
     retry = 0;
     // No error, set ready, process and return ok
     m_secureReady = true;
-    if (verifyCertFingerprint()) {
+    if (verify_cert_fingerprint(barrier::DataDirectories::trusted_servers_ssl_fingerprints_path())) {
         LOG((CLOG_INFO "connected to secure socket"));
-        if (!showCertificate()) {
+        if (!ensure_peer_certificate()) {
             disconnect();
             return -1;// Cert fail, error
         }
@@ -512,7 +548,7 @@ SecureSocket::secureConnect(int socket)
 }

 bool
-SecureSocket::showCertificate()
+SecureSocket::ensure_peer_certificate()
 {
     X509* cert;
     char* line;
@@ -521,12 +557,12 @@ SecureSocket::showCertificate()
     cert = SSL_get_peer_certificate(m_ssl->m_ssl);
     if (cert != NULL) {
         line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
-        LOG((CLOG_INFO "server ssl certificate info: %s", line));
+        LOG((CLOG_INFO "peer ssl certificate info: %s", line));
         OPENSSL_free(line);
         X509_free(cert);
     }
     else {
-        showError("server has no ssl certificate");
+        showError("peer has no ssl certificate");
         return false;
     }

@@ -649,8 +685,7 @@ SecureSocket::disconnect()
     sendEvent(getEvents()->forIStream().inputShutdown());
 }

-bool
-SecureSocket::verifyCertFingerprint()
+bool SecureSocket::verify_cert_fingerprint(const barrier::fs::path& fingerprint_db_path)
 {
     // calculate received certificate fingerprint
     barrier::FingerprintData fingerprint_sha1, fingerprint_sha256;
@@ -666,12 +701,10 @@ SecureSocket::verifyCertFingerprint()
     }

     // note: the GUI parses the following two lines of logs, don't change unnecessarily
-    LOG((CLOG_NOTE "server fingerprint (SHA1): %s (SHA256): %s",
+    LOG((CLOG_NOTE "peer fingerprint (SHA1): %s (SHA256): %s",
          barrier::format_ssl_fingerprint(fingerprint_sha1.data).c_str(),
          barrier::format_ssl_fingerprint(fingerprint_sha256.data).c_str()));

-    auto fingerprint_db_path = barrier::DataDirectories::trusted_servers_ssl_fingerprints_path();
-
     // Provide debug hint as to what file is being used to verify fingerprint trust
     LOG((CLOG_NOTE "fingerprint_db_path: %s", fingerprint_db_path.u8string().c_str()));


Add shape checks to GPU TridiagonalMatMul.

When given invalid shapes, the GPU TridiagonalMatMul op could read invalid or uninitialized GPU memory.

PiperOrigin-RevId: 401775483
Change-Id: Ib5500aeb8225e50d4ce790b06d2c34751f544ad8

@@ -19,12 +19,15 @@
 import numpy as np

 from tensorflow.python.client import session
+from tensorflow.python.eager import context
 from tensorflow.python.framework import constant_op
 from tensorflow.python.framework import dtypes
+from tensorflow.python.framework import errors_impl
 from tensorflow.python.framework import ops
 from tensorflow.python.ops import array_ops
 from tensorflow.python.ops import control_flow_ops
 from tensorflow.python.ops import gradient_checker_v2
+from tensorflow.python.ops import linalg_ops
 from tensorflow.python.ops import math_ops
 from tensorflow.python.ops import variables
 from tensorflow.python.ops.linalg import linalg_impl
@@ -175,6 +178,37 @@ def testGradientComplexWithBatches(self):
     rhs = self._randomComplexArray((b, m, n))
     self._gradientTest(diags, rhs, dtype=dtypes.complex128)

+  def _testErrorWithShapesEager(self, exception_regex, superdiag_shape,
+                                maindiag_shape, subdiag_shape, rhs_shape):
+    with context.eager_mode():
+      superdiag = array_ops.ones(superdiag_shape)
+      maindiag = array_ops.ones(maindiag_shape)
+      subdiag = array_ops.ones(subdiag_shape)
+      rhs = array_ops.ones(rhs_shape)
+      with self.assertRaisesRegex(errors_impl.InvalidArgumentError,
+                                  exception_regex):
+        linalg_ops.tridiagonal_mat_mul(superdiag, maindiag, subdiag, rhs)
+
+  def testInvalidShapesEagerGpu(self):
+    if not test.is_gpu_available():
+      self.skipTest('Test requires GPU')
+    self._testErrorWithShapesEager('Input must have rank >= 2, but got ',
+                                   [2], [2], [2], [2])
+    self._testErrorWithShapesEager(
+        'superdiag must have same rank as rhs, but got 3 and 2',
+        [2, 1, 2], [2, 1], [2, 1], [2, 2])
+    self._testErrorWithShapesEager(
+        'maindiag must have same outer dimensions as rhs, but for index 0, got '
+        '3 and 2',
+        [2, 1, 2], [3, 1, 2], [2, 1, 2], [2, 2, 2])
+    self._testErrorWithShapesEager(
+        "subdiag's second-to-last dimension must be 1, but got 3",
+        [2, 1, 2], [2, 1, 2], [2, 3, 2], [2, 2, 2])
+    self._testErrorWithShapesEager(
+        "subdiag's last dimension size must be rhs's second-to-last dimension "
+        "size, but got 3 and 2",
+        [2, 1, 2], [2, 1, 2], [2, 1, 3], [2, 2, 2])
+
   # Benchmark
   class TridiagonalMatMulBenchmark(test.Benchmark):
     sizes = [(100000, 1, 1), (1000000, 1, 1), (10000000, 1, 1), (100000, 10, 1),


Fix segfault in pools on empty shapes when certain dimension were very large.

Pooling ops multiply certain components of the input shape, e.g. by multiplying input.shape[1] * input.shape[2] * input.shape[3]. This multiplication could overflow an int64 value if shape[0] was 0 but shape[1], shape[2], and shape[3] were very large, e.g. by passing an input with shape (0, 2**25, 2**25, 2**25).

PiperOrigin-RevId: 404644978
Change-Id: Ic79f89c970357ca2962b1f231449066db9403146

@@ -189,6 +189,9 @@ class MaxPoolingOp : public OpKernel {
   void SpatialMaxPool(OpKernelContext* context, Tensor* output,
                       const Tensor& tensor_in, const PoolParameters& params,
                       const Padding& padding) {
+    if (output->NumElements() == 0) {
+      return;
+    }
     // On GPU, use Eigen's Spatial Max Pooling.  On CPU, use an
     // EigenMatrix version that is currently faster than Eigen's
     // Spatial MaxPooling implementation.
@@ -443,6 +446,9 @@ class MaxPoolingV2Op : public OpKernel {
   void SpatialMaxPool(OpKernelContext* context, Tensor* output,
                       const Tensor& tensor_in, const PoolParameters& params,
                       const Padding& padding) {
+    if (output->NumElements() == 0) {
+      return;
+    }
     // On GPU, use Eigen's Spatial Max Pooling.  On CPU, use an
     // EigenMatrix version that is currently faster than Eigen's
     // Spatial MaxPooling implementation.
@@ -561,6 +567,9 @@ template <typename Device, typename T>
 void SpatialAvgPool(OpKernelContext* context, Tensor* output,
                     const Tensor& input, const PoolParameters& params,
                     const Padding& padding) {
+  if (output->NumElements() == 0) {
+    return;
+  }
   typedef Eigen::Map<const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>
       ConstEigenMatrixMap;
   typedef Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>


Prevent crashes when loading tensor slices with unsupported types.

Also fix the `Tensor(const TensorShape&)` constructor swapping the LOG(FATAL)
messages for the unset and unsupported types.

PiperOrigin-RevId: 392695027
Change-Id: I4beda7db950db951d273e3259a7c8534ece49354

@@ -13,15 +13,19 @@ See the License for the specific language governing permissions and
 limitations under the License.
 ==============================================================================*/

-#include <utility>
-
 #include "tensorflow/core/util/tensor_slice_reader.h"

+#include <utility>
+#include <vector>
+
 #include "tensorflow/core/framework/types.h"
 #include "tensorflow/core/framework/versions.pb.h"
 #include "tensorflow/core/lib/core/status_test_util.h"
 #include "tensorflow/core/lib/core/stringpiece.h"
+#include "tensorflow/core/lib/io/iterator.h"
 #include "tensorflow/core/lib/io/path.h"
+#include "tensorflow/core/lib/io/table.h"
+#include "tensorflow/core/lib/io/table_builder.h"
 #include "tensorflow/core/lib/strings/str_util.h"
 #include "tensorflow/core/lib/strings/strcat.h"
 #include "tensorflow/core/platform/env.h"
@@ -30,6 +34,7 @@ limitations under the License.
 #include "tensorflow/core/platform/test.h"
 #include "tensorflow/core/platform/types.h"
 #include "tensorflow/core/public/version.h"
+#include "tensorflow/core/util/saved_tensor_slice.pb.h"
 #include "tensorflow/core/util/saved_tensor_slice_util.h"
 #include "tensorflow/core/util/tensor_slice_reader_cache.h"
 #include "tensorflow/core/util/tensor_slice_writer.h"
@@ -309,6 +314,102 @@ TEST_SIMPLE_INT(int16, int32)
 TEST_SIMPLE_INT(int8, int32)
 TEST_SIMPLE_INT(uint8, int32)

+// Modifies the SavedTensorSlices messages in a checkpoint to allow creating
+// malformed or unsupported checkpoints.
+void MutateSavedTensorSlices(
+    const std::string& fname,
+    const std::function<std::string(SavedTensorSlices)>& mutator) {
+  table::Options options;
+  options.compression = table::kNoCompression;
+
+  // Read all entres from the table.
+  std::vector<std::pair<std::string, std::string>> entries;
+  {
+    std::unique_ptr<RandomAccessFile> file;
+    TF_CHECK_OK(Env::Default()->NewRandomAccessFile(fname, &file));
+    uint64 file_size;
+    TF_CHECK_OK(Env::Default()->GetFileSize(fname, &file_size));
+    table::Table* t;
+    TF_CHECK_OK(table::Table::Open(options, file.get(), file_size, &t));
+    std::unique_ptr<table::Table> table(t);
+    std::unique_ptr<table::Iterator> it(table->NewIterator());
+    for (it->Seek(""); it->Valid(); it->Next()) {
+      entries.emplace_back(it->key(), it->value());
+    }
+    TF_CHECK_OK(it->status());
+  }
+
+  // Rewrite the table, mutating each value.
+  {
+    std::unique_ptr<WritableFile> file;
+    TF_CHECK_OK(Env::Default()->NewWritableFile(fname, &file));
+    table::TableBuilder builder(options, file.get());
+    for (const auto& entry : entries) {
+      SavedTensorSlices sts;
+      CHECK(sts.ParseFromString(entry.second));
+      builder.Add(entry.first, mutator(std::move(sts)));
+    }
+    TF_CHECK_OK(builder.Finish());
+    TF_CHECK_OK(file->Close());
+  }
+}
+
+TEST(TensorSliceReaderTest, MissingTensorType) {
+  const string fname = io::JoinPath(testing::TmpDir(), "invalid_checkpoint");
+  TensorSliceWriter writer(fname, CreateTableTensorSliceBuilder);
+  const int32 data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+  TensorShape shape({4, 5});
+  TensorSlice slice = TensorSlice::ParseOrDie("0,2:-");
+  TF_CHECK_OK(writer.Add("test", shape, slice, data));
+  TF_CHECK_OK(writer.Finish());
+
+  MutateSavedTensorSlices(fname, [](SavedTensorSlices sts) {
+    if (sts.has_meta()) {
+      for (auto& tensor : *sts.mutable_meta()->mutable_tensor()) {
+        tensor.clear_type();
+      }
+    }
+    return sts.SerializeAsString();
+  });
+
+  TensorSliceReader reader(fname, OpenTableTensorSliceReader);
+  TF_CHECK_OK(reader.status());
+
+  // The tensor should be present, but loading it should fail due to the
+  // unset (invalid) type.
+  EXPECT_TRUE(reader.HasTensor("test", nullptr, nullptr));
+  std::unique_ptr<Tensor> tensor;
+  EXPECT_FALSE(reader.GetTensor("test", &tensor).ok());
+}
+
+TEST(TensorSliceReaderTest, UnsupportedTensorType) {
+  const string fname = io::JoinPath(testing::TmpDir(), "int32_ref_checkpoint");
+  TensorSliceWriter writer(fname, CreateTableTensorSliceBuilder);
+  const int32 data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+  TensorShape shape({4, 5});
+  TensorSlice slice = TensorSlice::ParseOrDie("0,2:-");
+  TF_CHECK_OK(writer.Add("test", shape, slice, data));
+  TF_CHECK_OK(writer.Finish());
+
+  MutateSavedTensorSlices(fname, [](SavedTensorSlices sts) {
+    if (sts.has_meta()) {
+      for (auto& tensor : *sts.mutable_meta()->mutable_tensor()) {
+        tensor.set_type(DT_INT32_REF);
+      }
+    }
+    return sts.SerializeAsString();
+  });
+
+  TensorSliceReader reader(fname, OpenTableTensorSliceReader);
+  TF_CHECK_OK(reader.status());
+
+  // The tensor should be present, but loading it should fail due to the
+  // unsupported type.
+  EXPECT_TRUE(reader.HasTensor("test", nullptr, nullptr));
+  std::unique_ptr<Tensor> tensor;
+  EXPECT_FALSE(reader.GetTensor("test", &tensor).ok());
+}
+
 void CachedTensorSliceReaderTesterHelper(
     const TensorSliceWriter::CreateBuilderFunction& create_function,
     const TensorSliceReader::OpenTableFunction& open_function) {


@@ -171,7 +171,7 @@ static int src_parser_trans_stage_1_2_3(const int tmp_fd, const char *src, const
                             (PBUF_TMP_PREV_CHAR(pbuf) == ' ' || PBUF_TMP_PREV_CHAR(pbuf) == '\t' ||
                              PBUF_TMP_PREV_CHAR(pbuf) == '\n')) {
                         pbuf.f_indx++;
-                    } else if (pbuf.tmp_indx &&
+                    } else if (pbuf.tmp_indx &&
                             (PBUF_TMP_PREV_CHAR(pbuf) == '\\')) {
                         pbuf.tmp_indx--;
                         pbuf.f_indx++;
@@ -182,10 +182,12 @@ static int src_parser_trans_stage_1_2_3(const int tmp_fd, const char *src, const
                     continue;

                 case '\\':
+                    p_buf_write_tmp(&pbuf, tmp_fd);
                     p_buf_push_tmp_char(&pbuf, '\\');
                     continue;

                 case '/':
+                    p_buf_write_tmp(&pbuf, tmp_fd);
                     p_buf_push_tmp_char(&pbuf, '/');
                     continue;


patch 8.2.3950: going beyond the end of the line with /\%V

Problem:    Going beyond the end of the line with /\%V.
Solution:   Check for valid column in getvcol().

@@ -1240,10 +1240,15 @@ getvcol(
 	posptr = NULL;  // continue until the NUL
     else
     {
-	// Special check for an empty line, which can happen on exit, when
-	// ml_get_buf() always returns an empty string.
-	if (*ptr == NUL)
-	    pos->col = 0;
+	colnr_T i;
+
+	// In a few cases the position can be beyond the end of the line.
+	for (i = 0; i < pos->col; ++i)
+	    if (ptr[i] == NUL)
+	    {
+		pos->col = i;
+		break;
+	    }
 	posptr = ptr + pos->col;
 	if (has_mbyte)
 	    // always start on the first byte


@@ -985,7 +985,9 @@ static void uc_invalidate_tb(struct uc_struct *uc, uint64_t start_addr, size_t l
 {
     tb_page_addr_t start, end;

-    // GVA to GPA (GPA -> HVA via page_find, HVA->HPA via host mmu)
+    // GVA to GPA
+    // (GPA -> HVA via memory_region_get_ram_addr(mr) + GPA + block->host,
+    // HVA->HPA via host mmu)
     start = get_page_addr_code(uc->cpu->env_ptr, start_addr) & (target_ulong)(-1);

     // For 32bit target.


stream/tcp: handle RST with MD5 or AO header

Special handling for RST packets if they have an TCP MD5 or AO header option.
The options hash can't be validated. The end host might be able to validate
it, as it can have a key/password that was communicated out of band.

The sender could use this to move the TCP state to 'CLOSED', leading to
a desync of the TCP session.

This patch builds on top of
843d0b7a10bb ("stream: support RST getting lost/ignored")

It flags the receiver as having received an RST and moves the TCP state
into the CLOSED state. It then reverts this if the sender continues to
send traffic. In this case it sets the following event:

    stream-event:suspected_rst_inject;

Bug: #4710.

@@ -4433,6 +4433,9 @@ static int StreamTcpPacketStateClosed(ThreadVars *tv, Packet *p,
         if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
             if (StreamTcpStateDispatch(tv, p, stt, ssn, &stt->pseudo_queue, ssn->pstate) < 0)
                 return -1;
+            /* if state is still "closed", it wasn't updated by our dispatch. */
+            if (ssn->state == TCP_CLOSED)
+                ssn->state = ssn->pstate;
         }
     }
     return 0;
@@ -5410,7 +5413,6 @@ TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data)

 static int StreamTcpValidateRst(TcpSession *ssn, Packet *p)
 {
-
     uint8_t os_policy;

     if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
@@ -5448,6 +5450,21 @@ static int StreamTcpValidateRst(TcpSession *ssn, Packet *p)
         }
     }

+    /* RFC 2385 md5 signature header or RFC 5925 TCP AO headerpresent. Since we can't
+     * validate these (requires key that is set/transfered out of band), we can't know
+     * if the RST will be accepted or rejected by the end host. We accept it, but keep
+     * tracking if the sender of it ignores it, which would be a sign of injection. */
+    if (p->tcpvars.md5_option_present || p->tcpvars.ao_option_present) {
+        TcpStream *receiver_stream;
+        if (PKT_IS_TOSERVER(p)) {
+            receiver_stream = &ssn->server;
+        } else {
+            receiver_stream = &ssn->client;
+        }
+        SCLogDebug("ssn %p: setting STREAMTCP_STREAM_FLAG_RST_RECV on receiver stream", ssn);
+        receiver_stream->flags |= STREAMTCP_STREAM_FLAG_RST_RECV;
+    }
+
     if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
         if (PKT_IS_TOSERVER(p)) {
             if (SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.next_seq)) {


Harden /tmp/tmate directory

Suggested by Matthias Gerstner

@@ -98,6 +98,24 @@ static void setup_locale(void)
 	tzset();
 }

+static int check_owned_directory_mode(const char *path, mode_t expected_mode)
+{
+	struct stat stat;
+	if (lstat(path, &stat))
+		return -1;
+
+	if (!S_ISDIR(stat.st_mode))
+		return -1;
+
+	if (stat.st_uid != getuid())
+		return -1;
+
+	if ((stat.st_mode & 07777) != expected_mode)
+		return -1;
+
+	return 0;
+}
+
 int main(int argc, char **argv, char **envp)
 {
 	int opt;
@@ -151,17 +169,22 @@ int main(int argc, char **argv, char **envp)
 	tmate_catch_sigsegv();
 	tmate_init_rand();

-	if ((mkdir(TMATE_WORKDIR, 0701)             < 0 && errno != EEXIST) ||
-	    (mkdir(TMATE_WORKDIR "/sessions", 0703) < 0 && errno != EEXIST) ||
+	if ((mkdir(TMATE_WORKDIR, 0700)             < 0 && errno != EEXIST) ||
+	    (mkdir(TMATE_WORKDIR "/sessions", 0700) < 0 && errno != EEXIST) ||
 	    (mkdir(TMATE_WORKDIR "/jail", 0700)     < 0 && errno != EEXIST))
 		tmate_fatal("Cannot prepare session in " TMATE_WORKDIR);

-	/* The websocket server needs to access the /session dir to rename sockets */
-	if ((chmod(TMATE_WORKDIR, 0701)             < 0) ||
-	    (chmod(TMATE_WORKDIR "/sessions", 0703) < 0) ||
+	if ((chmod(TMATE_WORKDIR, 0700)             < 0) ||
+	    (chmod(TMATE_WORKDIR "/sessions", 0700) < 0) ||
 	    (chmod(TMATE_WORKDIR "/jail", 0700)     < 0))
 		tmate_fatal("Cannot prepare session in " TMATE_WORKDIR);

+	if (check_owned_directory_mode(TMATE_WORKDIR, 0700) ||
+	    check_owned_directory_mode(TMATE_WORKDIR "/sessions", 0700) ||
+	    check_owned_directory_mode(TMATE_WORKDIR "/jail", 0700))
+		tmate_fatal(TMATE_WORKDIR " and subdirectories has incorrect ownership/mode. "
+			    "Try deleting " TMATE_WORKDIR " and try again");
+
 	tmate_ssh_server_main(tmate_session,
 			      tmate_settings->keys_dir, tmate_settings->bind_addr, tmate_settings->ssh_port);
 	return 0;


ZipFile:  Add path checks to uncompressEntry()

@@ -105,7 +105,7 @@ bool TemporaryFile::deleteTemporaryFile() const
     // Have a few attempts at deleting the file before giving up..
     for (int i = 5; --i >= 0;)
     {
-        if (temporaryFile.deleteFile())
+        if (temporaryFile.isDirectory() ? temporaryFile.deleteRecursively() : temporaryFile.deleteFile())
             return true;

         Thread::sleep (50);


patch 8.2.4247: stack corruption when looking for spell suggestions

Problem:    Stack corruption when looking for spell suggestions.
Solution:   Prevent the depth increased too much.  Add a five second time
            limit to finding suggestions.

@@ -1205,7 +1205,7 @@ suggest_try_change(suginfo_T *su)

 // Check the maximum score, if we go over it we won't try this change.
 #define TRY_DEEPER(su, stack, depth, add) \
-		(stack[depth].ts_score + (add) < su->su_maxscore)
+	   (depth < MAXWLEN && stack[depth].ts_score + (add) < su->su_maxscore)

 /*
  * Try finding suggestions by adding/removing/swapping letters.
@@ -1277,6 +1277,9 @@ suggest_trie_walk(
     char_u	changename[MAXWLEN][80];
 #endif
     int		breakcheckcount = 1000;
+#ifdef FEAT_RELTIME
+    proftime_T	time_limit;
+#endif
     int		compound_ok;

     // Go through the whole case-fold tree, try changes at each node.
@@ -1321,6 +1324,11 @@ suggest_trie_walk(
 	    sp->ts_state = STATE_START;
 	}
     }
+#ifdef FEAT_RELTIME
+    // The loop may take an indefinite amount of time. Break out after five
+    // sectonds. TODO: add an option for the time limit.
+    profile_setlimit(5000, &time_limit);
+#endif

     // Loop to find all suggestions.  At each round we either:
     // - For the current state try one operation, advance "ts_curi",
@@ -1355,7 +1363,8 @@ suggest_trie_walk(

 		// At end of a prefix or at start of prefixtree: check for
 		// following word.
-		if (byts[arridx] == 0 || n == (int)STATE_NOPREFIX)
+		if (depth < MAXWLEN
+			    && (byts[arridx] == 0 || n == (int)STATE_NOPREFIX))
 		{
 		    // Set su->su_badflags to the caps type at this position.
 		    // Use the caps type until here for the prefix itself.
@@ -2649,6 +2658,10 @@ suggest_trie_walk(
 	    {
 		ui_breakcheck();
 		breakcheckcount = 1000;
+#ifdef FEAT_RELTIME
+		if (profile_passed_limit(&time_limit))
+		    got_int = TRUE;
+#endif
 	    }
 	}
     }


patch 8.2.4217: illegal memory access when undo makes Visual area invalid

Problem:    Illegal memory access when undo makes Visual area invalid.
Solution:   Correct the Visual area after undo.

@@ -750,6 +750,8 @@ static char *(features[]) =

 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4217,
 /**/
     4216,
 /**/


patch 8.2.4151: reading beyond the end of a line

Problem:    Reading beyond the end of a line.
Solution:   For block insert only use the offset for correcting the length.

@@ -529,24 +529,9 @@ block_insert(
 	}

 	if (has_mbyte && spaces > 0)
-	{
-	    int off;
+	    // avoid copying part of a multi-byte character
+	    offset -= (*mb_head_off)(oldp, oldp + offset);

-	    // Avoid starting halfway a multi-byte character.
-	    if (b_insert)
-	    {
-		off = (*mb_head_off)(oldp, oldp + offset + spaces);
-		spaces -= off;
-		count -= off;
-	    }
-	    else
-	    {
-		// spaces fill the gap, the character that's at the edge moves
-		// right
-		off = (*mb_head_off)(oldp, oldp + offset);
-		offset -= off;
-	    }
-	}
 	if (spaces < 0)  // can happen when the cursor was moved
 	    spaces = 0;


Make --nofilesystem=host/home remove access to subdirs of those

Previously --nofilesystem=host only removed specifically access to the
`host` permissions, and not necessarily other filesystems (like `home`
or `/some/path`). This isn't very useful to limit access because you
don't know what other filesystems the app may have access too.

We change this to mean that `--nofilesystem=host` removes *all* filesystem
access from the parent layer, and `--nofilesystem=home` removes all
file access to the homedir and paths inside it.

The available layers are, in order:

 * app permissions
 * overrides
 * commandline args

This allows you to start from scratch with the filesystem permissions
in the overrides or the commandline. This is a small change in
behaviour, but not a lot of things use --nofilesystem, and the ones
that do probably expects this behaviour.

@@ -852,6 +852,31 @@ flatpak_context_parse_filesystem (const char             *filesystem_and_mode,
   return FALSE;
 }

+/* Note: This only works with valid keys, i.e. they passed flatpak_context_parse_filesystem */
+static gboolean
+flatpak_filesystem_key_in_home (const char *filesystem)
+{
+  /* "home" is definitely in home */
+  if (strcmp (filesystem, "home") == 0)
+    return TRUE;
+
+  /* All the other special fs:es are non-home.
+   * Note: This considers absolute paths that are in the homedir as non-home.
+   */
+  if (g_strv_contains (flatpak_context_special_filesystems, filesystem) ||
+      g_str_has_prefix (filesystem, "/"))
+    return FALSE;
+
+  /* Files in xdg-run are not in home */
+  if (g_str_has_prefix (filesystem, "xdg-run"))
+    return FALSE;
+
+  /* All remaining keys (~/, xdg-data, etc) are considered in home,
+   * Note: technically $XDG_HOME_DATA could point outside the homedir, but we ignore that.
+   */
+  return TRUE;
+}
+
 static void
 flatpak_context_take_filesystem (FlatpakContext        *context,
                                  char                  *fs,
@@ -866,6 +891,8 @@ flatpak_context_merge (FlatpakContext *context,
 {
   GHashTableIter iter;
   gpointer key, value;
+  gboolean no_home = FALSE;
+  gboolean no_host = FALSE;

   context->shares &= ~other->shares_valid;
   context->shares |= other->shares;
@@ -888,6 +915,41 @@ flatpak_context_merge (FlatpakContext *context,
   while (g_hash_table_iter_next (&iter, &key, &value))
     g_hash_table_insert (context->persistent, g_strdup (key), value);

+  /* We first handle all negative home and host as they override other
+     keys than themselves from the parent */
+  if (g_hash_table_lookup_extended (other->filesystems,
+                                    "host",
+                                    NULL, &value))
+    {
+      FlatpakFilesystemMode host_mode = GPOINTER_TO_INT (value);
+      if (host_mode == FLATPAK_FILESYSTEM_MODE_NONE)
+        no_host = TRUE;
+    }
+
+  if (g_hash_table_lookup_extended (other->filesystems,
+                                    "home",
+                                    NULL, &value))
+    {
+      FlatpakFilesystemMode home_mode = GPOINTER_TO_INT (value);
+      if (home_mode == FLATPAK_FILESYSTEM_MODE_NONE)
+        no_home = TRUE;
+    }
+
+  if (no_host)
+    {
+      g_hash_table_remove_all (context->filesystems);
+    }
+  else if (no_home)
+    {
+      g_hash_table_iter_init (&iter, context->filesystems);
+      while (g_hash_table_iter_next (&iter, &key, &value))
+        {
+          if (flatpak_filesystem_key_in_home ((const char *)key))
+            g_hash_table_iter_remove (&iter);
+        }
+    }
+
+  /* Then set the new ones, which includes propagating the nohost and nohome ones. */
   g_hash_table_iter_init (&iter, other->filesystems);
   while (g_hash_table_iter_next (&iter, &key, &value))
     g_hash_table_insert (context->filesystems, g_strdup (key), value);


@@ -1241,7 +1241,7 @@ GF_Err gf_hinter_finalize(GF_ISOFile *file, GF_SDP_IODProfile IOD_Profile, u32 b
 		if (gf_isom_get_sample_count(file, sceneT)==1) {
 			samp = gf_isom_get_sample(file, sceneT, 1, &descIndex);
 			if (samp && gf_hinter_can_embbed_data(samp->data, samp->dataLength, GF_STREAM_SCENE)) {
-
+				InitSL_NULL(&slc);
 				slc.timeScale = slc.timestampResolution = gf_isom_get_media_timescale(file, sceneT);
 				slc.OCRResolution = 1000;
 				slc.startCTS = samp->DTS+samp->CTS_Offset;


Transaction: Fail the resolve if xa.metadata invalid or missing

If we fail to parse xa.metadata from the summary cache or the commit
xa.metadata we fail the resolve.

If xa.metadata is missing in the commit we fail the resolve (it is
always set in the summary cache, because summary update converts
missing xa.metadata to "", so we either get that, or cache miss which
leads to resolving from the commit.

This means that op->resolved_metadata is always set during install and
updates, which means we will show the app permissions. The transaction
will also always make sure that this data actually matches what gets
deployed.

Before this change an invalid metadata in the summary cache could lead
to a NULL resolved_metadata, which means we wouldn't print the app
permissions, yet we would still deploy some metadata file that could
have permissions. (NOTE: It would fail to deploy unless the
xa.metadata in the commit matched the metadata file, but in this
corner case we would't compare the summary and commit metadata, so
they may differ.)

@@ -2970,12 +2970,13 @@ emit_eol_and_maybe_skip (FlatpakTransaction          *self,
   g_signal_emit (self, signals[END_OF_LIFED_WITH_REBASE], 0, op->remote, flatpak_decomposed_get_ref (op->ref), op->eol, op->eol_rebase, previous_ids, &op->skip);
 }

-static void
+static gboolean
 mark_op_resolved (FlatpakTransactionOperation *op,
                   const char                  *commit,
                   GFile                       *sideload_path,
                   GBytes                      *metadata,
-                  GBytes                      *old_metadata)
+                  GBytes                      *old_metadata,
+                  GError                     **error)
 {
   g_debug ("marking op %s:%s resolved to %s", kind_to_str (op->kind), flatpak_decomposed_get_ref (op->ref), commit ? commit : "-");

@@ -2997,13 +2998,12 @@ mark_op_resolved (FlatpakTransactionOperation *op,
   if (metadata)
     {
       g_autoptr(GKeyFile) metakey = g_key_file_new ();
-      if (g_key_file_load_from_bytes (metakey, metadata, G_KEY_FILE_NONE, NULL))
-        {
-          op->resolved_metadata = g_bytes_ref (metadata);
-          op->resolved_metakey = g_steal_pointer (&metakey);
-        }
-      else
-        g_message ("Warning: Failed to parse metadata for %s\n", flatpak_decomposed_get_ref (op->ref));
+      if (!g_key_file_load_from_bytes (metakey, metadata, G_KEY_FILE_NONE, NULL))
+        return flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA,
+                                   "Metadata for %s is invalid", flatpak_decomposed_get_ref (op->ref));
+
+      op->resolved_metadata = g_bytes_ref (metadata);
+      op->resolved_metakey = g_steal_pointer (&metakey);
     }
   if (old_metadata)
     {
@@ -3014,31 +3014,40 @@ mark_op_resolved (FlatpakTransactionOperation *op,
           op->resolved_old_metakey = g_steal_pointer (&metakey);
         }
       else
-        g_message ("Warning: Failed to parse old metadata for %s\n", flatpak_decomposed_get_ref (op->ref));
+        {
+          /* This shouldn't happen, but a NULL old metadata is safe (all permisssions are considered new) */
+          g_message ("Warning: Failed to parse old metadata for %s\n", flatpak_decomposed_get_ref (op->ref));
+        }
     }
+
+  return TRUE;
 }

-static void
+static gboolean
 resolve_op_end (FlatpakTransaction *self,
                 FlatpakTransactionOperation *op,
                 const char *checksum,
                 GFile *sideload_path,
-                GBytes *metadata_bytes)
+                GBytes *metadata_bytes,
+                GError **error)
 {
   g_autoptr(GBytes) old_metadata_bytes = NULL;

   old_metadata_bytes = load_deployed_metadata (self, op->ref, NULL, NULL);
-  mark_op_resolved (op, checksum, sideload_path, metadata_bytes, old_metadata_bytes);
+  if (!mark_op_resolved (op, checksum, sideload_path, metadata_bytes, old_metadata_bytes, error))
+    return FALSE;
   emit_eol_and_maybe_skip (self, op);
+  return TRUE;
  }

-static void
+static gboolean
 resolve_op_from_commit (FlatpakTransaction *self,
                         FlatpakTransactionOperation *op,
                         const char *checksum,
                         GFile *sideload_path,
-                        GVariant *commit_data)
+                        GVariant *commit_data,
+                        GError **error)
 {
   g_autoptr(GBytes) metadata_bytes = NULL;
   g_autoptr(GVariant) commit_metadata = NULL;
@@ -3049,9 +3058,11 @@ resolve_op_from_commit (FlatpakTransaction *self,
   commit_metadata = g_variant_get_child_value (commit_data, 0);
   g_variant_lookup (commit_metadata, "xa.metadata", "&s", &xa_metadata);
   if (xa_metadata == NULL)
-    g_message ("Warning: No xa.metadata in local commit %s ref %s", checksum, flatpak_decomposed_get_ref (op->ref));
-  else
-    metadata_bytes = g_bytes_new (xa_metadata, strlen (xa_metadata));
+    return flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA,
+                               "No xa.metadata in local commit %s ref %s",
+                               checksum, flatpak_decomposed_get_ref (op->ref));
+
+  metadata_bytes = g_bytes_new (xa_metadata, strlen (xa_metadata));

   if (g_variant_lookup (commit_metadata, "xa.download-size", "t", &download_size))
     op->download_size = GUINT64_FROM_BE (download_size);
@@ -3061,15 +3072,19 @@ resolve_op_from_commit (FlatpakTransaction *self,
   g_variant_lookup (commit_metadata, OSTREE_COMMIT_META_KEY_ENDOFLIFE, "s", &op->eol);
   g_variant_lookup (commit_metadata, OSTREE_COMMIT_META_KEY_ENDOFLIFE_REBASE, "s", &op->eol_rebase);

-  resolve_op_end (self, op, checksum, sideload_path, metadata_bytes);
+  return resolve_op_end (self, op, checksum, sideload_path, metadata_bytes, error);
 }

+/* NOTE: In case of non-available summary this returns FALSE with a
+ * NULL error, but for other error cases it will be set.
+ */
 static gboolean
 try_resolve_op_from_metadata (FlatpakTransaction *self,
                               FlatpakTransactionOperation *op,
                               const char *checksum,
                               GFile *sideload_path,
-                              FlatpakRemoteState *state)
+                              FlatpakRemoteState *state,
+                              GError **error)
 {
   g_autoptr(GBytes) metadata_bytes = NULL;
   guint64 download_size = 0;
@@ -3109,8 +3124,7 @@ try_resolve_op_from_metadata (FlatpakTransaction *self,
       op->token_type = GINT32_FROM_LE (var_metadata_lookup_int32 (sparse_cache, FLATPAK_SPARSE_CACHE_KEY_TOKEN_TYPE, op->token_type));
     }

-  resolve_op_end (self, op, checksum, sideload_path, metadata_bytes);
-  return TRUE;
+  return resolve_op_end (self, op, checksum, sideload_path, metadata_bytes, error);
 }

 static gboolean
@@ -3153,7 +3167,8 @@ resolve_ops (FlatpakTransaction *self,
            * checksum we got was the version already installed.
            */
           g_assert (op->resolved_commit != NULL);
-          mark_op_resolved (op, op->resolved_commit, NULL, NULL, NULL);
+          if (!mark_op_resolved (op, op->resolved_commit, NULL, NULL, NULL, error))
+            return FALSE;
           continue;
         }

@@ -3167,14 +3182,16 @@ resolve_ops (FlatpakTransaction *self,
               op->skip = TRUE;
               continue;
             }
-          mark_op_resolved (op, checksum, NULL, metadata_bytes, NULL);
+          if (!mark_op_resolved (op, checksum, NULL, metadata_bytes, NULL, error))
+            return FALSE;
           continue;
         }

       if (op->kind == FLATPAK_TRANSACTION_OPERATION_INSTALL_BUNDLE)
         {
           g_assert (op->commit != NULL);
-          mark_op_resolved (op, op->commit, NULL, op->external_metadata, NULL);
+          if (!mark_op_resolved (op, op->commit, NULL, op->external_metadata, NULL, error))
+            return FALSE;
           continue;
         }

@@ -3205,7 +3222,8 @@ resolve_ops (FlatpakTransaction *self,
           if (commit_data == NULL)
             return FALSE;

-          resolve_op_from_commit (self, op, checksum, NULL, commit_data);
+          if (!resolve_op_from_commit (self, op, checksum, NULL, commit_data, error))
+            return FALSE;
         }
       else
         {
@@ -3264,9 +3282,16 @@ resolve_ops (FlatpakTransaction *self,
             }

           /* First try to resolve via metadata (if remote is available and its metadata matches the commit version) */
-          if (!try_resolve_op_from_metadata (self, op, checksum, sideload_path, state))
+          if (!try_resolve_op_from_metadata (self, op, checksum, sideload_path, state, &local_error))
             {
-              /* Else try to load the commit object.
+              if (local_error)
+                {
+                  /* Actual error, not just missing from summary */
+                  g_propagate_error (error, g_steal_pointer (&local_error));
+                  return FALSE;
+                }
+
+              /* Missing from summary, try to load the commit object.
                * Note, we don't have a token here, so this will not work for authenticated apps.
                * We handle this by catching the 401 http status and retrying. */
               g_autoptr(GVariant) commit_data = NULL;
@@ -3302,7 +3327,8 @@ resolve_ops (FlatpakTransaction *self,
                   return FALSE;
                 }

-              resolve_op_from_commit (self, op, checksum, sideload_path, commit_data);
+              if (!resolve_op_from_commit (self, op, checksum, sideload_path, commit_data, error))
+                return FALSE;
             }
         }
     }


Merge pull request from GHSA-8fmx-hqw7-6gmc

@@ -754,6 +754,7 @@ static pj_status_t and_media_alloc_codec(pjmedia_codec_factory *factory,
     }
     if (idx == -1) {
 	*p_codec = NULL;
+	pj_mutex_unlock(and_media_factory.mutex);
 	return PJMEDIA_CODEC_EFAILED;
     }


pvrdma: Ensure correct input on ring init (CVE-2021-3607)

Check the guest passed a non zero page count
for pvrdma device ring buffers.

Fixes: CVE-2021-3607
Reported-by: VictorV (Kunlun Lab) <vv474172261@gmail.com>
Reviewed-by: VictorV (Kunlun Lab) <vv474172261@gmail.com>
Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
Message-Id: <20210630114634.2168872-1-marcel@redhat.com>
Reviewed-by: Yuval Shaia <yuval.shaia.ml@gmail.com>
Tested-by: Yuval Shaia <yuval.shaia.ml@gmail.com>
Signed-off-by: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>

@@ -92,6 +92,11 @@ static int init_dev_ring(PvrdmaRing *ring, PvrdmaRingState **ring_state,
     uint64_t *dir, *tbl;
     int rc = 0;

+    if (!num_pages) {
+        rdma_error_report("Ring pages count must be strictly positive");
+        return -EINVAL;
+    }
+
     dir = rdma_pci_dma_map(pci_dev, dir_addr, TARGET_PAGE_SIZE);
     if (!dir) {
         rdma_error_report("Failed to map to page directory (ring %s)", name);


Fix DoS in PE/QNX/DYLDCACHE/PSX parsers ##crash

* Reported by lazymio
* Reproducer: AAA4AAAAAB4=

@@ -7,7 +7,7 @@ static int lmf_header_load(lmf_header *lmfh, RBuffer *buf, Sdb *db) {
 	if (r_buf_size (buf) < sizeof (lmf_header)) {
 		return false;
 	}
-	if (r_buf_fread_at (buf, QNX_HEADER_ADDR, (ut8 *) lmfh, "iiiiiiiicccciiiicc", 1) < QNX_HDR_SIZE) {
+	if (r_buf_fread_at (buf, QNX_HEADER_ADDR, (ut8 *) lmfh, "iiiiiiiicccciiiicc", 1) != QNX_HDR_SIZE) {
 		return false;
 	}
 	r_strf_buffer (32);
@@ -64,15 +64,15 @@ static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *buf, ut64 loadadd
 		goto beach;
 	}
 	// Read the first record
-	if (r_buf_fread_at (bf->buf, 0, (ut8 *)&lrec, "ccss", 1) < QNX_RECORD_SIZE) {
+	if (r_buf_fread_at (bf->buf, 0, (ut8 *)&lrec, "ccss", 1) != QNX_RECORD_SIZE) {
 		goto beach;
 	}
 	// Load the header
 	lmf_header_load (&qo->lmfh, bf->buf, qo->kv);
 	offset += lrec.data_nbytes;

 	for (;;) {
-		if (r_buf_fread_at (bf->buf, offset, (ut8 *)&lrec, "ccss", 1) < QNX_RECORD_SIZE) {
+		if (r_buf_fread_at (bf->buf, offset, (ut8 *)&lrec, "ccss", 1) != QNX_RECORD_SIZE) {
 			goto beach;
 		}
 		offset += sizeof (lmf_record);
@@ -84,7 +84,7 @@ static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *buf, ut64 loadadd
 			if (!ptr) {
 				goto beach;
 			}
-			if (r_buf_fread_at (bf->buf, offset, (ut8 *)&lres, "ssss", 1) < sizeof (lmf_resource)) {
+			if (r_buf_fread_at (bf->buf, offset, (ut8 *)&lres, "ssss", 1) != sizeof (lmf_resource)) {
 				goto beach;
 			}
 			ptr->name = strdup ("LMF_RESOURCE");
@@ -95,7 +95,7 @@ static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *buf, ut64 loadadd
 		 	r_list_append (sections, ptr);
 		} else if (lrec.rec_type == LMF_LOAD_REC) {
 			RBinSection *ptr = R_NEW0 (RBinSection);
-			if (r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) < sizeof (lmf_data)) {
+			if (r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) != sizeof (lmf_data)) {
 				goto beach;
 			}
 			if (!ptr) {
@@ -110,15 +110,15 @@ static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *buf, ut64 loadadd
 		 	r_list_append (sections, ptr);
 		} else if (lrec.rec_type == LMF_FIXUP_REC) {
 			RBinReloc *ptr = R_NEW0 (RBinReloc);
-			if (!ptr || r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) < sizeof (lmf_data)) {
+			if (!ptr || r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) != sizeof (lmf_data)) {
 				goto beach;
 			}
 			ptr->vaddr = ptr->paddr = ldata.offset;
 			ptr->type = 'f'; // "LMF_FIXUP";
 			r_list_append (fixups, ptr);
 		} else if (lrec.rec_type == LMF_8087_FIXUP_REC) {
 			RBinReloc *ptr = R_NEW0 (RBinReloc);
-			if (!ptr || r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) < sizeof (lmf_data)) {
+			if (!ptr || r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) != sizeof (lmf_data)) {
 				goto beach;
 			}
 			ptr->vaddr = ptr->paddr = ldata.offset;


chsh, chfn: remove readline support [CVE-2022-0563]

The readline library uses INPUTRC= environment variable to get a path
to the library config file. When the library cannot parse the
specified file, it prints an error message containing data from the
file.

Unfortunately, the library does not use secure_getenv() (or a similar
concept) to avoid vulnerabilities that could occur if set-user-ID or
set-group-ID programs.

Reported-by: Rory Mackie <rory.mackie@trailofbits.com>
Signed-off-by: Karel Zak <kzak@redhat.com>

@@ -56,11 +56,6 @@
 # include "auth.h"
 #endif

-#ifdef HAVE_LIBREADLINE
-# define _FUNCTION_DEF
-# include <readline/readline.h>
-#endif
-
 struct finfo {
 	char *full_name;
 	char *office;
@@ -228,24 +223,21 @@ static char *ask_new_field(struct chfn_control *ctl, const char *question,
 {
 	int len;
 	char *buf = NULL; /* leave initialized to NULL or getline segfaults */
-#ifndef HAVE_LIBREADLINE
 	size_t dummy = 0;
-#endif

 	if (!def_val)
 		def_val = "";
+
 	while (true) {
 		printf("%s [%s]:", question, def_val);
 		__fpurge(stdin);
-#ifdef HAVE_LIBREADLINE
-		rl_bind_key('\t', rl_insert);
-		if ((buf = readline(" ")) == NULL)
-#else
+
 		putchar(' ');
 		fflush(stdout);
+
 		if (getline(&buf, &dummy, stdin) < 0)
-#endif
 			errx(EXIT_FAILURE, _("Aborted."));
+
 		/* remove white spaces from string end */
 		ltrim_whitespace((unsigned char *) buf);
 		len = rtrim_whitespace((unsigned char *) buf);


vm.c: packed arguments length may be zero for `send` method.

@@ -689,9 +689,11 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
   regs = mrb->c->ci->stack+1;

   if (n == 0) {
+  argnum_error:
     mrb_argnum_error(mrb, 0, 1, -1);
   }
   else if (n == 15) {
+    if (RARRAY_LEN(regs[0]) == 0) goto argnum_error;
     name = mrb_obj_to_sym(mrb, RARRAY_PTR(regs[0])[0]);
   }
   else {


Fixed type confusion bug while resolving promises.

Previously, the internal function njs_promise_perform_then() which
implements PerformPromiseThen() expects its first argument to always be
a promise instance.  This assertion might be invalid because the
functions corresponding to Promise.prototype.then() and
Promise.resolve() incorrectly verified their arguments.

Specifically, the functions recognized their first argument as promise
if it was an object which was an Promise or had Promise object in its
prototype chain.  The later condition is not correct because internal
slots are not inherited according to the spec.

This closes #447 issue in Github.

@@ -771,25 +771,19 @@ njs_promise_resolve(njs_vm_t *vm, njs_value_t *constructor, njs_value_t *x)
 {
     njs_int_t                 ret;
     njs_value_t               value;
-    njs_object_t              *object;
     njs_promise_capability_t  *capability;

     static const njs_value_t  string_constructor = njs_string("constructor");

-    if (njs_is_object(x)) {
-        object = njs_object_proto_lookup(njs_object(x), NJS_PROMISE,
-                                         njs_object_t);
-
-        if (object != NULL) {
-            ret = njs_value_property(vm, x, njs_value_arg(&string_constructor),
-                                     &value);
-            if (njs_slow_path(ret == NJS_ERROR)) {
-                return NULL;
-            }
+    if (njs_is_promise(x)) {
+        ret = njs_value_property(vm, x, njs_value_arg(&string_constructor),
+                                 &value);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return NULL;
+        }

-            if (njs_values_same(&value, constructor)) {
-                return njs_promise(x);
-            }
+        if (njs_values_same(&value, constructor)) {
+            return njs_promise(x);
         }
     }

@@ -875,19 +869,12 @@ njs_promise_prototype_then(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 {
     njs_int_t                 ret;
     njs_value_t               *promise, *fulfilled, *rejected, constructor;
-    njs_object_t              *object;
     njs_function_t            *function;
     njs_promise_capability_t  *capability;

     promise = njs_argument(args, 0);

-    if (njs_slow_path(!njs_is_object(promise))) {
-        goto failed;
-    }
-
-    object = njs_object_proto_lookup(njs_object(promise), NJS_PROMISE,
-                                     njs_object_t);
-    if (njs_slow_path(object == NULL)) {
+    if (njs_slow_path(!njs_is_promise(promise))) {
         goto failed;
     }

@@ -933,6 +920,8 @@ njs_promise_perform_then(njs_vm_t *vm, njs_value_t *value,
     njs_promise_data_t      *data;
     njs_promise_reaction_t  *fulfilled_reaction, *rejected_reaction;

+    njs_assert(njs_is_promise(value));
+
     if (!njs_is_function(fulfilled)) {
         fulfilled = njs_value_arg(&njs_value_undefined);
     }


Fixed recursive async function calls.

Previously, PromiseCapability record was stored (function->context)
directly in function object during a function invocation.  This is
not correct, because PromiseCapability record should be linked to
current execution context.  As a result, function->context is
overwritten with consecutive recursive calls which results in
use-after-free.

This closes #451 issue on Github.

@@ -490,7 +490,7 @@ njs_vm_start(njs_vm_t *vm)
         return ret;
     }

-    ret = njs_vmcode_interpreter(vm, vm->start);
+    ret = njs_vmcode_interpreter(vm, vm->start, NULL, NULL);

     return (ret == NJS_ERROR) ? NJS_ERROR : NJS_OK;
 }


usb: gadget: clear related members when goto fail

dev->config and dev->hs_config and dev->dev need to be cleaned if
dev_config fails to avoid UAF.

Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Hangyu Hua <hbh25y@gmail.com>
Link: https://lore.kernel.org/r/20211231172138.7993-3-hbh25y@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

@@ -1875,8 +1875,8 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)

 	value = usb_gadget_probe_driver(&gadgetfs_driver);
 	if (value != 0) {
-		kfree (dev->buf);
-		dev->buf = NULL;
+		spin_lock_irq(&dev->lock);
+		goto fail;
 	} else {
 		/* at this point "good" hardware has for the first time
 		 * let the USB the host see us.  alternatively, if users
@@ -1893,6 +1893,9 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 	return value;

 fail:
+	dev->config = NULL;
+	dev->hs_config = NULL;
+	dev->dev = NULL;
 	spin_unlock_irq (&dev->lock);
 	pr_debug ("%s: %s fail %zd, %p\n", shortname, __func__, value, dev);
 	kfree (dev->buf);


Prevent stack overflow when FunctionLib in GraphDef has a self-recursive function.

It is likely that no recursivity is supported, but we should handle this separately.

PiperOrigin-RevId: 414860329
Change-Id: I02a2270e86282b37362ddd485eeef16fb986a9e0

@@ -25,6 +25,7 @@ limitations under the License.
 #include "tensorflow/core/framework/attr_value.pb.h"
 #include "tensorflow/core/framework/function.pb.h"
 #include "tensorflow/core/framework/node_def.pb.h"
+#include "tensorflow/core/framework/op_def.pb.h"
 #include "tensorflow/core/framework/tensor.pb.h"
 #include "tensorflow/core/lib/io/path.h"
 #include "tensorflow/core/lib/monitoring/counter.h"
@@ -99,6 +100,19 @@ static Status ValidateNode(const NodeDef& node) {
   return Status::OK();
 }

+static Status ValidateFunctionNotRecursive(const FunctionDef& function) {
+  const auto& function_name = function.signature().name();
+  for (const auto& node : function.node_def()) {
+    if (node.op() == function_name) {
+      return errors::FailedPrecondition(
+          "Function ", function_name,
+          " is self recursive and TensorFlow does not support this scenario.");
+    }
+  }
+
+  return Status::OK();
+}
+
 static Status ValidateSavedTensors(const GraphDef& graph_def) {
   for (const auto& node : graph_def.node()) {
     TF_RETURN_IF_ERROR(ValidateNode(node));
@@ -110,6 +124,10 @@ static Status ValidateSavedTensors(const GraphDef& graph_def) {
       for (const auto& node : function.node_def()) {
         TF_RETURN_IF_ERROR(ValidateNode(node));
       }
+
+      // Also check that there is no recursivity in the library
+      // TODO(mihaimaruseac): Do more than self-recursivity
+      TF_RETURN_IF_ERROR(ValidateFunctionNotRecursive(function));
     }
   }


bpf: Fix kernel address leakage in atomic fetch

The change in commit 37086bfdc737 ("bpf: Propagate stack bounds to registers
in atomics w/ BPF_FETCH") around check_mem_access() handling is buggy since
this would allow for unprivileged users to leak kernel pointers. For example,
an atomic fetch/and with -1 on a stack destination which holds a spilled
pointer will migrate the spilled register type into a scalar, which can then
be exported out of the program (since scalar != pointer) by dumping it into
a map value.

The original implementation of XADD was preventing this situation by using
a double call to check_mem_access() one with BPF_READ and a subsequent one
with BPF_WRITE, in both cases passing -1 as a placeholder value instead of
register as per XADD semantics since it didn't contain a value fetch. The
BPF_READ also included a check in check_stack_read_fixed_off() which rejects
the program if the stack slot is of __is_pointer_value() if dst_regno < 0.
The latter is to distinguish whether we're dealing with a regular stack spill/
fill or some arithmetical operation which is disallowed on non-scalars, see
also 6e7e63cbb023 ("bpf: Forbid XADD on spilled pointers for unprivileged
users") for more context on check_mem_access() and its handling of placeholder
value -1.

One minimally intrusive option to fix the leak is for the BPF_FETCH case to
initially check the BPF_READ case via check_mem_access() with -1 as register,
followed by the actual load case with non-negative load_reg to propagate
stack bounds to registers.

Fixes: 37086bfdc737 ("bpf: Propagate stack bounds to registers in atomics w/ BPF_FETCH")
Reported-by: <n4ke4mry@gmail.com>
Acked-by: Brendan Jackman <jackmanb@google.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

@@ -4584,13 +4584,19 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i
 		load_reg = -1;
 	}

-	/* check whether we can read the memory */
+	/* Check whether we can read the memory, with second call for fetch
+	 * case to simulate the register fill.
+	 */
 	err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
-			       BPF_SIZE(insn->code), BPF_READ, load_reg, true);
+			       BPF_SIZE(insn->code), BPF_READ, -1, true);
+	if (!err && load_reg >= 0)
+		err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
+				       BPF_SIZE(insn->code), BPF_READ, load_reg,
+				       true);
 	if (err)
 		return err;

-	/* check whether we can write into the same memory */
+	/* Check whether we can write into the same memory. */
 	err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
 			       BPF_SIZE(insn->code), BPF_WRITE, -1, true);
 	if (err)


postpone stream shutdown by H3 frame parsers

@@ -178,7 +178,7 @@ struct st_h2o_http3_server_stream_t {
     struct {
         h2o_buffer_t *buf;
         int (*handle_input)(struct st_h2o_http3_server_stream_t *stream, const uint8_t **src, const uint8_t *src_end,
-                            const char **err_desc);
+                            int in_generator, const char **err_desc);
         uint64_t bytes_left_in_data_frame;
     } recvbuf;
     struct {
@@ -244,9 +244,9 @@ struct st_h2o_http3_server_stream_t {
 static void on_stream_destroy(quicly_stream_t *qs, int err);
 static int retain_sendvecs(struct st_h2o_http3_server_stream_t *stream);
 static int handle_input_post_trailers(struct st_h2o_http3_server_stream_t *stream, const uint8_t **src, const uint8_t *src_end,
-                                      const char **err_desc);
+                                      int in_generator, const char **err_desc);
 static int handle_input_expect_data(struct st_h2o_http3_server_stream_t *stream, const uint8_t **src, const uint8_t *src_end,
-                                    const char **err_desc);
+                                    int in_generator, const char **err_desc);
 static void tunnel_write(struct st_h2o_http3_server_stream_t *stream);
 static void tunnel_write_delayed(h2o_timer_t *timer);

@@ -834,7 +834,7 @@ static void handle_buffered_input(struct st_h2o_http3_server_stream_t *stream, i
         while (src != src_end) {
             int err;
             const char *err_desc = NULL;
-            if ((err = stream->recvbuf.handle_input(stream, &src, src_end, &err_desc)) != 0) {
+            if ((err = stream->recvbuf.handle_input(stream, &src, src_end, in_generator, &err_desc)) != 0) {
                 if (err == H2O_HTTP3_ERROR_INCOMPLETE) {
                     if (!quicly_recvstate_transfer_complete(&stream->quic->recvstate))
                         break;
@@ -1036,7 +1036,7 @@ static void run_delayed(h2o_timer_t *timer)
 }

 int handle_input_post_trailers(struct st_h2o_http3_server_stream_t *stream, const uint8_t **src, const uint8_t *src_end,
-                               const char **err_desc)
+                               int in_generator, const char **err_desc)
 {
     h2o_http3_read_frame_t frame;
     int ret;
@@ -1056,7 +1056,7 @@ int handle_input_post_trailers(struct st_h2o_http3_server_stream_t *stream, cons
 }

 static int handle_input_expect_data_payload(struct st_h2o_http3_server_stream_t *stream, const uint8_t **src,
-                                            const uint8_t *src_end, const char **err_desc)
+                                            const uint8_t *src_end, int in_generator, const char **err_desc)
 {
     size_t bytes_avail = src_end - *src;

@@ -1079,7 +1079,7 @@ static int handle_input_expect_data_payload(struct st_h2o_http3_server_stream_t
 }

 int handle_input_expect_data(struct st_h2o_http3_server_stream_t *stream, const uint8_t **src, const uint8_t *src_end,
-                             const char **err_desc)
+                             int in_generator, const char **err_desc)
 {
     h2o_http3_read_frame_t frame;
     int ret;
@@ -1102,7 +1102,7 @@ int handle_input_expect_data(struct st_h2o_http3_server_stream_t *stream, const
             stream->req.content_length - stream->req.req_body_bytes_received < frame.length) {
             /* The only viable option here is to reset the stream, as we might have already started streaming the request body
              * upstream. This behavior is consistent with what we do in HTTP/2. */
-            shutdown_stream(stream, H2O_HTTP3_ERROR_EARLY_RESPONSE, H2O_HTTP3_ERROR_GENERAL_PROTOCOL, 0);
+            shutdown_stream(stream, H2O_HTTP3_ERROR_EARLY_RESPONSE, H2O_HTTP3_ERROR_GENERAL_PROTOCOL, in_generator);
             return 0;
         }
         break;
@@ -1134,8 +1134,10 @@ static int handle_input_expect_headers_send_http_error(struct st_h2o_http3_serve
 }

 static int handle_input_expect_headers(struct st_h2o_http3_server_stream_t *stream, const uint8_t **src, const uint8_t *src_end,
-                                       const char **err_desc)
+                                       int in_generator, const char **err_desc)
 {
+    assert(!in_generator); /* this function is processing headers (before generators get assigned), not trailers */
+
     struct st_h2o_http3_server_conn_t *conn = get_conn(stream);
     h2o_http3_read_frame_t frame;
     int header_exists_map = 0, ret;


drm/i915: Flush TLBs before releasing backing store

We need to flush TLBs before releasing backing store otherwise userspace
is able to encounter stale entries if a) it is not declaring access to
certain buffers and b) it races with the backing store release from a
such undeclared execution already executing on the GPU in parallel.

The approach taken is to mark any buffer objects which were ever bound
to the GPU and to trigger a serialized TLB flush when their backing
store is released.

Alternatively the flushing could be done on VMA unbind, at which point
we would be able to ascertain whether there is potential a parallel GPU
execution (which could race), but essentially it boils down to paying
the cost of TLB flushes potentially needlessly at VMA unbind time (when
the backing store is not known to be going away so not needed for
safety), versus potentially needlessly at backing store relase time
(since we at that point cannot tell whether there is anything executing
on the GPU which uses that object).

Thereforce simplicity of implementation has been chosen for now with
scope to benchmark and refine later as required.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reported-by: Sushma Venkatesh Reddy <sushma.venkatesh.reddy@intel.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Acked-by: Dave Airlie <airlied@redhat.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Jon Bloomfield <jon.bloomfield@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Jani Nikula <jani.nikula@intel.com>
Cc: stable@vger.kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

@@ -73,6 +73,8 @@ struct intel_gt {

 	struct intel_uc uc;

+	struct mutex tlb_invalidate_lock;
+
 	struct i915_wa_list wa_list;

 	struct intel_gt_timelines {


Fix a bug that can crash deflate on some input when using Z_FIXED.

This bug was reported by Danilo Ramos of Eideticom, Inc. It has
lain in wait 13 years before being found! The bug was introduced
in zlib 1.2.2.2, with the addition of the Z_FIXED option. That
option forces the use of fixed Huffman codes. For rare inputs with
a large number of distant matches, the pending buffer into which
the compressed data is written can overwrite the distance symbol
table which it overlays. That results in corrupted output due to
invalid distances, and can result in out-of-bound accesses,
crashing the application.

The fix here combines the distance buffer and literal/length
buffers into a single symbol buffer. Now three bytes of pending
buffer space are opened up for each literal or length/distance
pair consumed, instead of the previous two bytes. This assures
that the pending buffer cannot overwrite the symbol table, since
the maximum fixed code compressed length/distance is 31 bits, and
since there are four bytes of pending space for every three bytes
of symbol space.

@@ -416,7 +416,7 @@ local void init_block(s)

     s->dyn_ltree[END_BLOCK].Freq = 1;
     s->opt_len = s->static_len = 0L;
-    s->last_lit = s->matches = 0;
+    s->sym_next = s->matches = 0;
 }

 #define SMALLEST 1
@@ -948,7 +948,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)

         Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
                 opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
-                s->last_lit));
+                s->sym_next / 3));

         if (static_lenb <= opt_lenb) opt_lenb = static_lenb;

@@ -1017,8 +1017,9 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc)
     unsigned dist;  /* distance of matched string */
     unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
 {
-    s->d_buf[s->last_lit] = (ush)dist;
-    s->l_buf[s->last_lit++] = (uch)lc;
+    s->sym_buf[s->sym_next++] = dist;
+    s->sym_buf[s->sym_next++] = dist >> 8;
+    s->sym_buf[s->sym_next++] = lc;
     if (dist == 0) {
         /* lc is the unmatched char */
         s->dyn_ltree[lc].Freq++;
@@ -1033,30 +1034,7 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc)
         s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
         s->dyn_dtree[d_code(dist)].Freq++;
     }
-
-#ifdef TRUNCATE_BLOCK
-    /* Try to guess if it is profitable to stop the current block here */
-    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
-        /* Compute an upper bound for the compressed length */
-        ulg out_length = (ulg)s->last_lit*8L;
-        ulg in_length = (ulg)((long)s->strstart - s->block_start);
-        int dcode;
-        for (dcode = 0; dcode < D_CODES; dcode++) {
-            out_length += (ulg)s->dyn_dtree[dcode].Freq *
-                (5L+extra_dbits[dcode]);
-        }
-        out_length >>= 3;
-        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
-               s->last_lit, in_length, out_length,
-               100L - out_length*100L/in_length));
-        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
-    }
-#endif
-    return (s->last_lit == s->lit_bufsize-1);
-    /* We avoid equality with lit_bufsize because of wraparound at 64K
-     * on 16 bit machines and because stored blocks are restricted to
-     * 64K-1 bytes.
-     */
+    return (s->sym_next == s->sym_end);
 }

 /* ===========================================================================
@@ -1069,13 +1047,14 @@ local void compress_block(s, ltree, dtree)
 {
     unsigned dist;      /* distance of matched string */
     int lc;             /* match length or unmatched char (if dist == 0) */
-    unsigned lx = 0;    /* running index in l_buf */
+    unsigned sx = 0;    /* running index in sym_buf */
     unsigned code;      /* the code to send */
     int extra;          /* number of extra bits to send */

-    if (s->last_lit != 0) do {
-        dist = s->d_buf[lx];
-        lc = s->l_buf[lx++];
+    if (s->sym_next != 0) do {
+        dist = s->sym_buf[sx++] & 0xff;
+        dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8;
+        lc = s->sym_buf[sx++];
         if (dist == 0) {
             send_code(s, lc, ltree); /* send a literal byte */
             Tracecv(isgraph(lc), (stderr," '%c' ", lc));
@@ -1100,11 +1079,10 @@ local void compress_block(s, ltree, dtree)
             }
         } /* literal or match pair ? */

-        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
-        Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
-               "pendingBuf overflow");
+        /* Check that the overlay between pending_buf and sym_buf is ok: */
+        Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow");

-    } while (lx < s->last_lit);
+    } while (sx < s->sym_next);

     send_code(s, END_BLOCK, ltree);
 }


Fix UAF in aaaa on arm/thumb switching ##crash

* Reported by @peacock-doris via huntr.dev
* Reproducer tests_65185
* This is a logic fix, but not the fully safe as changes in the code
  can result on UAF again, to properly protect r2 from crashing we
  need to break the ABI and add refcounting to RRegItem, which can't
  happen in 5.6.x because of abi-compat rules

@@ -1048,7 +1048,7 @@ static void extract_arg(RAnal *anal, RAnalFunction *fcn, RAnalOp *op, const char
 		free (vartype);
 	} else {
 		st64 frame_off = -(ptr + fcn->bp_off);
-		if (maxstackframe != 0 && (frame_off > maxstackframe || frame_off < -maxstackframe)) {
+		if (maxstackframe > 0 && (frame_off > maxstackframe || frame_off < -maxstackframe)) {
 			goto beach;
 		}
 		RAnalVar *var = get_stack_var (fcn, frame_off);


patch 8.2.4563: "z=" in Visual mode may go beyond the end of the line

Problem:    "z=" in Visual mode may go beyond the end of the line.
Solution:   Adjust "badlen".

@@ -750,6 +750,8 @@ static char *(features[]) =

 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4563,
 /**/
     4562,
 /**/


shared/gatt-server: Fix heap overflow when appending prepare writes

The code shall check if the prepare writes would append more the
allowed maximum attribute length.

Fixes https://github.com/bluez/bluez/security/advisories/GHSA-479m-xcq5-9g2q

@@ -779,6 +779,20 @@ static uint8_t authorize_req(struct bt_gatt_server *server,
 						server->authorize_data);
 }

+static uint8_t check_length(uint16_t length, uint16_t offset)
+{
+	if (length > BT_ATT_MAX_VALUE_LEN)
+		return BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
+
+	if (offset > BT_ATT_MAX_VALUE_LEN)
+		return BT_ATT_ERROR_INVALID_OFFSET;
+
+	if (length + offset > BT_ATT_MAX_VALUE_LEN)
+		return BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
+
+	return 0;
+}
+
 static void write_cb(struct bt_att_chan *chan, uint8_t opcode, const void *pdu,
 					uint16_t length, void *user_data)
 {
@@ -809,6 +823,10 @@ static void write_cb(struct bt_att_chan *chan, uint8_t opcode, const void *pdu,
 				(opcode == BT_ATT_OP_WRITE_REQ) ? "Req" : "Cmd",
 				handle);

+	ecode = check_length(length, 0);
+	if (ecode)
+		goto error;
+
 	ecode = check_permissions(server, attr, BT_ATT_PERM_WRITE_MASK);
 	if (ecode)
 		goto error;
@@ -1299,6 +1317,10 @@ static void prep_write_cb(struct bt_att_chan *chan, uint8_t opcode,
 	util_debug(server->debug_callback, server->debug_data,
 				"Prep Write Req - handle: 0x%04x", handle);

+	ecode = check_length(length, offset);
+	if (ecode)
+		goto error;
+
 	ecode = check_permissions(server, attr, BT_ATT_PERM_WRITE_MASK);
 	if (ecode)
 		goto error;


nfc: st21nfca: Fix potential buffer overflows in EVT_TRANSACTION

It appears that there are some buffer overflows in EVT_TRANSACTION.
This happens because the length parameters that are passed to memcpy
come directly from skb->data and are not guarded in any way.

Signed-off-by: Jordy Zomer <jordy@pwning.systems>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

@@ -316,6 +316,11 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
 			return -ENOMEM;

 		transaction->aid_len = skb->data[1];
+
+		/* Checking if the length of the AID is valid */
+		if (transaction->aid_len > sizeof(transaction->aid))
+			return -EINVAL;
+
 		memcpy(transaction->aid, &skb->data[2],
 		       transaction->aid_len);

@@ -325,6 +330,11 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
 			return -EPROTO;

 		transaction->params_len = skb->data[transaction->aid_len + 3];
+
+		/* Total size is allocated (skb->len - 2) minus fixed array members */
+		if (transaction->params_len > ((skb->len - 2) - sizeof(struct nfc_evt_transaction)))
+			return -EINVAL;
+
 		memcpy(transaction->params, skb->data +
 		       transaction->aid_len + 4, transaction->params_len);


Merge pull request #10494 from whichbug/fix#10487

babeld: add a check for truncated packets

@@ -288,13 +288,18 @@ channels_len(unsigned char *channels)
 static int
 babel_packet_examin(const unsigned char *packet, int packetlen)
 {
-    unsigned i = 0, bodylen;
+    int i = 0, bodylen;
     const unsigned char *message;
     unsigned char type, len;

     if(packetlen < 4 || packet[0] != 42 || packet[1] != 2)
         return 1;
     DO_NTOHS(bodylen, packet + 2);
+    if(bodylen + 4 > packetlen) {
+        debugf(BABEL_DEBUG_COMMON, "Received truncated packet (%d + 4 > %d).",
+                 bodylen, packetlen);
+        return 1;
+    }
     while (i < bodylen){
         message = packet + 4 + i;
         type = message[0];
@@ -366,12 +371,6 @@ parse_packet(const unsigned char *from, struct interface *ifp,

     DO_NTOHS(bodylen, packet + 2);

-    if(bodylen + 4 > packetlen) {
-        flog_err(EC_BABEL_PACKET, "Received truncated packet (%d + 4 > %d).",
-                 bodylen, packetlen);
-        bodylen = packetlen - 4;
-    }
-
     i = 0;
     while(i < bodylen) {
         message = packet + 4 + i;